mirror of https://github.com/xemu-project/xemu.git
Merge remote-tracking branch 'origin/master' into xbox
Conflicts: qemu-config.c
This commit is contained in:
commit
cdcbc81ad8
|
@ -19,3 +19,6 @@
|
|||
[submodule "roms/sgabios"]
|
||||
path = roms/sgabios
|
||||
url = git://git.qemu.org/sgabios.git
|
||||
[submodule "pixman"]
|
||||
path = pixman
|
||||
url = git://anongit.freedesktop.org/pixman
|
||||
|
|
16
Makefile
16
Makefile
|
@ -118,6 +118,15 @@ endif
|
|||
|
||||
subdir-libcacard: $(oslib-obj-y) $(trace-obj-y) qemu-timer-common.o
|
||||
|
||||
subdir-pixman: pixman/Makefile
|
||||
$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C pixman V="$(V)" all,)
|
||||
|
||||
pixman/Makefile: $(SRC_PATH)/pixman/configure
|
||||
(cd pixman; $(SRC_PATH)/pixman/configure --disable-shared --enable-static)
|
||||
|
||||
$(SRC_PATH)/pixman/configure:
|
||||
(cd $(SRC_PATH)/pixman; autoreconf -v --install)
|
||||
|
||||
$(filter %-softmmu,$(SUBDIR_RULES)): $(universal-obj-y) $(trace-obj-y) $(common-obj-y) $(extra-obj-y) subdir-libdis
|
||||
|
||||
$(filter %-user,$(SUBDIR_RULES)): $(universal-obj-y) $(trace-obj-y) subdir-libdis-user subdir-libuser
|
||||
|
@ -171,8 +180,7 @@ endif
|
|||
qemu-img.o: qemu-img-cmds.h
|
||||
|
||||
tools-obj-y = $(oslib-obj-y) $(trace-obj-y) qemu-tool.o qemu-timer.o \
|
||||
qemu-timer-common.o main-loop.o notify.o \
|
||||
iohandler.o cutils.o iov.o async.o error.o
|
||||
main-loop.o iohandler.o error.o
|
||||
tools-obj-$(CONFIG_POSIX) += compatfd.o
|
||||
|
||||
qemu-img$(EXESUF): qemu-img.o $(tools-obj-y) $(block-obj-y)
|
||||
|
@ -181,7 +189,7 @@ qemu-io$(EXESUF): qemu-io.o cmd.o $(tools-obj-y) $(block-obj-y)
|
|||
|
||||
qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o
|
||||
|
||||
vscclient$(EXESUF): $(libcacard-y) $(oslib-obj-y) $(trace-obj-y) $(tools-obj-y) qemu-timer-common.o libcacard/vscclient.o
|
||||
vscclient$(EXESUF): $(libcacard-y) $(oslib-obj-y) $(trace-obj-y) libcacard/vscclient.o
|
||||
$(call quiet-command,$(CC) $(LDFLAGS) -o $@ $^ $(libcacard_libs) $(LIBS)," LINK $@")
|
||||
|
||||
fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/virtio-9p-marshal.o oslib-posix.o $(trace-obj-y)
|
||||
|
@ -224,7 +232,7 @@ $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
|
|||
QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h)
|
||||
$(qga-obj-y) qemu-ga.o: $(QGALIB_GEN)
|
||||
|
||||
qemu-ga$(EXESUF): qemu-ga.o $(qga-obj-y) $(tools-obj-y) $(qapi-obj-y) $(qobject-obj-y) $(version-obj-y)
|
||||
qemu-ga$(EXESUF): qemu-ga.o $(qga-obj-y) $(oslib-obj-y) $(trace-obj-y) $(qapi-obj-y) $(qobject-obj-y) $(version-obj-y)
|
||||
|
||||
QEMULIBS=libuser libdis libdis-user
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ universal-obj-y += $(qom-obj-y)
|
|||
|
||||
#######################################################################
|
||||
# oslib-obj-y is code depending on the OS (win32 vs posix)
|
||||
oslib-obj-y = osdep.o
|
||||
oslib-obj-y = osdep.o cutils.o qemu-timer-common.o
|
||||
oslib-obj-$(CONFIG_WIN32) += oslib-win32.o qemu-thread-win32.o
|
||||
oslib-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-thread-posix.o
|
||||
|
||||
|
@ -41,12 +41,12 @@ 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 iov.o cache-utils.o qemu-option.o module.o async.o
|
||||
block-obj-y += nbd.o block.o blockjob.o aio.o aes.o qemu-config.o
|
||||
block-obj-y += qemu-progress.o qemu-sockets.o uri.o notify.o
|
||||
block-obj-y = iov.o cache-utils.o qemu-option.o module.o async.o
|
||||
block-obj-y += nbd.o block.o blockjob.o aes.o qemu-config.o
|
||||
block-obj-y += thread-pool.o qemu-progress.o qemu-sockets.o uri.o notify.o
|
||||
block-obj-y += $(coroutine-obj-y) $(qobject-obj-y) $(version-obj-y)
|
||||
block-obj-$(CONFIG_POSIX) += posix-aio-compat.o
|
||||
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
|
||||
block-obj-$(CONFIG_POSIX) += event_notifier-posix.o aio-posix.o
|
||||
block-obj-$(CONFIG_WIN32) += event_notifier-win32.o aio-win32.o
|
||||
block-obj-y += block/
|
||||
block-obj-y += $(qapi-obj-y) qapi-types.o qapi-visit.o
|
||||
|
||||
|
@ -65,6 +65,7 @@ common-obj-y = $(block-obj-y) blockdev.o blockdev-nbd.o block/
|
|||
common-obj-y += net.o net/
|
||||
common-obj-y += qom/
|
||||
common-obj-y += readline.o console.o cursor.o
|
||||
common-obj-y += qemu-pixman.o
|
||||
common-obj-y += $(oslib-obj-y)
|
||||
common-obj-$(CONFIG_WIN32) += os-win32.o
|
||||
common-obj-$(CONFIG_POSIX) += os-posix.o
|
||||
|
@ -92,9 +93,8 @@ common-obj-y += ui/
|
|||
common-obj-y += bt-host.o bt-vhci.o
|
||||
|
||||
common-obj-y += dma-helpers.o
|
||||
common-obj-y += iov.o acl.o
|
||||
common-obj-y += acl.o
|
||||
common-obj-$(CONFIG_POSIX) += compatfd.o
|
||||
common-obj-y += event_notifier.o
|
||||
common-obj-y += qemu-timer.o qemu-timer-common.o
|
||||
common-obj-y += qtest.o
|
||||
common-obj-y += vl.o
|
||||
|
@ -113,7 +113,7 @@ endif
|
|||
user-obj-y =
|
||||
user-obj-y += envlist.o path.o
|
||||
user-obj-y += tcg-runtime.o host-utils.o
|
||||
user-obj-y += cutils.o iov.o cache-utils.o
|
||||
user-obj-y += cache-utils.o
|
||||
user-obj-y += module.o
|
||||
user-obj-y += qemu-user.o
|
||||
user-obj-y += $(trace-obj-y)
|
||||
|
@ -228,9 +228,8 @@ universal-obj-y += $(qapi-obj-y)
|
|||
######################################################################
|
||||
# guest agent
|
||||
|
||||
qga-obj-y = qga/ qemu-ga.o module.o
|
||||
qga-obj-$(CONFIG_WIN32) += oslib-win32.o
|
||||
qga-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-sockets.o qemu-option.o
|
||||
qga-obj-y = qga/ qemu-ga.o module.o qemu-tool.o
|
||||
qga-obj-$(CONFIG_POSIX) += qemu-sockets.o qemu-option.o
|
||||
|
||||
vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
|
||||
|
||||
|
|
|
@ -0,0 +1,268 @@
|
|||
/*
|
||||
* QEMU aio implementation
|
||||
*
|
||||
* Copyright IBM, Corp. 2008
|
||||
*
|
||||
* Authors:
|
||||
* Anthony Liguori <aliguori@us.ibm.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2. See
|
||||
* the COPYING file in the top-level directory.
|
||||
*
|
||||
* Contributions after 2012-01-13 are licensed under the terms of the
|
||||
* GNU GPL, version 2 or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "block.h"
|
||||
#include "qemu-queue.h"
|
||||
#include "qemu_socket.h"
|
||||
|
||||
struct AioHandler
|
||||
{
|
||||
GPollFD pfd;
|
||||
IOHandler *io_read;
|
||||
IOHandler *io_write;
|
||||
AioFlushHandler *io_flush;
|
||||
int deleted;
|
||||
void *opaque;
|
||||
QLIST_ENTRY(AioHandler) node;
|
||||
};
|
||||
|
||||
static AioHandler *find_aio_handler(AioContext *ctx, int fd)
|
||||
{
|
||||
AioHandler *node;
|
||||
|
||||
QLIST_FOREACH(node, &ctx->aio_handlers, node) {
|
||||
if (node->pfd.fd == fd)
|
||||
if (!node->deleted)
|
||||
return node;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void aio_set_fd_handler(AioContext *ctx,
|
||||
int fd,
|
||||
IOHandler *io_read,
|
||||
IOHandler *io_write,
|
||||
AioFlushHandler *io_flush,
|
||||
void *opaque)
|
||||
{
|
||||
AioHandler *node;
|
||||
|
||||
node = find_aio_handler(ctx, fd);
|
||||
|
||||
/* Are we deleting the fd handler? */
|
||||
if (!io_read && !io_write) {
|
||||
if (node) {
|
||||
g_source_remove_poll(&ctx->source, &node->pfd);
|
||||
|
||||
/* If the lock is held, just mark the node as deleted */
|
||||
if (ctx->walking_handlers) {
|
||||
node->deleted = 1;
|
||||
node->pfd.revents = 0;
|
||||
} else {
|
||||
/* Otherwise, delete it for real. We can't just mark it as
|
||||
* deleted because deleted nodes are only cleaned up after
|
||||
* releasing the walking_handlers lock.
|
||||
*/
|
||||
QLIST_REMOVE(node, node);
|
||||
g_free(node);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (node == NULL) {
|
||||
/* Alloc and insert if it's not already there */
|
||||
node = g_malloc0(sizeof(AioHandler));
|
||||
node->pfd.fd = fd;
|
||||
QLIST_INSERT_HEAD(&ctx->aio_handlers, node, node);
|
||||
|
||||
g_source_add_poll(&ctx->source, &node->pfd);
|
||||
}
|
||||
/* Update handler with latest information */
|
||||
node->io_read = io_read;
|
||||
node->io_write = io_write;
|
||||
node->io_flush = io_flush;
|
||||
node->opaque = opaque;
|
||||
|
||||
node->pfd.events = (io_read ? G_IO_IN | G_IO_HUP : 0);
|
||||
node->pfd.events |= (io_write ? G_IO_OUT : 0);
|
||||
}
|
||||
|
||||
aio_notify(ctx);
|
||||
}
|
||||
|
||||
void aio_set_event_notifier(AioContext *ctx,
|
||||
EventNotifier *notifier,
|
||||
EventNotifierHandler *io_read,
|
||||
AioFlushEventNotifierHandler *io_flush)
|
||||
{
|
||||
aio_set_fd_handler(ctx, event_notifier_get_fd(notifier),
|
||||
(IOHandler *)io_read, NULL,
|
||||
(AioFlushHandler *)io_flush, notifier);
|
||||
}
|
||||
|
||||
bool aio_pending(AioContext *ctx)
|
||||
{
|
||||
AioHandler *node;
|
||||
|
||||
QLIST_FOREACH(node, &ctx->aio_handlers, node) {
|
||||
int revents;
|
||||
|
||||
/*
|
||||
* FIXME: right now we cannot get G_IO_HUP and G_IO_ERR because
|
||||
* main-loop.c is still select based (due to the slirp legacy).
|
||||
* If main-loop.c ever switches to poll, G_IO_ERR should be
|
||||
* tested too. Dispatching G_IO_ERR to both handlers should be
|
||||
* okay, since handlers need to be ready for spurious wakeups.
|
||||
*/
|
||||
revents = node->pfd.revents & node->pfd.events;
|
||||
if (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR) && node->io_read) {
|
||||
return true;
|
||||
}
|
||||
if (revents & (G_IO_OUT | G_IO_ERR) && node->io_write) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool aio_poll(AioContext *ctx, bool blocking)
|
||||
{
|
||||
static struct timeval tv0;
|
||||
AioHandler *node;
|
||||
fd_set rdfds, wrfds;
|
||||
int max_fd = -1;
|
||||
int ret;
|
||||
bool busy, progress;
|
||||
|
||||
progress = false;
|
||||
|
||||
/*
|
||||
* If there are callbacks left that have been queued, we need to call then.
|
||||
* Do not call select in this case, because it is possible that the caller
|
||||
* does not need a complete flush (as is the case for qemu_aio_wait loops).
|
||||
*/
|
||||
if (aio_bh_poll(ctx)) {
|
||||
blocking = false;
|
||||
progress = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Then dispatch any pending callbacks from the GSource.
|
||||
*
|
||||
* We have to walk very carefully in case qemu_aio_set_fd_handler is
|
||||
* called while we're walking.
|
||||
*/
|
||||
node = QLIST_FIRST(&ctx->aio_handlers);
|
||||
while (node) {
|
||||
AioHandler *tmp;
|
||||
int revents;
|
||||
|
||||
ctx->walking_handlers++;
|
||||
|
||||
revents = node->pfd.revents & node->pfd.events;
|
||||
node->pfd.revents = 0;
|
||||
|
||||
/* See comment in aio_pending. */
|
||||
if (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR) && node->io_read) {
|
||||
node->io_read(node->opaque);
|
||||
progress = true;
|
||||
}
|
||||
if (revents & (G_IO_OUT | G_IO_ERR) && node->io_write) {
|
||||
node->io_write(node->opaque);
|
||||
progress = true;
|
||||
}
|
||||
|
||||
tmp = node;
|
||||
node = QLIST_NEXT(node, node);
|
||||
|
||||
ctx->walking_handlers--;
|
||||
|
||||
if (!ctx->walking_handlers && tmp->deleted) {
|
||||
QLIST_REMOVE(tmp, node);
|
||||
g_free(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
if (progress && !blocking) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ctx->walking_handlers++;
|
||||
|
||||
FD_ZERO(&rdfds);
|
||||
FD_ZERO(&wrfds);
|
||||
|
||||
/* fill fd sets */
|
||||
busy = false;
|
||||
QLIST_FOREACH(node, &ctx->aio_handlers, node) {
|
||||
/* If there aren't pending AIO operations, don't invoke callbacks.
|
||||
* Otherwise, if there are no AIO requests, qemu_aio_wait() would
|
||||
* wait indefinitely.
|
||||
*/
|
||||
if (!node->deleted && node->io_flush) {
|
||||
if (node->io_flush(node->opaque) == 0) {
|
||||
continue;
|
||||
}
|
||||
busy = true;
|
||||
}
|
||||
if (!node->deleted && node->io_read) {
|
||||
FD_SET(node->pfd.fd, &rdfds);
|
||||
max_fd = MAX(max_fd, node->pfd.fd + 1);
|
||||
}
|
||||
if (!node->deleted && node->io_write) {
|
||||
FD_SET(node->pfd.fd, &wrfds);
|
||||
max_fd = MAX(max_fd, node->pfd.fd + 1);
|
||||
}
|
||||
}
|
||||
|
||||
ctx->walking_handlers--;
|
||||
|
||||
/* No AIO operations? Get us out of here */
|
||||
if (!busy) {
|
||||
return progress;
|
||||
}
|
||||
|
||||
/* wait until next event */
|
||||
ret = select(max_fd, &rdfds, &wrfds, NULL, blocking ? NULL : &tv0);
|
||||
|
||||
/* if we have any readable fds, dispatch event */
|
||||
if (ret > 0) {
|
||||
/* we have to walk very carefully in case
|
||||
* qemu_aio_set_fd_handler is called while we're walking */
|
||||
node = QLIST_FIRST(&ctx->aio_handlers);
|
||||
while (node) {
|
||||
AioHandler *tmp;
|
||||
|
||||
ctx->walking_handlers++;
|
||||
|
||||
if (!node->deleted &&
|
||||
FD_ISSET(node->pfd.fd, &rdfds) &&
|
||||
node->io_read) {
|
||||
node->io_read(node->opaque);
|
||||
progress = true;
|
||||
}
|
||||
if (!node->deleted &&
|
||||
FD_ISSET(node->pfd.fd, &wrfds) &&
|
||||
node->io_write) {
|
||||
node->io_write(node->opaque);
|
||||
progress = true;
|
||||
}
|
||||
|
||||
tmp = node;
|
||||
node = QLIST_NEXT(node, node);
|
||||
|
||||
ctx->walking_handlers--;
|
||||
|
||||
if (!ctx->walking_handlers && tmp->deleted) {
|
||||
QLIST_REMOVE(tmp, node);
|
||||
g_free(tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return progress;
|
||||
}
|
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
* QEMU aio implementation
|
||||
*
|
||||
* Copyright IBM Corp., 2008
|
||||
* Copyright Red Hat Inc., 2012
|
||||
*
|
||||
* Authors:
|
||||
* Anthony Liguori <aliguori@us.ibm.com>
|
||||
* Paolo Bonzini <pbonzini@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2. See
|
||||
* the COPYING file in the top-level directory.
|
||||
*
|
||||
* Contributions after 2012-01-13 are licensed under the terms of the
|
||||
* GNU GPL, version 2 or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "block.h"
|
||||
#include "qemu-queue.h"
|
||||
#include "qemu_socket.h"
|
||||
|
||||
struct AioHandler {
|
||||
EventNotifier *e;
|
||||
EventNotifierHandler *io_notify;
|
||||
AioFlushEventNotifierHandler *io_flush;
|
||||
GPollFD pfd;
|
||||
int deleted;
|
||||
QLIST_ENTRY(AioHandler) node;
|
||||
};
|
||||
|
||||
void aio_set_event_notifier(AioContext *ctx,
|
||||
EventNotifier *e,
|
||||
EventNotifierHandler *io_notify,
|
||||
AioFlushEventNotifierHandler *io_flush)
|
||||
{
|
||||
AioHandler *node;
|
||||
|
||||
QLIST_FOREACH(node, &ctx->aio_handlers, node) {
|
||||
if (node->e == e && !node->deleted) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Are we deleting the fd handler? */
|
||||
if (!io_notify) {
|
||||
if (node) {
|
||||
g_source_remove_poll(&ctx->source, &node->pfd);
|
||||
|
||||
/* If the lock is held, just mark the node as deleted */
|
||||
if (ctx->walking_handlers) {
|
||||
node->deleted = 1;
|
||||
node->pfd.revents = 0;
|
||||
} else {
|
||||
/* Otherwise, delete it for real. We can't just mark it as
|
||||
* deleted because deleted nodes are only cleaned up after
|
||||
* releasing the walking_handlers lock.
|
||||
*/
|
||||
QLIST_REMOVE(node, node);
|
||||
g_free(node);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (node == NULL) {
|
||||
/* Alloc and insert if it's not already there */
|
||||
node = g_malloc0(sizeof(AioHandler));
|
||||
node->e = e;
|
||||
node->pfd.fd = (uintptr_t)event_notifier_get_handle(e);
|
||||
node->pfd.events = G_IO_IN;
|
||||
QLIST_INSERT_HEAD(&ctx->aio_handlers, node, node);
|
||||
|
||||
g_source_add_poll(&ctx->source, &node->pfd);
|
||||
}
|
||||
/* Update handler with latest information */
|
||||
node->io_notify = io_notify;
|
||||
node->io_flush = io_flush;
|
||||
}
|
||||
|
||||
aio_notify(ctx);
|
||||
}
|
||||
|
||||
bool aio_pending(AioContext *ctx)
|
||||
{
|
||||
AioHandler *node;
|
||||
|
||||
QLIST_FOREACH(node, &ctx->aio_handlers, node) {
|
||||
if (node->pfd.revents && node->io_notify) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool aio_poll(AioContext *ctx, bool blocking)
|
||||
{
|
||||
AioHandler *node;
|
||||
HANDLE events[MAXIMUM_WAIT_OBJECTS + 1];
|
||||
bool busy, progress;
|
||||
int count;
|
||||
|
||||
progress = false;
|
||||
|
||||
/*
|
||||
* If there are callbacks left that have been queued, we need to call then.
|
||||
* Do not call select in this case, because it is possible that the caller
|
||||
* does not need a complete flush (as is the case for qemu_aio_wait loops).
|
||||
*/
|
||||
if (aio_bh_poll(ctx)) {
|
||||
blocking = false;
|
||||
progress = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Then dispatch any pending callbacks from the GSource.
|
||||
*
|
||||
* We have to walk very carefully in case qemu_aio_set_fd_handler is
|
||||
* called while we're walking.
|
||||
*/
|
||||
node = QLIST_FIRST(&ctx->aio_handlers);
|
||||
while (node) {
|
||||
AioHandler *tmp;
|
||||
|
||||
ctx->walking_handlers++;
|
||||
|
||||
if (node->pfd.revents && node->io_notify) {
|
||||
node->pfd.revents = 0;
|
||||
node->io_notify(node->e);
|
||||
progress = true;
|
||||
}
|
||||
|
||||
tmp = node;
|
||||
node = QLIST_NEXT(node, node);
|
||||
|
||||
ctx->walking_handlers--;
|
||||
|
||||
if (!ctx->walking_handlers && tmp->deleted) {
|
||||
QLIST_REMOVE(tmp, node);
|
||||
g_free(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
if (progress && !blocking) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ctx->walking_handlers++;
|
||||
|
||||
/* fill fd sets */
|
||||
busy = false;
|
||||
count = 0;
|
||||
QLIST_FOREACH(node, &ctx->aio_handlers, node) {
|
||||
/* If there aren't pending AIO operations, don't invoke callbacks.
|
||||
* Otherwise, if there are no AIO requests, qemu_aio_wait() would
|
||||
* wait indefinitely.
|
||||
*/
|
||||
if (!node->deleted && node->io_flush) {
|
||||
if (node->io_flush(node->e) == 0) {
|
||||
continue;
|
||||
}
|
||||
busy = true;
|
||||
}
|
||||
if (!node->deleted && node->io_notify) {
|
||||
events[count++] = event_notifier_get_handle(node->e);
|
||||
}
|
||||
}
|
||||
|
||||
ctx->walking_handlers--;
|
||||
|
||||
/* No AIO operations? Get us out of here */
|
||||
if (!busy) {
|
||||
return progress;
|
||||
}
|
||||
|
||||
/* wait until next event */
|
||||
for (;;) {
|
||||
int timeout = blocking ? INFINITE : 0;
|
||||
int ret = WaitForMultipleObjects(count, events, FALSE, timeout);
|
||||
|
||||
/* if we have any signaled events, dispatch event */
|
||||
if ((DWORD) (ret - WAIT_OBJECT_0) >= count) {
|
||||
break;
|
||||
}
|
||||
|
||||
blocking = false;
|
||||
|
||||
/* we have to walk very carefully in case
|
||||
* qemu_aio_set_fd_handler is called while we're walking */
|
||||
node = QLIST_FIRST(&ctx->aio_handlers);
|
||||
while (node) {
|
||||
AioHandler *tmp;
|
||||
|
||||
ctx->walking_handlers++;
|
||||
|
||||
if (!node->deleted &&
|
||||
event_notifier_get_handle(node->e) == events[ret - WAIT_OBJECT_0] &&
|
||||
node->io_notify) {
|
||||
node->io_notify(node->e);
|
||||
progress = true;
|
||||
}
|
||||
|
||||
tmp = node;
|
||||
node = QLIST_NEXT(node, node);
|
||||
|
||||
ctx->walking_handlers--;
|
||||
|
||||
if (!ctx->walking_handlers && tmp->deleted) {
|
||||
QLIST_REMOVE(tmp, node);
|
||||
g_free(tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return progress;
|
||||
}
|
194
aio.c
194
aio.c
|
@ -1,194 +0,0 @@
|
|||
/*
|
||||
* QEMU aio implementation
|
||||
*
|
||||
* Copyright IBM, Corp. 2008
|
||||
*
|
||||
* Authors:
|
||||
* Anthony Liguori <aliguori@us.ibm.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2. See
|
||||
* the COPYING file in the top-level directory.
|
||||
*
|
||||
* Contributions after 2012-01-13 are licensed under the terms of the
|
||||
* GNU GPL, version 2 or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "block.h"
|
||||
#include "qemu-queue.h"
|
||||
#include "qemu_socket.h"
|
||||
|
||||
typedef struct AioHandler AioHandler;
|
||||
|
||||
/* The list of registered AIO handlers */
|
||||
static QLIST_HEAD(, AioHandler) aio_handlers;
|
||||
|
||||
/* This is a simple lock used to protect the aio_handlers list. Specifically,
|
||||
* it's used to ensure that no callbacks are removed while we're walking and
|
||||
* dispatching callbacks.
|
||||
*/
|
||||
static int walking_handlers;
|
||||
|
||||
struct AioHandler
|
||||
{
|
||||
int fd;
|
||||
IOHandler *io_read;
|
||||
IOHandler *io_write;
|
||||
AioFlushHandler *io_flush;
|
||||
int deleted;
|
||||
void *opaque;
|
||||
QLIST_ENTRY(AioHandler) node;
|
||||
};
|
||||
|
||||
static AioHandler *find_aio_handler(int fd)
|
||||
{
|
||||
AioHandler *node;
|
||||
|
||||
QLIST_FOREACH(node, &aio_handlers, node) {
|
||||
if (node->fd == fd)
|
||||
if (!node->deleted)
|
||||
return node;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int qemu_aio_set_fd_handler(int fd,
|
||||
IOHandler *io_read,
|
||||
IOHandler *io_write,
|
||||
AioFlushHandler *io_flush,
|
||||
void *opaque)
|
||||
{
|
||||
AioHandler *node;
|
||||
|
||||
node = find_aio_handler(fd);
|
||||
|
||||
/* Are we deleting the fd handler? */
|
||||
if (!io_read && !io_write) {
|
||||
if (node) {
|
||||
/* If the lock is held, just mark the node as deleted */
|
||||
if (walking_handlers)
|
||||
node->deleted = 1;
|
||||
else {
|
||||
/* Otherwise, delete it for real. We can't just mark it as
|
||||
* deleted because deleted nodes are only cleaned up after
|
||||
* releasing the walking_handlers lock.
|
||||
*/
|
||||
QLIST_REMOVE(node, node);
|
||||
g_free(node);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (node == NULL) {
|
||||
/* Alloc and insert if it's not already there */
|
||||
node = g_malloc0(sizeof(AioHandler));
|
||||
node->fd = fd;
|
||||
QLIST_INSERT_HEAD(&aio_handlers, node, node);
|
||||
}
|
||||
/* Update handler with latest information */
|
||||
node->io_read = io_read;
|
||||
node->io_write = io_write;
|
||||
node->io_flush = io_flush;
|
||||
node->opaque = opaque;
|
||||
}
|
||||
|
||||
qemu_set_fd_handler2(fd, NULL, io_read, io_write, opaque);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void qemu_aio_flush(void)
|
||||
{
|
||||
while (qemu_aio_wait());
|
||||
}
|
||||
|
||||
bool qemu_aio_wait(void)
|
||||
{
|
||||
AioHandler *node;
|
||||
fd_set rdfds, wrfds;
|
||||
int max_fd = -1;
|
||||
int ret;
|
||||
bool busy;
|
||||
|
||||
/*
|
||||
* If there are callbacks left that have been queued, we need to call then.
|
||||
* Do not call select in this case, because it is possible that the caller
|
||||
* does not need a complete flush (as is the case for qemu_aio_wait loops).
|
||||
*/
|
||||
if (qemu_bh_poll()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
walking_handlers++;
|
||||
|
||||
FD_ZERO(&rdfds);
|
||||
FD_ZERO(&wrfds);
|
||||
|
||||
/* fill fd sets */
|
||||
busy = false;
|
||||
QLIST_FOREACH(node, &aio_handlers, node) {
|
||||
/* If there aren't pending AIO operations, don't invoke callbacks.
|
||||
* Otherwise, if there are no AIO requests, qemu_aio_wait() would
|
||||
* wait indefinitely.
|
||||
*/
|
||||
if (node->io_flush) {
|
||||
if (node->io_flush(node->opaque) == 0) {
|
||||
continue;
|
||||
}
|
||||
busy = true;
|
||||
}
|
||||
if (!node->deleted && node->io_read) {
|
||||
FD_SET(node->fd, &rdfds);
|
||||
max_fd = MAX(max_fd, node->fd + 1);
|
||||
}
|
||||
if (!node->deleted && node->io_write) {
|
||||
FD_SET(node->fd, &wrfds);
|
||||
max_fd = MAX(max_fd, node->fd + 1);
|
||||
}
|
||||
}
|
||||
|
||||
walking_handlers--;
|
||||
|
||||
/* No AIO operations? Get us out of here */
|
||||
if (!busy) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* wait until next event */
|
||||
ret = select(max_fd, &rdfds, &wrfds, NULL, NULL);
|
||||
|
||||
/* if we have any readable fds, dispatch event */
|
||||
if (ret > 0) {
|
||||
/* we have to walk very carefully in case
|
||||
* qemu_aio_set_fd_handler is called while we're walking */
|
||||
node = QLIST_FIRST(&aio_handlers);
|
||||
while (node) {
|
||||
AioHandler *tmp;
|
||||
|
||||
walking_handlers++;
|
||||
|
||||
if (!node->deleted &&
|
||||
FD_ISSET(node->fd, &rdfds) &&
|
||||
node->io_read) {
|
||||
node->io_read(node->opaque);
|
||||
}
|
||||
if (!node->deleted &&
|
||||
FD_ISSET(node->fd, &wrfds) &&
|
||||
node->io_write) {
|
||||
node->io_write(node->opaque);
|
||||
}
|
||||
|
||||
tmp = node;
|
||||
node = QLIST_NEXT(node, node);
|
||||
|
||||
walking_handlers--;
|
||||
|
||||
if (!walking_handlers && tmp->deleted) {
|
||||
QLIST_REMOVE(tmp, node);
|
||||
g_free(tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
|
@ -34,6 +34,6 @@ int tcg_available(void);
|
|||
int kvm_available(void);
|
||||
int xen_available(void);
|
||||
|
||||
CpuDefinitionInfoList GCC_WEAK_DECL *arch_query_cpu_definitions(Error **errp);
|
||||
CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp);
|
||||
|
||||
#endif
|
||||
|
|
118
async.c
118
async.c
|
@ -26,13 +26,11 @@
|
|||
#include "qemu-aio.h"
|
||||
#include "main-loop.h"
|
||||
|
||||
/* 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) */
|
||||
|
||||
struct QEMUBH {
|
||||
AioContext *ctx;
|
||||
QEMUBHFunc *cb;
|
||||
void *opaque;
|
||||
QEMUBH *next;
|
||||
|
@ -41,27 +39,27 @@ struct QEMUBH {
|
|||
bool deleted;
|
||||
};
|
||||
|
||||
QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque)
|
||||
QEMUBH *aio_bh_new(AioContext *ctx, QEMUBHFunc *cb, void *opaque)
|
||||
{
|
||||
QEMUBH *bh;
|
||||
bh = g_malloc0(sizeof(QEMUBH));
|
||||
bh->ctx = ctx;
|
||||
bh->cb = cb;
|
||||
bh->opaque = opaque;
|
||||
bh->next = first_bh;
|
||||
first_bh = bh;
|
||||
bh->next = ctx->first_bh;
|
||||
ctx->first_bh = bh;
|
||||
return bh;
|
||||
}
|
||||
|
||||
int qemu_bh_poll(void)
|
||||
int aio_bh_poll(AioContext *ctx)
|
||||
{
|
||||
QEMUBH *bh, **bhp, *next;
|
||||
int ret;
|
||||
static int nesting = 0;
|
||||
|
||||
nesting++;
|
||||
ctx->walking_bh++;
|
||||
|
||||
ret = 0;
|
||||
for (bh = first_bh; bh; bh = next) {
|
||||
for (bh = ctx->first_bh; bh; bh = next) {
|
||||
next = bh->next;
|
||||
if (!bh->deleted && bh->scheduled) {
|
||||
bh->scheduled = 0;
|
||||
|
@ -72,11 +70,11 @@ int qemu_bh_poll(void)
|
|||
}
|
||||
}
|
||||
|
||||
nesting--;
|
||||
ctx->walking_bh--;
|
||||
|
||||
/* remove deleted bhs */
|
||||
if (!nesting) {
|
||||
bhp = &first_bh;
|
||||
if (!ctx->walking_bh) {
|
||||
bhp = &ctx->first_bh;
|
||||
while (*bhp) {
|
||||
bh = *bhp;
|
||||
if (bh->deleted) {
|
||||
|
@ -105,8 +103,7 @@ void qemu_bh_schedule(QEMUBH *bh)
|
|||
return;
|
||||
bh->scheduled = 1;
|
||||
bh->idle = 0;
|
||||
/* stop the currently executing CPU to execute the BH ASAP */
|
||||
qemu_notify_event();
|
||||
aio_notify(bh->ctx);
|
||||
}
|
||||
|
||||
void qemu_bh_cancel(QEMUBH *bh)
|
||||
|
@ -120,16 +117,20 @@ void qemu_bh_delete(QEMUBH *bh)
|
|||
bh->deleted = 1;
|
||||
}
|
||||
|
||||
void qemu_bh_update_timeout(uint32_t *timeout)
|
||||
static gboolean
|
||||
aio_ctx_prepare(GSource *source, gint *timeout)
|
||||
{
|
||||
AioContext *ctx = (AioContext *) source;
|
||||
QEMUBH *bh;
|
||||
bool scheduled = false;
|
||||
|
||||
for (bh = first_bh; bh; bh = bh->next) {
|
||||
for (bh = ctx->first_bh; bh; bh = bh->next) {
|
||||
if (!bh->deleted && bh->scheduled) {
|
||||
scheduled = true;
|
||||
if (bh->idle) {
|
||||
/* idle bottom halves will be polled at least
|
||||
* every 10ms */
|
||||
*timeout = MIN(10, *timeout);
|
||||
*timeout = 10;
|
||||
} else {
|
||||
/* non-idle bottom halves will be executed
|
||||
* immediately */
|
||||
|
@ -138,5 +139,86 @@ void qemu_bh_update_timeout(uint32_t *timeout)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
return scheduled;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
aio_ctx_check(GSource *source)
|
||||
{
|
||||
AioContext *ctx = (AioContext *) source;
|
||||
QEMUBH *bh;
|
||||
|
||||
for (bh = ctx->first_bh; bh; bh = bh->next) {
|
||||
if (!bh->deleted && bh->scheduled) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return aio_pending(ctx);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
aio_ctx_dispatch(GSource *source,
|
||||
GSourceFunc callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
AioContext *ctx = (AioContext *) source;
|
||||
|
||||
assert(callback == NULL);
|
||||
aio_poll(ctx, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
aio_ctx_finalize(GSource *source)
|
||||
{
|
||||
AioContext *ctx = (AioContext *) source;
|
||||
|
||||
aio_set_event_notifier(ctx, &ctx->notifier, NULL, NULL);
|
||||
event_notifier_cleanup(&ctx->notifier);
|
||||
}
|
||||
|
||||
static GSourceFuncs aio_source_funcs = {
|
||||
aio_ctx_prepare,
|
||||
aio_ctx_check,
|
||||
aio_ctx_dispatch,
|
||||
aio_ctx_finalize
|
||||
};
|
||||
|
||||
GSource *aio_get_g_source(AioContext *ctx)
|
||||
{
|
||||
g_source_ref(&ctx->source);
|
||||
return &ctx->source;
|
||||
}
|
||||
|
||||
void aio_notify(AioContext *ctx)
|
||||
{
|
||||
event_notifier_set(&ctx->notifier);
|
||||
}
|
||||
|
||||
AioContext *aio_context_new(void)
|
||||
{
|
||||
AioContext *ctx;
|
||||
ctx = (AioContext *) g_source_new(&aio_source_funcs, sizeof(AioContext));
|
||||
event_notifier_init(&ctx->notifier, false);
|
||||
aio_set_event_notifier(ctx, &ctx->notifier,
|
||||
(EventNotifierHandler *)
|
||||
event_notifier_test_and_clear, NULL);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void aio_context_ref(AioContext *ctx)
|
||||
{
|
||||
g_source_ref(&ctx->source);
|
||||
}
|
||||
|
||||
void aio_context_unref(AioContext *ctx)
|
||||
{
|
||||
g_source_unref(&ctx->source);
|
||||
}
|
||||
|
||||
void aio_flush(AioContext *ctx)
|
||||
{
|
||||
while (aio_poll(ctx, true));
|
||||
}
|
||||
|
|
|
@ -2,13 +2,18 @@ block-obj-y += raw.o cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat
|
|||
block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o
|
||||
block-obj-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o
|
||||
block-obj-y += qed-check.o
|
||||
block-obj-y += parallels.o nbd.o blkdebug.o sheepdog.o blkverify.o
|
||||
block-obj-$(CONFIG_WIN32) += raw-win32.o
|
||||
block-obj-y += parallels.o blkdebug.o blkverify.o
|
||||
block-obj-$(CONFIG_WIN32) += raw-win32.o win32-aio.o
|
||||
block-obj-$(CONFIG_POSIX) += raw-posix.o
|
||||
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
|
||||
|
||||
ifeq ($(CONFIG_POSIX),y)
|
||||
block-obj-y += nbd.o sheepdog.o
|
||||
block-obj-$(CONFIG_LIBISCSI) += iscsi.o
|
||||
block-obj-$(CONFIG_CURL) += curl.o
|
||||
block-obj-$(CONFIG_RBD) += rbd.o
|
||||
block-obj-$(CONFIG_GLUSTERFS) += gluster.o
|
||||
endif
|
||||
|
||||
common-obj-y += stream.o
|
||||
common-obj-y += commit.o
|
||||
|
|
|
@ -9,9 +9,10 @@
|
|||
*/
|
||||
#include "qemu-common.h"
|
||||
#include "qemu-aio.h"
|
||||
#include "block/raw-posix-aio.h"
|
||||
#include "qemu-queue.h"
|
||||
#include "block/raw-aio.h"
|
||||
#include "event_notifier.h"
|
||||
|
||||
#include <sys/eventfd.h>
|
||||
#include <libaio.h>
|
||||
|
||||
/*
|
||||
|
@ -37,7 +38,7 @@ struct qemu_laiocb {
|
|||
|
||||
struct qemu_laio_state {
|
||||
io_context_t ctx;
|
||||
int efd;
|
||||
EventNotifier e;
|
||||
int count;
|
||||
};
|
||||
|
||||
|
@ -76,29 +77,17 @@ static void qemu_laio_process_completion(struct qemu_laio_state *s,
|
|||
qemu_aio_release(laiocb);
|
||||
}
|
||||
|
||||
static void qemu_laio_completion_cb(void *opaque)
|
||||
static void qemu_laio_completion_cb(EventNotifier *e)
|
||||
{
|
||||
struct qemu_laio_state *s = opaque;
|
||||
struct qemu_laio_state *s = container_of(e, struct qemu_laio_state, e);
|
||||
|
||||
while (1) {
|
||||
while (event_notifier_test_and_clear(&s->e)) {
|
||||
struct io_event events[MAX_EVENTS];
|
||||
uint64_t val;
|
||||
ssize_t ret;
|
||||
struct timespec ts = { 0 };
|
||||
int nevents, i;
|
||||
|
||||
do {
|
||||
ret = read(s->efd, &val, sizeof(val));
|
||||
} while (ret == -1 && errno == EINTR);
|
||||
|
||||
if (ret == -1 && errno == EAGAIN)
|
||||
break;
|
||||
|
||||
if (ret != 8)
|
||||
break;
|
||||
|
||||
do {
|
||||
nevents = io_getevents(s->ctx, val, MAX_EVENTS, events, &ts);
|
||||
nevents = io_getevents(s->ctx, MAX_EVENTS, MAX_EVENTS, events, &ts);
|
||||
} while (nevents == -EINTR);
|
||||
|
||||
for (i = 0; i < nevents; i++) {
|
||||
|
@ -112,9 +101,9 @@ static void qemu_laio_completion_cb(void *opaque)
|
|||
}
|
||||
}
|
||||
|
||||
static int qemu_laio_flush_cb(void *opaque)
|
||||
static int qemu_laio_flush_cb(EventNotifier *e)
|
||||
{
|
||||
struct qemu_laio_state *s = opaque;
|
||||
struct qemu_laio_state *s = container_of(e, struct qemu_laio_state, e);
|
||||
|
||||
return (s->count > 0) ? 1 : 0;
|
||||
}
|
||||
|
@ -146,8 +135,9 @@ static void laio_cancel(BlockDriverAIOCB *blockacb)
|
|||
* We might be able to do this slightly more optimal by removing the
|
||||
* O_NONBLOCK flag.
|
||||
*/
|
||||
while (laiocb->ret == -EINPROGRESS)
|
||||
qemu_laio_completion_cb(laiocb->ctx);
|
||||
while (laiocb->ret == -EINPROGRESS) {
|
||||
qemu_laio_completion_cb(&laiocb->ctx->e);
|
||||
}
|
||||
}
|
||||
|
||||
static AIOPool laio_pool = {
|
||||
|
@ -186,7 +176,7 @@ BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
|
|||
__func__, type);
|
||||
goto out_free_aiocb;
|
||||
}
|
||||
io_set_eventfd(&laiocb->iocb, s->efd);
|
||||
io_set_eventfd(&laiocb->iocb, event_notifier_get_fd(&s->e));
|
||||
s->count++;
|
||||
|
||||
if (io_submit(s->ctx, 1, &iocbs) < 0)
|
||||
|
@ -205,21 +195,21 @@ void *laio_init(void)
|
|||
struct qemu_laio_state *s;
|
||||
|
||||
s = g_malloc0(sizeof(*s));
|
||||
s->efd = eventfd(0, 0);
|
||||
if (s->efd == -1)
|
||||
if (event_notifier_init(&s->e, false) < 0) {
|
||||
goto out_free_state;
|
||||
fcntl(s->efd, F_SETFL, O_NONBLOCK);
|
||||
}
|
||||
|
||||
if (io_setup(MAX_EVENTS, &s->ctx) != 0)
|
||||
if (io_setup(MAX_EVENTS, &s->ctx) != 0) {
|
||||
goto out_close_efd;
|
||||
}
|
||||
|
||||
qemu_aio_set_fd_handler(s->efd, qemu_laio_completion_cb, NULL,
|
||||
qemu_laio_flush_cb, s);
|
||||
qemu_aio_set_event_notifier(&s->e, qemu_laio_completion_cb,
|
||||
qemu_laio_flush_cb);
|
||||
|
||||
return s;
|
||||
|
||||
out_close_efd:
|
||||
close(s->efd);
|
||||
event_notifier_cleanup(&s->e);
|
||||
out_free_state:
|
||||
g_free(s);
|
||||
return NULL;
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* QEMU Posix block I/O backend AIO support
|
||||
* Declarations for AIO in the raw protocol
|
||||
*
|
||||
* Copyright IBM, Corp. 2008
|
||||
*
|
||||
|
@ -12,8 +12,8 @@
|
|||
* Contributions after 2012-01-13 are licensed under the terms of the
|
||||
* GNU GPL, version 2 or (at your option) any later version.
|
||||
*/
|
||||
#ifndef QEMU_RAW_POSIX_AIO_H
|
||||
#define QEMU_RAW_POSIX_AIO_H
|
||||
#ifndef QEMU_RAW_AIO_H
|
||||
#define QEMU_RAW_AIO_H
|
||||
|
||||
/* AIO request types */
|
||||
#define QEMU_AIO_READ 0x0001
|
||||
|
@ -27,19 +27,22 @@
|
|||
#define QEMU_AIO_MISALIGNED 0x1000
|
||||
|
||||
|
||||
/* posix-aio-compat.c - thread pool based implementation */
|
||||
int paio_init(void);
|
||||
BlockDriverAIOCB *paio_submit(BlockDriverState *bs, int fd,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque, int type);
|
||||
BlockDriverAIOCB *paio_ioctl(BlockDriverState *bs, int fd,
|
||||
unsigned long int req, void *buf,
|
||||
BlockDriverCompletionFunc *cb, void *opaque);
|
||||
|
||||
/* linux-aio.c - Linux native implementation */
|
||||
#ifdef CONFIG_LINUX_AIO
|
||||
void *laio_init(void);
|
||||
BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque, int type);
|
||||
#endif
|
||||
|
||||
#endif /* QEMU_RAW_POSIX_AIO_H */
|
||||
#ifdef _WIN32
|
||||
typedef struct QEMUWin32AIOState QEMUWin32AIOState;
|
||||
QEMUWin32AIOState *win32_aio_init(void);
|
||||
int win32_aio_attach(QEMUWin32AIOState *aio, HANDLE hfile);
|
||||
BlockDriverAIOCB *win32_aio_submit(BlockDriverState *bs,
|
||||
QEMUWin32AIOState *aio, HANDLE hfile,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque, int type);
|
||||
#endif
|
||||
|
||||
#endif /* QEMU_RAW_AIO_H */
|
|
@ -27,7 +27,10 @@
|
|||
#include "qemu-log.h"
|
||||
#include "block_int.h"
|
||||
#include "module.h"
|
||||
#include "block/raw-posix-aio.h"
|
||||
#include "trace.h"
|
||||
#include "thread-pool.h"
|
||||
#include "iov.h"
|
||||
#include "raw-aio.h"
|
||||
|
||||
#if defined(__APPLE__) && (__MACH__)
|
||||
#include <paths.h>
|
||||
|
@ -149,6 +152,20 @@ typedef struct BDRVRawReopenState {
|
|||
static int fd_open(BlockDriverState *bs);
|
||||
static int64_t raw_getlength(BlockDriverState *bs);
|
||||
|
||||
typedef struct RawPosixAIOData {
|
||||
BlockDriverState *bs;
|
||||
int aio_fildes;
|
||||
union {
|
||||
struct iovec *aio_iov;
|
||||
void *aio_ioctl_buf;
|
||||
};
|
||||
int aio_niov;
|
||||
size_t aio_nbytes;
|
||||
#define aio_ioctl_cmd aio_nbytes /* for QEMU_AIO_IOCTL */
|
||||
off_t aio_offset;
|
||||
int aio_type;
|
||||
} RawPosixAIOData;
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
static int cdrom_reopen(BlockDriverState *bs);
|
||||
#endif
|
||||
|
@ -266,14 +283,10 @@ static int raw_open_common(BlockDriverState *bs, const char *filename,
|
|||
}
|
||||
s->fd = fd;
|
||||
|
||||
/* We're falling back to POSIX AIO in some cases so init always */
|
||||
if (paio_init() < 0) {
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_LINUX_AIO
|
||||
if (raw_set_aio(&s->aio_ctx, &s->use_aio, bdrv_flags)) {
|
||||
goto out_close;
|
||||
qemu_close(fd);
|
||||
return -errno;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -284,10 +297,6 @@ static int raw_open_common(BlockDriverState *bs, const char *filename,
|
|||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
out_close:
|
||||
qemu_close(fd);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
static int raw_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
|
@ -434,6 +443,283 @@ static int qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static ssize_t handle_aiocb_ioctl(RawPosixAIOData *aiocb)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ioctl(aiocb->aio_fildes, aiocb->aio_ioctl_cmd, aiocb->aio_ioctl_buf);
|
||||
if (ret == -1) {
|
||||
return -errno;
|
||||
}
|
||||
|
||||
/*
|
||||
* This looks weird, but the aio code only considers a request
|
||||
* successful if it has written the full number of bytes.
|
||||
*
|
||||
* Now we overload aio_nbytes as aio_ioctl_cmd for the ioctl command,
|
||||
* so in fact we return the ioctl command here to make posix_aio_read()
|
||||
* happy..
|
||||
*/
|
||||
return aiocb->aio_nbytes;
|
||||
}
|
||||
|
||||
static ssize_t handle_aiocb_flush(RawPosixAIOData *aiocb)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = qemu_fdatasync(aiocb->aio_fildes);
|
||||
if (ret == -1) {
|
||||
return -errno;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PREADV
|
||||
|
||||
static bool preadv_present = true;
|
||||
|
||||
static ssize_t
|
||||
qemu_preadv(int fd, const struct iovec *iov, int nr_iov, off_t offset)
|
||||
{
|
||||
return preadv(fd, iov, nr_iov, offset);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
qemu_pwritev(int fd, const struct iovec *iov, int nr_iov, off_t offset)
|
||||
{
|
||||
return pwritev(fd, iov, nr_iov, offset);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static bool preadv_present = false;
|
||||
|
||||
static ssize_t
|
||||
qemu_preadv(int fd, const struct iovec *iov, int nr_iov, off_t offset)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
qemu_pwritev(int fd, const struct iovec *iov, int nr_iov, off_t offset)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static ssize_t handle_aiocb_rw_vector(RawPosixAIOData *aiocb)
|
||||
{
|
||||
ssize_t len;
|
||||
|
||||
do {
|
||||
if (aiocb->aio_type & QEMU_AIO_WRITE)
|
||||
len = qemu_pwritev(aiocb->aio_fildes,
|
||||
aiocb->aio_iov,
|
||||
aiocb->aio_niov,
|
||||
aiocb->aio_offset);
|
||||
else
|
||||
len = qemu_preadv(aiocb->aio_fildes,
|
||||
aiocb->aio_iov,
|
||||
aiocb->aio_niov,
|
||||
aiocb->aio_offset);
|
||||
} while (len == -1 && errno == EINTR);
|
||||
|
||||
if (len == -1) {
|
||||
return -errno;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read/writes the data to/from a given linear buffer.
|
||||
*
|
||||
* Returns the number of bytes handles or -errno in case of an error. Short
|
||||
* reads are only returned if the end of the file is reached.
|
||||
*/
|
||||
static ssize_t handle_aiocb_rw_linear(RawPosixAIOData *aiocb, char *buf)
|
||||
{
|
||||
ssize_t offset = 0;
|
||||
ssize_t len;
|
||||
|
||||
while (offset < aiocb->aio_nbytes) {
|
||||
if (aiocb->aio_type & QEMU_AIO_WRITE) {
|
||||
len = pwrite(aiocb->aio_fildes,
|
||||
(const char *)buf + offset,
|
||||
aiocb->aio_nbytes - offset,
|
||||
aiocb->aio_offset + offset);
|
||||
} else {
|
||||
len = pread(aiocb->aio_fildes,
|
||||
buf + offset,
|
||||
aiocb->aio_nbytes - offset,
|
||||
aiocb->aio_offset + offset);
|
||||
}
|
||||
if (len == -1 && errno == EINTR) {
|
||||
continue;
|
||||
} else if (len == -1) {
|
||||
offset = -errno;
|
||||
break;
|
||||
} else if (len == 0) {
|
||||
break;
|
||||
}
|
||||
offset += len;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
static ssize_t handle_aiocb_rw(RawPosixAIOData *aiocb)
|
||||
{
|
||||
ssize_t nbytes;
|
||||
char *buf;
|
||||
|
||||
if (!(aiocb->aio_type & QEMU_AIO_MISALIGNED)) {
|
||||
/*
|
||||
* If there is just a single buffer, and it is properly aligned
|
||||
* we can just use plain pread/pwrite without any problems.
|
||||
*/
|
||||
if (aiocb->aio_niov == 1) {
|
||||
return handle_aiocb_rw_linear(aiocb, aiocb->aio_iov->iov_base);
|
||||
}
|
||||
/*
|
||||
* We have more than one iovec, and all are properly aligned.
|
||||
*
|
||||
* Try preadv/pwritev first and fall back to linearizing the
|
||||
* buffer if it's not supported.
|
||||
*/
|
||||
if (preadv_present) {
|
||||
nbytes = handle_aiocb_rw_vector(aiocb);
|
||||
if (nbytes == aiocb->aio_nbytes ||
|
||||
(nbytes < 0 && nbytes != -ENOSYS)) {
|
||||
return nbytes;
|
||||
}
|
||||
preadv_present = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX(hch): short read/write. no easy way to handle the reminder
|
||||
* using these interfaces. For now retry using plain
|
||||
* pread/pwrite?
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* Ok, we have to do it the hard way, copy all segments into
|
||||
* a single aligned buffer.
|
||||
*/
|
||||
buf = qemu_blockalign(aiocb->bs, aiocb->aio_nbytes);
|
||||
if (aiocb->aio_type & QEMU_AIO_WRITE) {
|
||||
char *p = buf;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < aiocb->aio_niov; ++i) {
|
||||
memcpy(p, aiocb->aio_iov[i].iov_base, aiocb->aio_iov[i].iov_len);
|
||||
p += aiocb->aio_iov[i].iov_len;
|
||||
}
|
||||
}
|
||||
|
||||
nbytes = handle_aiocb_rw_linear(aiocb, buf);
|
||||
if (!(aiocb->aio_type & QEMU_AIO_WRITE)) {
|
||||
char *p = buf;
|
||||
size_t count = aiocb->aio_nbytes, copy;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < aiocb->aio_niov && count; ++i) {
|
||||
copy = count;
|
||||
if (copy > aiocb->aio_iov[i].iov_len) {
|
||||
copy = aiocb->aio_iov[i].iov_len;
|
||||
}
|
||||
memcpy(aiocb->aio_iov[i].iov_base, p, copy);
|
||||
p += copy;
|
||||
count -= copy;
|
||||
}
|
||||
}
|
||||
qemu_vfree(buf);
|
||||
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
static int aio_worker(void *arg)
|
||||
{
|
||||
RawPosixAIOData *aiocb = arg;
|
||||
ssize_t ret = 0;
|
||||
|
||||
switch (aiocb->aio_type & QEMU_AIO_TYPE_MASK) {
|
||||
case QEMU_AIO_READ:
|
||||
ret = handle_aiocb_rw(aiocb);
|
||||
if (ret >= 0 && ret < aiocb->aio_nbytes && aiocb->bs->growable) {
|
||||
iov_memset(aiocb->aio_iov, aiocb->aio_niov, ret,
|
||||
0, aiocb->aio_nbytes - ret);
|
||||
|
||||
ret = aiocb->aio_nbytes;
|
||||
}
|
||||
if (ret == aiocb->aio_nbytes) {
|
||||
ret = 0;
|
||||
} else if (ret >= 0 && ret < aiocb->aio_nbytes) {
|
||||
ret = -EINVAL;
|
||||
}
|
||||
break;
|
||||
case QEMU_AIO_WRITE:
|
||||
ret = handle_aiocb_rw(aiocb);
|
||||
if (ret == aiocb->aio_nbytes) {
|
||||
ret = 0;
|
||||
} else if (ret >= 0 && ret < aiocb->aio_nbytes) {
|
||||
ret = -EINVAL;
|
||||
}
|
||||
break;
|
||||
case QEMU_AIO_FLUSH:
|
||||
ret = handle_aiocb_flush(aiocb);
|
||||
break;
|
||||
case QEMU_AIO_IOCTL:
|
||||
ret = handle_aiocb_ioctl(aiocb);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "invalid aio request (0x%x)\n", aiocb->aio_type);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
g_slice_free(RawPosixAIOData, aiocb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *paio_submit(BlockDriverState *bs, int fd,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque, int type)
|
||||
{
|
||||
RawPosixAIOData *acb = g_slice_new(RawPosixAIOData);
|
||||
|
||||
acb->bs = bs;
|
||||
acb->aio_type = type;
|
||||
acb->aio_fildes = fd;
|
||||
|
||||
if (qiov) {
|
||||
acb->aio_iov = qiov->iov;
|
||||
acb->aio_niov = qiov->niov;
|
||||
}
|
||||
acb->aio_nbytes = nb_sectors * 512;
|
||||
acb->aio_offset = sector_num * 512;
|
||||
|
||||
trace_paio_submit(acb, opaque, sector_num, nb_sectors, type);
|
||||
return thread_pool_submit_aio(aio_worker, acb, cb, opaque);
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *paio_ioctl(BlockDriverState *bs, int fd,
|
||||
unsigned long int req, void *buf,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
RawPosixAIOData *acb = g_slice_new(RawPosixAIOData);
|
||||
|
||||
acb->bs = bs;
|
||||
acb->aio_type = QEMU_AIO_IOCTL;
|
||||
acb->aio_fildes = fd;
|
||||
acb->aio_offset = 0;
|
||||
acb->aio_ioctl_buf = buf;
|
||||
acb->aio_ioctl_cmd = req;
|
||||
|
||||
return thread_pool_submit_aio(aio_worker, acb, cb, opaque);
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *raw_aio_submit(BlockDriverState *bs,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque, int type)
|
||||
|
|
|
@ -25,6 +25,10 @@
|
|||
#include "qemu-timer.h"
|
||||
#include "block_int.h"
|
||||
#include "module.h"
|
||||
#include "raw-aio.h"
|
||||
#include "trace.h"
|
||||
#include "thread-pool.h"
|
||||
#include "iov.h"
|
||||
#include <windows.h>
|
||||
#include <winioctl.h>
|
||||
|
||||
|
@ -32,12 +36,130 @@
|
|||
#define FTYPE_CD 1
|
||||
#define FTYPE_HARDDISK 2
|
||||
|
||||
static QEMUWin32AIOState *aio;
|
||||
|
||||
typedef struct RawWin32AIOData {
|
||||
BlockDriverState *bs;
|
||||
HANDLE hfile;
|
||||
struct iovec *aio_iov;
|
||||
int aio_niov;
|
||||
size_t aio_nbytes;
|
||||
off64_t aio_offset;
|
||||
int aio_type;
|
||||
} RawWin32AIOData;
|
||||
|
||||
typedef struct BDRVRawState {
|
||||
HANDLE hfile;
|
||||
int type;
|
||||
char drive_path[16]; /* format: "d:\" */
|
||||
QEMUWin32AIOState *aio;
|
||||
} BDRVRawState;
|
||||
|
||||
/*
|
||||
* Read/writes the data to/from a given linear buffer.
|
||||
*
|
||||
* Returns the number of bytes handles or -errno in case of an error. Short
|
||||
* reads are only returned if the end of the file is reached.
|
||||
*/
|
||||
static size_t handle_aiocb_rw(RawWin32AIOData *aiocb)
|
||||
{
|
||||
size_t offset = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < aiocb->aio_niov; i++) {
|
||||
OVERLAPPED ov;
|
||||
DWORD ret, ret_count, len;
|
||||
|
||||
memset(&ov, 0, sizeof(ov));
|
||||
ov.Offset = (aiocb->aio_offset + offset);
|
||||
ov.OffsetHigh = (aiocb->aio_offset + offset) >> 32;
|
||||
len = aiocb->aio_iov[i].iov_len;
|
||||
if (aiocb->aio_type & QEMU_AIO_WRITE) {
|
||||
ret = WriteFile(aiocb->hfile, aiocb->aio_iov[i].iov_base,
|
||||
len, &ret_count, &ov);
|
||||
} else {
|
||||
ret = ReadFile(aiocb->hfile, aiocb->aio_iov[i].iov_base,
|
||||
len, &ret_count, &ov);
|
||||
}
|
||||
if (!ret) {
|
||||
ret_count = 0;
|
||||
}
|
||||
if (ret_count != len) {
|
||||
break;
|
||||
}
|
||||
offset += len;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
static int aio_worker(void *arg)
|
||||
{
|
||||
RawWin32AIOData *aiocb = arg;
|
||||
ssize_t ret = 0;
|
||||
size_t count;
|
||||
|
||||
switch (aiocb->aio_type & QEMU_AIO_TYPE_MASK) {
|
||||
case QEMU_AIO_READ:
|
||||
count = handle_aiocb_rw(aiocb);
|
||||
if (count < aiocb->aio_nbytes && aiocb->bs->growable) {
|
||||
/* A short read means that we have reached EOF. Pad the buffer
|
||||
* with zeros for bytes after EOF. */
|
||||
iov_memset(aiocb->aio_iov, aiocb->aio_niov, count,
|
||||
0, aiocb->aio_nbytes - count);
|
||||
|
||||
count = aiocb->aio_nbytes;
|
||||
}
|
||||
if (count == aiocb->aio_nbytes) {
|
||||
ret = 0;
|
||||
} else {
|
||||
ret = -EINVAL;
|
||||
}
|
||||
break;
|
||||
case QEMU_AIO_WRITE:
|
||||
count = handle_aiocb_rw(aiocb);
|
||||
if (count == aiocb->aio_nbytes) {
|
||||
count = 0;
|
||||
} else {
|
||||
count = -EINVAL;
|
||||
}
|
||||
break;
|
||||
case QEMU_AIO_FLUSH:
|
||||
if (!FlushFileBuffers(aiocb->hfile)) {
|
||||
return -EIO;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "invalid aio request (0x%x)\n", aiocb->aio_type);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
g_slice_free(RawWin32AIOData, aiocb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *paio_submit(BlockDriverState *bs, HANDLE hfile,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque, int type)
|
||||
{
|
||||
RawWin32AIOData *acb = g_slice_new(RawWin32AIOData);
|
||||
|
||||
acb->bs = bs;
|
||||
acb->hfile = hfile;
|
||||
acb->aio_type = type;
|
||||
|
||||
if (qiov) {
|
||||
acb->aio_iov = qiov->iov;
|
||||
acb->aio_niov = qiov->niov;
|
||||
}
|
||||
acb->aio_nbytes = nb_sectors * 512;
|
||||
acb->aio_offset = sector_num * 512;
|
||||
|
||||
trace_paio_submit(acb, opaque, sector_num, nb_sectors, type);
|
||||
return thread_pool_submit_aio(aio_worker, acb, cb, opaque);
|
||||
}
|
||||
|
||||
int qemu_ftruncate64(int fd, int64_t length)
|
||||
{
|
||||
LARGE_INTEGER li;
|
||||
|
@ -89,6 +211,9 @@ static void raw_parse_flags(int flags, int *access_flags, DWORD *overlapped)
|
|||
}
|
||||
|
||||
*overlapped = FILE_ATTRIBUTE_NORMAL;
|
||||
if (flags & BDRV_O_NATIVE_AIO) {
|
||||
*overlapped |= FILE_FLAG_OVERLAPPED;
|
||||
}
|
||||
if (flags & BDRV_O_NOCACHE) {
|
||||
*overlapped |= FILE_FLAG_NO_BUFFERING;
|
||||
}
|
||||
|
@ -103,6 +228,13 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags)
|
|||
s->type = FTYPE_FILE;
|
||||
|
||||
raw_parse_flags(flags, &access_flags, &overlapped);
|
||||
|
||||
if ((flags & BDRV_O_NATIVE_AIO) && aio == NULL) {
|
||||
aio = win32_aio_init();
|
||||
if (aio == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
s->hfile = CreateFile(filename, access_flags,
|
||||
FILE_SHARE_READ, NULL,
|
||||
|
@ -112,64 +244,53 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags)
|
|||
|
||||
if (err == ERROR_ACCESS_DENIED)
|
||||
return -EACCES;
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (flags & BDRV_O_NATIVE_AIO) {
|
||||
int ret = win32_aio_attach(aio, s->hfile);
|
||||
if (ret < 0) {
|
||||
CloseHandle(s->hfile);
|
||||
return ret;
|
||||
}
|
||||
s->aio = aio;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int raw_read(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors)
|
||||
static BlockDriverAIOCB *raw_aio_readv(BlockDriverState *bs,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
OVERLAPPED ov;
|
||||
DWORD ret_count;
|
||||
int ret;
|
||||
int64_t offset = sector_num * 512;
|
||||
int count = nb_sectors * 512;
|
||||
|
||||
memset(&ov, 0, sizeof(ov));
|
||||
ov.Offset = offset;
|
||||
ov.OffsetHigh = offset >> 32;
|
||||
ret = ReadFile(s->hfile, buf, count, &ret_count, &ov);
|
||||
if (!ret)
|
||||
return ret_count;
|
||||
if (ret_count == count)
|
||||
ret_count = 0;
|
||||
return ret_count;
|
||||
}
|
||||
|
||||
static int raw_write(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
OVERLAPPED ov;
|
||||
DWORD ret_count;
|
||||
int ret;
|
||||
int64_t offset = sector_num * 512;
|
||||
int count = nb_sectors * 512;
|
||||
|
||||
memset(&ov, 0, sizeof(ov));
|
||||
ov.Offset = offset;
|
||||
ov.OffsetHigh = offset >> 32;
|
||||
ret = WriteFile(s->hfile, buf, count, &ret_count, &ov);
|
||||
if (!ret)
|
||||
return ret_count;
|
||||
if (ret_count == count)
|
||||
ret_count = 0;
|
||||
return ret_count;
|
||||
}
|
||||
|
||||
static int raw_flush(BlockDriverState *bs)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
int ret;
|
||||
|
||||
ret = FlushFileBuffers(s->hfile);
|
||||
if (ret == 0) {
|
||||
return -EIO;
|
||||
if (s->aio) {
|
||||
return win32_aio_submit(bs, s->aio, s->hfile, sector_num, qiov,
|
||||
nb_sectors, cb, opaque, QEMU_AIO_READ);
|
||||
} else {
|
||||
return paio_submit(bs, s->hfile, sector_num, qiov, nb_sectors,
|
||||
cb, opaque, QEMU_AIO_READ);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
static BlockDriverAIOCB *raw_aio_writev(BlockDriverState *bs,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
if (s->aio) {
|
||||
return win32_aio_submit(bs, s->aio, s->hfile, sector_num, qiov,
|
||||
nb_sectors, cb, opaque, QEMU_AIO_WRITE);
|
||||
} else {
|
||||
return paio_submit(bs, s->hfile, sector_num, qiov, nb_sectors,
|
||||
cb, opaque, QEMU_AIO_WRITE);
|
||||
}
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *raw_aio_flush(BlockDriverState *bs,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
return paio_submit(bs, s->hfile, 0, NULL, 0, cb, opaque, QEMU_AIO_FLUSH);
|
||||
}
|
||||
|
||||
static void raw_close(BlockDriverState *bs)
|
||||
|
@ -290,9 +411,9 @@ static BlockDriver bdrv_file = {
|
|||
.bdrv_close = raw_close,
|
||||
.bdrv_create = raw_create,
|
||||
|
||||
.bdrv_read = raw_read,
|
||||
.bdrv_write = raw_write,
|
||||
.bdrv_co_flush_to_disk = raw_flush,
|
||||
.bdrv_aio_readv = raw_aio_readv,
|
||||
.bdrv_aio_writev = raw_aio_writev,
|
||||
.bdrv_aio_flush = raw_aio_flush,
|
||||
|
||||
.bdrv_truncate = raw_truncate,
|
||||
.bdrv_getlength = raw_getlength,
|
||||
|
@ -413,9 +534,9 @@ static BlockDriver bdrv_host_device = {
|
|||
.bdrv_close = raw_close,
|
||||
.bdrv_has_zero_init = hdev_has_zero_init,
|
||||
|
||||
.bdrv_read = raw_read,
|
||||
.bdrv_write = raw_write,
|
||||
.bdrv_co_flush_to_disk = raw_flush,
|
||||
.bdrv_aio_readv = raw_aio_readv,
|
||||
.bdrv_aio_writev = raw_aio_writev,
|
||||
.bdrv_aio_flush = raw_aio_flush,
|
||||
|
||||
.bdrv_getlength = raw_getlength,
|
||||
.bdrv_get_allocated_file_size
|
||||
|
|
|
@ -0,0 +1,226 @@
|
|||
/*
|
||||
* Block driver for RAW files (win32)
|
||||
*
|
||||
* Copyright (c) 2006 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* 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-timer.h"
|
||||
#include "block_int.h"
|
||||
#include "module.h"
|
||||
#include "qemu-common.h"
|
||||
#include "qemu-aio.h"
|
||||
#include "raw-aio.h"
|
||||
#include "event_notifier.h"
|
||||
#include <windows.h>
|
||||
#include <winioctl.h>
|
||||
|
||||
#define FTYPE_FILE 0
|
||||
#define FTYPE_CD 1
|
||||
#define FTYPE_HARDDISK 2
|
||||
|
||||
struct QEMUWin32AIOState {
|
||||
HANDLE hIOCP;
|
||||
EventNotifier e;
|
||||
int count;
|
||||
};
|
||||
|
||||
typedef struct QEMUWin32AIOCB {
|
||||
BlockDriverAIOCB common;
|
||||
struct QEMUWin32AIOState *ctx;
|
||||
int nbytes;
|
||||
OVERLAPPED ov;
|
||||
QEMUIOVector *qiov;
|
||||
void *buf;
|
||||
bool is_read;
|
||||
bool is_linear;
|
||||
} QEMUWin32AIOCB;
|
||||
|
||||
/*
|
||||
* Completes an AIO request (calls the callback and frees the ACB).
|
||||
*/
|
||||
static void win32_aio_process_completion(QEMUWin32AIOState *s,
|
||||
QEMUWin32AIOCB *waiocb, DWORD count)
|
||||
{
|
||||
int ret;
|
||||
s->count--;
|
||||
|
||||
if (waiocb->ov.Internal != 0) {
|
||||
ret = -EIO;
|
||||
} else {
|
||||
ret = 0;
|
||||
if (count < waiocb->nbytes) {
|
||||
/* Short reads mean EOF, pad with zeros. */
|
||||
if (waiocb->is_read) {
|
||||
qemu_iovec_memset(waiocb->qiov, count, 0,
|
||||
waiocb->qiov->size - count);
|
||||
} else {
|
||||
ret = -EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!waiocb->is_linear) {
|
||||
if (ret == 0 && waiocb->is_read) {
|
||||
QEMUIOVector *qiov = waiocb->qiov;
|
||||
char *p = waiocb->buf;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < qiov->niov; ++i) {
|
||||
memcpy(p, qiov->iov[i].iov_base, qiov->iov[i].iov_len);
|
||||
p += qiov->iov[i].iov_len;
|
||||
}
|
||||
g_free(waiocb->buf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
waiocb->common.cb(waiocb->common.opaque, ret);
|
||||
qemu_aio_release(waiocb);
|
||||
}
|
||||
|
||||
static void win32_aio_completion_cb(EventNotifier *e)
|
||||
{
|
||||
QEMUWin32AIOState *s = container_of(e, QEMUWin32AIOState, e);
|
||||
DWORD count;
|
||||
ULONG_PTR key;
|
||||
OVERLAPPED *ov;
|
||||
|
||||
event_notifier_test_and_clear(&s->e);
|
||||
while (GetQueuedCompletionStatus(s->hIOCP, &count, &key, &ov, 0)) {
|
||||
QEMUWin32AIOCB *waiocb = container_of(ov, QEMUWin32AIOCB, ov);
|
||||
|
||||
win32_aio_process_completion(s, waiocb, count);
|
||||
}
|
||||
}
|
||||
|
||||
static int win32_aio_flush_cb(EventNotifier *e)
|
||||
{
|
||||
QEMUWin32AIOState *s = container_of(e, QEMUWin32AIOState, e);
|
||||
|
||||
return (s->count > 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
static void win32_aio_cancel(BlockDriverAIOCB *blockacb)
|
||||
{
|
||||
QEMUWin32AIOCB *waiocb = (QEMUWin32AIOCB *)blockacb;
|
||||
|
||||
/*
|
||||
* CancelIoEx is only supported in Vista and newer. For now, just
|
||||
* wait for completion.
|
||||
*/
|
||||
while (!HasOverlappedIoCompleted(&waiocb->ov)) {
|
||||
qemu_aio_wait();
|
||||
}
|
||||
}
|
||||
|
||||
static AIOPool win32_aio_pool = {
|
||||
.aiocb_size = sizeof(QEMUWin32AIOCB),
|
||||
.cancel = win32_aio_cancel,
|
||||
};
|
||||
|
||||
BlockDriverAIOCB *win32_aio_submit(BlockDriverState *bs,
|
||||
QEMUWin32AIOState *aio, HANDLE hfile,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque, int type)
|
||||
{
|
||||
struct QEMUWin32AIOCB *waiocb;
|
||||
uint64_t offset = sector_num * 512;
|
||||
DWORD rc;
|
||||
|
||||
waiocb = qemu_aio_get(&win32_aio_pool, bs, cb, opaque);
|
||||
waiocb->nbytes = nb_sectors * 512;
|
||||
waiocb->qiov = qiov;
|
||||
waiocb->is_read = (type == QEMU_AIO_READ);
|
||||
|
||||
if (qiov->niov > 1) {
|
||||
waiocb->buf = qemu_blockalign(bs, qiov->size);
|
||||
if (type & QEMU_AIO_WRITE) {
|
||||
char *p = waiocb->buf;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < qiov->niov; ++i) {
|
||||
memcpy(p, qiov->iov[i].iov_base, qiov->iov[i].iov_len);
|
||||
p += qiov->iov[i].iov_len;
|
||||
}
|
||||
}
|
||||
waiocb->is_linear = false;
|
||||
} else {
|
||||
waiocb->buf = qiov->iov[0].iov_base;
|
||||
waiocb->is_linear = true;
|
||||
}
|
||||
|
||||
waiocb->ov = (OVERLAPPED) {
|
||||
.Offset = (DWORD) offset,
|
||||
.OffsetHigh = (DWORD) (offset >> 32),
|
||||
.hEvent = event_notifier_get_handle(&aio->e)
|
||||
};
|
||||
aio->count++;
|
||||
|
||||
if (type & QEMU_AIO_READ) {
|
||||
rc = ReadFile(hfile, waiocb->buf, waiocb->nbytes, NULL, &waiocb->ov);
|
||||
} else {
|
||||
rc = WriteFile(hfile, waiocb->buf, waiocb->nbytes, NULL, &waiocb->ov);
|
||||
}
|
||||
if(rc == 0 && GetLastError() != ERROR_IO_PENDING) {
|
||||
goto out_dec_count;
|
||||
}
|
||||
return &waiocb->common;
|
||||
|
||||
out_dec_count:
|
||||
aio->count--;
|
||||
qemu_aio_release(waiocb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int win32_aio_attach(QEMUWin32AIOState *aio, HANDLE hfile)
|
||||
{
|
||||
if (CreateIoCompletionPort(hfile, aio->hIOCP, (ULONG_PTR) 0, 0) == NULL) {
|
||||
return -EINVAL;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
QEMUWin32AIOState *win32_aio_init(void)
|
||||
{
|
||||
QEMUWin32AIOState *s;
|
||||
|
||||
s = g_malloc0(sizeof(*s));
|
||||
if (event_notifier_init(&s->e, false) < 0) {
|
||||
goto out_free_state;
|
||||
}
|
||||
|
||||
s->hIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
|
||||
if (s->hIOCP == NULL) {
|
||||
goto out_close_efd;
|
||||
}
|
||||
|
||||
qemu_aio_set_event_notifier(&s->e, win32_aio_completion_cb,
|
||||
win32_aio_flush_cb);
|
||||
|
||||
return s;
|
||||
|
||||
out_close_efd:
|
||||
event_notifier_cleanup(&s->e);
|
||||
out_free_state:
|
||||
g_free(s);
|
||||
return NULL;
|
||||
}
|
|
@ -436,6 +436,12 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (qemu_opt_get(opts, "boot") != NULL) {
|
||||
fprintf(stderr, "qemu-kvm: boot=on|off is deprecated and will be "
|
||||
"ignored. Future versions will reject this parameter. Please "
|
||||
"update your scripts.\n");
|
||||
}
|
||||
|
||||
on_write_error = BLOCKDEV_ON_ERROR_ENOSPC;
|
||||
if ((buf = qemu_opt_get(opts, "werror")) != NULL) {
|
||||
if (type != IF_IDE && type != IF_SCSI && type != IF_VIRTIO && type != IF_NONE) {
|
||||
|
|
|
@ -174,6 +174,13 @@ static int buffered_close(void *opaque)
|
|||
* 1: Time to stop
|
||||
* negative: There has been an error
|
||||
*/
|
||||
static int buffered_get_fd(void *opaque)
|
||||
{
|
||||
QEMUFileBuffered *s = opaque;
|
||||
|
||||
return qemu_get_fd(s->file);
|
||||
}
|
||||
|
||||
static int buffered_rate_limit(void *opaque)
|
||||
{
|
||||
QEMUFileBuffered *s = opaque;
|
||||
|
@ -234,6 +241,15 @@ static void buffered_rate_tick(void *opaque)
|
|||
buffered_put_buffer(s, NULL, 0, 0);
|
||||
}
|
||||
|
||||
static const QEMUFileOps buffered_file_ops = {
|
||||
.get_fd = buffered_get_fd,
|
||||
.put_buffer = buffered_put_buffer,
|
||||
.close = buffered_close,
|
||||
.rate_limit = buffered_rate_limit,
|
||||
.get_rate_limit = buffered_get_rate_limit,
|
||||
.set_rate_limit = buffered_set_rate_limit,
|
||||
};
|
||||
|
||||
QEMUFile *qemu_fopen_ops_buffered(MigrationState *migration_state)
|
||||
{
|
||||
QEMUFileBuffered *s;
|
||||
|
@ -243,10 +259,7 @@ QEMUFile *qemu_fopen_ops_buffered(MigrationState *migration_state)
|
|||
s->migration_state = migration_state;
|
||||
s->xfer_limit = migration_state->bandwidth_limit / 10;
|
||||
|
||||
s->file = qemu_fopen_ops(s, buffered_put_buffer, NULL,
|
||||
buffered_close, buffered_rate_limit,
|
||||
buffered_set_rate_limit,
|
||||
buffered_get_rate_limit);
|
||||
s->file = qemu_fopen_ops(s, &buffered_file_ops);
|
||||
|
||||
s->timer = qemu_new_timer_ms(rt_clock, buffered_rate_tick, s);
|
||||
|
||||
|
|
18
compiler.h
18
compiler.h
|
@ -50,16 +50,20 @@
|
|||
# define __printf__ __gnu_printf__
|
||||
# endif
|
||||
# endif
|
||||
#if defined(_WIN32)
|
||||
#define GCC_WEAK __attribute__((weak))
|
||||
#define GCC_WEAK_DECL GCC_WEAK
|
||||
#else
|
||||
#define GCC_WEAK __attribute__((weak))
|
||||
#define GCC_WEAK_DECL
|
||||
#endif
|
||||
# if defined(__APPLE__)
|
||||
# define QEMU_WEAK_ALIAS(newname, oldname) \
|
||||
static typeof(oldname) weak_##newname __attribute__((unused, weakref(#oldname)))
|
||||
# define QEMU_WEAK_REF(newname, oldname) (weak_##newname ? weak_##newname : oldname)
|
||||
# else
|
||||
# define QEMU_WEAK_ALIAS(newname, oldname) \
|
||||
typeof(oldname) newname __attribute__((weak, alias (#oldname)))
|
||||
# define QEMU_WEAK_REF(newname, oldname) newname
|
||||
# endif
|
||||
#else
|
||||
#define GCC_ATTR /**/
|
||||
#define GCC_FMT_ATTR(n, m)
|
||||
#define QEMU_WEAK_ALIAS(newname, oldname) \
|
||||
_Pragma("weak " #newname "=" #oldname)
|
||||
#endif
|
||||
|
||||
#endif /* COMPILER_H */
|
||||
|
|
|
@ -147,6 +147,7 @@ curses=""
|
|||
docs=""
|
||||
fdt=""
|
||||
nptl=""
|
||||
pixman=""
|
||||
sdl=""
|
||||
virtfs=""
|
||||
vnc="yes"
|
||||
|
@ -642,6 +643,10 @@ for opt do
|
|||
# configure to be used by RPM and similar macros that set
|
||||
# lots of directory switches by default.
|
||||
;;
|
||||
--with-system-pixman) pixman="system"
|
||||
;;
|
||||
--without-system-pixman) pixman="internal"
|
||||
;;
|
||||
--disable-sdl) sdl="no"
|
||||
;;
|
||||
--enable-sdl) sdl="yes"
|
||||
|
@ -2094,6 +2099,34 @@ else
|
|||
exit 1
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# pixman support probe
|
||||
|
||||
if test "$pixman" = ""; then
|
||||
if $pkg_config pixman-1 > /dev/null 2>&1; then
|
||||
pixman="system"
|
||||
else
|
||||
pixman="internal"
|
||||
fi
|
||||
fi
|
||||
if test "$pixman" = "system"; then
|
||||
pixman_cflags=`$pkg_config --cflags pixman-1 2>/dev/null`
|
||||
pixman_libs=`$pkg_config --libs pixman-1 2>/dev/null`
|
||||
else
|
||||
if test ! -d ${source_path}/pixman/pixman; then
|
||||
echo "ERROR: pixman not present. Your options:"
|
||||
echo " (1) Prefered: Install the pixman devel package (any recent"
|
||||
echo " distro should have packages as Xorg needs pixman too)."
|
||||
echo " (2) Fetch the pixman submodule, using:"
|
||||
echo " git submodule update --init pixman"
|
||||
exit 1
|
||||
fi
|
||||
pixman_cflags="-I${source_path}/pixman/pixman"
|
||||
pixman_libs="-Lpixman/pixman/.libs -lpixman-1"
|
||||
fi
|
||||
QEMU_CFLAGS="$QEMU_CFLAGS $pixman_cflags"
|
||||
libs_softmmu="$libs_softmmu $pixman_libs"
|
||||
|
||||
##########################################
|
||||
# libcap probe
|
||||
|
||||
|
@ -2768,7 +2801,7 @@ fi
|
|||
|
||||
# check for usbredirparser for usb network redirection support
|
||||
if test "$usb_redir" != "no" ; then
|
||||
if $pkg_config --atleast-version=0.5 libusbredirparser-0.5 >/dev/null 2>&1 ; then
|
||||
if $pkg_config --atleast-version=0.5.3 libusbredirparser-0.5 >/dev/null 2>&1 ; then
|
||||
usb_redir="yes"
|
||||
usb_redir_cflags=$($pkg_config --cflags libusbredirparser-0.5 2>/dev/null)
|
||||
usb_redir_libs=$($pkg_config --libs libusbredirparser-0.5 2>/dev/null)
|
||||
|
@ -3155,6 +3188,7 @@ echo "-Werror enabled $werror"
|
|||
if test "$darwin" = "yes" ; then
|
||||
echo "Cocoa support $cocoa"
|
||||
fi
|
||||
echo "pixman $pixman"
|
||||
echo "SDL support $sdl"
|
||||
echo "curses support $curses"
|
||||
echo "curl support $curl"
|
||||
|
@ -3859,6 +3893,12 @@ upper() {
|
|||
echo "$@"| LC_ALL=C tr '[a-z]' '[A-Z]'
|
||||
}
|
||||
|
||||
case "$cpu" in
|
||||
i386|x86_64|ppc)
|
||||
echo "CONFIG_QEMU_LDST_OPTIMIZATION=y" >> $config_target_mak
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "TARGET_SHORT_ALIGNMENT=$target_short_alignment" >> $config_target_mak
|
||||
echo "TARGET_INT_ALIGNMENT=$target_int_alignment" >> $config_target_mak
|
||||
echo "TARGET_LONG_ALIGNMENT=$target_long_alignment" >> $config_target_mak
|
||||
|
@ -3920,6 +3960,9 @@ if test "$target_softmmu" = "yes" ; then
|
|||
if test "$smartcard_nss" = "yes" ; then
|
||||
echo "subdir-$target: subdir-libcacard" >> $config_host_mak
|
||||
fi
|
||||
if test "$pixman" = "internal" ; then
|
||||
echo "subdir-$target: subdir-pixman" >> $config_host_mak
|
||||
fi
|
||||
case "$target_arch2" in
|
||||
i386|x86_64)
|
||||
echo "CONFIG_HAVE_CORE_DUMP=y" >> $config_target_mak
|
||||
|
@ -4123,6 +4166,7 @@ DIRS="$DIRS pc-bios/optionrom pc-bios/spapr-rtas"
|
|||
DIRS="$DIRS roms/seabios roms/vgabios"
|
||||
DIRS="$DIRS qapi-generated"
|
||||
DIRS="$DIRS libcacard libcacard/libcacard libcacard/trace"
|
||||
DIRS="$DIRS pixman"
|
||||
FILES="Makefile tests/tcg/Makefile qdict-test-data.txt"
|
||||
FILES="$FILES tests/tcg/cris/Makefile tests/tcg/cris/.gdbinit"
|
||||
FILES="$FILES tests/tcg/lm32/Makefile libcacard/Makefile"
|
||||
|
|
252
console.c
252
console.c
|
@ -114,20 +114,20 @@ typedef enum {
|
|||
TEXT_CONSOLE_FIXED_SIZE
|
||||
} console_type_t;
|
||||
|
||||
/* ??? This is mis-named.
|
||||
It is used for both text and graphical consoles. */
|
||||
struct TextConsole {
|
||||
struct QemuConsole {
|
||||
int index;
|
||||
console_type_t console_type;
|
||||
DisplayState *ds;
|
||||
|
||||
/* Graphic console state. */
|
||||
vga_hw_update_ptr hw_update;
|
||||
vga_hw_invalidate_ptr hw_invalidate;
|
||||
vga_hw_screen_dump_ptr hw_screen_dump;
|
||||
vga_hw_text_update_ptr hw_text_update;
|
||||
void *hw;
|
||||
|
||||
int g_width, g_height;
|
||||
|
||||
/* Text console state */
|
||||
int width;
|
||||
int height;
|
||||
int total_height;
|
||||
|
@ -161,8 +161,8 @@ struct TextConsole {
|
|||
};
|
||||
|
||||
static DisplayState *display_state;
|
||||
static TextConsole *active_console;
|
||||
static TextConsole *consoles[MAX_CONSOLES];
|
||||
static QemuConsole *active_console;
|
||||
static QemuConsole *consoles[MAX_CONSOLES];
|
||||
static int nb_consoles = 0;
|
||||
|
||||
void vga_hw_update(void)
|
||||
|
@ -179,7 +179,7 @@ void vga_hw_invalidate(void)
|
|||
|
||||
void qmp_screendump(const char *filename, Error **errp)
|
||||
{
|
||||
TextConsole *previous_active_console;
|
||||
QemuConsole *previous_active_console;
|
||||
bool cswitch;
|
||||
|
||||
previous_active_console = active_console;
|
||||
|
@ -521,7 +521,7 @@ static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
|
|||
}
|
||||
}
|
||||
|
||||
static void text_console_resize(TextConsole *s)
|
||||
static void text_console_resize(QemuConsole *s)
|
||||
{
|
||||
TextCell *cells, *c, *c1;
|
||||
int w1, x, y, last_width;
|
||||
|
@ -553,7 +553,7 @@ static void text_console_resize(TextConsole *s)
|
|||
s->cells = cells;
|
||||
}
|
||||
|
||||
static inline void text_update_xy(TextConsole *s, int x, int y)
|
||||
static inline void text_update_xy(QemuConsole *s, int x, int y)
|
||||
{
|
||||
s->text_x[0] = MIN(s->text_x[0], x);
|
||||
s->text_x[1] = MAX(s->text_x[1], x);
|
||||
|
@ -561,7 +561,7 @@ static inline void text_update_xy(TextConsole *s, int x, int y)
|
|||
s->text_y[1] = MAX(s->text_y[1], y);
|
||||
}
|
||||
|
||||
static void invalidate_xy(TextConsole *s, int x, int y)
|
||||
static void invalidate_xy(QemuConsole *s, int x, int y)
|
||||
{
|
||||
if (s->update_x0 > x * FONT_WIDTH)
|
||||
s->update_x0 = x * FONT_WIDTH;
|
||||
|
@ -573,7 +573,7 @@ static void invalidate_xy(TextConsole *s, int x, int y)
|
|||
s->update_y1 = (y + 1) * FONT_HEIGHT;
|
||||
}
|
||||
|
||||
static void update_xy(TextConsole *s, int x, int y)
|
||||
static void update_xy(QemuConsole *s, int x, int y)
|
||||
{
|
||||
TextCell *c;
|
||||
int y1, y2;
|
||||
|
@ -597,7 +597,7 @@ static void update_xy(TextConsole *s, int x, int y)
|
|||
}
|
||||
}
|
||||
|
||||
static void console_show_cursor(TextConsole *s, int show)
|
||||
static void console_show_cursor(QemuConsole *s, int show)
|
||||
{
|
||||
TextCell *c;
|
||||
int y, y1;
|
||||
|
@ -631,42 +631,45 @@ static void console_show_cursor(TextConsole *s, int show)
|
|||
}
|
||||
}
|
||||
|
||||
static void console_refresh(TextConsole *s)
|
||||
static void console_refresh(QemuConsole *s)
|
||||
{
|
||||
TextCell *c;
|
||||
int x, y, y1;
|
||||
|
||||
if (s != active_console)
|
||||
return;
|
||||
if (!ds_get_bits_per_pixel(s->ds)) {
|
||||
|
||||
if (s->ds->have_text) {
|
||||
s->text_x[0] = 0;
|
||||
s->text_y[0] = 0;
|
||||
s->text_x[1] = s->width - 1;
|
||||
s->text_y[1] = s->height - 1;
|
||||
s->cursor_invalidate = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds),
|
||||
color_table[0][COLOR_BLACK]);
|
||||
y1 = s->y_displayed;
|
||||
for(y = 0; y < s->height; y++) {
|
||||
c = s->cells + y1 * s->width;
|
||||
for(x = 0; x < s->width; x++) {
|
||||
vga_putcharxy(s->ds, x, y, c->ch,
|
||||
&(c->t_attrib));
|
||||
c++;
|
||||
if (s->ds->have_gfx) {
|
||||
vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds),
|
||||
color_table[0][COLOR_BLACK]);
|
||||
y1 = s->y_displayed;
|
||||
for (y = 0; y < s->height; y++) {
|
||||
c = s->cells + y1 * s->width;
|
||||
for (x = 0; x < s->width; x++) {
|
||||
vga_putcharxy(s->ds, x, y, c->ch,
|
||||
&(c->t_attrib));
|
||||
c++;
|
||||
}
|
||||
if (++y1 == s->total_height) {
|
||||
y1 = 0;
|
||||
}
|
||||
}
|
||||
if (++y1 == s->total_height)
|
||||
y1 = 0;
|
||||
console_show_cursor(s, 1);
|
||||
dpy_gfx_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
|
||||
}
|
||||
console_show_cursor(s, 1);
|
||||
dpy_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
|
||||
}
|
||||
|
||||
static void console_scroll(int ydelta)
|
||||
{
|
||||
TextConsole *s;
|
||||
QemuConsole *s;
|
||||
int i, y1;
|
||||
|
||||
s = active_console;
|
||||
|
@ -698,7 +701,7 @@ static void console_scroll(int ydelta)
|
|||
console_refresh(s);
|
||||
}
|
||||
|
||||
static void console_put_lf(TextConsole *s)
|
||||
static void console_put_lf(QemuConsole *s)
|
||||
{
|
||||
TextCell *c;
|
||||
int x, y1;
|
||||
|
@ -749,7 +752,7 @@ static void console_put_lf(TextConsole *s)
|
|||
* NOTE: I know this code is not very efficient (checking every color for it
|
||||
* self) but it is more readable and better maintainable.
|
||||
*/
|
||||
static void console_handle_escape(TextConsole *s)
|
||||
static void console_handle_escape(QemuConsole *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -842,7 +845,7 @@ static void console_handle_escape(TextConsole *s)
|
|||
}
|
||||
}
|
||||
|
||||
static void console_clear_xy(TextConsole *s, int x, int y)
|
||||
static void console_clear_xy(QemuConsole *s, int x, int y)
|
||||
{
|
||||
int y1 = (s->y_base + y) % s->total_height;
|
||||
TextCell *c = &s->cells[y1 * s->width + x];
|
||||
|
@ -852,7 +855,7 @@ static void console_clear_xy(TextConsole *s, int x, int y)
|
|||
}
|
||||
|
||||
/* set cursor, checking bounds */
|
||||
static void set_cursor(TextConsole *s, int x, int y)
|
||||
static void set_cursor(QemuConsole *s, int x, int y)
|
||||
{
|
||||
if (x < 0) {
|
||||
x = 0;
|
||||
|
@ -871,7 +874,7 @@ static void set_cursor(TextConsole *s, int x, int y)
|
|||
s->y = y;
|
||||
}
|
||||
|
||||
static void console_putchar(TextConsole *s, int ch)
|
||||
static void console_putchar(QemuConsole *s, int ch)
|
||||
{
|
||||
TextCell *c;
|
||||
int y1, i;
|
||||
|
@ -1078,7 +1081,7 @@ static void console_putchar(TextConsole *s, int ch)
|
|||
|
||||
void console_select(unsigned int index)
|
||||
{
|
||||
TextConsole *s;
|
||||
QemuConsole *s;
|
||||
|
||||
if (index >= MAX_CONSOLES)
|
||||
return;
|
||||
|
@ -1094,24 +1097,24 @@ void console_select(unsigned int index)
|
|||
qemu_del_timer(active_console->cursor_timer);
|
||||
}
|
||||
active_console = s;
|
||||
if (ds_get_bits_per_pixel(s->ds)) {
|
||||
if (ds->have_gfx) {
|
||||
ds->surface = qemu_resize_displaysurface(ds, s->g_width, s->g_height);
|
||||
} else {
|
||||
s->ds->surface->width = s->width;
|
||||
s->ds->surface->height = s->height;
|
||||
dpy_gfx_resize(ds);
|
||||
}
|
||||
if (ds->have_text) {
|
||||
dpy_text_resize(ds, s->width, s->height);
|
||||
}
|
||||
if (s->cursor_timer) {
|
||||
qemu_mod_timer(s->cursor_timer,
|
||||
qemu_get_clock_ms(rt_clock) + CONSOLE_CURSOR_PERIOD / 2);
|
||||
}
|
||||
dpy_resize(s->ds);
|
||||
vga_hw_invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
|
||||
{
|
||||
TextConsole *s = chr->opaque;
|
||||
QemuConsole *s = chr->opaque;
|
||||
int i;
|
||||
|
||||
s->update_x0 = s->width * FONT_WIDTH;
|
||||
|
@ -1123,17 +1126,17 @@ static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
|
|||
console_putchar(s, buf[i]);
|
||||
}
|
||||
console_show_cursor(s, 1);
|
||||
if (ds_get_bits_per_pixel(s->ds) && s->update_x0 < s->update_x1) {
|
||||
dpy_update(s->ds, s->update_x0, s->update_y0,
|
||||
s->update_x1 - s->update_x0,
|
||||
s->update_y1 - s->update_y0);
|
||||
if (s->ds->have_gfx && s->update_x0 < s->update_x1) {
|
||||
dpy_gfx_update(s->ds, s->update_x0, s->update_y0,
|
||||
s->update_x1 - s->update_x0,
|
||||
s->update_y1 - s->update_y0);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static void kbd_send_chars(void *opaque)
|
||||
{
|
||||
TextConsole *s = opaque;
|
||||
QemuConsole *s = opaque;
|
||||
int len;
|
||||
uint8_t buf[16];
|
||||
|
||||
|
@ -1156,7 +1159,7 @@ static void kbd_send_chars(void *opaque)
|
|||
/* called when an ascii key is pressed */
|
||||
void kbd_put_keysym(int keysym)
|
||||
{
|
||||
TextConsole *s;
|
||||
QemuConsole *s;
|
||||
uint8_t buf[16], *q;
|
||||
int c;
|
||||
|
||||
|
@ -1211,7 +1214,7 @@ void kbd_put_keysym(int keysym)
|
|||
|
||||
static void text_console_invalidate(void *opaque)
|
||||
{
|
||||
TextConsole *s = (TextConsole *) opaque;
|
||||
QemuConsole *s = (QemuConsole *) opaque;
|
||||
if (!ds_get_bits_per_pixel(s->ds) && s->console_type == TEXT_CONSOLE) {
|
||||
s->g_width = ds_get_width(s->ds);
|
||||
s->g_height = ds_get_height(s->ds);
|
||||
|
@ -1222,7 +1225,7 @@ static void text_console_invalidate(void *opaque)
|
|||
|
||||
static void text_console_update(void *opaque, console_ch_t *chardata)
|
||||
{
|
||||
TextConsole *s = (TextConsole *) opaque;
|
||||
QemuConsole *s = (QemuConsole *) opaque;
|
||||
int i, j, src;
|
||||
|
||||
if (s->text_x[0] <= s->text_x[1]) {
|
||||
|
@ -1234,23 +1237,23 @@ static void text_console_update(void *opaque, console_ch_t *chardata)
|
|||
(s->cells[src].t_attrib.fgcol << 12) |
|
||||
(s->cells[src].t_attrib.bgcol << 8) |
|
||||
(s->cells[src].t_attrib.bold << 21));
|
||||
dpy_update(s->ds, s->text_x[0], s->text_y[0],
|
||||
s->text_x[1] - s->text_x[0], i - s->text_y[0]);
|
||||
dpy_text_update(s->ds, s->text_x[0], s->text_y[0],
|
||||
s->text_x[1] - s->text_x[0], i - s->text_y[0]);
|
||||
s->text_x[0] = s->width;
|
||||
s->text_y[0] = s->height;
|
||||
s->text_x[1] = 0;
|
||||
s->text_y[1] = 0;
|
||||
}
|
||||
if (s->cursor_invalidate) {
|
||||
dpy_cursor(s->ds, s->x, s->y);
|
||||
dpy_text_cursor(s->ds, s->x, s->y);
|
||||
s->cursor_invalidate = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static TextConsole *get_graphic_console(DisplayState *ds)
|
||||
static QemuConsole *get_graphic_console(DisplayState *ds)
|
||||
{
|
||||
int i;
|
||||
TextConsole *s;
|
||||
QemuConsole *s;
|
||||
for (i = 0; i < nb_consoles; i++) {
|
||||
s = consoles[i];
|
||||
if (s->console_type == GRAPHIC_CONSOLE && s->ds == ds)
|
||||
|
@ -1259,14 +1262,14 @@ static TextConsole *get_graphic_console(DisplayState *ds)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
|
||||
static QemuConsole *new_console(DisplayState *ds, console_type_t console_type)
|
||||
{
|
||||
TextConsole *s;
|
||||
QemuConsole *s;
|
||||
int i;
|
||||
|
||||
if (nb_consoles >= MAX_CONSOLES)
|
||||
return NULL;
|
||||
s = g_malloc0(sizeof(TextConsole));
|
||||
s = g_malloc0(sizeof(QemuConsole));
|
||||
if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
|
||||
(console_type == GRAPHIC_CONSOLE))) {
|
||||
active_console = s;
|
||||
|
@ -1291,85 +1294,86 @@ static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
|
|||
return s;
|
||||
}
|
||||
|
||||
static DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
|
||||
static void qemu_alloc_display(DisplaySurface *surface, int width, int height,
|
||||
int linesize, PixelFormat pf, int newflags)
|
||||
{
|
||||
DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface));
|
||||
|
||||
int linesize = width * 4;
|
||||
qemu_alloc_display(surface, width, height, linesize,
|
||||
qemu_default_pixelformat(32), 0);
|
||||
return surface;
|
||||
}
|
||||
|
||||
static DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
|
||||
int width, int height)
|
||||
{
|
||||
int linesize = width * 4;
|
||||
qemu_alloc_display(surface, width, height, linesize,
|
||||
qemu_default_pixelformat(32), 0);
|
||||
return surface;
|
||||
}
|
||||
|
||||
void qemu_alloc_display(DisplaySurface *surface, int width, int height,
|
||||
int linesize, PixelFormat pf, int newflags)
|
||||
{
|
||||
void *data;
|
||||
surface->width = width;
|
||||
surface->height = height;
|
||||
surface->linesize = linesize;
|
||||
surface->pf = pf;
|
||||
if (surface->flags & QEMU_ALLOCATED_FLAG) {
|
||||
data = g_realloc(surface->data,
|
||||
surface->linesize * surface->height);
|
||||
} else {
|
||||
data = g_malloc(surface->linesize * surface->height);
|
||||
}
|
||||
surface->data = (uint8_t *)data;
|
||||
|
||||
qemu_pixman_image_unref(surface->image);
|
||||
surface->image = NULL;
|
||||
|
||||
surface->format = qemu_pixman_get_format(&pf);
|
||||
assert(surface->format != 0);
|
||||
surface->image = pixman_image_create_bits(surface->format,
|
||||
width, height,
|
||||
NULL, linesize);
|
||||
assert(surface->image != NULL);
|
||||
|
||||
surface->flags = newflags | QEMU_ALLOCATED_FLAG;
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
surface->flags |= QEMU_BIG_ENDIAN_FLAG;
|
||||
#endif
|
||||
}
|
||||
|
||||
DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
|
||||
int linesize, uint8_t *data)
|
||||
DisplaySurface *qemu_create_displaysurface(DisplayState *ds,
|
||||
int width, int height)
|
||||
{
|
||||
DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface));
|
||||
DisplaySurface *surface = g_new0(DisplaySurface, 1);
|
||||
|
||||
int linesize = width * 4;
|
||||
qemu_alloc_display(surface, width, height, linesize,
|
||||
qemu_default_pixelformat(32), 0);
|
||||
return surface;
|
||||
}
|
||||
|
||||
DisplaySurface *qemu_resize_displaysurface(DisplayState *ds,
|
||||
int width, int height)
|
||||
{
|
||||
int linesize = width * 4;
|
||||
|
||||
trace_displaysurface_resize(ds, ds->surface, width, height);
|
||||
qemu_alloc_display(ds->surface, width, height, linesize,
|
||||
qemu_default_pixelformat(32), 0);
|
||||
return ds->surface;
|
||||
}
|
||||
|
||||
DisplaySurface *qemu_create_displaysurface_from(int width, int height, int bpp,
|
||||
int linesize, uint8_t *data)
|
||||
{
|
||||
DisplaySurface *surface = g_new0(DisplaySurface, 1);
|
||||
|
||||
surface->width = width;
|
||||
surface->height = height;
|
||||
surface->linesize = linesize;
|
||||
surface->pf = qemu_default_pixelformat(bpp);
|
||||
|
||||
surface->format = qemu_pixman_get_format(&surface->pf);
|
||||
assert(surface->format != 0);
|
||||
surface->image = pixman_image_create_bits(surface->format,
|
||||
width, height,
|
||||
(void *)data, linesize);
|
||||
assert(surface->image != NULL);
|
||||
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
surface->flags = QEMU_BIG_ENDIAN_FLAG;
|
||||
#endif
|
||||
surface->data = data;
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
static void defaultallocator_free_displaysurface(DisplaySurface *surface)
|
||||
void qemu_free_displaysurface(DisplayState *ds)
|
||||
{
|
||||
if (surface == NULL)
|
||||
trace_displaysurface_free(ds, ds->surface);
|
||||
if (ds->surface == NULL) {
|
||||
return;
|
||||
if (surface->flags & QEMU_ALLOCATED_FLAG)
|
||||
g_free(surface->data);
|
||||
g_free(surface);
|
||||
}
|
||||
qemu_pixman_image_unref(ds->surface->image);
|
||||
g_free(ds->surface);
|
||||
}
|
||||
|
||||
static struct DisplayAllocator default_allocator = {
|
||||
defaultallocator_create_displaysurface,
|
||||
defaultallocator_resize_displaysurface,
|
||||
defaultallocator_free_displaysurface
|
||||
};
|
||||
|
||||
static void dumb_display_init(void)
|
||||
{
|
||||
DisplayState *ds = g_malloc0(sizeof(DisplayState));
|
||||
int width = 640;
|
||||
int height = 480;
|
||||
|
||||
ds->allocator = &default_allocator;
|
||||
if (is_fixedsize_console()) {
|
||||
width = active_console->g_width;
|
||||
height = active_console->g_height;
|
||||
|
@ -1399,29 +1403,16 @@ DisplayState *get_displaystate(void)
|
|||
return display_state;
|
||||
}
|
||||
|
||||
DisplayAllocator *register_displayallocator(DisplayState *ds, DisplayAllocator *da)
|
||||
{
|
||||
if(ds->allocator == &default_allocator) {
|
||||
DisplaySurface *surf;
|
||||
surf = da->create_displaysurface(ds_get_width(ds), ds_get_height(ds));
|
||||
defaultallocator_free_displaysurface(ds->surface);
|
||||
ds->surface = surf;
|
||||
ds->allocator = da;
|
||||
}
|
||||
return ds->allocator;
|
||||
}
|
||||
|
||||
DisplayState *graphic_console_init(vga_hw_update_ptr update,
|
||||
vga_hw_invalidate_ptr invalidate,
|
||||
vga_hw_screen_dump_ptr screen_dump,
|
||||
vga_hw_text_update_ptr text_update,
|
||||
void *opaque)
|
||||
{
|
||||
TextConsole *s;
|
||||
QemuConsole *s;
|
||||
DisplayState *ds;
|
||||
|
||||
ds = (DisplayState *) g_malloc0(sizeof(DisplayState));
|
||||
ds->allocator = &default_allocator;
|
||||
ds->surface = qemu_create_displaysurface(ds, 640, 480);
|
||||
|
||||
s = new_console(ds, GRAPHIC_CONSOLE);
|
||||
|
@ -1463,14 +1454,14 @@ void console_color_init(DisplayState *ds)
|
|||
|
||||
static void text_console_set_echo(CharDriverState *chr, bool echo)
|
||||
{
|
||||
TextConsole *s = chr->opaque;
|
||||
QemuConsole *s = chr->opaque;
|
||||
|
||||
s->echo = echo;
|
||||
}
|
||||
|
||||
static void text_console_update_cursor(void *opaque)
|
||||
{
|
||||
TextConsole *s = opaque;
|
||||
QemuConsole *s = opaque;
|
||||
|
||||
s->cursor_visible_phase = !s->cursor_visible_phase;
|
||||
vga_hw_invalidate();
|
||||
|
@ -1480,7 +1471,7 @@ static void text_console_update_cursor(void *opaque)
|
|||
|
||||
static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
|
||||
{
|
||||
TextConsole *s;
|
||||
QemuConsole *s;
|
||||
static int color_inited;
|
||||
|
||||
s = chr->opaque;
|
||||
|
@ -1543,7 +1534,7 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
|
|||
CharDriverState *text_console_init(QemuOpts *opts)
|
||||
{
|
||||
CharDriverState *chr;
|
||||
TextConsole *s;
|
||||
QemuConsole *s;
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
|
||||
|
@ -1589,14 +1580,14 @@ void text_consoles_set_display(DisplayState *ds)
|
|||
|
||||
void qemu_console_resize(DisplayState *ds, int width, int height)
|
||||
{
|
||||
TextConsole *s = get_graphic_console(ds);
|
||||
QemuConsole *s = get_graphic_console(ds);
|
||||
if (!s) return;
|
||||
|
||||
s->g_width = width;
|
||||
s->g_height = height;
|
||||
if (is_graphic_console()) {
|
||||
ds->surface = qemu_resize_displaysurface(ds, width, height);
|
||||
dpy_resize(ds);
|
||||
dpy_gfx_resize(ds);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1604,7 +1595,7 @@ void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
|
|||
int dst_x, int dst_y, int w, int h)
|
||||
{
|
||||
if (is_graphic_console()) {
|
||||
dpy_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
|
||||
dpy_gfx_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1715,18 +1706,15 @@ PixelFormat qemu_default_pixelformat(int bpp)
|
|||
pf.rmask = 0x00FF0000;
|
||||
pf.gmask = 0x0000FF00;
|
||||
pf.bmask = 0x000000FF;
|
||||
pf.amax = 255;
|
||||
pf.rmax = 255;
|
||||
pf.gmax = 255;
|
||||
pf.bmax = 255;
|
||||
pf.ashift = 24;
|
||||
pf.rshift = 16;
|
||||
pf.gshift = 8;
|
||||
pf.bshift = 0;
|
||||
pf.rbits = 8;
|
||||
pf.gbits = 8;
|
||||
pf.bbits = 8;
|
||||
pf.abits = 8;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
259
console.h
259
console.h
|
@ -2,6 +2,7 @@
|
|||
#define CONSOLE_H
|
||||
|
||||
#include "qemu-char.h"
|
||||
#include "qemu-pixman.h"
|
||||
#include "qdict.h"
|
||||
#include "notify.h"
|
||||
#include "monitor.h"
|
||||
|
@ -107,7 +108,6 @@ void kbd_put_keysym(int keysym);
|
|||
|
||||
#define QEMU_BIG_ENDIAN_FLAG 0x01
|
||||
#define QEMU_ALLOCATED_FLAG 0x02
|
||||
#define QEMU_REALPIXELS_FLAG 0x04
|
||||
|
||||
struct PixelFormat {
|
||||
uint8_t bits_per_pixel;
|
||||
|
@ -120,11 +120,9 @@ struct PixelFormat {
|
|||
};
|
||||
|
||||
struct DisplaySurface {
|
||||
pixman_format_code_t format;
|
||||
pixman_image_t *image;
|
||||
uint8_t flags;
|
||||
int width;
|
||||
int height;
|
||||
int linesize; /* bytes per line */
|
||||
uint8_t *data;
|
||||
|
||||
struct PixelFormat pf;
|
||||
};
|
||||
|
@ -154,35 +152,32 @@ struct DisplayChangeListener {
|
|||
int idle;
|
||||
uint64_t gui_timer_interval;
|
||||
|
||||
void (*dpy_update)(struct DisplayState *s, int x, int y, int w, int h);
|
||||
void (*dpy_resize)(struct DisplayState *s);
|
||||
void (*dpy_setdata)(struct DisplayState *s);
|
||||
void (*dpy_refresh)(struct DisplayState *s);
|
||||
void (*dpy_copy)(struct DisplayState *s, int src_x, int src_y,
|
||||
int dst_x, int dst_y, int w, int h);
|
||||
void (*dpy_fill)(struct DisplayState *s, int x, int y,
|
||||
int w, int h, uint32_t c);
|
||||
|
||||
void (*dpy_gfx_update)(struct DisplayState *s, int x, int y, int w, int h);
|
||||
void (*dpy_gfx_resize)(struct DisplayState *s);
|
||||
void (*dpy_gfx_setdata)(struct DisplayState *s);
|
||||
void (*dpy_gfx_copy)(struct DisplayState *s, int src_x, int src_y,
|
||||
int dst_x, int dst_y, int w, int h);
|
||||
|
||||
void (*dpy_text_cursor)(struct DisplayState *s, int x, int y);
|
||||
void (*dpy_text_resize)(struct DisplayState *s, int w, int h);
|
||||
void (*dpy_text_update)(struct DisplayState *s, int x, int y, int w, int h);
|
||||
|
||||
struct DisplayChangeListener *next;
|
||||
};
|
||||
void (*dpy_mouse_set)(struct DisplayState *s, int x, int y, int on);
|
||||
void (*dpy_cursor_define)(struct DisplayState *s, QEMUCursor *cursor);
|
||||
|
||||
struct DisplayAllocator {
|
||||
DisplaySurface* (*create_displaysurface)(int width, int height);
|
||||
DisplaySurface* (*resize_displaysurface)(DisplaySurface *surface, int width, int height);
|
||||
void (*free_displaysurface)(DisplaySurface *surface);
|
||||
QLIST_ENTRY(DisplayChangeListener) next;
|
||||
};
|
||||
|
||||
struct DisplayState {
|
||||
struct DisplaySurface *surface;
|
||||
void *opaque;
|
||||
struct QEMUTimer *gui_timer;
|
||||
bool have_gfx;
|
||||
bool have_text;
|
||||
|
||||
struct DisplayAllocator* allocator;
|
||||
struct DisplayChangeListener* listeners;
|
||||
|
||||
void (*mouse_set)(int x, int y, int on);
|
||||
void (*cursor_define)(QEMUCursor *cursor);
|
||||
QLIST_HEAD(, DisplayChangeListener) listeners;
|
||||
|
||||
struct DisplayState *next;
|
||||
};
|
||||
|
@ -191,29 +186,14 @@ void register_displaystate(DisplayState *ds);
|
|||
DisplayState *get_displaystate(void);
|
||||
DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
|
||||
int linesize, uint8_t *data);
|
||||
void qemu_alloc_display(DisplaySurface *surface, int width, int height,
|
||||
int linesize, PixelFormat pf, int newflags);
|
||||
PixelFormat qemu_different_endianness_pixelformat(int bpp);
|
||||
PixelFormat qemu_default_pixelformat(int bpp);
|
||||
|
||||
DisplayAllocator *register_displayallocator(DisplayState *ds, DisplayAllocator *da);
|
||||
|
||||
static inline DisplaySurface* qemu_create_displaysurface(DisplayState *ds, int width, int height)
|
||||
{
|
||||
return ds->allocator->create_displaysurface(width, height);
|
||||
}
|
||||
|
||||
static inline DisplaySurface* qemu_resize_displaysurface(DisplayState *ds, int width, int height)
|
||||
{
|
||||
trace_displaysurface_resize(ds, ds->surface, width, height);
|
||||
return ds->allocator->resize_displaysurface(ds->surface, width, height);
|
||||
}
|
||||
|
||||
static inline void qemu_free_displaysurface(DisplayState *ds)
|
||||
{
|
||||
trace_displaysurface_free(ds, ds->surface);
|
||||
ds->allocator->free_displaysurface(ds->surface);
|
||||
}
|
||||
DisplaySurface *qemu_create_displaysurface(DisplayState *ds,
|
||||
int width, int height);
|
||||
DisplaySurface *qemu_resize_displaysurface(DisplayState *ds,
|
||||
int width, int height);
|
||||
void qemu_free_displaysurface(DisplayState *ds);
|
||||
|
||||
static inline int is_surface_bgr(DisplaySurface *surface)
|
||||
{
|
||||
|
@ -225,109 +205,196 @@ static inline int is_surface_bgr(DisplaySurface *surface)
|
|||
|
||||
static inline int is_buffer_shared(DisplaySurface *surface)
|
||||
{
|
||||
return (!(surface->flags & QEMU_ALLOCATED_FLAG) &&
|
||||
!(surface->flags & QEMU_REALPIXELS_FLAG));
|
||||
return !(surface->flags & QEMU_ALLOCATED_FLAG);
|
||||
}
|
||||
|
||||
void gui_setup_refresh(DisplayState *ds);
|
||||
|
||||
static inline void register_displaychangelistener(DisplayState *ds, DisplayChangeListener *dcl)
|
||||
{
|
||||
dcl->next = ds->listeners;
|
||||
ds->listeners = dcl;
|
||||
}
|
||||
|
||||
static inline void dpy_update(DisplayState *s, int x, int y, int w, int h)
|
||||
{
|
||||
struct DisplayChangeListener *dcl = s->listeners;
|
||||
while (dcl != NULL) {
|
||||
dcl->dpy_update(s, x, y, w, h);
|
||||
dcl = dcl->next;
|
||||
QLIST_INSERT_HEAD(&ds->listeners, dcl, next);
|
||||
gui_setup_refresh(ds);
|
||||
if (dcl->dpy_gfx_resize) {
|
||||
dcl->dpy_gfx_resize(ds);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void dpy_resize(DisplayState *s)
|
||||
static inline void unregister_displaychangelistener(DisplayState *ds,
|
||||
DisplayChangeListener *dcl)
|
||||
{
|
||||
struct DisplayChangeListener *dcl = s->listeners;
|
||||
while (dcl != NULL) {
|
||||
dcl->dpy_resize(s);
|
||||
dcl = dcl->next;
|
||||
QLIST_REMOVE(dcl, next);
|
||||
gui_setup_refresh(ds);
|
||||
}
|
||||
|
||||
static inline void dpy_gfx_update(DisplayState *s, int x, int y, int w, int h)
|
||||
{
|
||||
struct DisplayChangeListener *dcl;
|
||||
QLIST_FOREACH(dcl, &s->listeners, next) {
|
||||
if (dcl->dpy_gfx_update) {
|
||||
dcl->dpy_gfx_update(s, x, y, w, h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void dpy_setdata(DisplayState *s)
|
||||
static inline void dpy_gfx_resize(DisplayState *s)
|
||||
{
|
||||
struct DisplayChangeListener *dcl = s->listeners;
|
||||
while (dcl != NULL) {
|
||||
if (dcl->dpy_setdata) dcl->dpy_setdata(s);
|
||||
dcl = dcl->next;
|
||||
struct DisplayChangeListener *dcl;
|
||||
QLIST_FOREACH(dcl, &s->listeners, next) {
|
||||
if (dcl->dpy_gfx_resize) {
|
||||
dcl->dpy_gfx_resize(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void dpy_gfx_setdata(DisplayState *s)
|
||||
{
|
||||
struct DisplayChangeListener *dcl;
|
||||
QLIST_FOREACH(dcl, &s->listeners, next) {
|
||||
if (dcl->dpy_gfx_setdata) {
|
||||
dcl->dpy_gfx_setdata(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void dpy_refresh(DisplayState *s)
|
||||
{
|
||||
struct DisplayChangeListener *dcl = s->listeners;
|
||||
while (dcl != NULL) {
|
||||
if (dcl->dpy_refresh) dcl->dpy_refresh(s);
|
||||
dcl = dcl->next;
|
||||
struct DisplayChangeListener *dcl;
|
||||
QLIST_FOREACH(dcl, &s->listeners, next) {
|
||||
if (dcl->dpy_refresh) {
|
||||
dcl->dpy_refresh(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void dpy_copy(struct DisplayState *s, int src_x, int src_y,
|
||||
int dst_x, int dst_y, int w, int h) {
|
||||
struct DisplayChangeListener *dcl = s->listeners;
|
||||
while (dcl != NULL) {
|
||||
if (dcl->dpy_copy)
|
||||
dcl->dpy_copy(s, src_x, src_y, dst_x, dst_y, w, h);
|
||||
else /* TODO */
|
||||
dcl->dpy_update(s, dst_x, dst_y, w, h);
|
||||
dcl = dcl->next;
|
||||
static inline void dpy_gfx_copy(struct DisplayState *s, int src_x, int src_y,
|
||||
int dst_x, int dst_y, int w, int h)
|
||||
{
|
||||
struct DisplayChangeListener *dcl;
|
||||
QLIST_FOREACH(dcl, &s->listeners, next) {
|
||||
if (dcl->dpy_gfx_copy) {
|
||||
dcl->dpy_gfx_copy(s, src_x, src_y, dst_x, dst_y, w, h);
|
||||
} else { /* TODO */
|
||||
dcl->dpy_gfx_update(s, dst_x, dst_y, w, h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void dpy_fill(struct DisplayState *s, int x, int y,
|
||||
int w, int h, uint32_t c) {
|
||||
struct DisplayChangeListener *dcl = s->listeners;
|
||||
while (dcl != NULL) {
|
||||
if (dcl->dpy_fill) dcl->dpy_fill(s, x, y, w, h, c);
|
||||
dcl = dcl->next;
|
||||
static inline void dpy_text_cursor(struct DisplayState *s, int x, int y)
|
||||
{
|
||||
struct DisplayChangeListener *dcl;
|
||||
QLIST_FOREACH(dcl, &s->listeners, next) {
|
||||
if (dcl->dpy_text_cursor) {
|
||||
dcl->dpy_text_cursor(s, x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void dpy_cursor(struct DisplayState *s, int x, int y) {
|
||||
struct DisplayChangeListener *dcl = s->listeners;
|
||||
while (dcl != NULL) {
|
||||
if (dcl->dpy_text_cursor) dcl->dpy_text_cursor(s, x, y);
|
||||
dcl = dcl->next;
|
||||
static inline void dpy_text_update(DisplayState *s, int x, int y, int w, int h)
|
||||
{
|
||||
struct DisplayChangeListener *dcl;
|
||||
QLIST_FOREACH(dcl, &s->listeners, next) {
|
||||
if (dcl->dpy_text_update) {
|
||||
dcl->dpy_text_update(s, x, y, w, h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void dpy_text_resize(DisplayState *s, int w, int h)
|
||||
{
|
||||
struct DisplayChangeListener *dcl;
|
||||
QLIST_FOREACH(dcl, &s->listeners, next) {
|
||||
if (dcl->dpy_text_resize) {
|
||||
dcl->dpy_text_resize(s, w, h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void dpy_mouse_set(struct DisplayState *s, int x, int y, int on)
|
||||
{
|
||||
struct DisplayChangeListener *dcl;
|
||||
QLIST_FOREACH(dcl, &s->listeners, next) {
|
||||
if (dcl->dpy_mouse_set) {
|
||||
dcl->dpy_mouse_set(s, x, y, on);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void dpy_cursor_define(struct DisplayState *s, QEMUCursor *cursor)
|
||||
{
|
||||
struct DisplayChangeListener *dcl;
|
||||
QLIST_FOREACH(dcl, &s->listeners, next) {
|
||||
if (dcl->dpy_cursor_define) {
|
||||
dcl->dpy_cursor_define(s, cursor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool dpy_cursor_define_supported(struct DisplayState *s)
|
||||
{
|
||||
struct DisplayChangeListener *dcl;
|
||||
QLIST_FOREACH(dcl, &s->listeners, next) {
|
||||
if (dcl->dpy_cursor_define) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline int ds_get_linesize(DisplayState *ds)
|
||||
{
|
||||
return ds->surface->linesize;
|
||||
return pixman_image_get_stride(ds->surface->image);
|
||||
}
|
||||
|
||||
static inline uint8_t* ds_get_data(DisplayState *ds)
|
||||
{
|
||||
return ds->surface->data;
|
||||
return (void *)pixman_image_get_data(ds->surface->image);
|
||||
}
|
||||
|
||||
static inline int ds_get_width(DisplayState *ds)
|
||||
{
|
||||
return ds->surface->width;
|
||||
return pixman_image_get_width(ds->surface->image);
|
||||
}
|
||||
|
||||
static inline int ds_get_height(DisplayState *ds)
|
||||
{
|
||||
return ds->surface->height;
|
||||
return pixman_image_get_height(ds->surface->image);
|
||||
}
|
||||
|
||||
static inline int ds_get_bits_per_pixel(DisplayState *ds)
|
||||
{
|
||||
return ds->surface->pf.bits_per_pixel;
|
||||
int bits = PIXMAN_FORMAT_BPP(ds->surface->format);
|
||||
return bits;
|
||||
}
|
||||
|
||||
static inline int ds_get_bytes_per_pixel(DisplayState *ds)
|
||||
{
|
||||
return ds->surface->pf.bytes_per_pixel;
|
||||
int bits = PIXMAN_FORMAT_BPP(ds->surface->format);
|
||||
return (bits + 7) / 8;
|
||||
}
|
||||
|
||||
static inline pixman_format_code_t ds_get_format(DisplayState *ds)
|
||||
{
|
||||
return ds->surface->format;
|
||||
}
|
||||
|
||||
static inline int ds_get_depth(DisplayState *ds)
|
||||
{
|
||||
return ds->surface->pf.depth;
|
||||
}
|
||||
|
||||
static inline int ds_get_rmask(DisplayState *ds)
|
||||
{
|
||||
return ds->surface->pf.rmask;
|
||||
}
|
||||
|
||||
static inline int ds_get_gmask(DisplayState *ds)
|
||||
{
|
||||
return ds->surface->pf.gmask;
|
||||
}
|
||||
|
||||
static inline int ds_get_bmask(DisplayState *ds)
|
||||
{
|
||||
return ds->surface->pf.bmask;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CURSES
|
||||
|
@ -377,10 +444,8 @@ void cocoa_display_init(DisplayState *ds, int full_screen);
|
|||
|
||||
/* vnc.c */
|
||||
void vnc_display_init(DisplayState *ds);
|
||||
void vnc_display_close(DisplayState *ds);
|
||||
void vnc_display_open(DisplayState *ds, const char *display, Error **errp);
|
||||
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
|
||||
int vnc_display_password(DisplayState *ds, const char *password);
|
||||
|
|
|
@ -438,8 +438,6 @@ void cpu_reset_interrupt(CPUArchState *env, int mask);
|
|||
|
||||
void cpu_exit(CPUArchState *s);
|
||||
|
||||
bool qemu_cpu_has_work(CPUArchState *env);
|
||||
|
||||
/* Breakpoint/watchpoint flags */
|
||||
#define BP_MEM_READ 0x01
|
||||
#define BP_MEM_WRITE 0x02
|
||||
|
@ -466,8 +464,6 @@ void cpu_watchpoint_remove_all(CPUArchState *env, int mask);
|
|||
#define SSTEP_NOTIMER 0x4 /* Do not Timers while single stepping */
|
||||
|
||||
void cpu_single_step(CPUArchState *env, int enabled);
|
||||
int cpu_is_stopped(CPUArchState *env);
|
||||
void run_on_cpu(CPUArchState *env, void (*func)(void *data), void *data);
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
|
||||
|
|
|
@ -39,10 +39,6 @@ typedef uint32_t CPUReadMemoryFunc(void *opaque, hwaddr addr);
|
|||
void qemu_ram_remap(ram_addr_t addr, ram_addr_t length);
|
||||
/* This should only be used for ram local to a device. */
|
||||
void *qemu_get_ram_ptr(ram_addr_t addr);
|
||||
void *qemu_ram_ptr_length(ram_addr_t addr, ram_addr_t *size);
|
||||
/* Same but slower, to use for migration, where the order of
|
||||
* RAMBlocks must not change. */
|
||||
void *qemu_safe_ram_ptr(ram_addr_t addr);
|
||||
void qemu_put_ram_ptr(void *addr);
|
||||
/* This should not be used by devices. */
|
||||
int qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr);
|
||||
|
@ -67,7 +63,6 @@ void *cpu_physical_memory_map(hwaddr addr,
|
|||
void cpu_physical_memory_unmap(void *buffer, hwaddr len,
|
||||
int is_write, hwaddr access_len);
|
||||
void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque));
|
||||
void cpu_unregister_map_client(void *cookie);
|
||||
|
||||
bool cpu_physical_memory_is_io(hwaddr phys_addr);
|
||||
|
||||
|
|
|
@ -201,15 +201,9 @@ typedef struct CPUWatchpoint {
|
|||
int nr_cores; /* number of cores within this CPU package */ \
|
||||
int nr_threads;/* number of threads within this CPU */ \
|
||||
int running; /* Nonzero if cpu is currently running(usermode). */ \
|
||||
int thread_id; \
|
||||
/* user data */ \
|
||||
void *opaque; \
|
||||
\
|
||||
uint32_t created; \
|
||||
uint32_t stop; /* Stop request */ \
|
||||
uint32_t stopped; /* Artificially stopped */ \
|
||||
struct QemuCond *halt_cond; \
|
||||
struct qemu_work_item *queued_work_first, *queued_work_last; \
|
||||
const char *cpu_model_str; \
|
||||
struct KVMState *kvm_state; \
|
||||
struct kvm_run *kvm_run; \
|
||||
|
|
|
@ -27,9 +27,9 @@ int tb_invalidated_flag;
|
|||
|
||||
//#define CONFIG_DEBUG_EXEC
|
||||
|
||||
bool qemu_cpu_has_work(CPUArchState *env)
|
||||
bool qemu_cpu_has_work(CPUState *cpu)
|
||||
{
|
||||
return cpu_has_work(env);
|
||||
return cpu_has_work(cpu);
|
||||
}
|
||||
|
||||
void cpu_loop_exit(CPUArchState *env)
|
||||
|
@ -181,16 +181,14 @@ volatile sig_atomic_t exit_request;
|
|||
|
||||
int cpu_exec(CPUArchState *env)
|
||||
{
|
||||
#ifdef TARGET_PPC
|
||||
CPUState *cpu = ENV_GET_CPU(env);
|
||||
#endif
|
||||
int ret, interrupt_request;
|
||||
TranslationBlock *tb;
|
||||
uint8_t *tc_ptr;
|
||||
tcg_target_ulong next_tb;
|
||||
|
||||
if (env->halted) {
|
||||
if (!cpu_has_work(env)) {
|
||||
if (!cpu_has_work(cpu)) {
|
||||
return EXCP_HALTED;
|
||||
}
|
||||
|
||||
|
|
193
cpus.c
193
cpus.c
|
@ -64,13 +64,15 @@ static CPUArchState *next_cpu;
|
|||
|
||||
static bool cpu_thread_is_idle(CPUArchState *env)
|
||||
{
|
||||
if (env->stop || env->queued_work_first) {
|
||||
CPUState *cpu = ENV_GET_CPU(env);
|
||||
|
||||
if (cpu->stop || cpu->queued_work_first) {
|
||||
return false;
|
||||
}
|
||||
if (env->stopped || !runstate_is_running()) {
|
||||
if (cpu->stopped || !runstate_is_running()) {
|
||||
return true;
|
||||
}
|
||||
if (!env->halted || qemu_cpu_has_work(env) ||
|
||||
if (!env->halted || qemu_cpu_has_work(cpu) ||
|
||||
kvm_async_interrupts_enabled()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -428,9 +430,9 @@ void cpu_synchronize_all_post_init(void)
|
|||
}
|
||||
}
|
||||
|
||||
int cpu_is_stopped(CPUArchState *env)
|
||||
bool cpu_is_stopped(CPUState *cpu)
|
||||
{
|
||||
return !runstate_is_running() || env->stopped;
|
||||
return !runstate_is_running() || cpu->stopped;
|
||||
}
|
||||
|
||||
static void do_vm_stop(RunState state)
|
||||
|
@ -446,22 +448,24 @@ static void do_vm_stop(RunState state)
|
|||
}
|
||||
}
|
||||
|
||||
static int cpu_can_run(CPUArchState *env)
|
||||
static bool cpu_can_run(CPUState *cpu)
|
||||
{
|
||||
if (env->stop) {
|
||||
return 0;
|
||||
if (cpu->stop) {
|
||||
return false;
|
||||
}
|
||||
if (env->stopped || !runstate_is_running()) {
|
||||
return 0;
|
||||
if (cpu->stopped || !runstate_is_running()) {
|
||||
return false;
|
||||
}
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void cpu_handle_guest_debug(CPUArchState *env)
|
||||
{
|
||||
CPUState *cpu = ENV_GET_CPU(env);
|
||||
|
||||
gdb_set_stop_cpu(env);
|
||||
qemu_system_debug_request();
|
||||
env->stopped = 1;
|
||||
cpu->stopped = true;
|
||||
}
|
||||
|
||||
static void cpu_signal(int sig)
|
||||
|
@ -636,27 +640,27 @@ void qemu_init_cpu_loop(void)
|
|||
qemu_thread_get_self(&io_thread);
|
||||
}
|
||||
|
||||
void run_on_cpu(CPUArchState *env, void (*func)(void *data), void *data)
|
||||
void run_on_cpu(CPUState *cpu, void (*func)(void *data), void *data)
|
||||
{
|
||||
struct qemu_work_item wi;
|
||||
|
||||
if (qemu_cpu_is_self(env)) {
|
||||
if (qemu_cpu_is_self(cpu)) {
|
||||
func(data);
|
||||
return;
|
||||
}
|
||||
|
||||
wi.func = func;
|
||||
wi.data = data;
|
||||
if (!env->queued_work_first) {
|
||||
env->queued_work_first = &wi;
|
||||
if (cpu->queued_work_first == NULL) {
|
||||
cpu->queued_work_first = &wi;
|
||||
} else {
|
||||
env->queued_work_last->next = &wi;
|
||||
cpu->queued_work_last->next = &wi;
|
||||
}
|
||||
env->queued_work_last = &wi;
|
||||
cpu->queued_work_last = &wi;
|
||||
wi.next = NULL;
|
||||
wi.done = false;
|
||||
|
||||
qemu_cpu_kick(env);
|
||||
qemu_cpu_kick(cpu);
|
||||
while (!wi.done) {
|
||||
CPUArchState *self_env = cpu_single_env;
|
||||
|
||||
|
@ -665,33 +669,31 @@ void run_on_cpu(CPUArchState *env, void (*func)(void *data), void *data)
|
|||
}
|
||||
}
|
||||
|
||||
static void flush_queued_work(CPUArchState *env)
|
||||
static void flush_queued_work(CPUState *cpu)
|
||||
{
|
||||
struct qemu_work_item *wi;
|
||||
|
||||
if (!env->queued_work_first) {
|
||||
if (cpu->queued_work_first == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
while ((wi = env->queued_work_first)) {
|
||||
env->queued_work_first = wi->next;
|
||||
while ((wi = cpu->queued_work_first)) {
|
||||
cpu->queued_work_first = wi->next;
|
||||
wi->func(wi->data);
|
||||
wi->done = true;
|
||||
}
|
||||
env->queued_work_last = NULL;
|
||||
cpu->queued_work_last = NULL;
|
||||
qemu_cond_broadcast(&qemu_work_cond);
|
||||
}
|
||||
|
||||
static void qemu_wait_io_event_common(CPUArchState *env)
|
||||
static void qemu_wait_io_event_common(CPUState *cpu)
|
||||
{
|
||||
CPUState *cpu = ENV_GET_CPU(env);
|
||||
|
||||
if (env->stop) {
|
||||
env->stop = 0;
|
||||
env->stopped = 1;
|
||||
if (cpu->stop) {
|
||||
cpu->stop = false;
|
||||
cpu->stopped = true;
|
||||
qemu_cond_signal(&qemu_pause_cond);
|
||||
}
|
||||
flush_queued_work(env);
|
||||
flush_queued_work(cpu);
|
||||
cpu->thread_kicked = false;
|
||||
}
|
||||
|
||||
|
@ -711,18 +713,20 @@ static void qemu_tcg_wait_io_event(void)
|
|||
}
|
||||
|
||||
for (env = first_cpu; env != NULL; env = env->next_cpu) {
|
||||
qemu_wait_io_event_common(env);
|
||||
qemu_wait_io_event_common(ENV_GET_CPU(env));
|
||||
}
|
||||
}
|
||||
|
||||
static void qemu_kvm_wait_io_event(CPUArchState *env)
|
||||
{
|
||||
CPUState *cpu = ENV_GET_CPU(env);
|
||||
|
||||
while (cpu_thread_is_idle(env)) {
|
||||
qemu_cond_wait(env->halt_cond, &qemu_global_mutex);
|
||||
qemu_cond_wait(cpu->halt_cond, &qemu_global_mutex);
|
||||
}
|
||||
|
||||
qemu_kvm_eat_signals(env);
|
||||
qemu_wait_io_event_common(env);
|
||||
qemu_wait_io_event_common(cpu);
|
||||
}
|
||||
|
||||
static void *qemu_kvm_cpu_thread_fn(void *arg)
|
||||
|
@ -733,7 +737,7 @@ static void *qemu_kvm_cpu_thread_fn(void *arg)
|
|||
|
||||
qemu_mutex_lock(&qemu_global_mutex);
|
||||
qemu_thread_get_self(cpu->thread);
|
||||
env->thread_id = qemu_get_thread_id();
|
||||
cpu->thread_id = qemu_get_thread_id();
|
||||
cpu_single_env = env;
|
||||
|
||||
r = kvm_init_vcpu(env);
|
||||
|
@ -745,11 +749,11 @@ static void *qemu_kvm_cpu_thread_fn(void *arg)
|
|||
qemu_kvm_init_cpu_signals(env);
|
||||
|
||||
/* signal CPU creation */
|
||||
env->created = 1;
|
||||
cpu->created = true;
|
||||
qemu_cond_signal(&qemu_cpu_cond);
|
||||
|
||||
while (1) {
|
||||
if (cpu_can_run(env)) {
|
||||
if (cpu_can_run(cpu)) {
|
||||
r = kvm_cpu_exec(env);
|
||||
if (r == EXCP_DEBUG) {
|
||||
cpu_handle_guest_debug(env);
|
||||
|
@ -774,13 +778,13 @@ static void *qemu_dummy_cpu_thread_fn(void *arg)
|
|||
|
||||
qemu_mutex_lock_iothread();
|
||||
qemu_thread_get_self(cpu->thread);
|
||||
env->thread_id = qemu_get_thread_id();
|
||||
cpu->thread_id = qemu_get_thread_id();
|
||||
|
||||
sigemptyset(&waitset);
|
||||
sigaddset(&waitset, SIG_IPI);
|
||||
|
||||
/* signal CPU creation */
|
||||
env->created = 1;
|
||||
cpu->created = true;
|
||||
qemu_cond_signal(&qemu_cpu_cond);
|
||||
|
||||
cpu_single_env = env;
|
||||
|
@ -797,7 +801,7 @@ static void *qemu_dummy_cpu_thread_fn(void *arg)
|
|||
}
|
||||
qemu_mutex_lock_iothread();
|
||||
cpu_single_env = env;
|
||||
qemu_wait_io_event_common(env);
|
||||
qemu_wait_io_event_common(cpu);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
@ -808,8 +812,8 @@ static void tcg_exec_all(void);
|
|||
|
||||
static void *qemu_tcg_cpu_thread_fn(void *arg)
|
||||
{
|
||||
CPUArchState *env = arg;
|
||||
CPUState *cpu = ENV_GET_CPU(env);
|
||||
CPUState *cpu = arg;
|
||||
CPUArchState *env;
|
||||
|
||||
qemu_tcg_init_cpu_signals();
|
||||
qemu_thread_get_self(cpu->thread);
|
||||
|
@ -817,18 +821,19 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
|
|||
/* signal CPU creation */
|
||||
qemu_mutex_lock(&qemu_global_mutex);
|
||||
for (env = first_cpu; env != NULL; env = env->next_cpu) {
|
||||
env->thread_id = qemu_get_thread_id();
|
||||
env->created = 1;
|
||||
cpu = ENV_GET_CPU(env);
|
||||
cpu->thread_id = qemu_get_thread_id();
|
||||
cpu->created = true;
|
||||
}
|
||||
qemu_cond_signal(&qemu_cpu_cond);
|
||||
|
||||
/* wait for initial kick-off after machine start */
|
||||
while (first_cpu->stopped) {
|
||||
while (ENV_GET_CPU(first_cpu)->stopped) {
|
||||
qemu_cond_wait(tcg_halt_cond, &qemu_global_mutex);
|
||||
|
||||
/* process any pending work */
|
||||
for (env = first_cpu; env != NULL; env = env->next_cpu) {
|
||||
qemu_wait_io_event_common(env);
|
||||
qemu_wait_io_event_common(ENV_GET_CPU(env));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -843,9 +848,8 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void qemu_cpu_kick_thread(CPUArchState *env)
|
||||
static void qemu_cpu_kick_thread(CPUState *cpu)
|
||||
{
|
||||
CPUState *cpu = ENV_GET_CPU(env);
|
||||
#ifndef _WIN32
|
||||
int err;
|
||||
|
||||
|
@ -855,7 +859,7 @@ static void qemu_cpu_kick_thread(CPUArchState *env)
|
|||
exit(1);
|
||||
}
|
||||
#else /* _WIN32 */
|
||||
if (!qemu_cpu_is_self(env)) {
|
||||
if (!qemu_cpu_is_self(cpu)) {
|
||||
SuspendThread(cpu->hThread);
|
||||
cpu_signal(0);
|
||||
ResumeThread(cpu->hThread);
|
||||
|
@ -863,14 +867,11 @@ static void qemu_cpu_kick_thread(CPUArchState *env)
|
|||
#endif
|
||||
}
|
||||
|
||||
void qemu_cpu_kick(void *_env)
|
||||
void qemu_cpu_kick(CPUState *cpu)
|
||||
{
|
||||
CPUArchState *env = _env;
|
||||
CPUState *cpu = ENV_GET_CPU(env);
|
||||
|
||||
qemu_cond_broadcast(env->halt_cond);
|
||||
qemu_cond_broadcast(cpu->halt_cond);
|
||||
if (!tcg_enabled() && !cpu->thread_kicked) {
|
||||
qemu_cpu_kick_thread(env);
|
||||
qemu_cpu_kick_thread(cpu);
|
||||
cpu->thread_kicked = true;
|
||||
}
|
||||
}
|
||||
|
@ -882,7 +883,7 @@ void qemu_cpu_kick_self(void)
|
|||
CPUState *cpu_single_cpu = ENV_GET_CPU(cpu_single_env);
|
||||
|
||||
if (!cpu_single_cpu->thread_kicked) {
|
||||
qemu_cpu_kick_thread(cpu_single_env);
|
||||
qemu_cpu_kick_thread(cpu_single_cpu);
|
||||
cpu_single_cpu->thread_kicked = true;
|
||||
}
|
||||
#else
|
||||
|
@ -890,17 +891,14 @@ void qemu_cpu_kick_self(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
int qemu_cpu_is_self(void *_env)
|
||||
bool qemu_cpu_is_self(CPUState *cpu)
|
||||
{
|
||||
CPUArchState *env = _env;
|
||||
CPUState *cpu = ENV_GET_CPU(env);
|
||||
|
||||
return qemu_thread_is_self(cpu->thread);
|
||||
}
|
||||
|
||||
static bool qemu_in_vcpu_thread(void)
|
||||
{
|
||||
return cpu_single_env && qemu_cpu_is_self(cpu_single_env);
|
||||
return cpu_single_env && qemu_cpu_is_self(ENV_GET_CPU(cpu_single_env));
|
||||
}
|
||||
|
||||
void qemu_mutex_lock_iothread(void)
|
||||
|
@ -910,7 +908,7 @@ void qemu_mutex_lock_iothread(void)
|
|||
} else {
|
||||
iothread_requesting_mutex = true;
|
||||
if (qemu_mutex_trylock(&qemu_global_mutex)) {
|
||||
qemu_cpu_kick_thread(first_cpu);
|
||||
qemu_cpu_kick_thread(ENV_GET_CPU(first_cpu));
|
||||
qemu_mutex_lock(&qemu_global_mutex);
|
||||
}
|
||||
iothread_requesting_mutex = false;
|
||||
|
@ -928,7 +926,8 @@ static int all_vcpus_paused(void)
|
|||
CPUArchState *penv = first_cpu;
|
||||
|
||||
while (penv) {
|
||||
if (!penv->stopped) {
|
||||
CPUState *pcpu = ENV_GET_CPU(penv);
|
||||
if (!pcpu->stopped) {
|
||||
return 0;
|
||||
}
|
||||
penv = penv->next_cpu;
|
||||
|
@ -943,8 +942,9 @@ void pause_all_vcpus(void)
|
|||
|
||||
qemu_clock_enable(vm_clock, false);
|
||||
while (penv) {
|
||||
penv->stop = 1;
|
||||
qemu_cpu_kick(penv);
|
||||
CPUState *pcpu = ENV_GET_CPU(penv);
|
||||
pcpu->stop = true;
|
||||
qemu_cpu_kick(pcpu);
|
||||
penv = penv->next_cpu;
|
||||
}
|
||||
|
||||
|
@ -952,8 +952,9 @@ void pause_all_vcpus(void)
|
|||
cpu_stop_current();
|
||||
if (!kvm_enabled()) {
|
||||
while (penv) {
|
||||
penv->stop = 0;
|
||||
penv->stopped = 1;
|
||||
CPUState *pcpu = ENV_GET_CPU(penv);
|
||||
pcpu->stop = 0;
|
||||
pcpu->stopped = true;
|
||||
penv = penv->next_cpu;
|
||||
}
|
||||
return;
|
||||
|
@ -964,7 +965,7 @@ void pause_all_vcpus(void)
|
|||
qemu_cond_wait(&qemu_pause_cond, &qemu_global_mutex);
|
||||
penv = first_cpu;
|
||||
while (penv) {
|
||||
qemu_cpu_kick(penv);
|
||||
qemu_cpu_kick(ENV_GET_CPU(penv));
|
||||
penv = penv->next_cpu;
|
||||
}
|
||||
}
|
||||
|
@ -976,36 +977,34 @@ void resume_all_vcpus(void)
|
|||
|
||||
qemu_clock_enable(vm_clock, true);
|
||||
while (penv) {
|
||||
penv->stop = 0;
|
||||
penv->stopped = 0;
|
||||
qemu_cpu_kick(penv);
|
||||
CPUState *pcpu = ENV_GET_CPU(penv);
|
||||
pcpu->stop = false;
|
||||
pcpu->stopped = false;
|
||||
qemu_cpu_kick(pcpu);
|
||||
penv = penv->next_cpu;
|
||||
}
|
||||
}
|
||||
|
||||
static void qemu_tcg_init_vcpu(void *_env)
|
||||
static void qemu_tcg_init_vcpu(CPUState *cpu)
|
||||
{
|
||||
CPUArchState *env = _env;
|
||||
CPUState *cpu = ENV_GET_CPU(env);
|
||||
|
||||
/* share a single thread for all cpus with TCG */
|
||||
if (!tcg_cpu_thread) {
|
||||
cpu->thread = g_malloc0(sizeof(QemuThread));
|
||||
env->halt_cond = g_malloc0(sizeof(QemuCond));
|
||||
qemu_cond_init(env->halt_cond);
|
||||
tcg_halt_cond = env->halt_cond;
|
||||
qemu_thread_create(cpu->thread, qemu_tcg_cpu_thread_fn, env,
|
||||
cpu->halt_cond = g_malloc0(sizeof(QemuCond));
|
||||
qemu_cond_init(cpu->halt_cond);
|
||||
tcg_halt_cond = cpu->halt_cond;
|
||||
qemu_thread_create(cpu->thread, qemu_tcg_cpu_thread_fn, cpu,
|
||||
QEMU_THREAD_JOINABLE);
|
||||
#ifdef _WIN32
|
||||
cpu->hThread = qemu_thread_get_handle(cpu->thread);
|
||||
#endif
|
||||
while (env->created == 0) {
|
||||
while (!cpu->created) {
|
||||
qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex);
|
||||
}
|
||||
tcg_cpu_thread = cpu->thread;
|
||||
} else {
|
||||
cpu->thread = tcg_cpu_thread;
|
||||
env->halt_cond = tcg_halt_cond;
|
||||
cpu->halt_cond = tcg_halt_cond;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1014,11 +1013,11 @@ static void qemu_kvm_start_vcpu(CPUArchState *env)
|
|||
CPUState *cpu = ENV_GET_CPU(env);
|
||||
|
||||
cpu->thread = g_malloc0(sizeof(QemuThread));
|
||||
env->halt_cond = g_malloc0(sizeof(QemuCond));
|
||||
qemu_cond_init(env->halt_cond);
|
||||
cpu->halt_cond = g_malloc0(sizeof(QemuCond));
|
||||
qemu_cond_init(cpu->halt_cond);
|
||||
qemu_thread_create(cpu->thread, qemu_kvm_cpu_thread_fn, env,
|
||||
QEMU_THREAD_JOINABLE);
|
||||
while (env->created == 0) {
|
||||
while (!cpu->created) {
|
||||
qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex);
|
||||
}
|
||||
}
|
||||
|
@ -1028,11 +1027,11 @@ static void qemu_dummy_start_vcpu(CPUArchState *env)
|
|||
CPUState *cpu = ENV_GET_CPU(env);
|
||||
|
||||
cpu->thread = g_malloc0(sizeof(QemuThread));
|
||||
env->halt_cond = g_malloc0(sizeof(QemuCond));
|
||||
qemu_cond_init(env->halt_cond);
|
||||
cpu->halt_cond = g_malloc0(sizeof(QemuCond));
|
||||
qemu_cond_init(cpu->halt_cond);
|
||||
qemu_thread_create(cpu->thread, qemu_dummy_cpu_thread_fn, env,
|
||||
QEMU_THREAD_JOINABLE);
|
||||
while (env->created == 0) {
|
||||
while (!cpu->created) {
|
||||
qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex);
|
||||
}
|
||||
}
|
||||
|
@ -1040,14 +1039,15 @@ static void qemu_dummy_start_vcpu(CPUArchState *env)
|
|||
void qemu_init_vcpu(void *_env)
|
||||
{
|
||||
CPUArchState *env = _env;
|
||||
CPUState *cpu = ENV_GET_CPU(env);
|
||||
|
||||
env->nr_cores = smp_cores;
|
||||
env->nr_threads = smp_threads;
|
||||
env->stopped = 1;
|
||||
cpu->stopped = true;
|
||||
if (kvm_enabled()) {
|
||||
qemu_kvm_start_vcpu(env);
|
||||
} else if (tcg_enabled()) {
|
||||
qemu_tcg_init_vcpu(env);
|
||||
qemu_tcg_init_vcpu(cpu);
|
||||
} else {
|
||||
qemu_dummy_start_vcpu(env);
|
||||
}
|
||||
|
@ -1056,8 +1056,9 @@ void qemu_init_vcpu(void *_env)
|
|||
void cpu_stop_current(void)
|
||||
{
|
||||
if (cpu_single_env) {
|
||||
cpu_single_env->stop = 0;
|
||||
cpu_single_env->stopped = 1;
|
||||
CPUState *cpu_single_cpu = ENV_GET_CPU(cpu_single_env);
|
||||
cpu_single_cpu->stop = false;
|
||||
cpu_single_cpu->stopped = true;
|
||||
cpu_exit(cpu_single_env);
|
||||
qemu_cond_signal(&qemu_pause_cond);
|
||||
}
|
||||
|
@ -1138,17 +1139,18 @@ static void tcg_exec_all(void)
|
|||
}
|
||||
for (; next_cpu != NULL && !exit_request; next_cpu = next_cpu->next_cpu) {
|
||||
CPUArchState *env = next_cpu;
|
||||
CPUState *cpu = ENV_GET_CPU(env);
|
||||
|
||||
qemu_clock_enable(vm_clock,
|
||||
(env->singlestep_enabled & SSTEP_NOTIMER) == 0);
|
||||
|
||||
if (cpu_can_run(env)) {
|
||||
if (cpu_can_run(cpu)) {
|
||||
r = tcg_cpu_exec(env);
|
||||
if (r == EXCP_DEBUG) {
|
||||
cpu_handle_guest_debug(env);
|
||||
break;
|
||||
}
|
||||
} else if (env->stop || env->stopped) {
|
||||
} else if (cpu->stop || cpu->stopped) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1203,7 +1205,8 @@ CpuInfoList *qmp_query_cpus(Error **errp)
|
|||
CpuInfoList *head = NULL, *cur_item = NULL;
|
||||
CPUArchState *env;
|
||||
|
||||
for(env = first_cpu; env != NULL; env = env->next_cpu) {
|
||||
for (env = first_cpu; env != NULL; env = env->next_cpu) {
|
||||
CPUState *cpu = ENV_GET_CPU(env);
|
||||
CpuInfoList *info;
|
||||
|
||||
cpu_synchronize_state(env);
|
||||
|
@ -1213,7 +1216,7 @@ CpuInfoList *qmp_query_cpus(Error **errp)
|
|||
info->value->CPU = env->cpu_index;
|
||||
info->value->current = (env == first_cpu);
|
||||
info->value->halted = env->halted;
|
||||
info->value->thread_id = env->thread_id;
|
||||
info->value->thread_id = cpu->thread_id;
|
||||
#if defined(TARGET_I386)
|
||||
info->value->has_pc = true;
|
||||
info->value->pc = env->eip + env->segs[R_CS].base;
|
||||
|
|
108
cutils.c
108
cutils.c
|
@ -142,109 +142,6 @@ int qemu_fdatasync(int fd)
|
|||
#endif
|
||||
}
|
||||
|
||||
/* io vectors */
|
||||
|
||||
void qemu_iovec_init(QEMUIOVector *qiov, int alloc_hint)
|
||||
{
|
||||
qiov->iov = g_malloc(alloc_hint * sizeof(struct iovec));
|
||||
qiov->niov = 0;
|
||||
qiov->nalloc = alloc_hint;
|
||||
qiov->size = 0;
|
||||
}
|
||||
|
||||
void qemu_iovec_init_external(QEMUIOVector *qiov, struct iovec *iov, int niov)
|
||||
{
|
||||
int i;
|
||||
|
||||
qiov->iov = iov;
|
||||
qiov->niov = niov;
|
||||
qiov->nalloc = -1;
|
||||
qiov->size = 0;
|
||||
for (i = 0; i < niov; i++)
|
||||
qiov->size += iov[i].iov_len;
|
||||
}
|
||||
|
||||
void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len)
|
||||
{
|
||||
assert(qiov->nalloc != -1);
|
||||
|
||||
if (qiov->niov == qiov->nalloc) {
|
||||
qiov->nalloc = 2 * qiov->nalloc + 1;
|
||||
qiov->iov = g_realloc(qiov->iov, qiov->nalloc * sizeof(struct iovec));
|
||||
}
|
||||
qiov->iov[qiov->niov].iov_base = base;
|
||||
qiov->iov[qiov->niov].iov_len = len;
|
||||
qiov->size += len;
|
||||
++qiov->niov;
|
||||
}
|
||||
|
||||
/*
|
||||
* Concatenates (partial) iovecs from src to the end of dst.
|
||||
* It starts copying after skipping `soffset' bytes at the
|
||||
* beginning of src and adds individual vectors from src to
|
||||
* dst copies up to `sbytes' bytes total, or up to the end
|
||||
* of src if it comes first. This way, it is okay to specify
|
||||
* very large value for `sbytes' to indicate "up to the end
|
||||
* of src".
|
||||
* Only vector pointers are processed, not the actual data buffers.
|
||||
*/
|
||||
void qemu_iovec_concat(QEMUIOVector *dst,
|
||||
QEMUIOVector *src, size_t soffset, size_t sbytes)
|
||||
{
|
||||
int i;
|
||||
size_t done;
|
||||
struct iovec *siov = src->iov;
|
||||
assert(dst->nalloc != -1);
|
||||
assert(src->size >= soffset);
|
||||
for (i = 0, done = 0; done < sbytes && i < src->niov; i++) {
|
||||
if (soffset < siov[i].iov_len) {
|
||||
size_t len = MIN(siov[i].iov_len - soffset, sbytes - done);
|
||||
qemu_iovec_add(dst, siov[i].iov_base + soffset, len);
|
||||
done += len;
|
||||
soffset = 0;
|
||||
} else {
|
||||
soffset -= siov[i].iov_len;
|
||||
}
|
||||
}
|
||||
/* return done; */
|
||||
}
|
||||
|
||||
void qemu_iovec_destroy(QEMUIOVector *qiov)
|
||||
{
|
||||
assert(qiov->nalloc != -1);
|
||||
|
||||
qemu_iovec_reset(qiov);
|
||||
g_free(qiov->iov);
|
||||
qiov->nalloc = 0;
|
||||
qiov->iov = NULL;
|
||||
}
|
||||
|
||||
void qemu_iovec_reset(QEMUIOVector *qiov)
|
||||
{
|
||||
assert(qiov->nalloc != -1);
|
||||
|
||||
qiov->niov = 0;
|
||||
qiov->size = 0;
|
||||
}
|
||||
|
||||
size_t qemu_iovec_to_buf(QEMUIOVector *qiov, size_t offset,
|
||||
void *buf, size_t bytes)
|
||||
{
|
||||
return iov_to_buf(qiov->iov, qiov->niov, offset, buf, bytes);
|
||||
}
|
||||
|
||||
size_t qemu_iovec_from_buf(QEMUIOVector *qiov, size_t offset,
|
||||
const void *buf, size_t bytes)
|
||||
{
|
||||
return iov_from_buf(qiov->iov, qiov->niov, offset, buf, bytes);
|
||||
}
|
||||
|
||||
size_t qemu_iovec_memset(QEMUIOVector *qiov, size_t offset,
|
||||
int fillc, size_t bytes)
|
||||
{
|
||||
return iov_memset(qiov->iov, qiov->niov, offset, fillc, bytes);
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks if a buffer is all zeroes
|
||||
*
|
||||
|
@ -383,11 +280,6 @@ int qemu_parse_fd(const char *param)
|
|||
return fd;
|
||||
}
|
||||
|
||||
int qemu_parse_fdset(const char *param)
|
||||
{
|
||||
return qemu_parse_fd(param);
|
||||
}
|
||||
|
||||
/* round down to the nearest power of 2*/
|
||||
int64_t pow2floor(int64_t value)
|
||||
{
|
||||
|
|
149
disas.c
149
disas.c
|
@ -7,6 +7,11 @@
|
|||
#include "cpu.h"
|
||||
#include "disas.h"
|
||||
|
||||
typedef struct CPUDebug {
|
||||
struct disassemble_info info;
|
||||
CPUArchState *env;
|
||||
} CPUDebug;
|
||||
|
||||
/* Filled in by elfload.c. Simplistic, but will do for now. */
|
||||
struct syminfo *syminfos = NULL;
|
||||
|
||||
|
@ -32,7 +37,9 @@ target_read_memory (bfd_vma memaddr,
|
|||
int length,
|
||||
struct disassemble_info *info)
|
||||
{
|
||||
cpu_memory_rw_debug(cpu_single_env, memaddr, myaddr, length, 0);
|
||||
CPUDebug *s = container_of(info, CPUDebug, info);
|
||||
|
||||
cpu_memory_rw_debug(s->env, memaddr, myaddr, length, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -158,32 +165,35 @@ print_insn_thumb1(bfd_vma pc, disassemble_info *info)
|
|||
ppc - nonzero means little endian
|
||||
other targets - unused
|
||||
*/
|
||||
void target_disas(FILE *out, target_ulong code, target_ulong size, int flags)
|
||||
void target_disas(FILE *out, CPUArchState *env, target_ulong code,
|
||||
target_ulong size, int flags)
|
||||
{
|
||||
target_ulong pc;
|
||||
int count;
|
||||
struct disassemble_info disasm_info;
|
||||
CPUDebug s;
|
||||
int (*print_insn)(bfd_vma pc, disassemble_info *info);
|
||||
|
||||
INIT_DISASSEMBLE_INFO(disasm_info, out, fprintf);
|
||||
INIT_DISASSEMBLE_INFO(s.info, out, fprintf);
|
||||
|
||||
disasm_info.read_memory_func = target_read_memory;
|
||||
disasm_info.buffer_vma = code;
|
||||
disasm_info.buffer_length = size;
|
||||
disasm_info.print_address_func = generic_print_target_address;
|
||||
s.env = env;
|
||||
s.info.read_memory_func = target_read_memory;
|
||||
s.info.buffer_vma = code;
|
||||
s.info.buffer_length = size;
|
||||
s.info.print_address_func = generic_print_target_address;
|
||||
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
disasm_info.endian = BFD_ENDIAN_BIG;
|
||||
s.info.endian = BFD_ENDIAN_BIG;
|
||||
#else
|
||||
disasm_info.endian = BFD_ENDIAN_LITTLE;
|
||||
s.info.endian = BFD_ENDIAN_LITTLE;
|
||||
#endif
|
||||
#if defined(TARGET_I386)
|
||||
if (flags == 2)
|
||||
disasm_info.mach = bfd_mach_x86_64;
|
||||
else if (flags == 1)
|
||||
disasm_info.mach = bfd_mach_i386_i8086;
|
||||
else
|
||||
disasm_info.mach = bfd_mach_i386_i386;
|
||||
if (flags == 2) {
|
||||
s.info.mach = bfd_mach_x86_64;
|
||||
} else if (flags == 1) {
|
||||
s.info.mach = bfd_mach_i386_i8086;
|
||||
} else {
|
||||
s.info.mach = bfd_mach_i386_i386;
|
||||
}
|
||||
print_insn = print_insn_i386;
|
||||
#elif defined(TARGET_ARM)
|
||||
if (flags & 1) {
|
||||
|
@ -193,27 +203,28 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags)
|
|||
}
|
||||
if (flags & 2) {
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
disasm_info.endian = BFD_ENDIAN_LITTLE;
|
||||
s.info.endian = BFD_ENDIAN_LITTLE;
|
||||
#else
|
||||
disasm_info.endian = BFD_ENDIAN_BIG;
|
||||
s.info.endian = BFD_ENDIAN_BIG;
|
||||
#endif
|
||||
}
|
||||
#elif defined(TARGET_SPARC)
|
||||
print_insn = print_insn_sparc;
|
||||
#ifdef TARGET_SPARC64
|
||||
disasm_info.mach = bfd_mach_sparc_v9b;
|
||||
s.info.mach = bfd_mach_sparc_v9b;
|
||||
#endif
|
||||
#elif defined(TARGET_PPC)
|
||||
if (flags >> 16)
|
||||
disasm_info.endian = BFD_ENDIAN_LITTLE;
|
||||
if (flags >> 16) {
|
||||
s.info.endian = BFD_ENDIAN_LITTLE;
|
||||
}
|
||||
if (flags & 0xFFFF) {
|
||||
/* If we have a precise definitions of the instructions set, use it */
|
||||
disasm_info.mach = flags & 0xFFFF;
|
||||
s.info.mach = flags & 0xFFFF;
|
||||
} else {
|
||||
#ifdef TARGET_PPC64
|
||||
disasm_info.mach = bfd_mach_ppc64;
|
||||
s.info.mach = bfd_mach_ppc64;
|
||||
#else
|
||||
disasm_info.mach = bfd_mach_ppc;
|
||||
s.info.mach = bfd_mach_ppc;
|
||||
#endif
|
||||
}
|
||||
print_insn = print_insn_ppc;
|
||||
|
@ -226,27 +237,27 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags)
|
|||
print_insn = print_insn_little_mips;
|
||||
#endif
|
||||
#elif defined(TARGET_SH4)
|
||||
disasm_info.mach = bfd_mach_sh4;
|
||||
s.info.mach = bfd_mach_sh4;
|
||||
print_insn = print_insn_sh;
|
||||
#elif defined(TARGET_ALPHA)
|
||||
disasm_info.mach = bfd_mach_alpha_ev6;
|
||||
s.info.mach = bfd_mach_alpha_ev6;
|
||||
print_insn = print_insn_alpha;
|
||||
#elif defined(TARGET_CRIS)
|
||||
if (flags != 32) {
|
||||
disasm_info.mach = bfd_mach_cris_v0_v10;
|
||||
s.info.mach = bfd_mach_cris_v0_v10;
|
||||
print_insn = print_insn_crisv10;
|
||||
} else {
|
||||
disasm_info.mach = bfd_mach_cris_v32;
|
||||
s.info.mach = bfd_mach_cris_v32;
|
||||
print_insn = print_insn_crisv32;
|
||||
}
|
||||
#elif defined(TARGET_S390X)
|
||||
disasm_info.mach = bfd_mach_s390_64;
|
||||
s.info.mach = bfd_mach_s390_64;
|
||||
print_insn = print_insn_s390;
|
||||
#elif defined(TARGET_MICROBLAZE)
|
||||
disasm_info.mach = bfd_arch_microblaze;
|
||||
s.info.mach = bfd_arch_microblaze;
|
||||
print_insn = print_insn_microblaze;
|
||||
#elif defined(TARGET_LM32)
|
||||
disasm_info.mach = bfd_mach_lm32;
|
||||
s.info.mach = bfd_mach_lm32;
|
||||
print_insn = print_insn_lm32;
|
||||
#else
|
||||
fprintf(out, "0x" TARGET_FMT_lx
|
||||
|
@ -256,14 +267,14 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags)
|
|||
|
||||
for (pc = code; size > 0; pc += count, size -= count) {
|
||||
fprintf(out, "0x" TARGET_FMT_lx ": ", pc);
|
||||
count = print_insn(pc, &disasm_info);
|
||||
count = print_insn(pc, &s.info);
|
||||
#if 0
|
||||
{
|
||||
int i;
|
||||
uint8_t b;
|
||||
fprintf(out, " {");
|
||||
for(i = 0; i < count; i++) {
|
||||
target_read_memory(pc + i, &b, 1, &disasm_info);
|
||||
target_read_memory(pc + i, &b, 1, &s.info);
|
||||
fprintf(out, " %02x", b);
|
||||
}
|
||||
fprintf(out, " }");
|
||||
|
@ -287,28 +298,28 @@ void disas(FILE *out, void *code, unsigned long size)
|
|||
{
|
||||
uintptr_t pc;
|
||||
int count;
|
||||
struct disassemble_info disasm_info;
|
||||
CPUDebug s;
|
||||
int (*print_insn)(bfd_vma pc, disassemble_info *info);
|
||||
|
||||
INIT_DISASSEMBLE_INFO(disasm_info, out, fprintf);
|
||||
disasm_info.print_address_func = generic_print_host_address;
|
||||
INIT_DISASSEMBLE_INFO(s.info, out, fprintf);
|
||||
s.info.print_address_func = generic_print_host_address;
|
||||
|
||||
disasm_info.buffer = code;
|
||||
disasm_info.buffer_vma = (uintptr_t)code;
|
||||
disasm_info.buffer_length = size;
|
||||
s.info.buffer = code;
|
||||
s.info.buffer_vma = (uintptr_t)code;
|
||||
s.info.buffer_length = size;
|
||||
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
disasm_info.endian = BFD_ENDIAN_BIG;
|
||||
s.info.endian = BFD_ENDIAN_BIG;
|
||||
#else
|
||||
disasm_info.endian = BFD_ENDIAN_LITTLE;
|
||||
s.info.endian = BFD_ENDIAN_LITTLE;
|
||||
#endif
|
||||
#if defined(CONFIG_TCG_INTERPRETER)
|
||||
print_insn = print_insn_tci;
|
||||
#elif defined(__i386__)
|
||||
disasm_info.mach = bfd_mach_i386_i386;
|
||||
s.info.mach = bfd_mach_i386_i386;
|
||||
print_insn = print_insn_i386;
|
||||
#elif defined(__x86_64__)
|
||||
disasm_info.mach = bfd_mach_x86_64;
|
||||
s.info.mach = bfd_mach_x86_64;
|
||||
print_insn = print_insn_i386;
|
||||
#elif defined(_ARCH_PPC)
|
||||
print_insn = print_insn_ppc;
|
||||
|
@ -316,7 +327,7 @@ void disas(FILE *out, void *code, unsigned long size)
|
|||
print_insn = print_insn_alpha;
|
||||
#elif defined(__sparc__)
|
||||
print_insn = print_insn_sparc;
|
||||
disasm_info.mach = bfd_mach_sparc_v9b;
|
||||
s.info.mach = bfd_mach_sparc_v9b;
|
||||
#elif defined(__arm__)
|
||||
print_insn = print_insn_arm;
|
||||
#elif defined(__MIPSEB__)
|
||||
|
@ -338,7 +349,7 @@ void disas(FILE *out, void *code, unsigned long size)
|
|||
#endif
|
||||
for (pc = (uintptr_t)code; size > 0; pc += count, size -= count) {
|
||||
fprintf(out, "0x%08" PRIxPTR ": ", pc);
|
||||
count = print_insn(pc, &disasm_info);
|
||||
count = print_insn(pc, &s.info);
|
||||
fprintf(out, "\n");
|
||||
if (count < 0)
|
||||
break;
|
||||
|
@ -366,16 +377,17 @@ const char *lookup_symbol(target_ulong orig_addr)
|
|||
#include "monitor.h"
|
||||
|
||||
static int monitor_disas_is_physical;
|
||||
static CPUArchState *monitor_disas_env;
|
||||
|
||||
static int
|
||||
monitor_read_memory (bfd_vma memaddr, bfd_byte *myaddr, int length,
|
||||
struct disassemble_info *info)
|
||||
{
|
||||
CPUDebug *s = container_of(info, CPUDebug, info);
|
||||
|
||||
if (monitor_disas_is_physical) {
|
||||
cpu_physical_memory_read(memaddr, myaddr, length);
|
||||
} else {
|
||||
cpu_memory_rw_debug(monitor_disas_env, memaddr,myaddr, length, 0);
|
||||
cpu_memory_rw_debug(s->env, memaddr,myaddr, length, 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -394,30 +406,31 @@ void monitor_disas(Monitor *mon, CPUArchState *env,
|
|||
target_ulong pc, int nb_insn, int is_physical, int flags)
|
||||
{
|
||||
int count, i;
|
||||
struct disassemble_info disasm_info;
|
||||
CPUDebug s;
|
||||
int (*print_insn)(bfd_vma pc, disassemble_info *info);
|
||||
|
||||
INIT_DISASSEMBLE_INFO(disasm_info, (FILE *)mon, monitor_fprintf);
|
||||
INIT_DISASSEMBLE_INFO(s.info, (FILE *)mon, monitor_fprintf);
|
||||
|
||||
monitor_disas_env = env;
|
||||
s.env = env;
|
||||
monitor_disas_is_physical = is_physical;
|
||||
disasm_info.read_memory_func = monitor_read_memory;
|
||||
disasm_info.print_address_func = generic_print_target_address;
|
||||
s.info.read_memory_func = monitor_read_memory;
|
||||
s.info.print_address_func = generic_print_target_address;
|
||||
|
||||
disasm_info.buffer_vma = pc;
|
||||
s.info.buffer_vma = pc;
|
||||
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
disasm_info.endian = BFD_ENDIAN_BIG;
|
||||
s.info.endian = BFD_ENDIAN_BIG;
|
||||
#else
|
||||
disasm_info.endian = BFD_ENDIAN_LITTLE;
|
||||
s.info.endian = BFD_ENDIAN_LITTLE;
|
||||
#endif
|
||||
#if defined(TARGET_I386)
|
||||
if (flags == 2)
|
||||
disasm_info.mach = bfd_mach_x86_64;
|
||||
else if (flags == 1)
|
||||
disasm_info.mach = bfd_mach_i386_i8086;
|
||||
else
|
||||
disasm_info.mach = bfd_mach_i386_i386;
|
||||
if (flags == 2) {
|
||||
s.info.mach = bfd_mach_x86_64;
|
||||
} else if (flags == 1) {
|
||||
s.info.mach = bfd_mach_i386_i8086;
|
||||
} else {
|
||||
s.info.mach = bfd_mach_i386_i386;
|
||||
}
|
||||
print_insn = print_insn_i386;
|
||||
#elif defined(TARGET_ARM)
|
||||
print_insn = print_insn_arm;
|
||||
|
@ -426,13 +439,13 @@ void monitor_disas(Monitor *mon, CPUArchState *env,
|
|||
#elif defined(TARGET_SPARC)
|
||||
print_insn = print_insn_sparc;
|
||||
#ifdef TARGET_SPARC64
|
||||
disasm_info.mach = bfd_mach_sparc_v9b;
|
||||
s.info.mach = bfd_mach_sparc_v9b;
|
||||
#endif
|
||||
#elif defined(TARGET_PPC)
|
||||
#ifdef TARGET_PPC64
|
||||
disasm_info.mach = bfd_mach_ppc64;
|
||||
s.info.mach = bfd_mach_ppc64;
|
||||
#else
|
||||
disasm_info.mach = bfd_mach_ppc;
|
||||
s.info.mach = bfd_mach_ppc;
|
||||
#endif
|
||||
print_insn = print_insn_ppc;
|
||||
#elif defined(TARGET_M68K)
|
||||
|
@ -444,13 +457,13 @@ void monitor_disas(Monitor *mon, CPUArchState *env,
|
|||
print_insn = print_insn_little_mips;
|
||||
#endif
|
||||
#elif defined(TARGET_SH4)
|
||||
disasm_info.mach = bfd_mach_sh4;
|
||||
s.info.mach = bfd_mach_sh4;
|
||||
print_insn = print_insn_sh;
|
||||
#elif defined(TARGET_S390X)
|
||||
disasm_info.mach = bfd_mach_s390_64;
|
||||
s.info.mach = bfd_mach_s390_64;
|
||||
print_insn = print_insn_s390;
|
||||
#elif defined(TARGET_LM32)
|
||||
disasm_info.mach = bfd_mach_lm32;
|
||||
s.info.mach = bfd_mach_lm32;
|
||||
print_insn = print_insn_lm32;
|
||||
#else
|
||||
monitor_printf(mon, "0x" TARGET_FMT_lx
|
||||
|
@ -460,7 +473,7 @@ void monitor_disas(Monitor *mon, CPUArchState *env,
|
|||
|
||||
for(i = 0; i < nb_insn; i++) {
|
||||
monitor_printf(mon, "0x" TARGET_FMT_lx ": ", pc);
|
||||
count = print_insn(pc, &disasm_info);
|
||||
count = print_insn(pc, &s.info);
|
||||
monitor_printf(mon, "\n");
|
||||
if (count < 0)
|
||||
break;
|
||||
|
|
3
disas.h
3
disas.h
|
@ -6,7 +6,8 @@
|
|||
#ifdef NEED_CPU_H
|
||||
/* Disassemble this for me please... (debugging). */
|
||||
void disas(FILE *out, void *code, unsigned long size);
|
||||
void target_disas(FILE *out, target_ulong code, target_ulong size, int flags);
|
||||
void target_disas(FILE *out, CPUArchState *env, target_ulong code,
|
||||
target_ulong size, int flags);
|
||||
|
||||
void monitor_disas(Monitor *mon, CPUArchState *env,
|
||||
target_ulong pc, int nb_insn, int is_physical, int flags);
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* event notifier support
|
||||
*
|
||||
* Copyright Red Hat, Inc. 2010
|
||||
*
|
||||
* Authors:
|
||||
* Michael S. Tsirkin <mst@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "event_notifier.h"
|
||||
#include "qemu-char.h"
|
||||
|
||||
#ifdef CONFIG_EVENTFD
|
||||
#include <sys/eventfd.h>
|
||||
#endif
|
||||
|
||||
void event_notifier_init_fd(EventNotifier *e, int fd)
|
||||
{
|
||||
e->rfd = fd;
|
||||
e->wfd = fd;
|
||||
}
|
||||
|
||||
int event_notifier_init(EventNotifier *e, int active)
|
||||
{
|
||||
int fds[2];
|
||||
int ret;
|
||||
|
||||
#ifdef CONFIG_EVENTFD
|
||||
ret = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
|
||||
#else
|
||||
ret = -1;
|
||||
errno = ENOSYS;
|
||||
#endif
|
||||
if (ret >= 0) {
|
||||
e->rfd = e->wfd = ret;
|
||||
} else {
|
||||
if (errno != ENOSYS) {
|
||||
return -errno;
|
||||
}
|
||||
if (qemu_pipe(fds) < 0) {
|
||||
return -errno;
|
||||
}
|
||||
ret = fcntl_setfl(fds[0], O_NONBLOCK);
|
||||
if (ret < 0) {
|
||||
ret = -errno;
|
||||
goto fail;
|
||||
}
|
||||
ret = fcntl_setfl(fds[1], O_NONBLOCK);
|
||||
if (ret < 0) {
|
||||
ret = -errno;
|
||||
goto fail;
|
||||
}
|
||||
e->rfd = fds[0];
|
||||
e->wfd = fds[1];
|
||||
}
|
||||
if (active) {
|
||||
event_notifier_set(e);
|
||||
}
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
close(fds[0]);
|
||||
close(fds[1]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void event_notifier_cleanup(EventNotifier *e)
|
||||
{
|
||||
if (e->rfd != e->wfd) {
|
||||
close(e->rfd);
|
||||
}
|
||||
close(e->wfd);
|
||||
}
|
||||
|
||||
int event_notifier_get_fd(EventNotifier *e)
|
||||
{
|
||||
return e->rfd;
|
||||
}
|
||||
|
||||
int event_notifier_set_handler(EventNotifier *e,
|
||||
EventNotifierHandler *handler)
|
||||
{
|
||||
return qemu_set_fd_handler(e->rfd, (IOHandler *)handler, NULL, e);
|
||||
}
|
||||
|
||||
int event_notifier_set(EventNotifier *e)
|
||||
{
|
||||
static const uint64_t value = 1;
|
||||
ssize_t ret;
|
||||
|
||||
do {
|
||||
ret = write(e->wfd, &value, sizeof(value));
|
||||
} while (ret < 0 && errno == EINTR);
|
||||
|
||||
/* EAGAIN is fine, a read must be pending. */
|
||||
if (ret < 0 && errno != EAGAIN) {
|
||||
return -errno;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int event_notifier_test_and_clear(EventNotifier *e)
|
||||
{
|
||||
int value;
|
||||
ssize_t len;
|
||||
char buffer[512];
|
||||
|
||||
/* Drain the notify pipe. For eventfd, only 8 bytes will be read. */
|
||||
value = 0;
|
||||
do {
|
||||
len = read(e->rfd, buffer, sizeof(buffer));
|
||||
value |= (len > 0);
|
||||
} while ((len == -1 && errno == EINTR) || len == sizeof(buffer));
|
||||
|
||||
return value;
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* event notifier support
|
||||
*
|
||||
* Copyright Red Hat, Inc. 2010
|
||||
*
|
||||
* Authors:
|
||||
* Michael S. Tsirkin <mst@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "event_notifier.h"
|
||||
#include "main-loop.h"
|
||||
|
||||
int event_notifier_init(EventNotifier *e, int active)
|
||||
{
|
||||
e->event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
assert(e->event);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void event_notifier_cleanup(EventNotifier *e)
|
||||
{
|
||||
CloseHandle(e->event);
|
||||
}
|
||||
|
||||
HANDLE event_notifier_get_handle(EventNotifier *e)
|
||||
{
|
||||
return e->event;
|
||||
}
|
||||
|
||||
int event_notifier_set_handler(EventNotifier *e,
|
||||
EventNotifierHandler *handler)
|
||||
{
|
||||
if (handler) {
|
||||
return qemu_add_wait_object(e->event, (IOHandler *)handler, e);
|
||||
} else {
|
||||
qemu_del_wait_object(e->event, (IOHandler *)handler, e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int event_notifier_set(EventNotifier *e)
|
||||
{
|
||||
SetEvent(e->event);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int event_notifier_test_and_clear(EventNotifier *e)
|
||||
{
|
||||
int ret = WaitForSingleObject(e->event, 0);
|
||||
if (ret == WAIT_OBJECT_0) {
|
||||
ResetEvent(e->event);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
/*
|
||||
* event notifier support
|
||||
*
|
||||
* Copyright Red Hat, Inc. 2010
|
||||
*
|
||||
* Authors:
|
||||
* Michael S. Tsirkin <mst@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "event_notifier.h"
|
||||
#include "qemu-char.h"
|
||||
|
||||
#ifdef CONFIG_EVENTFD
|
||||
#include <sys/eventfd.h>
|
||||
#endif
|
||||
|
||||
void event_notifier_init_fd(EventNotifier *e, int fd)
|
||||
{
|
||||
e->fd = fd;
|
||||
}
|
||||
|
||||
int event_notifier_init(EventNotifier *e, int active)
|
||||
{
|
||||
#ifdef CONFIG_EVENTFD
|
||||
int fd = eventfd(!!active, EFD_NONBLOCK | EFD_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
e->fd = fd;
|
||||
return 0;
|
||||
#else
|
||||
return -ENOSYS;
|
||||
#endif
|
||||
}
|
||||
|
||||
void event_notifier_cleanup(EventNotifier *e)
|
||||
{
|
||||
close(e->fd);
|
||||
}
|
||||
|
||||
int event_notifier_get_fd(EventNotifier *e)
|
||||
{
|
||||
return e->fd;
|
||||
}
|
||||
|
||||
int event_notifier_set_handler(EventNotifier *e,
|
||||
EventNotifierHandler *handler)
|
||||
{
|
||||
return qemu_set_fd_handler(e->fd, (IOHandler *)handler, NULL, e);
|
||||
}
|
||||
|
||||
int event_notifier_set(EventNotifier *e)
|
||||
{
|
||||
uint64_t value = 1;
|
||||
int r = write(e->fd, &value, sizeof(value));
|
||||
return r == sizeof(value);
|
||||
}
|
||||
|
||||
int event_notifier_test_and_clear(EventNotifier *e)
|
||||
{
|
||||
uint64_t value;
|
||||
int r = read(e->fd, &value, sizeof(value));
|
||||
return r == sizeof(value);
|
||||
}
|
|
@ -15,18 +15,32 @@
|
|||
|
||||
#include "qemu-common.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
struct EventNotifier {
|
||||
int fd;
|
||||
#ifdef _WIN32
|
||||
HANDLE event;
|
||||
#else
|
||||
int rfd;
|
||||
int wfd;
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef void EventNotifierHandler(EventNotifier *);
|
||||
|
||||
void event_notifier_init_fd(EventNotifier *, int fd);
|
||||
int event_notifier_init(EventNotifier *, int active);
|
||||
void event_notifier_cleanup(EventNotifier *);
|
||||
int event_notifier_get_fd(EventNotifier *);
|
||||
int event_notifier_set(EventNotifier *);
|
||||
int event_notifier_test_and_clear(EventNotifier *);
|
||||
int event_notifier_set_handler(EventNotifier *, EventNotifierHandler *);
|
||||
|
||||
#ifdef CONFIG_POSIX
|
||||
void event_notifier_init_fd(EventNotifier *, int fd);
|
||||
int event_notifier_get_fd(EventNotifier *);
|
||||
#else
|
||||
HANDLE event_notifier_get_handle(EventNotifier *);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
41
exec-all.h
41
exec-all.h
|
@ -194,8 +194,6 @@ static inline unsigned int tb_phys_hash_func(tb_page_addr_t pc)
|
|||
|
||||
void tb_free(TranslationBlock *tb);
|
||||
void tb_flush(CPUArchState *env);
|
||||
void tb_link_page(TranslationBlock *tb,
|
||||
tb_page_addr_t phys_pc, tb_page_addr_t phys_page2);
|
||||
void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr);
|
||||
|
||||
extern TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
|
||||
|
@ -310,6 +308,45 @@ extern uintptr_t tci_tb_ptr;
|
|||
# define GETPC() ((uintptr_t)__builtin_return_address(0) - 1)
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_QEMU_LDST_OPTIMIZATION) && defined(CONFIG_SOFTMMU)
|
||||
/* qemu_ld/st optimization split code generation to fast and slow path, thus,
|
||||
it needs special handling for an MMU helper which is called from the slow
|
||||
path, to get the fast path's pc without any additional argument.
|
||||
It uses a tricky solution which embeds the fast path pc into the slow path.
|
||||
|
||||
Code flow in slow path:
|
||||
(1) pre-process
|
||||
(2) call MMU helper
|
||||
(3) jump to (5)
|
||||
(4) fast path information (implementation specific)
|
||||
(5) post-process (e.g. stack adjust)
|
||||
(6) jump to corresponding code of the next of fast path
|
||||
*/
|
||||
# if defined(__i386__) || defined(__x86_64__)
|
||||
/* To avoid broken disassembling, long jmp is used for embedding fast path pc,
|
||||
so that the destination is the next code of fast path, though this jmp is
|
||||
never executed.
|
||||
|
||||
call MMU helper
|
||||
jmp POST_PROC (2byte) <- GETRA()
|
||||
jmp NEXT_CODE (5byte)
|
||||
POST_PROCESS ... <- GETRA() + 7
|
||||
*/
|
||||
# define GETRA() ((uintptr_t)__builtin_return_address(0))
|
||||
# define GETPC_LDST() ((uintptr_t)(GETRA() + 7 + \
|
||||
*(int32_t *)((void *)GETRA() + 3) - 1))
|
||||
# elif defined (_ARCH_PPC) && !defined (_ARCH_PPC64)
|
||||
# define GETRA() ((uintptr_t)__builtin_return_address(0))
|
||||
# define GETPC_LDST() ((uintptr_t) ((*(int32_t *)(GETRA() - 4)) - 1))
|
||||
# else
|
||||
# error "CONFIG_QEMU_LDST_OPTIMIZATION needs GETPC_LDST() implementation!"
|
||||
# endif
|
||||
bool is_tcg_gen_code(uintptr_t pc_ptr);
|
||||
# define GETPC_EXT() (is_tcg_gen_code(GETRA()) ? GETPC_LDST() : GETPC())
|
||||
#else
|
||||
# define GETPC_EXT() GETPC()
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
|
||||
struct MemoryRegion *iotlb_to_region(hwaddr index);
|
||||
|
|
36
exec.c
36
exec.c
|
@ -188,9 +188,12 @@ static unsigned phys_map_nodes_nb, phys_map_nodes_nb_alloc;
|
|||
|
||||
static void io_mem_init(void);
|
||||
static void memory_map_init(void);
|
||||
static void *qemu_safe_ram_ptr(ram_addr_t addr);
|
||||
|
||||
static MemoryRegion io_mem_watch;
|
||||
#endif
|
||||
static void tb_link_page(TranslationBlock *tb, tb_page_addr_t phys_pc,
|
||||
tb_page_addr_t phys_page2);
|
||||
|
||||
/* statistics */
|
||||
static int tb_flush_count;
|
||||
|
@ -689,6 +692,9 @@ CPUArchState *qemu_get_cpu(int cpu)
|
|||
|
||||
void cpu_exec_init(CPUArchState *env)
|
||||
{
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
CPUState *cpu = ENV_GET_CPU(env);
|
||||
#endif
|
||||
CPUArchState **penv;
|
||||
int cpu_index;
|
||||
|
||||
|
@ -707,7 +713,7 @@ void cpu_exec_init(CPUArchState *env)
|
|||
QTAILQ_INIT(&env->breakpoints);
|
||||
QTAILQ_INIT(&env->watchpoints);
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
env->thread_id = qemu_get_thread_id();
|
||||
cpu->thread_id = qemu_get_thread_id();
|
||||
#endif
|
||||
*penv = env;
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
|
@ -1349,8 +1355,8 @@ static inline void tb_alloc_page(TranslationBlock *tb,
|
|||
|
||||
/* add a new TB and link it to the physical page tables. phys_page2 is
|
||||
(-1) to indicate that only one page contains the TB. */
|
||||
void tb_link_page(TranslationBlock *tb,
|
||||
tb_page_addr_t phys_pc, tb_page_addr_t phys_page2)
|
||||
static void tb_link_page(TranslationBlock *tb, tb_page_addr_t phys_pc,
|
||||
tb_page_addr_t phys_page2)
|
||||
{
|
||||
unsigned int h;
|
||||
TranslationBlock **ptb;
|
||||
|
@ -1387,6 +1393,17 @@ void tb_link_page(TranslationBlock *tb,
|
|||
mmap_unlock();
|
||||
}
|
||||
|
||||
#if defined(CONFIG_QEMU_LDST_OPTIMIZATION) && defined(CONFIG_SOFTMMU)
|
||||
/* check whether the given addr is in TCG generated code buffer or not */
|
||||
bool is_tcg_gen_code(uintptr_t tc_ptr)
|
||||
{
|
||||
/* This can be called during code generation, code_gen_buffer_max_size
|
||||
is used instead of code_gen_ptr for upper boundary checking */
|
||||
return (tc_ptr >= (uintptr_t)code_gen_buffer &&
|
||||
tc_ptr < (uintptr_t)(code_gen_buffer + code_gen_buffer_max_size));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
|
||||
tb[1].tc_ptr. Return NULL if not found */
|
||||
TranslationBlock *tb_find_pc(uintptr_t tc_ptr)
|
||||
|
@ -1693,6 +1710,7 @@ static void cpu_unlink_tb(CPUArchState *env)
|
|||
/* mask must never be zero, except for A20 change call */
|
||||
static void tcg_handle_interrupt(CPUArchState *env, int mask)
|
||||
{
|
||||
CPUState *cpu = ENV_GET_CPU(env);
|
||||
int old_mask;
|
||||
|
||||
old_mask = env->interrupt_request;
|
||||
|
@ -1702,8 +1720,8 @@ static void tcg_handle_interrupt(CPUArchState *env, int mask)
|
|||
* If called from iothread context, wake the target cpu in
|
||||
* case its halted.
|
||||
*/
|
||||
if (!qemu_cpu_is_self(env)) {
|
||||
qemu_cpu_kick(env);
|
||||
if (!qemu_cpu_is_self(cpu)) {
|
||||
qemu_cpu_kick(cpu);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1859,7 +1877,7 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
|
|||
}
|
||||
}
|
||||
|
||||
int cpu_physical_memory_set_dirty_tracking(int enable)
|
||||
static int cpu_physical_memory_set_dirty_tracking(int enable)
|
||||
{
|
||||
int ret = 0;
|
||||
in_migration = enable;
|
||||
|
@ -2741,7 +2759,7 @@ void *qemu_get_ram_ptr(ram_addr_t addr)
|
|||
/* Return a host pointer to ram allocated with qemu_ram_alloc.
|
||||
* Same as qemu_get_ram_ptr but avoid reordering ramblocks.
|
||||
*/
|
||||
void *qemu_safe_ram_ptr(ram_addr_t addr)
|
||||
static void *qemu_safe_ram_ptr(ram_addr_t addr)
|
||||
{
|
||||
RAMBlock *block;
|
||||
|
||||
|
@ -2771,7 +2789,7 @@ void *qemu_safe_ram_ptr(ram_addr_t addr)
|
|||
|
||||
/* Return a host pointer to guest's ram. Similar to qemu_get_ram_ptr
|
||||
* but takes a size argument */
|
||||
void *qemu_ram_ptr_length(ram_addr_t addr, ram_addr_t *size)
|
||||
static void *qemu_ram_ptr_length(ram_addr_t addr, ram_addr_t *size)
|
||||
{
|
||||
if (*size == 0) {
|
||||
return NULL;
|
||||
|
@ -3519,7 +3537,7 @@ void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque))
|
|||
return client;
|
||||
}
|
||||
|
||||
void cpu_unregister_map_client(void *_client)
|
||||
static void cpu_unregister_map_client(void *_client)
|
||||
{
|
||||
MapClient *client = (MapClient *)_client;
|
||||
|
||||
|
|
|
@ -486,6 +486,33 @@ static int pickNaNMulAdd(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
|
|||
return 1;
|
||||
}
|
||||
}
|
||||
#elif defined(TARGET_MIPS)
|
||||
static int pickNaNMulAdd(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
|
||||
flag cIsQNaN, flag cIsSNaN, flag infzero STATUS_PARAM)
|
||||
{
|
||||
/* For MIPS, the (inf,zero,qnan) case sets InvalidOp and returns
|
||||
* the default NaN
|
||||
*/
|
||||
if (infzero) {
|
||||
float_raise(float_flag_invalid STATUS_VAR);
|
||||
return 3;
|
||||
}
|
||||
|
||||
/* Prefer sNaN over qNaN, in the a, b, c order. */
|
||||
if (aIsSNaN) {
|
||||
return 0;
|
||||
} else if (bIsSNaN) {
|
||||
return 1;
|
||||
} else if (cIsSNaN) {
|
||||
return 2;
|
||||
} else if (aIsQNaN) {
|
||||
return 0;
|
||||
} else if (bIsQNaN) {
|
||||
return 1;
|
||||
} else {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
#elif defined(TARGET_PPC)
|
||||
static int pickNaNMulAdd(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
|
||||
flag cIsQNaN, flag cIsSNaN, flag infzero STATUS_PARAM)
|
||||
|
|
8
hw/adb.c
8
hw/adb.c
|
@ -108,10 +108,10 @@ int adb_poll(ADBBusState *s, uint8_t *obuf)
|
|||
return olen;
|
||||
}
|
||||
|
||||
ADBDevice *adb_register_device(ADBBusState *s, int devaddr,
|
||||
ADBDeviceRequest *devreq,
|
||||
ADBDeviceReset *devreset,
|
||||
void *opaque)
|
||||
static ADBDevice *adb_register_device(ADBBusState *s, int devaddr,
|
||||
ADBDeviceRequest *devreq,
|
||||
ADBDeviceReset *devreset,
|
||||
void *opaque)
|
||||
{
|
||||
ADBDevice *d;
|
||||
if (s->nb_devices >= MAX_ADB_DEVICES)
|
||||
|
|
4
hw/adb.h
4
hw/adb.h
|
@ -56,10 +56,6 @@ int adb_request(ADBBusState *s, uint8_t *buf_out,
|
|||
const uint8_t *buf, int len);
|
||||
int adb_poll(ADBBusState *s, uint8_t *buf_out);
|
||||
|
||||
ADBDevice *adb_register_device(ADBBusState *s, int devaddr,
|
||||
ADBDeviceRequest *devreq,
|
||||
ADBDeviceReset *devreset,
|
||||
void *opaque);
|
||||
void adb_kbd_init(ADBBusState *bus);
|
||||
void adb_mouse_init(ADBBusState *bus);
|
||||
|
||||
|
|
40
hw/apic.c
40
hw/apic.c
|
@ -107,7 +107,7 @@ static void apic_sync_vapic(APICCommonState *s, int sync_type)
|
|||
length = offsetof(VAPICState, enabled) - offsetof(VAPICState, isr);
|
||||
|
||||
if (sync_type & SYNC_TO_VAPIC) {
|
||||
assert(qemu_cpu_is_self(s->cpu_env));
|
||||
assert(qemu_cpu_is_self(CPU(s->cpu)));
|
||||
|
||||
vapic_state.tpr = s->tpr;
|
||||
vapic_state.enabled = 1;
|
||||
|
@ -151,15 +151,15 @@ static void apic_local_deliver(APICCommonState *s, int vector)
|
|||
|
||||
switch ((lvt >> 8) & 7) {
|
||||
case APIC_DM_SMI:
|
||||
cpu_interrupt(s->cpu_env, CPU_INTERRUPT_SMI);
|
||||
cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_SMI);
|
||||
break;
|
||||
|
||||
case APIC_DM_NMI:
|
||||
cpu_interrupt(s->cpu_env, CPU_INTERRUPT_NMI);
|
||||
cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_NMI);
|
||||
break;
|
||||
|
||||
case APIC_DM_EXTINT:
|
||||
cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
|
||||
cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_HARD);
|
||||
break;
|
||||
|
||||
case APIC_DM_FIXED:
|
||||
|
@ -187,7 +187,7 @@ void apic_deliver_pic_intr(DeviceState *d, int level)
|
|||
reset_bit(s->irr, lvt & 0xff);
|
||||
/* fall through */
|
||||
case APIC_DM_EXTINT:
|
||||
cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
|
||||
cpu_reset_interrupt(&s->cpu->env, CPU_INTERRUPT_HARD);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -248,18 +248,22 @@ static void apic_bus_deliver(const uint32_t *deliver_bitmask,
|
|||
|
||||
case APIC_DM_SMI:
|
||||
foreach_apic(apic_iter, deliver_bitmask,
|
||||
cpu_interrupt(apic_iter->cpu_env, CPU_INTERRUPT_SMI) );
|
||||
cpu_interrupt(&apic_iter->cpu->env, CPU_INTERRUPT_SMI)
|
||||
);
|
||||
return;
|
||||
|
||||
case APIC_DM_NMI:
|
||||
foreach_apic(apic_iter, deliver_bitmask,
|
||||
cpu_interrupt(apic_iter->cpu_env, CPU_INTERRUPT_NMI) );
|
||||
cpu_interrupt(&apic_iter->cpu->env, CPU_INTERRUPT_NMI)
|
||||
);
|
||||
return;
|
||||
|
||||
case APIC_DM_INIT:
|
||||
/* normal INIT IPI sent to processors */
|
||||
foreach_apic(apic_iter, deliver_bitmask,
|
||||
cpu_interrupt(apic_iter->cpu_env, CPU_INTERRUPT_INIT) );
|
||||
cpu_interrupt(&apic_iter->cpu->env,
|
||||
CPU_INTERRUPT_INIT)
|
||||
);
|
||||
return;
|
||||
|
||||
case APIC_DM_EXTINT:
|
||||
|
@ -293,7 +297,7 @@ static void apic_set_base(APICCommonState *s, uint64_t val)
|
|||
/* if disabled, cannot be enabled again */
|
||||
if (!(val & MSR_IA32_APICBASE_ENABLE)) {
|
||||
s->apicbase &= ~MSR_IA32_APICBASE_ENABLE;
|
||||
cpu_clear_apic_feature(s->cpu_env);
|
||||
cpu_clear_apic_feature(&s->cpu->env);
|
||||
s->spurious_vec &= ~APIC_SV_ENABLE;
|
||||
}
|
||||
}
|
||||
|
@ -359,13 +363,15 @@ static int apic_irq_pending(APICCommonState *s)
|
|||
/* signal the CPU if an irq is pending */
|
||||
static void apic_update_irq(APICCommonState *s)
|
||||
{
|
||||
CPUState *cpu = CPU(s->cpu);
|
||||
|
||||
if (!(s->spurious_vec & APIC_SV_ENABLE)) {
|
||||
return;
|
||||
}
|
||||
if (!qemu_cpu_is_self(s->cpu_env)) {
|
||||
cpu_interrupt(s->cpu_env, CPU_INTERRUPT_POLL);
|
||||
if (!qemu_cpu_is_self(cpu)) {
|
||||
cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_POLL);
|
||||
} else if (apic_irq_pending(s) > 0) {
|
||||
cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
|
||||
cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_HARD);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -472,18 +478,18 @@ static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
|
|||
static void apic_startup(APICCommonState *s, int vector_num)
|
||||
{
|
||||
s->sipi_vector = vector_num;
|
||||
cpu_interrupt(s->cpu_env, CPU_INTERRUPT_SIPI);
|
||||
cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_SIPI);
|
||||
}
|
||||
|
||||
void apic_sipi(DeviceState *d)
|
||||
{
|
||||
APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
|
||||
|
||||
cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_SIPI);
|
||||
cpu_reset_interrupt(&s->cpu->env, CPU_INTERRUPT_SIPI);
|
||||
|
||||
if (!s->wait_for_sipi)
|
||||
return;
|
||||
cpu_x86_load_seg_cache_sipi(s->cpu_env, s->sipi_vector);
|
||||
cpu_x86_load_seg_cache_sipi(s->cpu, s->sipi_vector);
|
||||
s->wait_for_sipi = 0;
|
||||
}
|
||||
|
||||
|
@ -672,7 +678,7 @@ static uint32_t apic_mem_readl(void *opaque, hwaddr addr)
|
|||
case 0x08:
|
||||
apic_sync_vapic(s, SYNC_FROM_VAPIC);
|
||||
if (apic_report_tpr_access) {
|
||||
cpu_report_tpr_access(s->cpu_env, TPR_ACCESS_READ);
|
||||
cpu_report_tpr_access(&s->cpu->env, TPR_ACCESS_READ);
|
||||
}
|
||||
val = s->tpr;
|
||||
break;
|
||||
|
@ -774,7 +780,7 @@ static void apic_mem_writel(void *opaque, hwaddr addr, uint32_t val)
|
|||
break;
|
||||
case 0x08:
|
||||
if (apic_report_tpr_access) {
|
||||
cpu_report_tpr_access(s->cpu_env, TPR_ACCESS_WRITE);
|
||||
cpu_report_tpr_access(&s->cpu->env, TPR_ACCESS_WRITE);
|
||||
}
|
||||
s->tpr = val;
|
||||
apic_sync_vapic(s, SYNC_TO_VAPIC);
|
||||
|
|
|
@ -103,7 +103,7 @@ void apic_handle_tpr_access_report(DeviceState *d, target_ulong ip,
|
|||
{
|
||||
APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
|
||||
|
||||
vapic_report_tpr_access(s->vapic, s->cpu_env, ip, access);
|
||||
vapic_report_tpr_access(s->vapic, &s->cpu->env, ip, access);
|
||||
}
|
||||
|
||||
void apic_report_irq_delivered(int delivered)
|
||||
|
@ -217,7 +217,7 @@ static void apic_reset_common(DeviceState *d)
|
|||
APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
|
||||
bool bsp;
|
||||
|
||||
bsp = cpu_is_bsp(x86_env_get_cpu(s->cpu_env));
|
||||
bsp = cpu_is_bsp(s->cpu);
|
||||
s->apicbase = 0xfee00000 |
|
||||
(bsp ? MSR_IA32_APICBASE_BSP : 0) | MSR_IA32_APICBASE_ENABLE;
|
||||
|
||||
|
@ -368,7 +368,6 @@ static const VMStateDescription vmstate_apic_common = {
|
|||
|
||||
static Property apic_properties_common[] = {
|
||||
DEFINE_PROP_UINT8("id", APICCommonState, id, -1),
|
||||
DEFINE_PROP_PTR("cpu_env", APICCommonState, cpu_env),
|
||||
DEFINE_PROP_BIT("vapic", APICCommonState, vapic_control, VAPIC_ENABLE_BIT,
|
||||
true),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
|
|
|
@ -95,8 +95,9 @@ typedef struct APICCommonClass
|
|||
|
||||
struct APICCommonState {
|
||||
SysBusDevice busdev;
|
||||
|
||||
MemoryRegion io_memory;
|
||||
void *cpu_env;
|
||||
X86CPU *cpu;
|
||||
uint32_t apicbase;
|
||||
uint8_t id;
|
||||
uint8_t arb_id;
|
||||
|
|
|
@ -56,6 +56,7 @@ struct arm_boot_info {
|
|||
const struct arm_boot_info *info);
|
||||
/* Used internally by arm_boot.c */
|
||||
int is_linux;
|
||||
hwaddr initrd_start;
|
||||
hwaddr initrd_size;
|
||||
hwaddr entry;
|
||||
};
|
||||
|
|
|
@ -44,7 +44,9 @@ static uint64_t mpcore_scu_read(void *opaque, hwaddr offset,
|
|||
case 0x0c: /* Invalidate all. */
|
||||
return 0;
|
||||
default:
|
||||
hw_error("mpcore_priv_read: Bad offset %x\n", (int)offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"mpcore_priv_read: Bad offset %x\n", (int)offset);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -61,7 +63,8 @@ static void mpcore_scu_write(void *opaque, hwaddr offset,
|
|||
/* This is a no-op as cache is not emulated. */
|
||||
break;
|
||||
default:
|
||||
hw_error("mpcore_priv_read: Bad offset %x\n", (int)offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"mpcore_priv_read: Bad offset %x\n", (int)offset);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
|
||||
#define KERNEL_ARGS_ADDR 0x100
|
||||
#define KERNEL_LOAD_ADDR 0x00010000
|
||||
#define INITRD_LOAD_ADDR 0x00d00000
|
||||
|
||||
/* The worlds second smallest bootloader. Set r0-r2, then jump to kernel. */
|
||||
static uint32_t bootloader[] = {
|
||||
|
@ -109,7 +108,7 @@ static void set_kernel_args(const struct arm_boot_info *info)
|
|||
/* ATAG_INITRD2 */
|
||||
WRITE_WORD(p, 4);
|
||||
WRITE_WORD(p, 0x54420005);
|
||||
WRITE_WORD(p, info->loader_start + INITRD_LOAD_ADDR);
|
||||
WRITE_WORD(p, info->initrd_start);
|
||||
WRITE_WORD(p, initrd_size);
|
||||
}
|
||||
if (info->kernel_cmdline && *info->kernel_cmdline) {
|
||||
|
@ -185,10 +184,11 @@ static void set_kernel_args_old(const struct arm_boot_info *info)
|
|||
/* pages_in_vram */
|
||||
WRITE_WORD(p, 0);
|
||||
/* initrd_start */
|
||||
if (initrd_size)
|
||||
WRITE_WORD(p, info->loader_start + INITRD_LOAD_ADDR);
|
||||
else
|
||||
if (initrd_size) {
|
||||
WRITE_WORD(p, info->initrd_start);
|
||||
} else {
|
||||
WRITE_WORD(p, 0);
|
||||
}
|
||||
/* initrd_size */
|
||||
WRITE_WORD(p, initrd_size);
|
||||
/* rd_start */
|
||||
|
@ -281,14 +281,13 @@ static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo)
|
|||
|
||||
if (binfo->initrd_size) {
|
||||
rc = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start",
|
||||
binfo->loader_start + INITRD_LOAD_ADDR);
|
||||
binfo->initrd_start);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
|
||||
}
|
||||
|
||||
rc = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end",
|
||||
binfo->loader_start + INITRD_LOAD_ADDR +
|
||||
binfo->initrd_size);
|
||||
binfo->initrd_start + binfo->initrd_size);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
|
||||
}
|
||||
|
@ -375,6 +374,19 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
|
|||
big_endian = 0;
|
||||
#endif
|
||||
|
||||
/* We want to put the initrd far enough into RAM that when the
|
||||
* kernel is uncompressed it will not clobber the initrd. However
|
||||
* on boards without much RAM we must ensure that we still leave
|
||||
* enough room for a decent sized initrd, and on boards with large
|
||||
* amounts of RAM we must avoid the initrd being so far up in RAM
|
||||
* that it is outside lowmem and inaccessible to the kernel.
|
||||
* So for boards with less than 256MB of RAM we put the initrd
|
||||
* halfway into RAM, and for boards with 256MB of RAM or more we put
|
||||
* the initrd at 128MB.
|
||||
*/
|
||||
info->initrd_start = info->loader_start +
|
||||
MIN(info->ram_size / 2, 128 * 1024 * 1024);
|
||||
|
||||
/* Assume that raw images are linux kernels, and ELF images are not. */
|
||||
kernel_size = load_elf(info->kernel_filename, NULL, NULL, &elf_entry,
|
||||
NULL, NULL, big_endian, ELF_MACHINE, 1);
|
||||
|
@ -398,10 +410,9 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
|
|||
if (is_linux) {
|
||||
if (info->initrd_filename) {
|
||||
initrd_size = load_image_targphys(info->initrd_filename,
|
||||
info->loader_start
|
||||
+ INITRD_LOAD_ADDR,
|
||||
info->ram_size
|
||||
- INITRD_LOAD_ADDR);
|
||||
info->initrd_start,
|
||||
info->ram_size -
|
||||
info->initrd_start);
|
||||
if (initrd_size < 0) {
|
||||
fprintf(stderr, "qemu: could not load initrd '%s'\n",
|
||||
info->initrd_filename);
|
||||
|
@ -419,9 +430,8 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
|
|||
*/
|
||||
if (info->dtb_filename) {
|
||||
/* Place the DTB after the initrd in memory */
|
||||
hwaddr dtb_start = TARGET_PAGE_ALIGN(info->loader_start
|
||||
+ INITRD_LOAD_ADDR
|
||||
+ initrd_size);
|
||||
hwaddr dtb_start = TARGET_PAGE_ALIGN(info->initrd_start +
|
||||
initrd_size);
|
||||
if (load_dtb(dtb_start, info)) {
|
||||
exit(1);
|
||||
}
|
||||
|
|
12
hw/arm_gic.c
12
hw/arm_gic.c
|
@ -324,7 +324,8 @@ static uint32_t gic_dist_readb(void *opaque, hwaddr offset)
|
|||
}
|
||||
return res;
|
||||
bad_reg:
|
||||
hw_error("gic_dist_readb: Bad offset %x\n", (int)offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"gic_dist_readb: Bad offset %x\n", (int)offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -487,7 +488,8 @@ static void gic_dist_writeb(void *opaque, hwaddr offset,
|
|||
gic_update(s);
|
||||
return;
|
||||
bad_reg:
|
||||
hw_error("gic_dist_writeb: Bad offset %x\n", (int)offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"gic_dist_writeb: Bad offset %x\n", (int)offset);
|
||||
}
|
||||
|
||||
static void gic_dist_writew(void *opaque, hwaddr offset,
|
||||
|
@ -556,7 +558,8 @@ static uint32_t gic_cpu_read(GICState *s, int cpu, int offset)
|
|||
case 0x18: /* Highest Pending Interrupt */
|
||||
return s->current_pending[cpu];
|
||||
default:
|
||||
hw_error("gic_cpu_read: Bad offset %x\n", (int)offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"gic_cpu_read: Bad offset %x\n", (int)offset);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -577,7 +580,8 @@ static void gic_cpu_write(GICState *s, int cpu, int offset, uint32_t value)
|
|||
case 0x10: /* End Of Interrupt */
|
||||
return gic_complete_irq(s, cpu, value & 0x3ff);
|
||||
default:
|
||||
hw_error("gic_cpu_write: Bad offset %x\n", (int)offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"gic_cpu_write: Bad offset %x\n", (int)offset);
|
||||
return;
|
||||
}
|
||||
gic_update(s);
|
||||
|
|
|
@ -87,7 +87,8 @@ static uint64_t l2x0_priv_read(void *opaque, hwaddr offset,
|
|||
case 0xF80:
|
||||
return 0;
|
||||
default:
|
||||
fprintf(stderr, "l2x0_priv_read: Bad offset %x\n", (int)offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"l2x0_priv_read: Bad offset %x\n", (int)offset);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
|
@ -128,7 +129,8 @@ static void l2x0_priv_write(void *opaque, hwaddr offset,
|
|||
case 0xF80:
|
||||
return;
|
||||
default:
|
||||
fprintf(stderr, "l2x0_priv_write: Bad offset %x\n", (int)offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"l2x0_priv_write: Bad offset %x\n", (int)offset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -184,7 +184,9 @@ static uint64_t arm_sysctl_read(void *opaque, hwaddr offset,
|
|||
return s->sys_cfgstat;
|
||||
default:
|
||||
bad_reg:
|
||||
printf ("arm_sysctl_read: Bad register offset 0x%x\n", (int)offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"arm_sysctl_read: Bad register offset 0x%x\n",
|
||||
(int)offset);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -339,7 +341,9 @@ static void arm_sysctl_write(void *opaque, hwaddr offset,
|
|||
return;
|
||||
default:
|
||||
bad_reg:
|
||||
printf ("arm_sysctl_write: Bad register offset 0x%x\n", (int)offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"arm_sysctl_write: Bad register offset 0x%x\n",
|
||||
(int)offset);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,7 +64,8 @@ static uint32_t arm_timer_read(void *opaque, hwaddr offset)
|
|||
return 0;
|
||||
return s->int_level;
|
||||
default:
|
||||
hw_error("%s: Bad offset %x\n", __func__, (int)offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Bad offset %x\n", __func__, (int)offset);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -131,7 +132,8 @@ static void arm_timer_write(void *opaque, hwaddr offset,
|
|||
arm_timer_recalibrate(s, 0);
|
||||
break;
|
||||
default:
|
||||
hw_error("%s: Bad offset %x\n", __func__, (int)offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Bad offset %x\n", __func__, (int)offset);
|
||||
}
|
||||
arm_timer_update(s);
|
||||
}
|
||||
|
@ -223,10 +225,14 @@ static uint64_t sp804_read(void *opaque, hwaddr offset,
|
|||
/* Integration Test control registers, which we won't support */
|
||||
case 0xf00: /* TimerITCR */
|
||||
case 0xf04: /* TimerITOP (strictly write only but..) */
|
||||
qemu_log_mask(LOG_UNIMP,
|
||||
"%s: integration test registers unimplemented\n",
|
||||
__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
hw_error("%s: Bad offset %x\n", __func__, (int)offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Bad offset %x\n", __func__, (int)offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -246,7 +252,8 @@ static void sp804_write(void *opaque, hwaddr offset,
|
|||
}
|
||||
|
||||
/* Technically we could be writing to the Test Registers, but not likely */
|
||||
hw_error("%s: Bad offset %x\n", __func__, (int)offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %x\n",
|
||||
__func__, (int)offset);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps sp804_ops = {
|
||||
|
@ -300,7 +307,7 @@ static uint64_t icp_pit_read(void *opaque, hwaddr offset,
|
|||
/* ??? Don't know the PrimeCell ID for this device. */
|
||||
n = offset >> 8;
|
||||
if (n > 2) {
|
||||
hw_error("%s: Bad timer %d\n", __func__, n);
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad timer %d\n", __func__, n);
|
||||
}
|
||||
|
||||
return arm_timer_read(s->timer[n], offset & 0xff);
|
||||
|
@ -314,7 +321,7 @@ static void icp_pit_write(void *opaque, hwaddr offset,
|
|||
|
||||
n = offset >> 8;
|
||||
if (n > 2) {
|
||||
hw_error("%s: Bad timer %d\n", __func__, n);
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad timer %d\n", __func__, n);
|
||||
}
|
||||
|
||||
arm_timer_write(s->timer[n], offset & 0xff, value);
|
||||
|
|
|
@ -138,9 +138,8 @@ void armv7m_nvic_complete_irq(void *opaque, int irq)
|
|||
gic_complete_irq(&s->gic, 0, irq);
|
||||
}
|
||||
|
||||
static uint32_t nvic_readl(void *opaque, uint32_t offset)
|
||||
static uint32_t nvic_readl(nvic_state *s, uint32_t offset)
|
||||
{
|
||||
nvic_state *s = (nvic_state *)opaque;
|
||||
uint32_t val;
|
||||
int irq;
|
||||
|
||||
|
@ -216,14 +215,6 @@ static uint32_t nvic_readl(void *opaque, uint32_t offset)
|
|||
case 0xd14: /* Configuration Control. */
|
||||
/* TODO: Implement Configuration Control bits. */
|
||||
return 0;
|
||||
case 0xd18: case 0xd1c: case 0xd20: /* System Handler Priority. */
|
||||
irq = offset - 0xd14;
|
||||
val = 0;
|
||||
val |= s->gic.priority1[irq++][0];
|
||||
val |= s->gic.priority1[irq++][0] << 8;
|
||||
val |= s->gic.priority1[irq++][0] << 16;
|
||||
val |= s->gic.priority1[irq][0] << 24;
|
||||
return val;
|
||||
case 0xd24: /* System Handler Status. */
|
||||
val = 0;
|
||||
if (s->gic.irq_state[ARMV7M_EXCP_MEM].active) val |= (1 << 0);
|
||||
|
@ -243,7 +234,7 @@ static uint32_t nvic_readl(void *opaque, uint32_t offset)
|
|||
return val;
|
||||
case 0xd28: /* Configurable Fault Status. */
|
||||
/* TODO: Implement Fault Status. */
|
||||
hw_error("Not implemented: Configurable Fault Status.");
|
||||
qemu_log_mask(LOG_UNIMP, "Configurable Fault Status unimplemented\n");
|
||||
return 0;
|
||||
case 0xd2c: /* Hard Fault Status. */
|
||||
case 0xd30: /* Debug Fault Status. */
|
||||
|
@ -251,7 +242,8 @@ static uint32_t nvic_readl(void *opaque, uint32_t offset)
|
|||
case 0xd38: /* Bus Fault Address. */
|
||||
case 0xd3c: /* Aux Fault Status. */
|
||||
/* TODO: Implement fault status registers. */
|
||||
goto bad_reg;
|
||||
qemu_log_mask(LOG_UNIMP, "Fault status registers unimplemented\n");
|
||||
return 0;
|
||||
case 0xd40: /* PFR0. */
|
||||
return 0x00000030;
|
||||
case 0xd44: /* PRF1. */
|
||||
|
@ -280,14 +272,13 @@ static uint32_t nvic_readl(void *opaque, uint32_t offset)
|
|||
return 0x01310102;
|
||||
/* TODO: Implement debug registers. */
|
||||
default:
|
||||
bad_reg:
|
||||
hw_error("NVIC: Bad read offset 0x%x\n", offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "NVIC: Bad read offset 0x%x\n", offset);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void nvic_writel(void *opaque, uint32_t offset, uint32_t value)
|
||||
static void nvic_writel(nvic_state *s, uint32_t offset, uint32_t value)
|
||||
{
|
||||
nvic_state *s = (nvic_state *)opaque;
|
||||
uint32_t oldval;
|
||||
switch (offset) {
|
||||
case 0x10: /* SysTick Control and Status. */
|
||||
|
@ -345,27 +336,17 @@ static void nvic_writel(void *opaque, uint32_t offset, uint32_t value)
|
|||
case 0xd0c: /* Application Interrupt/Reset Control. */
|
||||
if ((value >> 16) == 0x05fa) {
|
||||
if (value & 2) {
|
||||
hw_error("VECTCLRACTIVE not implemented");
|
||||
qemu_log_mask(LOG_UNIMP, "VECTCLRACTIVE unimplemented\n");
|
||||
}
|
||||
if (value & 5) {
|
||||
hw_error("System reset");
|
||||
qemu_log_mask(LOG_UNIMP, "AIRCR system reset unimplemented\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xd10: /* System Control. */
|
||||
case 0xd14: /* Configuration Control. */
|
||||
/* TODO: Implement control registers. */
|
||||
goto bad_reg;
|
||||
case 0xd18: case 0xd1c: case 0xd20: /* System Handler Priority. */
|
||||
{
|
||||
int irq;
|
||||
irq = offset - 0xd14;
|
||||
s->gic.priority1[irq++][0] = value & 0xff;
|
||||
s->gic.priority1[irq++][0] = (value >> 8) & 0xff;
|
||||
s->gic.priority1[irq++][0] = (value >> 16) & 0xff;
|
||||
s->gic.priority1[irq][0] = (value >> 24) & 0xff;
|
||||
gic_update(&s->gic);
|
||||
}
|
||||
qemu_log_mask(LOG_UNIMP, "NVIC: SCR and CCR unimplemented\n");
|
||||
break;
|
||||
case 0xd24: /* System Handler Control. */
|
||||
/* TODO: Real hardware allows you to set/clear the active bits
|
||||
|
@ -380,47 +361,71 @@ static void nvic_writel(void *opaque, uint32_t offset, uint32_t value)
|
|||
case 0xd34: /* Mem Manage Address. */
|
||||
case 0xd38: /* Bus Fault Address. */
|
||||
case 0xd3c: /* Aux Fault Status. */
|
||||
goto bad_reg;
|
||||
qemu_log_mask(LOG_UNIMP,
|
||||
"NVIC: fault status registers unimplemented\n");
|
||||
break;
|
||||
case 0xf00: /* Software Triggered Interrupt Register */
|
||||
if ((value & 0x1ff) < s->num_irq) {
|
||||
gic_set_pending_private(&s->gic, 0, value & 0x1ff);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
bad_reg:
|
||||
hw_error("NVIC: Bad write offset 0x%x\n", offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"NVIC: Bad write offset 0x%x\n", offset);
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t nvic_sysreg_read(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
/* At the moment we only support the ID registers for byte/word access.
|
||||
* This is not strictly correct as a few of the other registers also
|
||||
* allow byte access.
|
||||
*/
|
||||
nvic_state *s = (nvic_state *)opaque;
|
||||
uint32_t offset = addr;
|
||||
if (offset >= 0xfe0) {
|
||||
int i;
|
||||
uint32_t val;
|
||||
|
||||
switch (offset) {
|
||||
case 0xd18 ... 0xd23: /* System Handler Priority. */
|
||||
val = 0;
|
||||
for (i = 0; i < size; i++) {
|
||||
val |= s->gic.priority1[(offset - 0xd14) + i][0] << (i * 8);
|
||||
}
|
||||
return val;
|
||||
case 0xfe0 ... 0xfff: /* ID. */
|
||||
if (offset & 3) {
|
||||
return 0;
|
||||
}
|
||||
return nvic_id[(offset - 0xfe0) >> 2];
|
||||
}
|
||||
if (size == 4) {
|
||||
return nvic_readl(opaque, offset);
|
||||
return nvic_readl(s, offset);
|
||||
}
|
||||
hw_error("NVIC: Bad read of size %d at offset 0x%x\n", size, offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"NVIC: Bad read of size %d at offset 0x%x\n", size, offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nvic_sysreg_write(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
nvic_state *s = (nvic_state *)opaque;
|
||||
uint32_t offset = addr;
|
||||
if (size == 4) {
|
||||
nvic_writel(opaque, offset, value);
|
||||
int i;
|
||||
|
||||
switch (offset) {
|
||||
case 0xd18 ... 0xd23: /* System Handler Priority. */
|
||||
for (i = 0; i < size; i++) {
|
||||
s->gic.priority1[(offset - 0xd14) + i][0] =
|
||||
(value >> (i * 8)) & 0xff;
|
||||
}
|
||||
gic_update(&s->gic);
|
||||
return;
|
||||
}
|
||||
hw_error("NVIC: Bad write of size %d at offset 0x%x\n", size, offset);
|
||||
if (size == 4) {
|
||||
nvic_writel(s, offset, value);
|
||||
return;
|
||||
}
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"NVIC: Bad write of size %d at offset 0x%x\n", size, offset);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps nvic_sysreg_ops = {
|
||||
|
|
|
@ -921,8 +921,8 @@ static void blizzard_update_display(void *opaque)
|
|||
for (; y < s->my[1]; y ++, src += bypl, dst += bypl)
|
||||
memcpy(dst, src, bwidth);
|
||||
|
||||
dpy_update(s->state, s->mx[0], s->my[0],
|
||||
s->mx[1] - s->mx[0], y - s->my[0]);
|
||||
dpy_gfx_update(s->state, s->mx[0], s->my[0],
|
||||
s->mx[1] - s->mx[0], y - s->my[0]);
|
||||
|
||||
s->mx[0] = s->x;
|
||||
s->mx[1] = 0;
|
||||
|
|
|
@ -359,7 +359,7 @@ static void uart_write(void *opaque, hwaddr offset,
|
|||
{
|
||||
UartState *s = (UartState *)opaque;
|
||||
|
||||
DB_PRINT(" offset:%x data:%08x\n", offset, (unsigned)value);
|
||||
DB_PRINT(" offset:%x data:%08x\n", (unsigned)offset, (unsigned)value);
|
||||
offset >>= 2;
|
||||
switch (offset) {
|
||||
case R_IER: /* ier (wts imr) */
|
||||
|
@ -405,12 +405,15 @@ static uint64_t uart_read(void *opaque, hwaddr offset,
|
|||
|
||||
offset >>= 2;
|
||||
if (offset >= R_MAX) {
|
||||
return 0;
|
||||
c = 0;
|
||||
} else if (offset == R_TX_RX) {
|
||||
uart_read_rx_fifo(s, &c);
|
||||
return c;
|
||||
} else {
|
||||
c = s->r[offset];
|
||||
}
|
||||
return s->r[offset];
|
||||
|
||||
DB_PRINT(" offset:%x data:%08x\n", (unsigned)(offset << 2), (unsigned)c);
|
||||
return c;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps uart_ops = {
|
||||
|
|
|
@ -42,8 +42,6 @@
|
|||
//#define DEBUG_CIRRUS
|
||||
//#define DEBUG_BITBLT
|
||||
|
||||
#define VGA_RAM_SIZE (8192 * 1024)
|
||||
|
||||
/***************************************
|
||||
*
|
||||
* definitions
|
||||
|
@ -2856,7 +2854,8 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci,
|
|||
|
||||
/* I/O handler for LFB */
|
||||
memory_region_init_io(&s->cirrus_linear_io, &cirrus_linear_io_ops, s,
|
||||
"cirrus-linear-io", VGA_RAM_SIZE);
|
||||
"cirrus-linear-io", s->vga.vram_size_mb
|
||||
* 1024 * 1024);
|
||||
memory_region_set_flush_coalesced(&s->cirrus_linear_io);
|
||||
|
||||
/* I/O handler for LFB */
|
||||
|
@ -2899,7 +2898,6 @@ static int vga_initfn(ISADevice *dev)
|
|||
ISACirrusVGAState *d = DO_UPCAST(ISACirrusVGAState, dev, dev);
|
||||
VGACommonState *s = &d->cirrus_vga.vga;
|
||||
|
||||
s->vram_size_mb = VGA_RAM_SIZE >> 20;
|
||||
vga_common_init(s);
|
||||
cirrus_init_common(&d->cirrus_vga, CIRRUS_ID_CLGD5430, 0,
|
||||
isa_address_space(dev));
|
||||
|
@ -2912,6 +2910,12 @@ static int vga_initfn(ISADevice *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static Property isa_vga_cirrus_properties[] = {
|
||||
DEFINE_PROP_UINT32("vgamem_mb", struct ISACirrusVGAState,
|
||||
cirrus_vga.vga.vram_size_mb, 8),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void isa_cirrus_vga_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
ISADeviceClass *k = ISA_DEVICE_CLASS(klass);
|
||||
|
@ -2919,6 +2923,7 @@ static void isa_cirrus_vga_class_init(ObjectClass *klass, void *data)
|
|||
|
||||
dc->vmsd = &vmstate_cirrus_vga;
|
||||
k->init = vga_initfn;
|
||||
dc->props = isa_vga_cirrus_properties;
|
||||
}
|
||||
|
||||
static TypeInfo isa_cirrus_vga_info = {
|
||||
|
@ -2942,7 +2947,6 @@ static int pci_cirrus_vga_initfn(PCIDevice *dev)
|
|||
int16_t device_id = pc->device_id;
|
||||
|
||||
/* setup VGA */
|
||||
s->vga.vram_size_mb = VGA_RAM_SIZE >> 20;
|
||||
vga_common_init(&s->vga);
|
||||
cirrus_init_common(s, device_id, 1, pci_address_space(dev));
|
||||
s->vga.ds = graphic_console_init(s->vga.update, s->vga.invalidate,
|
||||
|
@ -2969,6 +2973,12 @@ static int pci_cirrus_vga_initfn(PCIDevice *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static Property pci_vga_cirrus_properties[] = {
|
||||
DEFINE_PROP_UINT32("vgamem_mb", struct PCICirrusVGAState,
|
||||
cirrus_vga.vga.vram_size_mb, 8),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void cirrus_vga_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
@ -2982,6 +2992,7 @@ static void cirrus_vga_class_init(ObjectClass *klass, void *data)
|
|||
k->class_id = PCI_CLASS_DISPLAY_VGA;
|
||||
dc->desc = "Cirrus CLGD 54xx VGA";
|
||||
dc->vmsd = &vmstate_pci_cirrus_vga;
|
||||
dc->props = pci_vga_cirrus_properties;
|
||||
}
|
||||
|
||||
static TypeInfo cirrus_vga_info = {
|
||||
|
|
17
hw/e1000.c
17
hw/e1000.c
|
@ -92,7 +92,6 @@ typedef struct E1000State_st {
|
|||
|
||||
uint32_t rxbuf_size;
|
||||
uint32_t rxbuf_min_shift;
|
||||
int check_rxov;
|
||||
struct e1000_tx {
|
||||
unsigned char header[256];
|
||||
unsigned char vlan_header[4];
|
||||
|
@ -266,6 +265,8 @@ rxbufsize(uint32_t v)
|
|||
static void e1000_reset(void *opaque)
|
||||
{
|
||||
E1000State *d = opaque;
|
||||
uint8_t *macaddr = d->conf.macaddr.a;
|
||||
int i;
|
||||
|
||||
qemu_del_timer(d->autoneg_timer);
|
||||
memset(d->phy_reg, 0, sizeof d->phy_reg);
|
||||
|
@ -278,6 +279,14 @@ static void e1000_reset(void *opaque)
|
|||
if (d->nic->nc.link_down) {
|
||||
e1000_link_down(d);
|
||||
}
|
||||
|
||||
/* Some guests expect pre-initialized RAH/RAL (AddrValid flag + MACaddr) */
|
||||
d->mac_reg[RA] = 0;
|
||||
d->mac_reg[RA + 1] = E1000_RAH_AV;
|
||||
for (i = 0; i < 4; i++) {
|
||||
d->mac_reg[RA] |= macaddr[i] << (8 * i);
|
||||
d->mac_reg[RA + 1] |= (i < 2) ? macaddr[i + 4] << (8 * i) : 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -741,11 +750,11 @@ static bool e1000_has_rxbufs(E1000State *s, size_t total_size)
|
|||
int bufs;
|
||||
/* Fast-path short packets */
|
||||
if (total_size <= s->rxbuf_size) {
|
||||
return s->mac_reg[RDH] != s->mac_reg[RDT] || !s->check_rxov;
|
||||
return s->mac_reg[RDH] != s->mac_reg[RDT];
|
||||
}
|
||||
if (s->mac_reg[RDH] < s->mac_reg[RDT]) {
|
||||
bufs = s->mac_reg[RDT] - s->mac_reg[RDH];
|
||||
} else if (s->mac_reg[RDH] > s->mac_reg[RDT] || !s->check_rxov) {
|
||||
} else if (s->mac_reg[RDH] > s->mac_reg[RDT]) {
|
||||
bufs = s->mac_reg[RDLEN] / sizeof(struct e1000_rx_desc) +
|
||||
s->mac_reg[RDT] - s->mac_reg[RDH];
|
||||
} else {
|
||||
|
@ -848,7 +857,6 @@ e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size)
|
|||
|
||||
if (++s->mac_reg[RDH] * sizeof(desc) >= s->mac_reg[RDLEN])
|
||||
s->mac_reg[RDH] = 0;
|
||||
s->check_rxov = 1;
|
||||
/* see comment in start_xmit; same here */
|
||||
if (s->mac_reg[RDH] == rdh_start) {
|
||||
DBGOUT(RXERR, "RDH wraparound @%x, RDT %x, RDLEN %x\n",
|
||||
|
@ -925,7 +933,6 @@ mac_writereg(E1000State *s, int index, uint32_t val)
|
|||
static void
|
||||
set_rdt(E1000State *s, int index, uint32_t val)
|
||||
{
|
||||
s->check_rxov = 0;
|
||||
s->mac_reg[index] = val & 0xffff;
|
||||
if (e1000_has_rxbufs(s, 1)) {
|
||||
qemu_flush_queued_packets(&s->nic->nc);
|
||||
|
|
|
@ -1307,7 +1307,7 @@ static void exynos4210_fimd_update(void *opaque)
|
|||
fimd_copy_line_toqemu(global_width, s->ifb + global_width * line *
|
||||
RGBA_SIZE, d + global_width * line * bpp);
|
||||
}
|
||||
dpy_update(s->console, 0, 0, global_width, global_height);
|
||||
dpy_gfx_update(s->console, 0, 0, global_width, global_height);
|
||||
}
|
||||
s->invalidate = false;
|
||||
s->vidintcon[1] |= FIMD_VIDINT_INTFRMPEND;
|
||||
|
|
|
@ -93,11 +93,8 @@ static void lan9215_init(uint32_t base, qemu_irq irq)
|
|||
}
|
||||
}
|
||||
|
||||
static Exynos4210State *exynos4_boards_init_common(
|
||||
const char *kernel_filename,
|
||||
const char *kernel_cmdline,
|
||||
const char *initrd_filename,
|
||||
Exynos4BoardType board_type)
|
||||
static Exynos4210State *exynos4_boards_init_common(QEMUMachineInitArgs *args,
|
||||
Exynos4BoardType board_type)
|
||||
{
|
||||
if (smp_cpus != EXYNOS4210_NCPUS) {
|
||||
fprintf(stderr, "%s board supports only %d CPU cores. Ignoring smp_cpus"
|
||||
|
@ -110,9 +107,9 @@ static Exynos4210State *exynos4_boards_init_common(
|
|||
exynos4_board_binfo.board_id = exynos4_board_id[board_type];
|
||||
exynos4_board_binfo.smp_bootreg_addr =
|
||||
exynos4_board_smp_bootreg_addr[board_type];
|
||||
exynos4_board_binfo.kernel_filename = kernel_filename;
|
||||
exynos4_board_binfo.initrd_filename = initrd_filename;
|
||||
exynos4_board_binfo.kernel_cmdline = kernel_cmdline;
|
||||
exynos4_board_binfo.kernel_filename = args->kernel_filename;
|
||||
exynos4_board_binfo.initrd_filename = args->initrd_filename;
|
||||
exynos4_board_binfo.kernel_cmdline = args->kernel_cmdline;
|
||||
exynos4_board_binfo.gic_cpu_if_addr =
|
||||
EXYNOS4210_SMP_PRIVATE_BASE_ADDR + 0x100;
|
||||
|
||||
|
@ -122,9 +119,9 @@ static Exynos4210State *exynos4_boards_init_common(
|
|||
" initrd_filename: %s\n",
|
||||
exynos4_board_ram_size[board_type] / 1048576,
|
||||
exynos4_board_ram_size[board_type],
|
||||
kernel_filename,
|
||||
kernel_cmdline,
|
||||
initrd_filename);
|
||||
args->kernel_filename,
|
||||
args->kernel_cmdline,
|
||||
args->initrd_filename);
|
||||
|
||||
return exynos4210_init(get_system_memory(),
|
||||
exynos4_board_ram_size[board_type]);
|
||||
|
@ -132,22 +129,15 @@ static Exynos4210State *exynos4_boards_init_common(
|
|||
|
||||
static void nuri_init(QEMUMachineInitArgs *args)
|
||||
{
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
exynos4_boards_init_common(kernel_filename, kernel_cmdline,
|
||||
initrd_filename, EXYNOS4_BOARD_NURI);
|
||||
exynos4_boards_init_common(args, EXYNOS4_BOARD_NURI);
|
||||
|
||||
arm_load_kernel(arm_env_get_cpu(first_cpu), &exynos4_board_binfo);
|
||||
}
|
||||
|
||||
static void smdkc210_init(QEMUMachineInitArgs *args)
|
||||
{
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
Exynos4210State *s = exynos4_boards_init_common(kernel_filename,
|
||||
kernel_cmdline, initrd_filename, EXYNOS4_BOARD_SMDKC210);
|
||||
Exynos4210State *s = exynos4_boards_init_common(args,
|
||||
EXYNOS4_BOARD_SMDKC210);
|
||||
|
||||
lan9215_init(SMDK_LAN9118_BASE_ADDR,
|
||||
qemu_irq_invert(s->irq_table[exynos4210_get_irq(37, 1)]));
|
||||
|
|
|
@ -197,7 +197,8 @@ static void g364fb_draw_graphic8(G364State *s)
|
|||
reset_dirty(s, page_min, page_max);
|
||||
page_min = (ram_addr_t)-1;
|
||||
page_max = 0;
|
||||
dpy_update(s->ds, xmin, ymin, xmax - xmin + 1, ymax - ymin + 1);
|
||||
dpy_gfx_update(s->ds, xmin, ymin,
|
||||
xmax - xmin + 1, ymax - ymin + 1);
|
||||
xmin = s->width;
|
||||
xmax = 0;
|
||||
ymin = s->height;
|
||||
|
@ -216,7 +217,7 @@ static void g364fb_draw_graphic8(G364State *s)
|
|||
|
||||
done:
|
||||
if (page_min != (ram_addr_t)-1) {
|
||||
dpy_update(s->ds, xmin, ymin, xmax - xmin + 1, ymax - ymin + 1);
|
||||
dpy_gfx_update(s->ds, xmin, ymin, xmax - xmin + 1, ymax - ymin + 1);
|
||||
reset_dirty(s, page_min, page_max);
|
||||
}
|
||||
}
|
||||
|
@ -238,7 +239,7 @@ static void g364fb_draw_blank(G364State *s)
|
|||
d += ds_get_linesize(s->ds);
|
||||
}
|
||||
|
||||
dpy_update(s->ds, 0, 0, s->width, s->height);
|
||||
dpy_gfx_update(s->ds, 0, 0, s->width, s->height);
|
||||
s->blanked = 1;
|
||||
}
|
||||
|
||||
|
|
1
hw/hw.h
1
hw/hw.h
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "ioport.h"
|
||||
#include "irq.h"
|
||||
#include "qemu-aio.h"
|
||||
#include "qemu-file.h"
|
||||
#include "vmstate.h"
|
||||
#include "qemu-log.h"
|
||||
|
|
|
@ -196,7 +196,7 @@ static void jazz_led_update_display(void *opaque)
|
|||
}
|
||||
|
||||
s->state = REDRAW_NONE;
|
||||
dpy_update(ds, 0, 0, ds_get_width(ds), ds_get_height(ds));
|
||||
dpy_gfx_update(ds, 0, 0, ds_get_width(ds), ds_get_height(ds));
|
||||
}
|
||||
|
||||
static void jazz_led_invalidate_display(void *opaque)
|
||||
|
@ -210,7 +210,7 @@ static void jazz_led_text_update(void *opaque, console_ch_t *chardata)
|
|||
LedState *s = opaque;
|
||||
char buf[2];
|
||||
|
||||
dpy_cursor(s->ds, -1, -1);
|
||||
dpy_text_cursor(s->ds, -1, -1);
|
||||
qemu_console_resize(s->ds, 2, 1);
|
||||
|
||||
/* TODO: draw the segments */
|
||||
|
@ -218,7 +218,7 @@ static void jazz_led_text_update(void *opaque, console_ch_t *chardata)
|
|||
console_write_ch(chardata++, 0x00200100 | buf[0]);
|
||||
console_write_ch(chardata++, 0x00200100 | buf[1]);
|
||||
|
||||
dpy_update(s->ds, 0, 0, 2, 1);
|
||||
dpy_text_update(s->ds, 0, 0, 2, 1);
|
||||
}
|
||||
|
||||
static int jazz_led_post_load(void *opaque, int version_id)
|
||||
|
|
|
@ -104,7 +104,7 @@ static void kvm_apic_enable_tpr_reporting(APICCommonState *s, bool enable)
|
|||
.enabled = enable
|
||||
};
|
||||
|
||||
kvm_vcpu_ioctl(s->cpu_env, KVM_TPR_ACCESS_REPORTING, &ctl);
|
||||
kvm_vcpu_ioctl(&s->cpu->env, KVM_TPR_ACCESS_REPORTING, &ctl);
|
||||
}
|
||||
|
||||
static void kvm_apic_vapic_base_update(APICCommonState *s)
|
||||
|
@ -114,7 +114,7 @@ static void kvm_apic_vapic_base_update(APICCommonState *s)
|
|||
};
|
||||
int ret;
|
||||
|
||||
ret = kvm_vcpu_ioctl(s->cpu_env, KVM_SET_VAPIC_ADDR, &vapid_addr);
|
||||
ret = kvm_vcpu_ioctl(&s->cpu->env, KVM_SET_VAPIC_ADDR, &vapid_addr);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "KVM: setting VAPIC address failed (%s)\n",
|
||||
strerror(-ret));
|
||||
|
@ -125,7 +125,7 @@ static void kvm_apic_vapic_base_update(APICCommonState *s)
|
|||
static void do_inject_external_nmi(void *data)
|
||||
{
|
||||
APICCommonState *s = data;
|
||||
CPUX86State *env = s->cpu_env;
|
||||
CPUX86State *env = &s->cpu->env;
|
||||
uint32_t lvt;
|
||||
int ret;
|
||||
|
||||
|
@ -143,7 +143,7 @@ static void do_inject_external_nmi(void *data)
|
|||
|
||||
static void kvm_apic_external_nmi(APICCommonState *s)
|
||||
{
|
||||
run_on_cpu(s->cpu_env, do_inject_external_nmi, s);
|
||||
run_on_cpu(CPU(s->cpu), do_inject_external_nmi, s);
|
||||
}
|
||||
|
||||
static uint64_t kvm_apic_mem_read(void *opaque, hwaddr addr,
|
||||
|
|
|
@ -384,10 +384,13 @@ static void patch_call(VAPICROMState *s, CPUX86State *env, target_ulong ip,
|
|||
|
||||
static void patch_instruction(VAPICROMState *s, CPUX86State *env, target_ulong ip)
|
||||
{
|
||||
hwaddr paddr;
|
||||
VAPICHandlers *handlers;
|
||||
uint8_t opcode[2];
|
||||
uint32_t imm32;
|
||||
TranslationBlock *current_tb;
|
||||
target_ulong current_pc = 0;
|
||||
target_ulong current_cs_base = 0;
|
||||
int current_flags = 0;
|
||||
|
||||
if (smp_cpus == 1) {
|
||||
handlers = &s->rom_state.up;
|
||||
|
@ -395,6 +398,13 @@ static void patch_instruction(VAPICROMState *s, CPUX86State *env, target_ulong i
|
|||
handlers = &s->rom_state.mp;
|
||||
}
|
||||
|
||||
if (!kvm_enabled()) {
|
||||
current_tb = tb_find_pc(env->mem_io_pc);
|
||||
cpu_restore_state(current_tb, env, env->mem_io_pc);
|
||||
cpu_get_tb_cpu_state(env, ¤t_pc, ¤t_cs_base,
|
||||
¤t_flags);
|
||||
}
|
||||
|
||||
pause_all_vcpus();
|
||||
|
||||
cpu_memory_rw_debug(env, ip, opcode, sizeof(opcode), 0);
|
||||
|
@ -430,9 +440,11 @@ static void patch_instruction(VAPICROMState *s, CPUX86State *env, target_ulong i
|
|||
|
||||
resume_all_vcpus();
|
||||
|
||||
paddr = cpu_get_phys_page_debug(env, ip);
|
||||
paddr += ip & ~TARGET_PAGE_MASK;
|
||||
tb_invalidate_phys_page_range(paddr, paddr + 1, 1);
|
||||
if (!kvm_enabled()) {
|
||||
env->current_tb = NULL;
|
||||
tb_gen_code(env, current_pc, current_cs_base, current_flags, 1);
|
||||
cpu_resume_from_signal(env, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void vapic_report_tpr_access(DeviceState *dev, void *cpu, target_ulong ip,
|
||||
|
@ -475,11 +487,13 @@ static void vapic_enable_tpr_reporting(bool enable)
|
|||
VAPICEnableTPRReporting info = {
|
||||
.enable = enable,
|
||||
};
|
||||
X86CPU *cpu;
|
||||
CPUX86State *env;
|
||||
|
||||
for (env = first_cpu; env != NULL; env = env->next_cpu) {
|
||||
cpu = x86_env_get_cpu(env);
|
||||
info.apic = env->apic_state;
|
||||
run_on_cpu(env, vapic_do_enable_tpr_reporting, &info);
|
||||
run_on_cpu(CPU(cpu), vapic_do_enable_tpr_reporting, &info);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -717,7 +731,7 @@ static int vapic_post_load(void *opaque, int version_id)
|
|||
}
|
||||
if (s->state == VAPIC_ACTIVE) {
|
||||
if (smp_cpus == 1) {
|
||||
run_on_cpu(first_cpu, do_vapic_enable, s);
|
||||
run_on_cpu(ENV_GET_CPU(first_cpu), do_vapic_enable, s);
|
||||
} else {
|
||||
zero = g_malloc0(s->rom_state.vapic_size);
|
||||
cpu_physical_memory_rw(s->vapic_paddr, zero,
|
||||
|
|
|
@ -468,13 +468,6 @@ uint32_t m48t59_read (void *opaque, uint32_t addr)
|
|||
return retval;
|
||||
}
|
||||
|
||||
void m48t59_set_addr (void *opaque, uint32_t addr)
|
||||
{
|
||||
M48t59State *NVRAM = opaque;
|
||||
|
||||
NVRAM->addr = addr;
|
||||
}
|
||||
|
||||
void m48t59_toggle_lock (void *opaque, int lock)
|
||||
{
|
||||
M48t59State *NVRAM = opaque;
|
||||
|
|
|
@ -95,10 +95,8 @@ static struct arm_boot_info mainstone_binfo = {
|
|||
};
|
||||
|
||||
static void mainstone_common_init(MemoryRegion *address_space_mem,
|
||||
ram_addr_t ram_size,
|
||||
const char *kernel_filename,
|
||||
const char *kernel_cmdline, const char *initrd_filename,
|
||||
const char *cpu_model, enum mainstone_model_e model, int arm_id)
|
||||
QEMUMachineInitArgs *args,
|
||||
enum mainstone_model_e model, int arm_id)
|
||||
{
|
||||
uint32_t sector_len = 256 * 1024;
|
||||
hwaddr mainstone_flash_base[] = { MST_FLASH_0, MST_FLASH_1 };
|
||||
|
@ -108,6 +106,7 @@ static void mainstone_common_init(MemoryRegion *address_space_mem,
|
|||
int i;
|
||||
int be;
|
||||
MemoryRegion *rom = g_new(MemoryRegion, 1);
|
||||
const char *cpu_model = args->cpu_model;
|
||||
|
||||
if (!cpu_model)
|
||||
cpu_model = "pxa270-c5";
|
||||
|
@ -164,22 +163,16 @@ static void mainstone_common_init(MemoryRegion *address_space_mem,
|
|||
smc91c111_init(&nd_table[0], MST_ETH_PHYS,
|
||||
qdev_get_gpio_in(mst_irq, ETHERNET_IRQ));
|
||||
|
||||
mainstone_binfo.kernel_filename = kernel_filename;
|
||||
mainstone_binfo.kernel_cmdline = kernel_cmdline;
|
||||
mainstone_binfo.initrd_filename = initrd_filename;
|
||||
mainstone_binfo.kernel_filename = args->kernel_filename;
|
||||
mainstone_binfo.kernel_cmdline = args->kernel_cmdline;
|
||||
mainstone_binfo.initrd_filename = args->initrd_filename;
|
||||
mainstone_binfo.board_id = arm_id;
|
||||
arm_load_kernel(mpu->cpu, &mainstone_binfo);
|
||||
}
|
||||
|
||||
static void mainstone_init(QEMUMachineInitArgs *args)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
mainstone_common_init(get_system_memory(), ram_size, kernel_filename,
|
||||
kernel_cmdline, initrd_filename, cpu_model, mainstone, 0x196);
|
||||
mainstone_common_init(get_system_memory(), args, mainstone, 0x196);
|
||||
}
|
||||
|
||||
static QEMUMachine mainstone2_machine = {
|
||||
|
|
|
@ -134,7 +134,7 @@ static void vgafb_update_display(void *opaque)
|
|||
&first, &last);
|
||||
|
||||
if (first >= 0) {
|
||||
dpy_update(s->ds, 0, first, s->regs[R_HRES], last - first + 1);
|
||||
dpy_gfx_update(s->ds, 0, first, s->regs[R_HRES], last - first + 1);
|
||||
}
|
||||
s->invalidate = 0;
|
||||
}
|
||||
|
|
|
@ -526,7 +526,7 @@ static void lcd_refresh(void *opaque)
|
|||
ds_get_bits_per_pixel(s->ds));
|
||||
}
|
||||
|
||||
dpy_update(s->ds, 0, 0, 128*3, 64*3);
|
||||
dpy_gfx_update(s->ds, 0, 0, 128*3, 64*3);
|
||||
}
|
||||
|
||||
static void lcd_invalidate(void *opaque)
|
||||
|
|
41
hw/nseries.c
41
hw/nseries.c
|
@ -1284,17 +1284,15 @@ static int n810_atag_setup(const struct arm_boot_info *info, void *p)
|
|||
return n8x0_atag_setup(p, 810);
|
||||
}
|
||||
|
||||
static void n8x0_init(ram_addr_t ram_size, const char *boot_device,
|
||||
const char *kernel_filename,
|
||||
const char *kernel_cmdline, const char *initrd_filename,
|
||||
const char *cpu_model, struct arm_boot_info *binfo, int model)
|
||||
static void n8x0_init(QEMUMachineInitArgs *args,
|
||||
struct arm_boot_info *binfo, int model)
|
||||
{
|
||||
MemoryRegion *sysmem = get_system_memory();
|
||||
struct n800_s *s = (struct n800_s *) g_malloc0(sizeof(*s));
|
||||
int sdram_size = binfo->ram_size;
|
||||
DisplayState *ds;
|
||||
|
||||
s->mpu = omap2420_mpu_init(sysmem, sdram_size, cpu_model);
|
||||
s->mpu = omap2420_mpu_init(sysmem, sdram_size, args->cpu_model);
|
||||
|
||||
/* Setup peripherals
|
||||
*
|
||||
|
@ -1338,17 +1336,18 @@ static void n8x0_init(ram_addr_t ram_size, const char *boot_device,
|
|||
n8x0_usb_setup(s);
|
||||
}
|
||||
|
||||
if (kernel_filename) {
|
||||
if (args->kernel_filename) {
|
||||
/* Or at the linux loader. */
|
||||
binfo->kernel_filename = kernel_filename;
|
||||
binfo->kernel_cmdline = kernel_cmdline;
|
||||
binfo->initrd_filename = initrd_filename;
|
||||
binfo->kernel_filename = args->kernel_filename;
|
||||
binfo->kernel_cmdline = args->kernel_cmdline;
|
||||
binfo->initrd_filename = args->initrd_filename;
|
||||
arm_load_kernel(s->mpu->cpu, binfo);
|
||||
|
||||
qemu_register_reset(n8x0_boot_init, s);
|
||||
}
|
||||
|
||||
if (option_rom[0].name && (boot_device[0] == 'n' || !kernel_filename)) {
|
||||
if (option_rom[0].name &&
|
||||
(args->boot_device[0] == 'n' || !args->kernel_filename)) {
|
||||
int rom_size;
|
||||
uint8_t nolo_tags[0x10000];
|
||||
/* No, wait, better start at the ROM. */
|
||||
|
@ -1376,7 +1375,7 @@ static void n8x0_init(ram_addr_t ram_size, const char *boot_device,
|
|||
size until the guest activates the display. */
|
||||
ds = get_displaystate();
|
||||
ds->surface = qemu_resize_displaysurface(ds, 800, 480);
|
||||
dpy_resize(ds);
|
||||
dpy_gfx_resize(ds);
|
||||
}
|
||||
|
||||
static struct arm_boot_info n800_binfo = {
|
||||
|
@ -1400,28 +1399,12 @@ static struct arm_boot_info n810_binfo = {
|
|||
|
||||
static void n800_init(QEMUMachineInitArgs *args)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
const char *boot_device = args->boot_device;
|
||||
return n8x0_init(ram_size, boot_device,
|
||||
kernel_filename, kernel_cmdline, initrd_filename,
|
||||
cpu_model, &n800_binfo, 800);
|
||||
return n8x0_init(args, &n800_binfo, 800);
|
||||
}
|
||||
|
||||
static void n810_init(QEMUMachineInitArgs *args)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
const char *boot_device = args->boot_device;
|
||||
return n8x0_init(ram_size, boot_device,
|
||||
kernel_filename, kernel_cmdline, initrd_filename,
|
||||
cpu_model, &n810_binfo, 810);
|
||||
return n8x0_init(args, &n810_binfo, 810);
|
||||
}
|
||||
|
||||
static QEMUMachine n800_machine = {
|
||||
|
|
11
hw/nvram.h
11
hw/nvram.h
|
@ -10,17 +10,9 @@ typedef struct nvram_t {
|
|||
nvram_write_t write_fn;
|
||||
} nvram_t;
|
||||
|
||||
void NVRAM_set_byte (nvram_t *nvram, uint32_t addr, uint8_t value);
|
||||
uint8_t NVRAM_get_byte (nvram_t *nvram, uint32_t addr);
|
||||
void NVRAM_set_word (nvram_t *nvram, uint32_t addr, uint16_t value);
|
||||
uint16_t NVRAM_get_word (nvram_t *nvram, uint32_t addr);
|
||||
void NVRAM_set_lword (nvram_t *nvram, uint32_t addr, uint32_t value);
|
||||
uint32_t NVRAM_get_lword (nvram_t *nvram, uint32_t addr);
|
||||
void NVRAM_set_string (nvram_t *nvram, uint32_t addr,
|
||||
const char *str, uint32_t max);
|
||||
int NVRAM_get_string (nvram_t *nvram, uint8_t *dst, uint16_t addr, int max);
|
||||
void NVRAM_set_crc (nvram_t *nvram, uint32_t addr,
|
||||
uint32_t start, uint32_t count);
|
||||
|
||||
int PPC_NVRAM_set_params (nvram_t *nvram, uint16_t NVRAM_size,
|
||||
const char *arch,
|
||||
uint32_t RAM_size, int boot_device,
|
||||
|
@ -38,6 +30,5 @@ M48t59State *m48t59_init_isa(ISABus *bus, uint32_t io_base, uint16_t size,
|
|||
int type);
|
||||
M48t59State *m48t59_init(qemu_irq IRQ, hwaddr mem_base,
|
||||
uint32_t io_base, uint16_t size, int type);
|
||||
void m48t59_set_addr (void *opaque, uint32_t addr);
|
||||
|
||||
#endif /* !NVRAM_H */
|
||||
|
|
|
@ -219,7 +219,7 @@ static void omap_update_display(void *opaque)
|
|||
draw_line, omap_lcd->palette,
|
||||
&first, &last);
|
||||
if (first >= 0) {
|
||||
dpy_update(omap_lcd->state, 0, first, width, last - first + 1);
|
||||
dpy_gfx_update(omap_lcd->state, 0, first, width, last - first + 1);
|
||||
}
|
||||
omap_lcd->invalidate = 0;
|
||||
}
|
||||
|
|
|
@ -97,11 +97,7 @@ static struct arm_boot_info sx1_binfo = {
|
|||
.board_id = 0x265,
|
||||
};
|
||||
|
||||
static void sx1_init(ram_addr_t ram_size,
|
||||
const char *boot_device,
|
||||
const char *kernel_filename, const char *kernel_cmdline,
|
||||
const char *initrd_filename, const char *cpu_model,
|
||||
const int version)
|
||||
static void sx1_init(QEMUMachineInitArgs *args, const int version)
|
||||
{
|
||||
struct omap_mpu_state_s *mpu;
|
||||
MemoryRegion *address_space = get_system_memory();
|
||||
|
@ -121,7 +117,7 @@ static void sx1_init(ram_addr_t ram_size,
|
|||
flash_size = flash2_size;
|
||||
}
|
||||
|
||||
mpu = omap310_mpu_init(address_space, sx1_binfo.ram_size, cpu_model);
|
||||
mpu = omap310_mpu_init(address_space, sx1_binfo.ram_size, args->cpu_model);
|
||||
|
||||
/* External Flash (EMIFS) */
|
||||
memory_region_init_ram(flash, "omap_sx1.flash0-0", flash_size);
|
||||
|
@ -192,16 +188,16 @@ static void sx1_init(ram_addr_t ram_size,
|
|||
OMAP_CS1_BASE, &cs[1]);
|
||||
}
|
||||
|
||||
if (!kernel_filename && !fl_idx) {
|
||||
if (!args->kernel_filename && !fl_idx) {
|
||||
fprintf(stderr, "Kernel or Flash image must be specified\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Load the kernel. */
|
||||
if (kernel_filename) {
|
||||
sx1_binfo.kernel_filename = kernel_filename;
|
||||
sx1_binfo.kernel_cmdline = kernel_cmdline;
|
||||
sx1_binfo.initrd_filename = initrd_filename;
|
||||
if (args->kernel_filename) {
|
||||
sx1_binfo.kernel_filename = args->kernel_filename;
|
||||
sx1_binfo.kernel_cmdline = args->kernel_cmdline;
|
||||
sx1_binfo.initrd_filename = args->initrd_filename;
|
||||
arm_load_kernel(mpu->cpu, &sx1_binfo);
|
||||
}
|
||||
|
||||
|
@ -211,26 +207,12 @@ static void sx1_init(ram_addr_t ram_size,
|
|||
|
||||
static void sx1_init_v1(QEMUMachineInitArgs *args)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
const char *boot_device = args->boot_device;
|
||||
sx1_init(ram_size, boot_device, kernel_filename,
|
||||
kernel_cmdline, initrd_filename, cpu_model, 1);
|
||||
sx1_init(args, 1);
|
||||
}
|
||||
|
||||
static void sx1_init_v2(QEMUMachineInitArgs *args)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
const char *boot_device = args->boot_device;
|
||||
sx1_init(ram_size, boot_device, kernel_filename,
|
||||
kernel_cmdline, initrd_filename, cpu_model, 2);
|
||||
sx1_init(args, 2);
|
||||
}
|
||||
|
||||
static QEMUMachine sx1_machine_v2 = {
|
||||
|
|
|
@ -273,7 +273,7 @@ static void palmte_init(QEMUMachineInitArgs *args)
|
|||
will set the size once configured, so this just sets an initial
|
||||
size until the guest activates the display. */
|
||||
ds->surface = qemu_resize_displaysurface(ds, 320, 320);
|
||||
dpy_resize(ds);
|
||||
dpy_gfx_resize(ds);
|
||||
}
|
||||
|
||||
static QEMUMachine palmte_machine = {
|
||||
|
|
56
hw/pc.c
56
hw/pc.c
|
@ -71,8 +71,6 @@
|
|||
#define FW_CFG_E820_TABLE (FW_CFG_ARCH_LOCAL + 3)
|
||||
#define FW_CFG_HPET (FW_CFG_ARCH_LOCAL + 4)
|
||||
|
||||
#define MSI_ADDR_BASE 0xfee00000
|
||||
|
||||
#define E820_NR_ENTRIES 16
|
||||
|
||||
struct e820_entry {
|
||||
|
@ -849,35 +847,6 @@ DeviceState *cpu_get_current_apic(void)
|
|||
}
|
||||
}
|
||||
|
||||
static DeviceState *apic_init(void *env, uint8_t apic_id)
|
||||
{
|
||||
DeviceState *dev;
|
||||
static int apic_mapped;
|
||||
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
dev = qdev_create(NULL, "kvm-apic");
|
||||
} else if (xen_enabled()) {
|
||||
dev = qdev_create(NULL, "xen-apic");
|
||||
} else {
|
||||
dev = qdev_create(NULL, "apic");
|
||||
}
|
||||
|
||||
qdev_prop_set_uint8(dev, "id", apic_id);
|
||||
qdev_prop_set_ptr(dev, "cpu_env", env);
|
||||
qdev_init_nofail(dev);
|
||||
|
||||
/* XXX: mapping more APICs at the same memory location */
|
||||
if (apic_mapped == 0) {
|
||||
/* NOTE: the APIC is directly connected to the CPU - it is not
|
||||
on the global memory bus. */
|
||||
/* XXX: what if the base changes? */
|
||||
sysbus_mmio_map(sysbus_from_qdev(dev), 0, MSI_ADDR_BASE);
|
||||
apic_mapped = 1;
|
||||
}
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
void pc_acpi_smi_interrupt(void *opaque, int irq, int level)
|
||||
{
|
||||
CPUX86State *s = opaque;
|
||||
|
@ -887,24 +856,6 @@ void pc_acpi_smi_interrupt(void *opaque, int irq, int level)
|
|||
}
|
||||
}
|
||||
|
||||
static X86CPU *pc_new_cpu(const char *cpu_model)
|
||||
{
|
||||
X86CPU *cpu;
|
||||
CPUX86State *env;
|
||||
|
||||
cpu = cpu_x86_init(cpu_model);
|
||||
if (cpu == NULL) {
|
||||
fprintf(stderr, "Unable to find x86 CPU definition\n");
|
||||
exit(1);
|
||||
}
|
||||
env = &cpu->env;
|
||||
if ((env->cpuid_features & CPUID_APIC) || smp_cpus > 1) {
|
||||
env->apic_state = apic_init(env, env->cpuid_apic_id);
|
||||
}
|
||||
cpu_reset(CPU(cpu));
|
||||
return cpu;
|
||||
}
|
||||
|
||||
void pc_cpus_init(const char *cpu_model)
|
||||
{
|
||||
int i;
|
||||
|
@ -918,8 +869,11 @@ void pc_cpus_init(const char *cpu_model)
|
|||
#endif
|
||||
}
|
||||
|
||||
for(i = 0; i < smp_cpus; i++) {
|
||||
pc_new_cpu(cpu_model);
|
||||
for (i = 0; i < smp_cpus; i++) {
|
||||
if (!cpu_x86_init(cpu_model)) {
|
||||
fprintf(stderr, "Unable to find x86 CPU definition\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -178,7 +178,7 @@ static void pc_init1(MemoryRegion *system_memory,
|
|||
fw_cfg = pc_memory_init(system_memory,
|
||||
kernel_filename, kernel_cmdline, initrd_filename,
|
||||
below_4g_mem_size, above_4g_mem_size,
|
||||
pci_enabled ? rom_memory : system_memory, &ram_memory);
|
||||
rom_memory, &ram_memory);
|
||||
}
|
||||
|
||||
gsi_state = g_malloc0(sizeof(*gsi_state));
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "qemu-timer.h"
|
||||
#include "exec-memory.h"
|
||||
#include "host-utils.h"
|
||||
#include "sysbus.h"
|
||||
|
||||
#define PFLASH_BUG(fmt, ...) \
|
||||
do { \
|
||||
|
@ -60,23 +61,28 @@ do { \
|
|||
#endif
|
||||
|
||||
struct pflash_t {
|
||||
SysBusDevice busdev;
|
||||
BlockDriverState *bs;
|
||||
hwaddr base;
|
||||
hwaddr sector_len;
|
||||
hwaddr total_len;
|
||||
int width;
|
||||
uint32_t nb_blocs;
|
||||
uint64_t sector_len;
|
||||
uint8_t width;
|
||||
uint8_t be;
|
||||
int wcycle; /* if 0, the flash is read normally */
|
||||
int bypass;
|
||||
int ro;
|
||||
uint8_t cmd;
|
||||
uint8_t status;
|
||||
uint16_t ident[4];
|
||||
uint16_t ident0;
|
||||
uint16_t ident1;
|
||||
uint16_t ident2;
|
||||
uint16_t ident3;
|
||||
uint8_t cfi_len;
|
||||
uint8_t cfi_table[0x52];
|
||||
hwaddr counter;
|
||||
unsigned int writeblock_size;
|
||||
QEMUTimer *timer;
|
||||
MemoryRegion mem;
|
||||
char *name;
|
||||
void *storage;
|
||||
};
|
||||
|
||||
|
@ -168,15 +174,16 @@ static uint32_t pflash_read (pflash_t *pfl, hwaddr offset,
|
|||
case 0x90:
|
||||
switch (boff) {
|
||||
case 0:
|
||||
ret = pfl->ident[0] << 8 | pfl->ident[1];
|
||||
ret = pfl->ident0 << 8 | pfl->ident1;
|
||||
DPRINTF("%s: Manufacturer Code %04x\n", __func__, ret);
|
||||
break;
|
||||
case 1:
|
||||
ret = pfl->ident[2] << 8 | pfl->ident[3];
|
||||
ret = pfl->ident2 << 8 | pfl->ident3;
|
||||
DPRINTF("%s: Device ID Code %04x\n", __func__, ret);
|
||||
break;
|
||||
default:
|
||||
DPRINTF("%s: Read Device Information boff=%x\n", __func__, boff);
|
||||
DPRINTF("%s: Read Device Information boff=%x\n", __func__,
|
||||
(unsigned)boff);
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
@ -279,9 +286,8 @@ static void pflash_write(pflash_t *pfl, hwaddr offset,
|
|||
p = pfl->storage;
|
||||
offset &= ~(pfl->sector_len - 1);
|
||||
|
||||
DPRINTF("%s: block erase at " TARGET_FMT_plx " bytes "
|
||||
TARGET_FMT_plx "\n",
|
||||
__func__, offset, pfl->sector_len);
|
||||
DPRINTF("%s: block erase at " TARGET_FMT_plx " bytes %x\n",
|
||||
__func__, offset, (unsigned)pfl->sector_len);
|
||||
|
||||
if (!pfl->ro) {
|
||||
memset(p + offset, 0xff, pfl->sector_len);
|
||||
|
@ -543,19 +549,13 @@ static const MemoryRegionOps pflash_cfi01_ops_le = {
|
|||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
pflash_t *pflash_cfi01_register(hwaddr base,
|
||||
DeviceState *qdev, const char *name,
|
||||
hwaddr size,
|
||||
BlockDriverState *bs, uint32_t sector_len,
|
||||
int nb_blocs, int width,
|
||||
uint16_t id0, uint16_t id1,
|
||||
uint16_t id2, uint16_t id3, int be)
|
||||
static int pflash_cfi01_init(SysBusDevice *dev)
|
||||
{
|
||||
pflash_t *pfl;
|
||||
hwaddr total_len;
|
||||
pflash_t *pfl = FROM_SYSBUS(typeof(*pfl), dev);
|
||||
uint64_t total_len;
|
||||
int ret;
|
||||
|
||||
total_len = sector_len * nb_blocs;
|
||||
total_len = pfl->sector_len * pfl->nb_blocs;
|
||||
|
||||
/* XXX: to be fixed */
|
||||
#if 0
|
||||
|
@ -564,27 +564,22 @@ pflash_t *pflash_cfi01_register(hwaddr base,
|
|||
return NULL;
|
||||
#endif
|
||||
|
||||
pfl = g_malloc0(sizeof(pflash_t));
|
||||
|
||||
memory_region_init_rom_device(
|
||||
&pfl->mem, be ? &pflash_cfi01_ops_be : &pflash_cfi01_ops_le, pfl,
|
||||
name, size);
|
||||
vmstate_register_ram(&pfl->mem, qdev);
|
||||
&pfl->mem, pfl->be ? &pflash_cfi01_ops_be : &pflash_cfi01_ops_le, pfl,
|
||||
pfl->name, total_len);
|
||||
vmstate_register_ram(&pfl->mem, DEVICE(pfl));
|
||||
pfl->storage = memory_region_get_ram_ptr(&pfl->mem);
|
||||
memory_region_add_subregion(get_system_memory(), base, &pfl->mem);
|
||||
sysbus_init_mmio(dev, &pfl->mem);
|
||||
|
||||
pfl->bs = bs;
|
||||
if (pfl->bs) {
|
||||
/* read the initial flash content */
|
||||
ret = bdrv_read(pfl->bs, 0, pfl->storage, total_len >> 9);
|
||||
|
||||
if (ret < 0) {
|
||||
memory_region_del_subregion(get_system_memory(), &pfl->mem);
|
||||
vmstate_unregister_ram(&pfl->mem, qdev);
|
||||
vmstate_unregister_ram(&pfl->mem, DEVICE(pfl));
|
||||
memory_region_destroy(&pfl->mem);
|
||||
g_free(pfl);
|
||||
return NULL;
|
||||
return 1;
|
||||
}
|
||||
bdrv_attach_dev_nofail(pfl->bs, pfl);
|
||||
}
|
||||
|
||||
if (pfl->bs) {
|
||||
|
@ -594,17 +589,9 @@ pflash_t *pflash_cfi01_register(hwaddr base,
|
|||
}
|
||||
|
||||
pfl->timer = qemu_new_timer_ns(vm_clock, pflash_timer, pfl);
|
||||
pfl->base = base;
|
||||
pfl->sector_len = sector_len;
|
||||
pfl->total_len = total_len;
|
||||
pfl->width = width;
|
||||
pfl->wcycle = 0;
|
||||
pfl->cmd = 0;
|
||||
pfl->status = 0;
|
||||
pfl->ident[0] = id0;
|
||||
pfl->ident[1] = id1;
|
||||
pfl->ident[2] = id2;
|
||||
pfl->ident[3] = id3;
|
||||
/* Hardcoded CFI table */
|
||||
pfl->cfi_len = 0x52;
|
||||
/* Standard "QRY" string */
|
||||
|
@ -653,7 +640,7 @@ pflash_t *pflash_cfi01_register(hwaddr base,
|
|||
pfl->cfi_table[0x28] = 0x02;
|
||||
pfl->cfi_table[0x29] = 0x00;
|
||||
/* Max number of bytes in multi-bytes write */
|
||||
if (width == 1) {
|
||||
if (pfl->width == 1) {
|
||||
pfl->cfi_table[0x2A] = 0x08;
|
||||
} else {
|
||||
pfl->cfi_table[0x2A] = 0x0B;
|
||||
|
@ -664,10 +651,10 @@ pflash_t *pflash_cfi01_register(hwaddr base,
|
|||
/* Number of erase block regions (uniform) */
|
||||
pfl->cfi_table[0x2C] = 0x01;
|
||||
/* Erase block region 1 */
|
||||
pfl->cfi_table[0x2D] = nb_blocs - 1;
|
||||
pfl->cfi_table[0x2E] = (nb_blocs - 1) >> 8;
|
||||
pfl->cfi_table[0x2F] = sector_len >> 8;
|
||||
pfl->cfi_table[0x30] = sector_len >> 16;
|
||||
pfl->cfi_table[0x2D] = pfl->nb_blocs - 1;
|
||||
pfl->cfi_table[0x2E] = (pfl->nb_blocs - 1) >> 8;
|
||||
pfl->cfi_table[0x2F] = pfl->sector_len >> 8;
|
||||
pfl->cfi_table[0x30] = pfl->sector_len >> 16;
|
||||
|
||||
/* Extended */
|
||||
pfl->cfi_table[0x31] = 'P';
|
||||
|
@ -689,6 +676,75 @@ pflash_t *pflash_cfi01_register(hwaddr base,
|
|||
|
||||
pfl->cfi_table[0x3f] = 0x01; /* Number of protection fields */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Property pflash_cfi01_properties[] = {
|
||||
DEFINE_PROP_DRIVE("drive", struct pflash_t, bs),
|
||||
DEFINE_PROP_UINT32("num-blocks", struct pflash_t, nb_blocs, 0),
|
||||
DEFINE_PROP_UINT64("sector-length", struct pflash_t, sector_len, 0),
|
||||
DEFINE_PROP_UINT8("width", struct pflash_t, width, 0),
|
||||
DEFINE_PROP_UINT8("big-endian", struct pflash_t, be, 0),
|
||||
DEFINE_PROP_UINT16("id0", struct pflash_t, ident0, 0),
|
||||
DEFINE_PROP_UINT16("id1", struct pflash_t, ident1, 0),
|
||||
DEFINE_PROP_UINT16("id2", struct pflash_t, ident2, 0),
|
||||
DEFINE_PROP_UINT16("id3", struct pflash_t, ident3, 0),
|
||||
DEFINE_PROP_STRING("name", struct pflash_t, name),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void pflash_cfi01_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = pflash_cfi01_init;
|
||||
dc->props = pflash_cfi01_properties;
|
||||
}
|
||||
|
||||
|
||||
static const TypeInfo pflash_cfi01_info = {
|
||||
.name = "cfi.pflash01",
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(struct pflash_t),
|
||||
.class_init = pflash_cfi01_class_init,
|
||||
};
|
||||
|
||||
static void pflash_cfi01_register_types(void)
|
||||
{
|
||||
type_register_static(&pflash_cfi01_info);
|
||||
}
|
||||
|
||||
type_init(pflash_cfi01_register_types)
|
||||
|
||||
pflash_t *pflash_cfi01_register(hwaddr base,
|
||||
DeviceState *qdev, const char *name,
|
||||
hwaddr size,
|
||||
BlockDriverState *bs,
|
||||
uint32_t sector_len, int nb_blocs, int width,
|
||||
uint16_t id0, uint16_t id1,
|
||||
uint16_t id2, uint16_t id3, int be)
|
||||
{
|
||||
DeviceState *dev = qdev_create(NULL, "cfi.pflash01");
|
||||
SysBusDevice *busdev = sysbus_from_qdev(dev);
|
||||
pflash_t *pfl = (pflash_t *)object_dynamic_cast(OBJECT(dev),
|
||||
"cfi.pflash01");
|
||||
|
||||
if (bs && qdev_prop_set_drive(dev, "drive", bs)) {
|
||||
abort();
|
||||
}
|
||||
qdev_prop_set_uint32(dev, "num-blocks", nb_blocs);
|
||||
qdev_prop_set_uint64(dev, "sector-length", sector_len);
|
||||
qdev_prop_set_uint8(dev, "width", width);
|
||||
qdev_prop_set_uint8(dev, "big-endian", !!be);
|
||||
qdev_prop_set_uint16(dev, "id0", id0);
|
||||
qdev_prop_set_uint16(dev, "id1", id1);
|
||||
qdev_prop_set_uint16(dev, "id2", id2);
|
||||
qdev_prop_set_uint16(dev, "id3", id3);
|
||||
qdev_prop_set_string(dev, "name", name);
|
||||
qdev_init_nofail(dev);
|
||||
|
||||
sysbus_mmio_map(busdev, 0, base);
|
||||
return pfl;
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "block.h"
|
||||
#include "exec-memory.h"
|
||||
#include "host-utils.h"
|
||||
#include "sysbus.h"
|
||||
|
||||
//#define PFLASH_DEBUG
|
||||
#ifdef PFLASH_DEBUG
|
||||
|
@ -55,19 +56,26 @@ do { \
|
|||
#define PFLASH_LAZY_ROMD_THRESHOLD 42
|
||||
|
||||
struct pflash_t {
|
||||
SysBusDevice busdev;
|
||||
BlockDriverState *bs;
|
||||
hwaddr base;
|
||||
uint32_t sector_len;
|
||||
uint32_t nb_blocs;
|
||||
uint32_t chip_len;
|
||||
int mappings;
|
||||
int width;
|
||||
uint8_t mappings;
|
||||
uint8_t width;
|
||||
uint8_t be;
|
||||
int wcycle; /* if 0, the flash is read normally */
|
||||
int bypass;
|
||||
int ro;
|
||||
uint8_t cmd;
|
||||
uint8_t status;
|
||||
uint16_t ident[4];
|
||||
uint16_t unlock_addr[2];
|
||||
/* FIXME: implement array device properties */
|
||||
uint16_t ident0;
|
||||
uint16_t ident1;
|
||||
uint16_t ident2;
|
||||
uint16_t ident3;
|
||||
uint16_t unlock_addr0;
|
||||
uint16_t unlock_addr1;
|
||||
uint8_t cfi_len;
|
||||
uint8_t cfi_table[0x52];
|
||||
QEMUTimer *timer;
|
||||
|
@ -80,6 +88,7 @@ struct pflash_t {
|
|||
MemoryRegion orig_mem;
|
||||
int rom_mode;
|
||||
int read_counter; /* used for lazy switch-back to rom mode */
|
||||
char *name;
|
||||
void *storage;
|
||||
};
|
||||
|
||||
|
@ -190,16 +199,17 @@ static uint32_t pflash_read (pflash_t *pfl, hwaddr offset,
|
|||
switch (boff) {
|
||||
case 0x00:
|
||||
case 0x01:
|
||||
ret = pfl->ident[boff & 0x01];
|
||||
ret = boff & 0x01 ? pfl->ident1 : pfl->ident0;
|
||||
break;
|
||||
case 0x02:
|
||||
ret = 0x00; /* Pretend all sectors are unprotected */
|
||||
break;
|
||||
case 0x0E:
|
||||
case 0x0F:
|
||||
if (pfl->ident[2 + (boff & 0x01)] == (uint8_t)-1)
|
||||
ret = boff & 0x01 ? pfl->ident3 : pfl->ident2;
|
||||
if (ret == (uint8_t)-1) {
|
||||
goto flash_read;
|
||||
ret = pfl->ident[2 + (boff & 0x01)];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto flash_read;
|
||||
|
@ -283,9 +293,9 @@ static void pflash_write (pflash_t *pfl, hwaddr offset,
|
|||
pfl->cmd = 0x98;
|
||||
return;
|
||||
}
|
||||
if (boff != pfl->unlock_addr[0] || cmd != 0xAA) {
|
||||
if (boff != pfl->unlock_addr0 || cmd != 0xAA) {
|
||||
DPRINTF("%s: unlock0 failed " TARGET_FMT_plx " %02x %04x\n",
|
||||
__func__, boff, cmd, pfl->unlock_addr[0]);
|
||||
__func__, boff, cmd, pfl->unlock_addr0);
|
||||
goto reset_flash;
|
||||
}
|
||||
DPRINTF("%s: unlock sequence started\n", __func__);
|
||||
|
@ -293,7 +303,7 @@ static void pflash_write (pflash_t *pfl, hwaddr offset,
|
|||
case 1:
|
||||
/* We started an unlock sequence */
|
||||
check_unlock1:
|
||||
if (boff != pfl->unlock_addr[1] || cmd != 0x55) {
|
||||
if (boff != pfl->unlock_addr1 || cmd != 0x55) {
|
||||
DPRINTF("%s: unlock1 failed " TARGET_FMT_plx " %02x\n", __func__,
|
||||
boff, cmd);
|
||||
goto reset_flash;
|
||||
|
@ -302,7 +312,7 @@ static void pflash_write (pflash_t *pfl, hwaddr offset,
|
|||
break;
|
||||
case 2:
|
||||
/* We finished an unlock sequence */
|
||||
if (!pfl->bypass && boff != pfl->unlock_addr[0]) {
|
||||
if (!pfl->bypass && boff != pfl->unlock_addr0) {
|
||||
DPRINTF("%s: command failed " TARGET_FMT_plx " %02x\n", __func__,
|
||||
boff, cmd);
|
||||
goto reset_flash;
|
||||
|
@ -400,7 +410,7 @@ static void pflash_write (pflash_t *pfl, hwaddr offset,
|
|||
case 5:
|
||||
switch (cmd) {
|
||||
case 0x10:
|
||||
if (boff != pfl->unlock_addr[0]) {
|
||||
if (boff != pfl->unlock_addr0) {
|
||||
DPRINTF("%s: chip erase: invalid address " TARGET_FMT_plx "\n",
|
||||
__func__, offset);
|
||||
goto reset_flash;
|
||||
|
@ -575,50 +585,38 @@ static const MemoryRegionOps pflash_cfi02_ops_le = {
|
|||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
pflash_t *pflash_cfi02_register(hwaddr base,
|
||||
DeviceState *qdev, const char *name,
|
||||
hwaddr size,
|
||||
BlockDriverState *bs, uint32_t sector_len,
|
||||
int nb_blocs, int nb_mappings, int width,
|
||||
uint16_t id0, uint16_t id1,
|
||||
uint16_t id2, uint16_t id3,
|
||||
uint16_t unlock_addr0, uint16_t unlock_addr1,
|
||||
int be)
|
||||
static int pflash_cfi02_init(SysBusDevice *dev)
|
||||
{
|
||||
pflash_t *pfl;
|
||||
int32_t chip_len;
|
||||
pflash_t *pfl = FROM_SYSBUS(typeof(*pfl), dev);
|
||||
uint32_t chip_len;
|
||||
int ret;
|
||||
|
||||
chip_len = sector_len * nb_blocs;
|
||||
chip_len = pfl->sector_len * pfl->nb_blocs;
|
||||
/* XXX: to be fixed */
|
||||
#if 0
|
||||
if (total_len != (8 * 1024 * 1024) && total_len != (16 * 1024 * 1024) &&
|
||||
total_len != (32 * 1024 * 1024) && total_len != (64 * 1024 * 1024))
|
||||
return NULL;
|
||||
#endif
|
||||
pfl = g_malloc0(sizeof(pflash_t));
|
||||
memory_region_init_rom_device(
|
||||
&pfl->orig_mem, be ? &pflash_cfi02_ops_be : &pflash_cfi02_ops_le, pfl,
|
||||
name, size);
|
||||
vmstate_register_ram(&pfl->orig_mem, qdev);
|
||||
|
||||
memory_region_init_rom_device(&pfl->orig_mem, pfl->be ?
|
||||
&pflash_cfi02_ops_be : &pflash_cfi02_ops_le,
|
||||
pfl, pfl->name, chip_len);
|
||||
vmstate_register_ram(&pfl->orig_mem, DEVICE(pfl));
|
||||
pfl->storage = memory_region_get_ram_ptr(&pfl->orig_mem);
|
||||
pfl->base = base;
|
||||
pfl->chip_len = chip_len;
|
||||
pfl->mappings = nb_mappings;
|
||||
pfl->bs = bs;
|
||||
if (pfl->bs) {
|
||||
/* read the initial flash content */
|
||||
ret = bdrv_read(pfl->bs, 0, pfl->storage, chip_len >> 9);
|
||||
if (ret < 0) {
|
||||
g_free(pfl);
|
||||
return NULL;
|
||||
return 1;
|
||||
}
|
||||
bdrv_attach_dev_nofail(pfl->bs, pfl);
|
||||
}
|
||||
|
||||
pflash_setup_mappings(pfl);
|
||||
pfl->rom_mode = 1;
|
||||
memory_region_add_subregion(get_system_memory(), pfl->base, &pfl->mem);
|
||||
sysbus_init_mmio(dev, &pfl->mem);
|
||||
|
||||
if (pfl->bs) {
|
||||
pfl->ro = bdrv_is_read_only(pfl->bs);
|
||||
|
@ -627,17 +625,9 @@ pflash_t *pflash_cfi02_register(hwaddr base,
|
|||
}
|
||||
|
||||
pfl->timer = qemu_new_timer_ns(vm_clock, pflash_timer, pfl);
|
||||
pfl->sector_len = sector_len;
|
||||
pfl->width = width;
|
||||
pfl->wcycle = 0;
|
||||
pfl->cmd = 0;
|
||||
pfl->status = 0;
|
||||
pfl->ident[0] = id0;
|
||||
pfl->ident[1] = id1;
|
||||
pfl->ident[2] = id2;
|
||||
pfl->ident[3] = id3;
|
||||
pfl->unlock_addr[0] = unlock_addr0;
|
||||
pfl->unlock_addr[1] = unlock_addr1;
|
||||
/* Hardcoded CFI table (mostly from SG29 Spansion flash) */
|
||||
pfl->cfi_len = 0x52;
|
||||
/* Standard "QRY" string */
|
||||
|
@ -693,10 +683,10 @@ pflash_t *pflash_cfi02_register(hwaddr base,
|
|||
/* Number of erase block regions (uniform) */
|
||||
pfl->cfi_table[0x2C] = 0x01;
|
||||
/* Erase block region 1 */
|
||||
pfl->cfi_table[0x2D] = nb_blocs - 1;
|
||||
pfl->cfi_table[0x2E] = (nb_blocs - 1) >> 8;
|
||||
pfl->cfi_table[0x2F] = sector_len >> 8;
|
||||
pfl->cfi_table[0x30] = sector_len >> 16;
|
||||
pfl->cfi_table[0x2D] = pfl->nb_blocs - 1;
|
||||
pfl->cfi_table[0x2E] = (pfl->nb_blocs - 1) >> 8;
|
||||
pfl->cfi_table[0x2F] = pfl->sector_len >> 8;
|
||||
pfl->cfi_table[0x30] = pfl->sector_len >> 16;
|
||||
|
||||
/* Extended */
|
||||
pfl->cfi_table[0x31] = 'P';
|
||||
|
@ -716,5 +706,81 @@ pflash_t *pflash_cfi02_register(hwaddr base,
|
|||
pfl->cfi_table[0x3b] = 0x00;
|
||||
pfl->cfi_table[0x3c] = 0x00;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Property pflash_cfi02_properties[] = {
|
||||
DEFINE_PROP_DRIVE("drive", struct pflash_t, bs),
|
||||
DEFINE_PROP_UINT32("num-blocks", struct pflash_t, nb_blocs, 0),
|
||||
DEFINE_PROP_UINT32("sector-length", struct pflash_t, sector_len, 0),
|
||||
DEFINE_PROP_UINT8("width", struct pflash_t, width, 0),
|
||||
DEFINE_PROP_UINT8("mappings", struct pflash_t, mappings, 0),
|
||||
DEFINE_PROP_UINT8("big-endian", struct pflash_t, be, 0),
|
||||
DEFINE_PROP_UINT16("id0", struct pflash_t, ident0, 0),
|
||||
DEFINE_PROP_UINT16("id1", struct pflash_t, ident1, 0),
|
||||
DEFINE_PROP_UINT16("id2", struct pflash_t, ident2, 0),
|
||||
DEFINE_PROP_UINT16("id3", struct pflash_t, ident3, 0),
|
||||
DEFINE_PROP_UINT16("unlock-addr0", struct pflash_t, unlock_addr0, 0),
|
||||
DEFINE_PROP_UINT16("unlock-addr1", struct pflash_t, unlock_addr1, 0),
|
||||
DEFINE_PROP_STRING("name", struct pflash_t, name),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void pflash_cfi02_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = pflash_cfi02_init;
|
||||
dc->props = pflash_cfi02_properties;
|
||||
}
|
||||
|
||||
static const TypeInfo pflash_cfi02_info = {
|
||||
.name = "cfi.pflash02",
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(struct pflash_t),
|
||||
.class_init = pflash_cfi02_class_init,
|
||||
};
|
||||
|
||||
static void pflash_cfi02_register_types(void)
|
||||
{
|
||||
type_register_static(&pflash_cfi02_info);
|
||||
}
|
||||
|
||||
type_init(pflash_cfi02_register_types)
|
||||
|
||||
pflash_t *pflash_cfi02_register(hwaddr base,
|
||||
DeviceState *qdev, const char *name,
|
||||
hwaddr size,
|
||||
BlockDriverState *bs, uint32_t sector_len,
|
||||
int nb_blocs, int nb_mappings, int width,
|
||||
uint16_t id0, uint16_t id1,
|
||||
uint16_t id2, uint16_t id3,
|
||||
uint16_t unlock_addr0, uint16_t unlock_addr1,
|
||||
int be)
|
||||
{
|
||||
DeviceState *dev = qdev_create(NULL, "cfi.pflash02");
|
||||
SysBusDevice *busdev = sysbus_from_qdev(dev);
|
||||
pflash_t *pfl = (pflash_t *)object_dynamic_cast(OBJECT(dev),
|
||||
"cfi.pflash02");
|
||||
|
||||
if (bs && qdev_prop_set_drive(dev, "drive", bs)) {
|
||||
abort();
|
||||
}
|
||||
qdev_prop_set_uint32(dev, "num-blocks", nb_blocs);
|
||||
qdev_prop_set_uint32(dev, "sector-length", sector_len);
|
||||
qdev_prop_set_uint8(dev, "width", width);
|
||||
qdev_prop_set_uint8(dev, "mappings", nb_mappings);
|
||||
qdev_prop_set_uint8(dev, "big-endian", !!be);
|
||||
qdev_prop_set_uint16(dev, "id0", id0);
|
||||
qdev_prop_set_uint16(dev, "id1", id1);
|
||||
qdev_prop_set_uint16(dev, "id2", id2);
|
||||
qdev_prop_set_uint16(dev, "id3", id3);
|
||||
qdev_prop_set_uint16(dev, "unlock-addr0", unlock_addr0);
|
||||
qdev_prop_set_uint16(dev, "unlock-addr1", unlock_addr1);
|
||||
qdev_prop_set_string(dev, "name", name);
|
||||
qdev_init_nofail(dev);
|
||||
|
||||
sysbus_mmio_map(busdev, 0, base);
|
||||
return pfl;
|
||||
}
|
||||
|
|
|
@ -95,7 +95,8 @@ static uint64_t pl050_read(void *opaque, hwaddr offset,
|
|||
case 4: /* KMIIR */
|
||||
return s->pending | 2;
|
||||
default:
|
||||
hw_error("pl050_read: Bad offset %x\n", (int)offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"pl050_read: Bad offset %x\n", (int)offset);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -123,7 +124,8 @@ static void pl050_write(void *opaque, hwaddr offset,
|
|||
s->clk = value;
|
||||
return;
|
||||
default:
|
||||
hw_error("pl050_write: Bad offset %x\n", (int)offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"pl050_write: Bad offset %x\n", (int)offset);
|
||||
}
|
||||
}
|
||||
static const MemoryRegionOps pl050_ops = {
|
||||
|
|
|
@ -164,7 +164,8 @@ static uint64_t pl061_read(void *opaque, hwaddr offset,
|
|||
case 0x528: /* Analog mode select */
|
||||
return s->amsel;
|
||||
default:
|
||||
hw_error("pl061_read: Bad offset %x\n", (int)offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"pl061_read: Bad offset %x\n", (int)offset);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -239,7 +240,8 @@ static void pl061_write(void *opaque, hwaddr offset,
|
|||
s->amsel = value & 0xff;
|
||||
break;
|
||||
default:
|
||||
hw_error("pl061_write: Bad offset %x\n", (int)offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"pl061_write: Bad offset %x\n", (int)offset);
|
||||
}
|
||||
pl061_update(s);
|
||||
}
|
||||
|
|
11
hw/pl080.c
11
hw/pl080.c
|
@ -281,7 +281,8 @@ static uint64_t pl080_read(void *opaque, hwaddr offset,
|
|||
return s->sync;
|
||||
default:
|
||||
bad_offset:
|
||||
hw_error("pl080_read: Bad offset %x\n", (int)offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"pl080_read: Bad offset %x\n", (int)offset);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -327,12 +328,13 @@ static void pl080_write(void *opaque, hwaddr offset,
|
|||
case 10: /* SoftLBReq */
|
||||
case 11: /* SoftLSReq */
|
||||
/* ??? Implement these. */
|
||||
hw_error("pl080_write: Soft DMA not implemented\n");
|
||||
qemu_log_mask(LOG_UNIMP, "pl080_write: Soft DMA not implemented\n");
|
||||
break;
|
||||
case 12: /* Configuration */
|
||||
s->conf = value;
|
||||
if (s->conf & (PL080_CONF_M1 | PL080_CONF_M1)) {
|
||||
hw_error("pl080_write: Big-endian DMA not implemented\n");
|
||||
qemu_log_mask(LOG_UNIMP,
|
||||
"pl080_write: Big-endian DMA not implemented\n");
|
||||
}
|
||||
pl080_run(s);
|
||||
break;
|
||||
|
@ -341,7 +343,8 @@ static void pl080_write(void *opaque, hwaddr offset,
|
|||
break;
|
||||
default:
|
||||
bad_offset:
|
||||
hw_error("pl080_write: Bad offset %x\n", (int)offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"pl080_write: Bad offset %x\n", (int)offset);
|
||||
}
|
||||
pl080_update(s);
|
||||
}
|
||||
|
|
|
@ -239,7 +239,7 @@ static void pl110_update_display(void *opaque)
|
|||
fn, s->palette,
|
||||
&first, &last);
|
||||
if (first >= 0) {
|
||||
dpy_update(s->ds, 0, first, s->cols, last - first + 1);
|
||||
dpy_gfx_update(s->ds, 0, first, s->cols, last - first + 1);
|
||||
}
|
||||
s->invalidate = 0;
|
||||
}
|
||||
|
@ -349,7 +349,8 @@ static uint64_t pl110_read(void *opaque, hwaddr offset,
|
|||
case 12: /* LCDLPCURR */
|
||||
return s->lpbase;
|
||||
default:
|
||||
hw_error("pl110_read: Bad offset %x\n", (int)offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"pl110_read: Bad offset %x\n", (int)offset);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -417,7 +418,8 @@ static void pl110_write(void *opaque, hwaddr offset,
|
|||
pl110_update(s);
|
||||
break;
|
||||
default:
|
||||
hw_error("pl110_write: Bad offset %x\n", (int)offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"pl110_write: Bad offset %x\n", (int)offset);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -199,7 +199,7 @@ static void pl190_write(void *opaque, hwaddr offset,
|
|||
break;
|
||||
case 0xc0: /* ITCR */
|
||||
if (val) {
|
||||
hw_error("pl190: Test mode not implemented\n");
|
||||
qemu_log_mask(LOG_UNIMP, "pl190: Test mode not implemented\n");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
75
hw/ppc.c
75
hw/ppc.c
|
@ -75,9 +75,10 @@ void ppc_set_irq(CPUPPCState *env, int n_IRQ, int level)
|
|||
}
|
||||
|
||||
/* PowerPC 6xx / 7xx internal IRQ controller */
|
||||
static void ppc6xx_set_irq (void *opaque, int pin, int level)
|
||||
static void ppc6xx_set_irq(void *opaque, int pin, int level)
|
||||
{
|
||||
CPUPPCState *env = opaque;
|
||||
PowerPCCPU *cpu = opaque;
|
||||
CPUPPCState *env = &cpu->env;
|
||||
int cur_level;
|
||||
|
||||
LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
|
||||
|
@ -151,17 +152,20 @@ static void ppc6xx_set_irq (void *opaque, int pin, int level)
|
|||
}
|
||||
}
|
||||
|
||||
void ppc6xx_irq_init (CPUPPCState *env)
|
||||
void ppc6xx_irq_init(CPUPPCState *env)
|
||||
{
|
||||
env->irq_inputs = (void **)qemu_allocate_irqs(&ppc6xx_set_irq, env,
|
||||
PowerPCCPU *cpu = ppc_env_get_cpu(env);
|
||||
|
||||
env->irq_inputs = (void **)qemu_allocate_irqs(&ppc6xx_set_irq, cpu,
|
||||
PPC6xx_INPUT_NB);
|
||||
}
|
||||
|
||||
#if defined(TARGET_PPC64)
|
||||
/* PowerPC 970 internal IRQ controller */
|
||||
static void ppc970_set_irq (void *opaque, int pin, int level)
|
||||
static void ppc970_set_irq(void *opaque, int pin, int level)
|
||||
{
|
||||
CPUPPCState *env = opaque;
|
||||
PowerPCCPU *cpu = opaque;
|
||||
CPUPPCState *env = &cpu->env;
|
||||
int cur_level;
|
||||
|
||||
LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
|
||||
|
@ -202,7 +206,7 @@ static void ppc970_set_irq (void *opaque, int pin, int level)
|
|||
} else {
|
||||
LOG_IRQ("%s: restart the CPU\n", __func__);
|
||||
env->halted = 0;
|
||||
qemu_cpu_kick(env);
|
||||
qemu_cpu_kick(CPU(cpu));
|
||||
}
|
||||
break;
|
||||
case PPC970_INPUT_HRESET:
|
||||
|
@ -233,16 +237,19 @@ static void ppc970_set_irq (void *opaque, int pin, int level)
|
|||
}
|
||||
}
|
||||
|
||||
void ppc970_irq_init (CPUPPCState *env)
|
||||
void ppc970_irq_init(CPUPPCState *env)
|
||||
{
|
||||
env->irq_inputs = (void **)qemu_allocate_irqs(&ppc970_set_irq, env,
|
||||
PowerPCCPU *cpu = ppc_env_get_cpu(env);
|
||||
|
||||
env->irq_inputs = (void **)qemu_allocate_irqs(&ppc970_set_irq, cpu,
|
||||
PPC970_INPUT_NB);
|
||||
}
|
||||
|
||||
/* POWER7 internal IRQ controller */
|
||||
static void power7_set_irq (void *opaque, int pin, int level)
|
||||
static void power7_set_irq(void *opaque, int pin, int level)
|
||||
{
|
||||
CPUPPCState *env = opaque;
|
||||
PowerPCCPU *cpu = opaque;
|
||||
CPUPPCState *env = &cpu->env;
|
||||
|
||||
LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
|
||||
env, pin, level);
|
||||
|
@ -266,17 +273,20 @@ static void power7_set_irq (void *opaque, int pin, int level)
|
|||
}
|
||||
}
|
||||
|
||||
void ppcPOWER7_irq_init (CPUPPCState *env)
|
||||
void ppcPOWER7_irq_init(CPUPPCState *env)
|
||||
{
|
||||
env->irq_inputs = (void **)qemu_allocate_irqs(&power7_set_irq, env,
|
||||
PowerPCCPU *cpu = ppc_env_get_cpu(env);
|
||||
|
||||
env->irq_inputs = (void **)qemu_allocate_irqs(&power7_set_irq, cpu,
|
||||
POWER7_INPUT_NB);
|
||||
}
|
||||
#endif /* defined(TARGET_PPC64) */
|
||||
|
||||
/* PowerPC 40x internal IRQ controller */
|
||||
static void ppc40x_set_irq (void *opaque, int pin, int level)
|
||||
static void ppc40x_set_irq(void *opaque, int pin, int level)
|
||||
{
|
||||
CPUPPCState *env = opaque;
|
||||
PowerPCCPU *cpu = opaque;
|
||||
CPUPPCState *env = &cpu->env;
|
||||
int cur_level;
|
||||
|
||||
LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
|
||||
|
@ -325,7 +335,7 @@ static void ppc40x_set_irq (void *opaque, int pin, int level)
|
|||
} else {
|
||||
LOG_IRQ("%s: restart the CPU\n", __func__);
|
||||
env->halted = 0;
|
||||
qemu_cpu_kick(env);
|
||||
qemu_cpu_kick(CPU(cpu));
|
||||
}
|
||||
break;
|
||||
case PPC40x_INPUT_DEBUG:
|
||||
|
@ -346,16 +356,19 @@ static void ppc40x_set_irq (void *opaque, int pin, int level)
|
|||
}
|
||||
}
|
||||
|
||||
void ppc40x_irq_init (CPUPPCState *env)
|
||||
void ppc40x_irq_init(CPUPPCState *env)
|
||||
{
|
||||
PowerPCCPU *cpu = ppc_env_get_cpu(env);
|
||||
|
||||
env->irq_inputs = (void **)qemu_allocate_irqs(&ppc40x_set_irq,
|
||||
env, PPC40x_INPUT_NB);
|
||||
cpu, PPC40x_INPUT_NB);
|
||||
}
|
||||
|
||||
/* PowerPC E500 internal IRQ controller */
|
||||
static void ppce500_set_irq (void *opaque, int pin, int level)
|
||||
static void ppce500_set_irq(void *opaque, int pin, int level)
|
||||
{
|
||||
CPUPPCState *env = opaque;
|
||||
PowerPCCPU *cpu = opaque;
|
||||
CPUPPCState *env = &cpu->env;
|
||||
int cur_level;
|
||||
|
||||
LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
|
||||
|
@ -407,10 +420,12 @@ static void ppce500_set_irq (void *opaque, int pin, int level)
|
|||
}
|
||||
}
|
||||
|
||||
void ppce500_irq_init (CPUPPCState *env)
|
||||
void ppce500_irq_init(CPUPPCState *env)
|
||||
{
|
||||
PowerPCCPU *cpu = ppc_env_get_cpu(env);
|
||||
|
||||
env->irq_inputs = (void **)qemu_allocate_irqs(&ppce500_set_irq,
|
||||
env, PPCE500_INPUT_NB);
|
||||
cpu, PPCE500_INPUT_NB);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
/* PowerPC time base and decrementer emulation */
|
||||
|
@ -721,7 +736,7 @@ static void cpu_ppc_hdecr_cb (void *opaque)
|
|||
_cpu_ppc_store_hdecr(opaque, 0x00000000, 0xFFFFFFFF, 1);
|
||||
}
|
||||
|
||||
void cpu_ppc_store_purr (CPUPPCState *env, uint64_t value)
|
||||
static void cpu_ppc_store_purr(CPUPPCState *env, uint64_t value)
|
||||
{
|
||||
ppc_tb_t *tb_env = env->tb_env;
|
||||
|
||||
|
@ -1152,23 +1167,23 @@ static inline void nvram_write (nvram_t *nvram, uint32_t addr, uint32_t val)
|
|||
(*nvram->write_fn)(nvram->opaque, addr, val);
|
||||
}
|
||||
|
||||
void NVRAM_set_byte (nvram_t *nvram, uint32_t addr, uint8_t value)
|
||||
static void NVRAM_set_byte(nvram_t *nvram, uint32_t addr, uint8_t value)
|
||||
{
|
||||
nvram_write(nvram, addr, value);
|
||||
}
|
||||
|
||||
uint8_t NVRAM_get_byte (nvram_t *nvram, uint32_t addr)
|
||||
static uint8_t NVRAM_get_byte(nvram_t *nvram, uint32_t addr)
|
||||
{
|
||||
return nvram_read(nvram, addr);
|
||||
}
|
||||
|
||||
void NVRAM_set_word (nvram_t *nvram, uint32_t addr, uint16_t value)
|
||||
static void NVRAM_set_word(nvram_t *nvram, uint32_t addr, uint16_t value)
|
||||
{
|
||||
nvram_write(nvram, addr, value >> 8);
|
||||
nvram_write(nvram, addr + 1, value & 0xFF);
|
||||
}
|
||||
|
||||
uint16_t NVRAM_get_word (nvram_t *nvram, uint32_t addr)
|
||||
static uint16_t NVRAM_get_word(nvram_t *nvram, uint32_t addr)
|
||||
{
|
||||
uint16_t tmp;
|
||||
|
||||
|
@ -1178,7 +1193,7 @@ uint16_t NVRAM_get_word (nvram_t *nvram, uint32_t addr)
|
|||
return tmp;
|
||||
}
|
||||
|
||||
void NVRAM_set_lword (nvram_t *nvram, uint32_t addr, uint32_t value)
|
||||
static void NVRAM_set_lword(nvram_t *nvram, uint32_t addr, uint32_t value)
|
||||
{
|
||||
nvram_write(nvram, addr, value >> 24);
|
||||
nvram_write(nvram, addr + 1, (value >> 16) & 0xFF);
|
||||
|
@ -1198,8 +1213,8 @@ uint32_t NVRAM_get_lword (nvram_t *nvram, uint32_t addr)
|
|||
return tmp;
|
||||
}
|
||||
|
||||
void NVRAM_set_string (nvram_t *nvram, uint32_t addr,
|
||||
const char *str, uint32_t max)
|
||||
static void NVRAM_set_string(nvram_t *nvram, uint32_t addr, const char *str,
|
||||
uint32_t max)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ typedef struct spin_state {
|
|||
} SpinState;
|
||||
|
||||
typedef struct spin_kick {
|
||||
CPUPPCState *env;
|
||||
PowerPCCPU *cpu;
|
||||
SpinInfo *spin;
|
||||
} SpinKick;
|
||||
|
||||
|
@ -92,7 +92,8 @@ static void mmubooke_create_initial_mapping(CPUPPCState *env,
|
|||
static void spin_kick(void *data)
|
||||
{
|
||||
SpinKick *kick = data;
|
||||
CPUPPCState *env = kick->env;
|
||||
CPUState *cpu = CPU(kick->cpu);
|
||||
CPUPPCState *env = &kick->cpu->env;
|
||||
SpinInfo *curspin = kick->spin;
|
||||
hwaddr map_size = 64 * 1024 * 1024;
|
||||
hwaddr map_start;
|
||||
|
@ -113,8 +114,8 @@ static void spin_kick(void *data)
|
|||
|
||||
env->halted = 0;
|
||||
env->exception_index = -1;
|
||||
env->stopped = 0;
|
||||
qemu_cpu_kick(env);
|
||||
cpu->stopped = false;
|
||||
qemu_cpu_kick(cpu);
|
||||
}
|
||||
|
||||
static void spin_write(void *opaque, hwaddr addr, uint64_t value,
|
||||
|
@ -158,11 +159,11 @@ static void spin_write(void *opaque, hwaddr addr, uint64_t value,
|
|||
if (!(ldq_p(&curspin->addr) & 1)) {
|
||||
/* run CPU */
|
||||
SpinKick kick = {
|
||||
.env = env,
|
||||
.cpu = ppc_env_get_cpu(env),
|
||||
.spin = curspin,
|
||||
};
|
||||
|
||||
run_on_cpu(env, spin_kick, &kick);
|
||||
run_on_cpu(CPU(kick.cpu), spin_kick, &kick);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -871,20 +871,20 @@ static void pxa2xx_update_display(void *opaque)
|
|||
if (miny >= 0) {
|
||||
switch (s->orientation) {
|
||||
case 0:
|
||||
dpy_update(s->ds, 0, miny, s->xres, maxy - miny + 1);
|
||||
dpy_gfx_update(s->ds, 0, miny, s->xres, maxy - miny + 1);
|
||||
break;
|
||||
case 90:
|
||||
dpy_update(s->ds, miny, 0, maxy - miny + 1, s->xres);
|
||||
dpy_gfx_update(s->ds, miny, 0, maxy - miny + 1, s->xres);
|
||||
break;
|
||||
case 180:
|
||||
maxy = s->yres - maxy - 1;
|
||||
miny = s->yres - miny - 1;
|
||||
dpy_update(s->ds, 0, maxy, s->xres, miny - maxy + 1);
|
||||
dpy_gfx_update(s->ds, 0, maxy, s->xres, miny - maxy + 1);
|
||||
break;
|
||||
case 270:
|
||||
maxy = s->yres - maxy - 1;
|
||||
miny = s->yres - miny - 1;
|
||||
dpy_update(s->ds, maxy, 0, miny - maxy + 1, s->xres);
|
||||
dpy_gfx_update(s->ds, maxy, 0, miny - maxy + 1, s->xres);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
static void qxl_blit(PCIQXLDevice *qxl, QXLRect *rect)
|
||||
{
|
||||
uint8_t *src;
|
||||
uint8_t *dst = qxl->vga.ds->surface->data;
|
||||
uint8_t *dst = ds_get_data(qxl->vga.ds);
|
||||
int len, i;
|
||||
|
||||
if (is_buffer_shared(qxl->vga.ds->surface)) {
|
||||
|
@ -123,17 +123,17 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl)
|
|||
qxl->guest_primary.surface.width,
|
||||
qxl->guest_primary.surface.height);
|
||||
}
|
||||
dpy_resize(vga->ds);
|
||||
dpy_gfx_resize(vga->ds);
|
||||
}
|
||||
for (i = 0; i < qxl->num_dirty_rects; i++) {
|
||||
if (qemu_spice_rect_is_empty(qxl->dirty+i)) {
|
||||
break;
|
||||
}
|
||||
qxl_blit(qxl, qxl->dirty+i);
|
||||
dpy_update(vga->ds,
|
||||
qxl->dirty[i].left, qxl->dirty[i].top,
|
||||
qxl->dirty[i].right - qxl->dirty[i].left,
|
||||
qxl->dirty[i].bottom - qxl->dirty[i].top);
|
||||
dpy_gfx_update(vga->ds,
|
||||
qxl->dirty[i].left, qxl->dirty[i].top,
|
||||
qxl->dirty[i].right - qxl->dirty[i].left,
|
||||
qxl->dirty[i].bottom - qxl->dirty[i].top);
|
||||
}
|
||||
qxl->num_dirty_rects = 0;
|
||||
}
|
||||
|
@ -234,7 +234,7 @@ int qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext)
|
|||
return 1;
|
||||
}
|
||||
|
||||
if (!qxl->ssd.ds->mouse_set || !qxl->ssd.ds->cursor_define) {
|
||||
if (!dpy_cursor_define_supported(qxl->ssd.ds)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
4
hw/qxl.c
4
hw/qxl.c
|
@ -1864,8 +1864,8 @@ static void display_refresh(struct DisplayState *ds)
|
|||
}
|
||||
|
||||
static DisplayChangeListener display_listener = {
|
||||
.dpy_update = display_update,
|
||||
.dpy_resize = display_resize,
|
||||
.dpy_gfx_update = display_update,
|
||||
.dpy_gfx_resize = display_resize,
|
||||
.dpy_refresh = display_refresh,
|
||||
};
|
||||
|
||||
|
|
|
@ -44,11 +44,8 @@ static const int realview_board_id[] = {
|
|||
0x76d
|
||||
};
|
||||
|
||||
static void realview_init(ram_addr_t ram_size,
|
||||
const char *boot_device,
|
||||
const char *kernel_filename, const char *kernel_cmdline,
|
||||
const char *initrd_filename, const char *cpu_model,
|
||||
enum realview_board_type board_type)
|
||||
static void realview_init(QEMUMachineInitArgs *args,
|
||||
enum realview_board_type board_type)
|
||||
{
|
||||
ARMCPU *cpu = NULL;
|
||||
CPUARMState *env;
|
||||
|
@ -73,6 +70,7 @@ static void realview_init(ram_addr_t ram_size,
|
|||
uint32_t proc_id = 0;
|
||||
uint32_t sys_id;
|
||||
ram_addr_t low_ram_size;
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
|
||||
switch (board_type) {
|
||||
case BOARD_EB:
|
||||
|
@ -89,7 +87,7 @@ static void realview_init(ram_addr_t ram_size,
|
|||
break;
|
||||
}
|
||||
for (n = 0; n < smp_cpus; n++) {
|
||||
cpu = cpu_arm_init(cpu_model);
|
||||
cpu = cpu_arm_init(args->cpu_model);
|
||||
if (!cpu) {
|
||||
fprintf(stderr, "Unable to find CPU definition\n");
|
||||
exit(1);
|
||||
|
@ -321,9 +319,9 @@ static void realview_init(ram_addr_t ram_size,
|
|||
memory_region_add_subregion(sysmem, SMP_BOOT_ADDR, ram_hack);
|
||||
|
||||
realview_binfo.ram_size = ram_size;
|
||||
realview_binfo.kernel_filename = kernel_filename;
|
||||
realview_binfo.kernel_cmdline = kernel_cmdline;
|
||||
realview_binfo.initrd_filename = initrd_filename;
|
||||
realview_binfo.kernel_filename = args->kernel_filename;
|
||||
realview_binfo.kernel_cmdline = args->kernel_cmdline;
|
||||
realview_binfo.initrd_filename = args->initrd_filename;
|
||||
realview_binfo.nb_cpus = smp_cpus;
|
||||
realview_binfo.board_id = realview_board_id[board_type];
|
||||
realview_binfo.loader_start = (board_type == BOARD_PB_A8 ? 0x70000000 : 0);
|
||||
|
@ -332,62 +330,34 @@ static void realview_init(ram_addr_t ram_size,
|
|||
|
||||
static void realview_eb_init(QEMUMachineInitArgs *args)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
const char *boot_device = args->boot_device;
|
||||
if (!cpu_model) {
|
||||
cpu_model = "arm926";
|
||||
if (!args->cpu_model) {
|
||||
args->cpu_model = "arm926";
|
||||
}
|
||||
realview_init(ram_size, boot_device, kernel_filename, kernel_cmdline,
|
||||
initrd_filename, cpu_model, BOARD_EB);
|
||||
realview_init(args, BOARD_EB);
|
||||
}
|
||||
|
||||
static void realview_eb_mpcore_init(QEMUMachineInitArgs *args)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
const char *boot_device = args->boot_device;
|
||||
if (!cpu_model) {
|
||||
cpu_model = "arm11mpcore";
|
||||
if (!args->cpu_model) {
|
||||
args->cpu_model = "arm11mpcore";
|
||||
}
|
||||
realview_init(ram_size, boot_device, kernel_filename, kernel_cmdline,
|
||||
initrd_filename, cpu_model, BOARD_EB_MPCORE);
|
||||
realview_init(args, BOARD_EB_MPCORE);
|
||||
}
|
||||
|
||||
static void realview_pb_a8_init(QEMUMachineInitArgs *args)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
const char *boot_device = args->boot_device;
|
||||
if (!cpu_model) {
|
||||
cpu_model = "cortex-a8";
|
||||
if (!args->cpu_model) {
|
||||
args->cpu_model = "cortex-a8";
|
||||
}
|
||||
realview_init(ram_size, boot_device, kernel_filename, kernel_cmdline,
|
||||
initrd_filename, cpu_model, BOARD_PB_A8);
|
||||
realview_init(args, BOARD_PB_A8);
|
||||
}
|
||||
|
||||
static void realview_pbx_a9_init(QEMUMachineInitArgs *args)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
const char *boot_device = args->boot_device;
|
||||
if (!cpu_model) {
|
||||
cpu_model = "cortex-a9";
|
||||
if (!args->cpu_model) {
|
||||
args->cpu_model = "cortex-a9";
|
||||
}
|
||||
realview_init(ram_size, boot_device, kernel_filename, kernel_cmdline,
|
||||
initrd_filename, cpu_model, BOARD_PBX_A9);
|
||||
realview_init(args, BOARD_PBX_A9);
|
||||
}
|
||||
|
||||
static QEMUMachine realview_eb_machine = {
|
||||
|
|
106
hw/sd.c
106
hw/sd.c
|
@ -55,24 +55,28 @@ typedef enum {
|
|||
sd_illegal = -2,
|
||||
} sd_rsp_type_t;
|
||||
|
||||
enum SDCardModes {
|
||||
sd_inactive,
|
||||
sd_card_identification_mode,
|
||||
sd_data_transfer_mode,
|
||||
};
|
||||
|
||||
enum SDCardStates {
|
||||
sd_inactive_state = -1,
|
||||
sd_idle_state = 0,
|
||||
sd_ready_state,
|
||||
sd_identification_state,
|
||||
sd_standby_state,
|
||||
sd_transfer_state,
|
||||
sd_sendingdata_state,
|
||||
sd_receivingdata_state,
|
||||
sd_programming_state,
|
||||
sd_disconnect_state,
|
||||
};
|
||||
|
||||
struct SDState {
|
||||
enum {
|
||||
sd_inactive,
|
||||
sd_card_identification_mode,
|
||||
sd_data_transfer_mode,
|
||||
} mode;
|
||||
enum {
|
||||
sd_inactive_state = -1,
|
||||
sd_idle_state = 0,
|
||||
sd_ready_state,
|
||||
sd_identification_state,
|
||||
sd_standby_state,
|
||||
sd_transfer_state,
|
||||
sd_sendingdata_state,
|
||||
sd_receivingdata_state,
|
||||
sd_programming_state,
|
||||
sd_disconnect_state,
|
||||
} state;
|
||||
uint32_t mode; /* current card mode, one of SDCardModes */
|
||||
int32_t state; /* current card state, one of SDCardStates */
|
||||
uint32_t ocr;
|
||||
uint8_t scr[8];
|
||||
uint8_t cid[16];
|
||||
|
@ -83,21 +87,22 @@ struct SDState {
|
|||
uint32_t vhs;
|
||||
bool wp_switch;
|
||||
unsigned long *wp_groups;
|
||||
int32_t wpgrps_size;
|
||||
uint64_t size;
|
||||
int blk_len;
|
||||
uint32_t blk_len;
|
||||
uint32_t erase_start;
|
||||
uint32_t erase_end;
|
||||
uint8_t pwd[16];
|
||||
int pwd_len;
|
||||
int function_group[6];
|
||||
uint32_t pwd_len;
|
||||
uint8_t function_group[6];
|
||||
|
||||
bool spi;
|
||||
int current_cmd;
|
||||
uint8_t current_cmd;
|
||||
/* True if we will handle the next command as an ACMD. Note that this does
|
||||
* *not* track the APP_CMD status bit!
|
||||
*/
|
||||
bool expecting_acmd;
|
||||
int blk_written;
|
||||
uint32_t blk_written;
|
||||
uint64_t data_start;
|
||||
uint32_t data_offset;
|
||||
uint8_t data[512];
|
||||
|
@ -421,8 +426,9 @@ static void sd_reset(SDState *sd, BlockDriverState *bdrv)
|
|||
if (sd->wp_groups)
|
||||
g_free(sd->wp_groups);
|
||||
sd->wp_switch = bdrv ? bdrv_is_read_only(bdrv) : false;
|
||||
sd->wp_groups = bitmap_new(sect);
|
||||
memset(sd->function_group, 0, sizeof(int) * 6);
|
||||
sd->wpgrps_size = sect;
|
||||
sd->wp_groups = bitmap_new(sd->wpgrps_size);
|
||||
memset(sd->function_group, 0, sizeof(sd->function_group));
|
||||
sd->erase_start = 0;
|
||||
sd->erase_end = 0;
|
||||
sd->size = size;
|
||||
|
@ -446,6 +452,38 @@ static const BlockDevOps sd_block_ops = {
|
|||
.change_media_cb = sd_cardchange,
|
||||
};
|
||||
|
||||
static const VMStateDescription sd_vmstate = {
|
||||
.name = "sd-card",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(mode, SDState),
|
||||
VMSTATE_INT32(state, SDState),
|
||||
VMSTATE_UINT8_ARRAY(cid, SDState, 16),
|
||||
VMSTATE_UINT8_ARRAY(csd, SDState, 16),
|
||||
VMSTATE_UINT16(rca, SDState),
|
||||
VMSTATE_UINT32(card_status, SDState),
|
||||
VMSTATE_PARTIAL_BUFFER(sd_status, SDState, 1),
|
||||
VMSTATE_UINT32(vhs, SDState),
|
||||
VMSTATE_BITMAP(wp_groups, SDState, 0, wpgrps_size),
|
||||
VMSTATE_UINT32(blk_len, SDState),
|
||||
VMSTATE_UINT32(erase_start, SDState),
|
||||
VMSTATE_UINT32(erase_end, SDState),
|
||||
VMSTATE_UINT8_ARRAY(pwd, SDState, 16),
|
||||
VMSTATE_UINT32(pwd_len, SDState),
|
||||
VMSTATE_UINT8_ARRAY(function_group, SDState, 6),
|
||||
VMSTATE_UINT8(current_cmd, SDState),
|
||||
VMSTATE_BOOL(expecting_acmd, SDState),
|
||||
VMSTATE_UINT32(blk_written, SDState),
|
||||
VMSTATE_UINT64(data_start, SDState),
|
||||
VMSTATE_UINT32(data_offset, SDState),
|
||||
VMSTATE_UINT8_ARRAY(data, SDState, 512),
|
||||
VMSTATE_BUFFER_UNSAFE(buf, SDState, 1, 512),
|
||||
VMSTATE_BOOL(enable, SDState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
/* We do not model the chip select pin, so allow the board to select
|
||||
whether card should be in SSI or MMC/SD mode. It is also up to the
|
||||
board to ensure that ssi transfers only occur when the chip select
|
||||
|
@ -463,6 +501,7 @@ SDState *sd_init(BlockDriverState *bs, bool is_spi)
|
|||
bdrv_attach_dev_nofail(sd->bdrv, sd);
|
||||
bdrv_set_dev_ops(sd->bdrv, &sd_block_ops, sd);
|
||||
}
|
||||
vmstate_register(NULL, -1, &sd_vmstate, sd);
|
||||
return sd;
|
||||
}
|
||||
|
||||
|
@ -476,19 +515,28 @@ void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert)
|
|||
|
||||
static void sd_erase(SDState *sd)
|
||||
{
|
||||
int i, start, end;
|
||||
int i;
|
||||
uint64_t erase_start = sd->erase_start;
|
||||
uint64_t erase_end = sd->erase_end;
|
||||
|
||||
if (!sd->erase_start || !sd->erase_end) {
|
||||
sd->card_status |= ERASE_SEQ_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
start = sd_addr_to_wpnum(sd->erase_start);
|
||||
end = sd_addr_to_wpnum(sd->erase_end);
|
||||
if (extract32(sd->ocr, OCR_CCS_BITN, 1)) {
|
||||
/* High capacity memory card: erase units are 512 byte blocks */
|
||||
erase_start *= 512;
|
||||
erase_end *= 512;
|
||||
}
|
||||
|
||||
erase_start = sd_addr_to_wpnum(erase_start);
|
||||
erase_end = sd_addr_to_wpnum(erase_end);
|
||||
sd->erase_start = 0;
|
||||
sd->erase_end = 0;
|
||||
sd->csd[14] |= 0x40;
|
||||
|
||||
for (i = start; i <= end; i++) {
|
||||
for (i = erase_start; i <= erase_end; i++) {
|
||||
if (test_bit(i, sd->wp_groups)) {
|
||||
sd->card_status |= WP_ERASE_SKIP;
|
||||
}
|
||||
|
@ -567,7 +615,7 @@ static void sd_lock_command(SDState *sd)
|
|||
sd->card_status |= LOCK_UNLOCK_FAILED;
|
||||
return;
|
||||
}
|
||||
bitmap_zero(sd->wp_groups, sd_addr_to_wpnum(sd->size) + 1);
|
||||
bitmap_zero(sd->wp_groups, sd->wpgrps_size);
|
||||
sd->csd[14] &= ~0x10;
|
||||
sd->card_status &= ~CARD_IS_LOCKED;
|
||||
sd->pwd_len = 0;
|
||||
|
|
1
hw/sd.h
1
hw/sd.h
|
@ -50,6 +50,7 @@
|
|||
#define READY_FOR_DATA (1 << 8)
|
||||
#define APP_CMD (1 << 5)
|
||||
#define AKE_SEQ_ERROR (1 << 3)
|
||||
#define OCR_CCS_BITN 30
|
||||
|
||||
typedef enum {
|
||||
sd_none = -1,
|
||||
|
|
|
@ -1351,7 +1351,7 @@ static void sm501_draw_crt(SM501State * s)
|
|||
} else {
|
||||
if (y_start >= 0) {
|
||||
/* flush to display */
|
||||
dpy_update(s->ds, 0, y_start, width, y - y_start);
|
||||
dpy_gfx_update(s->ds, 0, y_start, width, y - y_start);
|
||||
y_start = -1;
|
||||
}
|
||||
}
|
||||
|
@ -1362,7 +1362,7 @@ static void sm501_draw_crt(SM501State * s)
|
|||
|
||||
/* complete flush to display */
|
||||
if (y_start >= 0)
|
||||
dpy_update(s->ds, 0, y_start, width, y - y_start);
|
||||
dpy_gfx_update(s->ds, 0, y_start, width, y - y_start);
|
||||
|
||||
/* clear dirty flags */
|
||||
if (page_min != ~0l) {
|
||||
|
|
|
@ -576,13 +576,15 @@ static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
|
|||
return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR;
|
||||
}
|
||||
|
||||
static void emulate_spapr_hypercall(CPUPPCState *env)
|
||||
static void emulate_spapr_hypercall(PowerPCCPU *cpu)
|
||||
{
|
||||
CPUPPCState *env = &cpu->env;
|
||||
|
||||
if (msr_pr) {
|
||||
hcall_dprintf("Hypercall made with MSR[PR]=1\n");
|
||||
env->gpr[3] = H_PRIVILEGE;
|
||||
} else {
|
||||
env->gpr[3] = spapr_hypercall(env, env->gpr[3], &env->gpr[4]);
|
||||
env->gpr[3] = spapr_hypercall(cpu, env->gpr[3], &env->gpr[4]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -286,12 +286,12 @@ extern sPAPREnvironment *spapr;
|
|||
do { } while (0)
|
||||
#endif
|
||||
|
||||
typedef target_ulong (*spapr_hcall_fn)(CPUPPCState *env, sPAPREnvironment *spapr,
|
||||
typedef target_ulong (*spapr_hcall_fn)(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
target_ulong opcode,
|
||||
target_ulong *args);
|
||||
|
||||
void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn);
|
||||
target_ulong spapr_hypercall(CPUPPCState *env, target_ulong opcode,
|
||||
target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode,
|
||||
target_ulong *args);
|
||||
|
||||
int spapr_allocate_irq(int hint, bool lsi);
|
||||
|
|
|
@ -75,9 +75,10 @@ static target_ulong compute_tlbie_rb(target_ulong v, target_ulong r,
|
|||
return rb;
|
||||
}
|
||||
|
||||
static target_ulong h_enter(CPUPPCState *env, sPAPREnvironment *spapr,
|
||||
static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
target_ulong opcode, target_ulong *args)
|
||||
{
|
||||
CPUPPCState *env = &cpu->env;
|
||||
target_ulong flags = args[0];
|
||||
target_ulong pte_index = args[1];
|
||||
target_ulong pteh = args[2];
|
||||
|
@ -192,9 +193,10 @@ static target_ulong remove_hpte(CPUPPCState *env, target_ulong ptex,
|
|||
return REMOVE_SUCCESS;
|
||||
}
|
||||
|
||||
static target_ulong h_remove(CPUPPCState *env, sPAPREnvironment *spapr,
|
||||
static target_ulong h_remove(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
target_ulong opcode, target_ulong *args)
|
||||
{
|
||||
CPUPPCState *env = &cpu->env;
|
||||
target_ulong flags = args[0];
|
||||
target_ulong pte_index = args[1];
|
||||
target_ulong avpn = args[2];
|
||||
|
@ -238,9 +240,10 @@ static target_ulong h_remove(CPUPPCState *env, sPAPREnvironment *spapr,
|
|||
|
||||
#define H_BULK_REMOVE_MAX_BATCH 4
|
||||
|
||||
static target_ulong h_bulk_remove(CPUPPCState *env, sPAPREnvironment *spapr,
|
||||
static target_ulong h_bulk_remove(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
target_ulong opcode, target_ulong *args)
|
||||
{
|
||||
CPUPPCState *env = &cpu->env;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < H_BULK_REMOVE_MAX_BATCH; i++) {
|
||||
|
@ -284,9 +287,10 @@ static target_ulong h_bulk_remove(CPUPPCState *env, sPAPREnvironment *spapr,
|
|||
return H_SUCCESS;
|
||||
}
|
||||
|
||||
static target_ulong h_protect(CPUPPCState *env, sPAPREnvironment *spapr,
|
||||
static target_ulong h_protect(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
target_ulong opcode, target_ulong *args)
|
||||
{
|
||||
CPUPPCState *env = &cpu->env;
|
||||
target_ulong flags = args[0];
|
||||
target_ulong pte_index = args[1];
|
||||
target_ulong avpn = args[2];
|
||||
|
@ -321,7 +325,7 @@ static target_ulong h_protect(CPUPPCState *env, sPAPREnvironment *spapr,
|
|||
return H_SUCCESS;
|
||||
}
|
||||
|
||||
static target_ulong h_set_dabr(CPUPPCState *env, sPAPREnvironment *spapr,
|
||||
static target_ulong h_set_dabr(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
target_ulong opcode, target_ulong *args)
|
||||
{
|
||||
/* FIXME: actually implement this */
|
||||
|
@ -457,7 +461,7 @@ static target_ulong deregister_dtl(CPUPPCState *env, target_ulong addr)
|
|||
return H_SUCCESS;
|
||||
}
|
||||
|
||||
static target_ulong h_register_vpa(CPUPPCState *env, sPAPREnvironment *spapr,
|
||||
static target_ulong h_register_vpa(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
target_ulong opcode, target_ulong *args)
|
||||
{
|
||||
target_ulong flags = args[0];
|
||||
|
@ -505,12 +509,14 @@ static target_ulong h_register_vpa(CPUPPCState *env, sPAPREnvironment *spapr,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static target_ulong h_cede(CPUPPCState *env, sPAPREnvironment *spapr,
|
||||
static target_ulong h_cede(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
target_ulong opcode, target_ulong *args)
|
||||
{
|
||||
CPUPPCState *env = &cpu->env;
|
||||
|
||||
env->msr |= (1ULL << MSR_EE);
|
||||
hreg_compute_hflags(env);
|
||||
if (!cpu_has_work(env)) {
|
||||
if (!cpu_has_work(CPU(cpu))) {
|
||||
env->halted = 1;
|
||||
env->exception_index = EXCP_HLT;
|
||||
env->exit_request = 1;
|
||||
|
@ -518,7 +524,7 @@ static target_ulong h_cede(CPUPPCState *env, sPAPREnvironment *spapr,
|
|||
return H_SUCCESS;
|
||||
}
|
||||
|
||||
static target_ulong h_rtas(CPUPPCState *env, sPAPREnvironment *spapr,
|
||||
static target_ulong h_rtas(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
target_ulong opcode, target_ulong *args)
|
||||
{
|
||||
target_ulong rtas_r3 = args[0];
|
||||
|
@ -530,7 +536,7 @@ static target_ulong h_rtas(CPUPPCState *env, sPAPREnvironment *spapr,
|
|||
nret, rtas_r3 + 12 + 4*nargs);
|
||||
}
|
||||
|
||||
static target_ulong h_logical_load(CPUPPCState *env, sPAPREnvironment *spapr,
|
||||
static target_ulong h_logical_load(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
target_ulong opcode, target_ulong *args)
|
||||
{
|
||||
target_ulong size = args[0];
|
||||
|
@ -553,7 +559,7 @@ static target_ulong h_logical_load(CPUPPCState *env, sPAPREnvironment *spapr,
|
|||
return H_PARAMETER;
|
||||
}
|
||||
|
||||
static target_ulong h_logical_store(CPUPPCState *env, sPAPREnvironment *spapr,
|
||||
static target_ulong h_logical_store(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
target_ulong opcode, target_ulong *args)
|
||||
{
|
||||
target_ulong size = args[0];
|
||||
|
@ -577,7 +583,7 @@ static target_ulong h_logical_store(CPUPPCState *env, sPAPREnvironment *spapr,
|
|||
return H_PARAMETER;
|
||||
}
|
||||
|
||||
static target_ulong h_logical_memop(CPUPPCState *env, sPAPREnvironment *spapr,
|
||||
static target_ulong h_logical_memop(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
target_ulong opcode, target_ulong *args)
|
||||
{
|
||||
target_ulong dst = args[0]; /* Destination address */
|
||||
|
@ -644,14 +650,14 @@ static target_ulong h_logical_memop(CPUPPCState *env, sPAPREnvironment *spapr,
|
|||
return H_SUCCESS;
|
||||
}
|
||||
|
||||
static target_ulong h_logical_icbi(CPUPPCState *env, sPAPREnvironment *spapr,
|
||||
static target_ulong h_logical_icbi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
target_ulong opcode, target_ulong *args)
|
||||
{
|
||||
/* Nothing to do on emulation, KVM will trap this in the kernel */
|
||||
return H_SUCCESS;
|
||||
}
|
||||
|
||||
static target_ulong h_logical_dcbf(CPUPPCState *env, sPAPREnvironment *spapr,
|
||||
static target_ulong h_logical_dcbf(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
target_ulong opcode, target_ulong *args)
|
||||
{
|
||||
/* Nothing to do on emulation, KVM will trap this in the kernel */
|
||||
|
@ -679,7 +685,7 @@ void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn)
|
|||
*slot = fn;
|
||||
}
|
||||
|
||||
target_ulong spapr_hypercall(CPUPPCState *env, target_ulong opcode,
|
||||
target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode,
|
||||
target_ulong *args)
|
||||
{
|
||||
if ((opcode <= MAX_HCALL_OPCODE)
|
||||
|
@ -687,14 +693,14 @@ target_ulong spapr_hypercall(CPUPPCState *env, target_ulong opcode,
|
|||
spapr_hcall_fn fn = papr_hypercall_table[opcode / 4];
|
||||
|
||||
if (fn) {
|
||||
return fn(env, spapr, opcode, args);
|
||||
return fn(cpu, spapr, opcode, args);
|
||||
}
|
||||
} else if ((opcode >= KVMPPC_HCALL_BASE) &&
|
||||
(opcode <= KVMPPC_HCALL_MAX)) {
|
||||
spapr_hcall_fn fn = kvmppc_hypercall_table[opcode - KVMPPC_HCALL_BASE];
|
||||
|
||||
if (fn) {
|
||||
return fn(env, spapr, opcode, args);
|
||||
return fn(cpu, spapr, opcode, args);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -204,7 +204,7 @@ static target_ulong put_tce_emu(sPAPRTCETable *tcet, target_ulong ioba,
|
|||
return H_SUCCESS;
|
||||
}
|
||||
|
||||
static target_ulong h_put_tce(CPUPPCState *env, sPAPREnvironment *spapr,
|
||||
static target_ulong h_put_tce(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
target_ulong opcode, target_ulong *args)
|
||||
{
|
||||
target_ulong liobn = args[0];
|
||||
|
|
|
@ -264,7 +264,7 @@ static int check_bd(VIOsPAPRVLANDevice *dev, vlan_bd_t bd,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static target_ulong h_register_logical_lan(CPUPPCState *env,
|
||||
static target_ulong h_register_logical_lan(PowerPCCPU *cpu,
|
||||
sPAPREnvironment *spapr,
|
||||
target_ulong opcode,
|
||||
target_ulong *args)
|
||||
|
@ -328,7 +328,7 @@ static target_ulong h_register_logical_lan(CPUPPCState *env,
|
|||
}
|
||||
|
||||
|
||||
static target_ulong h_free_logical_lan(CPUPPCState *env, sPAPREnvironment *spapr,
|
||||
static target_ulong h_free_logical_lan(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
target_ulong opcode, target_ulong *args)
|
||||
{
|
||||
target_ulong reg = args[0];
|
||||
|
@ -349,7 +349,7 @@ static target_ulong h_free_logical_lan(CPUPPCState *env, sPAPREnvironment *spapr
|
|||
return H_SUCCESS;
|
||||
}
|
||||
|
||||
static target_ulong h_add_logical_lan_buffer(CPUPPCState *env,
|
||||
static target_ulong h_add_logical_lan_buffer(PowerPCCPU *cpu,
|
||||
sPAPREnvironment *spapr,
|
||||
target_ulong opcode,
|
||||
target_ulong *args)
|
||||
|
@ -398,7 +398,7 @@ static target_ulong h_add_logical_lan_buffer(CPUPPCState *env,
|
|||
return H_SUCCESS;
|
||||
}
|
||||
|
||||
static target_ulong h_send_logical_lan(CPUPPCState *env, sPAPREnvironment *spapr,
|
||||
static target_ulong h_send_logical_lan(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
target_ulong opcode, target_ulong *args)
|
||||
{
|
||||
target_ulong reg = args[0];
|
||||
|
@ -467,7 +467,7 @@ static target_ulong h_send_logical_lan(CPUPPCState *env, sPAPREnvironment *spapr
|
|||
return H_SUCCESS;
|
||||
}
|
||||
|
||||
static target_ulong h_multicast_ctrl(CPUPPCState *env, sPAPREnvironment *spapr,
|
||||
static target_ulong h_multicast_ctrl(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
target_ulong opcode, target_ulong *args)
|
||||
{
|
||||
target_ulong reg = args[0];
|
||||
|
|
|
@ -439,6 +439,43 @@ static void pci_spapr_set_irq(void *opaque, int irq_num, int level)
|
|||
qemu_set_irq(spapr_phb_lsi_qirq(phb, irq_num), level);
|
||||
}
|
||||
|
||||
static uint64_t spapr_io_read(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
switch (size) {
|
||||
case 1:
|
||||
return cpu_inb(addr);
|
||||
case 2:
|
||||
return cpu_inw(addr);
|
||||
case 4:
|
||||
return cpu_inl(addr);
|
||||
}
|
||||
assert(0);
|
||||
}
|
||||
|
||||
static void spapr_io_write(void *opaque, hwaddr addr,
|
||||
uint64_t data, unsigned size)
|
||||
{
|
||||
switch (size) {
|
||||
case 1:
|
||||
cpu_outb(addr, data);
|
||||
return;
|
||||
case 2:
|
||||
cpu_outw(addr, data);
|
||||
return;
|
||||
case 4:
|
||||
cpu_outl(addr, data);
|
||||
return;
|
||||
}
|
||||
assert(0);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps spapr_io_ops = {
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
.read = spapr_io_read,
|
||||
.write = spapr_io_write
|
||||
};
|
||||
|
||||
/*
|
||||
* MSI/MSIX memory region implementation.
|
||||
* The handler handles both MSI and MSIX.
|
||||
|
@ -508,9 +545,14 @@ static int spapr_phb_init(SysBusDevice *s)
|
|||
* old_portion are updated */
|
||||
sprintf(namebuf, "%s.io", sphb->dtbusname);
|
||||
memory_region_init(&sphb->iospace, namebuf, SPAPR_PCI_IO_WIN_SIZE);
|
||||
/* FIXME: fix to support multiple PHBs */
|
||||
memory_region_add_subregion(get_system_io(), 0, &sphb->iospace);
|
||||
|
||||
sprintf(namebuf, "%s.io-alias", sphb->dtbusname);
|
||||
memory_region_init_io(&sphb->iowindow, &spapr_io_ops, sphb,
|
||||
namebuf, SPAPR_PCI_IO_WIN_SIZE);
|
||||
memory_region_add_subregion(get_system_memory(), sphb->io_win_addr,
|
||||
&sphb->iospace);
|
||||
&sphb->iowindow);
|
||||
|
||||
/* As MSI/MSIX interrupts trigger by writing at MSI/MSIX vectors,
|
||||
* we need to allocate some memory to catch those writes coming
|
||||
|
|
|
@ -44,7 +44,7 @@ typedef struct sPAPRPHBState {
|
|||
MemoryRegion memspace, iospace;
|
||||
hwaddr mem_win_addr, mem_win_size, io_win_addr, io_win_size;
|
||||
hwaddr msi_win_addr;
|
||||
MemoryRegion memwindow, msiwindow;
|
||||
MemoryRegion memwindow, iowindow, msiwindow;
|
||||
|
||||
uint32_t dma_liobn;
|
||||
uint64_t dma_window_start;
|
||||
|
|
|
@ -163,6 +163,7 @@ static void rtas_start_cpu(sPAPREnvironment *spapr,
|
|||
uint32_t nret, target_ulong rets)
|
||||
{
|
||||
target_ulong id, start, r3;
|
||||
CPUState *cpu;
|
||||
CPUPPCState *env;
|
||||
|
||||
if (nargs != 3 || nret != 1) {
|
||||
|
@ -175,6 +176,8 @@ static void rtas_start_cpu(sPAPREnvironment *spapr,
|
|||
r3 = rtas_ld(args, 2);
|
||||
|
||||
for (env = first_cpu; env; env = env->next_cpu) {
|
||||
cpu = ENV_GET_CPU(env);
|
||||
|
||||
if (env->cpu_index != id) {
|
||||
continue;
|
||||
}
|
||||
|
@ -194,7 +197,7 @@ static void rtas_start_cpu(sPAPREnvironment *spapr,
|
|||
env->gpr[3] = r3;
|
||||
env->halted = 0;
|
||||
|
||||
qemu_cpu_kick(env);
|
||||
qemu_cpu_kick(cpu);
|
||||
|
||||
rtas_st(rets, 0, 0);
|
||||
return;
|
||||
|
|
|
@ -161,7 +161,7 @@ static int vio_make_devnode(VIOsPAPRDevice *dev,
|
|||
/*
|
||||
* CRQ handling
|
||||
*/
|
||||
static target_ulong h_reg_crq(CPUPPCState *env, sPAPREnvironment *spapr,
|
||||
static target_ulong h_reg_crq(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
target_ulong opcode, target_ulong *args)
|
||||
{
|
||||
target_ulong reg = args[0];
|
||||
|
@ -219,7 +219,7 @@ static target_ulong free_crq(VIOsPAPRDevice *dev)
|
|||
return H_SUCCESS;
|
||||
}
|
||||
|
||||
static target_ulong h_free_crq(CPUPPCState *env, sPAPREnvironment *spapr,
|
||||
static target_ulong h_free_crq(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
target_ulong opcode, target_ulong *args)
|
||||
{
|
||||
target_ulong reg = args[0];
|
||||
|
@ -233,7 +233,7 @@ static target_ulong h_free_crq(CPUPPCState *env, sPAPREnvironment *spapr,
|
|||
return free_crq(dev);
|
||||
}
|
||||
|
||||
static target_ulong h_send_crq(CPUPPCState *env, sPAPREnvironment *spapr,
|
||||
static target_ulong h_send_crq(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
target_ulong opcode, target_ulong *args)
|
||||
{
|
||||
target_ulong reg = args[0];
|
||||
|
@ -256,7 +256,7 @@ static target_ulong h_send_crq(CPUPPCState *env, sPAPREnvironment *spapr,
|
|||
return H_HARDWARE;
|
||||
}
|
||||
|
||||
static target_ulong h_enable_crq(CPUPPCState *env, sPAPREnvironment *spapr,
|
||||
static target_ulong h_enable_crq(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
target_ulong opcode, target_ulong *args)
|
||||
{
|
||||
target_ulong reg = args[0];
|
||||
|
@ -463,7 +463,7 @@ static int spapr_vio_busdev_init(DeviceState *qdev)
|
|||
return pc->init(dev);
|
||||
}
|
||||
|
||||
static target_ulong h_vio_signal(CPUPPCState *env, sPAPREnvironment *spapr,
|
||||
static target_ulong h_vio_signal(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
target_ulong opcode,
|
||||
target_ulong *args)
|
||||
{
|
||||
|
|
|
@ -70,7 +70,7 @@ static int spapr_vty_init(VIOsPAPRDevice *sdev)
|
|||
}
|
||||
|
||||
/* Forward declaration */
|
||||
static target_ulong h_put_term_char(CPUPPCState *env, sPAPREnvironment *spapr,
|
||||
static target_ulong h_put_term_char(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
target_ulong opcode, target_ulong *args)
|
||||
{
|
||||
target_ulong reg = args[0];
|
||||
|
@ -97,7 +97,7 @@ static target_ulong h_put_term_char(CPUPPCState *env, sPAPREnvironment *spapr,
|
|||
return H_SUCCESS;
|
||||
}
|
||||
|
||||
static target_ulong h_get_term_char(CPUPPCState *env, sPAPREnvironment *spapr,
|
||||
static target_ulong h_get_term_char(PowerPCCPU *cpu, sPAPREnvironment *spapr,
|
||||
target_ulong opcode, target_ulong *args)
|
||||
{
|
||||
target_ulong reg = args[0];
|
||||
|
|
45
hw/spitz.c
45
hw/spitz.c
|
@ -879,15 +879,14 @@ static struct arm_boot_info spitz_binfo = {
|
|||
.ram_size = 0x04000000,
|
||||
};
|
||||
|
||||
static void spitz_common_init(ram_addr_t ram_size,
|
||||
const char *kernel_filename,
|
||||
const char *kernel_cmdline, const char *initrd_filename,
|
||||
const char *cpu_model, enum spitz_model_e model, int arm_id)
|
||||
static void spitz_common_init(QEMUMachineInitArgs *args,
|
||||
enum spitz_model_e model, int arm_id)
|
||||
{
|
||||
PXA2xxState *mpu;
|
||||
DeviceState *scp0, *scp1 = NULL;
|
||||
MemoryRegion *address_space_mem = get_system_memory();
|
||||
MemoryRegion *rom = g_new(MemoryRegion, 1);
|
||||
const char *cpu_model = args->cpu_model;
|
||||
|
||||
if (!cpu_model)
|
||||
cpu_model = (model == terrier) ? "pxa270-c5" : "pxa270-c0";
|
||||
|
@ -928,9 +927,9 @@ static void spitz_common_init(ram_addr_t ram_size,
|
|||
/* A 4.0 GB microdrive is permanently sitting in CF slot 0. */
|
||||
spitz_microdrive_attach(mpu, 0);
|
||||
|
||||
spitz_binfo.kernel_filename = kernel_filename;
|
||||
spitz_binfo.kernel_cmdline = kernel_cmdline;
|
||||
spitz_binfo.initrd_filename = initrd_filename;
|
||||
spitz_binfo.kernel_filename = args->kernel_filename;
|
||||
spitz_binfo.kernel_cmdline = args->kernel_cmdline;
|
||||
spitz_binfo.initrd_filename = args->initrd_filename;
|
||||
spitz_binfo.board_id = arm_id;
|
||||
arm_load_kernel(mpu->cpu, &spitz_binfo);
|
||||
sl_bootparam_write(SL_PXA_PARAM_BASE);
|
||||
|
@ -938,46 +937,22 @@ static void spitz_common_init(ram_addr_t ram_size,
|
|||
|
||||
static void spitz_init(QEMUMachineInitArgs *args)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
spitz_common_init(ram_size, kernel_filename,
|
||||
kernel_cmdline, initrd_filename, cpu_model, spitz, 0x2c9);
|
||||
spitz_common_init(args, spitz, 0x2c9);
|
||||
}
|
||||
|
||||
static void borzoi_init(QEMUMachineInitArgs *args)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
spitz_common_init(ram_size, kernel_filename,
|
||||
kernel_cmdline, initrd_filename, cpu_model, borzoi, 0x33f);
|
||||
spitz_common_init(args, borzoi, 0x33f);
|
||||
}
|
||||
|
||||
static void akita_init(QEMUMachineInitArgs *args)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
spitz_common_init(ram_size, kernel_filename,
|
||||
kernel_cmdline, initrd_filename, cpu_model, akita, 0x2e8);
|
||||
spitz_common_init(args, akita, 0x2e8);
|
||||
}
|
||||
|
||||
static void terrier_init(QEMUMachineInitArgs *args)
|
||||
{
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
const char *cpu_model = args->cpu_model;
|
||||
const char *kernel_filename = args->kernel_filename;
|
||||
const char *kernel_cmdline = args->kernel_cmdline;
|
||||
const char *initrd_filename = args->initrd_filename;
|
||||
spitz_common_init(ram_size, kernel_filename,
|
||||
kernel_cmdline, initrd_filename, cpu_model, terrier, 0x33f);
|
||||
spitz_common_init(args, terrier, 0x33f);
|
||||
}
|
||||
|
||||
static QEMUMachine akitapda_machine = {
|
||||
|
|
|
@ -252,7 +252,7 @@ static void ssd0303_update_display(void *opaque)
|
|||
}
|
||||
}
|
||||
s->redraw = 0;
|
||||
dpy_update(s->ds, 0, 0, 96 * MAGNIFY, 16 * MAGNIFY);
|
||||
dpy_gfx_update(s->ds, 0, 0, 96 * MAGNIFY, 16 * MAGNIFY);
|
||||
}
|
||||
|
||||
static void ssd0303_invalidate_display(void * opaque)
|
||||
|
|
|
@ -260,7 +260,7 @@ static void ssd0323_update_display(void *opaque)
|
|||
}
|
||||
}
|
||||
s->redraw = 0;
|
||||
dpy_update(s->ds, 0, 0, 128 * MAGNIFY, 64 * MAGNIFY);
|
||||
dpy_gfx_update(s->ds, 0, 0, 128 * MAGNIFY, 64 * MAGNIFY);
|
||||
}
|
||||
|
||||
static void ssd0323_invalidate_display(void * opaque)
|
||||
|
|
|
@ -94,29 +94,6 @@ static const MemoryRegionOps sun4c_intctl_mem_ops = {
|
|||
},
|
||||
};
|
||||
|
||||
void sun4c_pic_info(Monitor *mon, void *opaque)
|
||||
{
|
||||
Sun4c_INTCTLState *s = opaque;
|
||||
|
||||
monitor_printf(mon, "master: pending 0x%2.2x, enabled 0x%2.2x\n",
|
||||
s->pending, s->reg);
|
||||
}
|
||||
|
||||
void sun4c_irq_info(Monitor *mon, void *opaque)
|
||||
{
|
||||
#ifndef DEBUG_IRQ_COUNT
|
||||
monitor_printf(mon, "irq statistic code not compiled.\n");
|
||||
#else
|
||||
Sun4c_INTCTLState *s = opaque;
|
||||
int64_t count;
|
||||
|
||||
monitor_printf(mon, "IRQ statistics:\n");
|
||||
count = s->irq_count;
|
||||
if (count > 0)
|
||||
monitor_printf(mon, " %" PRId64 "\n", count);
|
||||
#endif
|
||||
}
|
||||
|
||||
static const uint32_t intbit_to_level[] = { 0, 1, 4, 6, 8, 10, 0, 14, };
|
||||
|
||||
static void sun4c_check_interrupts(void *opaque)
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue