mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging
* NBD and chardev conversion to QIONetListener (Daniel) * MTTCG fixes (David) * Hyper-V fixes (Roman, Evgeny) * share-rw option (Fam) * Mux chardev event bugfix (Marc-André) * Add systemd unit files in contrib/ (me) * SCSI and block/iscsi.c bugfixes (me, Peter L.) * unassigned_mem_ops fixes (Peter M.) * VEX decoding fix (Peter M.) * "info pic" and "info irq" improvements (Peter Xu) * vmport trace events (Philippe) * Braille chardev bugfix (Samuel) * Compiler warnings fix (Stefan) * initial support for TCG smoke test of more boards (Thomas) * New CPU features (Yang) * Reduce startup memory usage (Yang) * QemuThread race fix (linhecheng) # gpg: Signature made Thu 21 Dec 2017 08:30:49 GMT # gpg: using RSA key 0xBFFBD25F78C7AE83 # gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" # gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" # Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4 E2F7 7E15 100C CD36 69B1 # Subkey fingerprint: F133 3857 4B66 2389 866C 7682 BFFB D25F 78C7 AE83 * remotes/bonzini/tags/for-upstream: (41 commits) chardev: convert the socket server to QIONetListener blockdev: convert qemu-nbd server to QIONetListener blockdev: convert internal NBD server to QIONetListener test: add some chardev mux event tests chardev: fix backend events regression with mux chardev rcu: reduce more than 7MB heap memory by malloc_trim() checkpatch: volatile with a comment or sig_atomic_t is okay i8259: move TYPE_INTERRUPT_STATS_PROVIDER upper kvm-i8259: support "info pic" and "info irq" i8259: generalize statistics into common code i8259: use DEBUG_IRQ_COUNT always i8259: convert DPRINTFs into trace Remove legacy -no-kvm-pit option scsi: replace hex constants with #defines scsi: provide general-purpose functions to manage sense data hw/i386/vmport: replace fprintf() by trace events or LOG_UNIMP hw/mips/boston: Remove workaround for writes to ROM aborting exec: Don't reuse unassigned_mem_ops for io_mem_rom block/iscsi: only report an iSCSI Failure if we don't handle it gracefully block/iscsi: dont leave allocmap in an invalid state on UNMAP failure ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
@@ -1011,6 +1011,7 @@ T: git git://github.com/jasowang/qemu.git net
|
||||
|
||||
SCSI
|
||||
M: Paolo Bonzini <pbonzini@redhat.com>
|
||||
R: Fam Zheng <famz@redhat.com>
|
||||
S: Supported
|
||||
F: include/hw/scsi/*
|
||||
F: hw/scsi/*
|
||||
@@ -1271,6 +1272,7 @@ T: git git://github.com/stefanha/qemu.git block
|
||||
|
||||
Block SCSI subsystem
|
||||
M: Paolo Bonzini <pbonzini@redhat.com>
|
||||
R: Fam Zheng <famz@redhat.com>
|
||||
L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: include/scsi/*
|
||||
|
||||
@@ -525,19 +525,13 @@ static inline bool cpu_handle_interrupt(CPUState *cpu,
|
||||
TranslationBlock **last_tb)
|
||||
{
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
int32_t insns_left;
|
||||
|
||||
/* Clear the interrupt flag now since we're processing
|
||||
* cpu->interrupt_request and cpu->exit_request.
|
||||
* Ensure zeroing happens before reading cpu->exit_request or
|
||||
* cpu->interrupt_request (see also smp_wmb in cpu_exit())
|
||||
*/
|
||||
insns_left = atomic_read(&cpu->icount_decr.u32);
|
||||
atomic_set(&cpu->icount_decr.u16.high, 0);
|
||||
if (unlikely(insns_left < 0)) {
|
||||
/* Ensure the zeroing of icount_decr comes before the next read
|
||||
* of cpu->exit_request or cpu->interrupt_request.
|
||||
*/
|
||||
smp_mb();
|
||||
}
|
||||
atomic_mb_set(&cpu->icount_decr.u16.high, 0);
|
||||
|
||||
if (unlikely(atomic_read(&cpu->interrupt_request))) {
|
||||
int interrupt_request;
|
||||
|
||||
+36
-15
@@ -2,7 +2,7 @@
|
||||
* QEMU Block driver for iSCSI images
|
||||
*
|
||||
* Copyright (c) 2010-2011 Ronnie Sahlberg <ronniesahlberg@gmail.com>
|
||||
* Copyright (c) 2012-2016 Peter Lieven <pl@kamp.de>
|
||||
* Copyright (c) 2012-2017 Peter Lieven <pl@kamp.de>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -104,6 +104,7 @@ typedef struct IscsiTask {
|
||||
IscsiLun *iscsilun;
|
||||
QEMUTimer retry_timer;
|
||||
int err_code;
|
||||
char *err_str;
|
||||
} IscsiTask;
|
||||
|
||||
typedef struct IscsiAIOCB {
|
||||
@@ -265,7 +266,7 @@ iscsi_co_generic_cb(struct iscsi_context *iscsi, int status,
|
||||
}
|
||||
}
|
||||
iTask->err_code = iscsi_translate_sense(&task->sense);
|
||||
error_report("iSCSI Failure: %s", iscsi_get_error(iscsi));
|
||||
iTask->err_str = g_strdup(iscsi_get_error(iscsi));
|
||||
}
|
||||
|
||||
out:
|
||||
@@ -629,6 +630,8 @@ retry:
|
||||
|
||||
if (iTask.status != SCSI_STATUS_GOOD) {
|
||||
iscsi_allocmap_set_invalid(iscsilun, sector_num, nb_sectors);
|
||||
error_report("iSCSI WRITE10/16 failed at lba %" PRIu64 ": %s", lba,
|
||||
iTask.err_str);
|
||||
r = iTask.err_code;
|
||||
goto out_unlock;
|
||||
}
|
||||
@@ -637,6 +640,7 @@ retry:
|
||||
|
||||
out_unlock:
|
||||
qemu_mutex_unlock(&iscsilun->mutex);
|
||||
g_free(iTask.err_str);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -651,10 +655,9 @@ static int64_t coroutine_fn iscsi_co_get_block_status(BlockDriverState *bs,
|
||||
struct scsi_get_lba_status *lbas = NULL;
|
||||
struct scsi_lba_status_descriptor *lbasd = NULL;
|
||||
struct IscsiTask iTask;
|
||||
uint64_t lba;
|
||||
int64_t ret;
|
||||
|
||||
iscsi_co_init_iscsitask(iscsilun, &iTask);
|
||||
|
||||
if (!is_sector_request_lun_aligned(sector_num, nb_sectors, iscsilun)) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
@@ -670,11 +673,13 @@ static int64_t coroutine_fn iscsi_co_get_block_status(BlockDriverState *bs,
|
||||
goto out;
|
||||
}
|
||||
|
||||
lba = sector_qemu2lun(sector_num, iscsilun);
|
||||
|
||||
iscsi_co_init_iscsitask(iscsilun, &iTask);
|
||||
qemu_mutex_lock(&iscsilun->mutex);
|
||||
retry:
|
||||
if (iscsi_get_lba_status_task(iscsilun->iscsi, iscsilun->lun,
|
||||
sector_qemu2lun(sector_num, iscsilun),
|
||||
8 + 16, iscsi_co_generic_cb,
|
||||
lba, 8 + 16, iscsi_co_generic_cb,
|
||||
&iTask) == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto out_unlock;
|
||||
@@ -701,6 +706,8 @@ retry:
|
||||
* because the device is busy or the cmd is not
|
||||
* supported) we pretend all blocks are allocated
|
||||
* for backwards compatibility */
|
||||
error_report("iSCSI GET_LBA_STATUS failed at lba %" PRIu64 ": %s",
|
||||
lba, iTask.err_str);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
@@ -738,6 +745,7 @@ retry:
|
||||
}
|
||||
out_unlock:
|
||||
qemu_mutex_unlock(&iscsilun->mutex);
|
||||
g_free(iTask.err_str);
|
||||
out:
|
||||
if (iTask.task != NULL) {
|
||||
scsi_free_scsi_task(iTask.task);
|
||||
@@ -756,6 +764,7 @@ static int coroutine_fn iscsi_co_readv(BlockDriverState *bs,
|
||||
struct IscsiTask iTask;
|
||||
uint64_t lba;
|
||||
uint32_t num_sectors;
|
||||
int r = 0;
|
||||
|
||||
if (!is_sector_request_lun_aligned(sector_num, nb_sectors, iscsilun)) {
|
||||
return -EINVAL;
|
||||
@@ -853,19 +862,23 @@ retry:
|
||||
iTask.complete = 0;
|
||||
goto retry;
|
||||
}
|
||||
qemu_mutex_unlock(&iscsilun->mutex);
|
||||
|
||||
if (iTask.status != SCSI_STATUS_GOOD) {
|
||||
return iTask.err_code;
|
||||
error_report("iSCSI READ10/16 failed at lba %" PRIu64 ": %s",
|
||||
lba, iTask.err_str);
|
||||
r = iTask.err_code;
|
||||
}
|
||||
|
||||
return 0;
|
||||
qemu_mutex_unlock(&iscsilun->mutex);
|
||||
g_free(iTask.err_str);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int coroutine_fn iscsi_co_flush(BlockDriverState *bs)
|
||||
{
|
||||
IscsiLun *iscsilun = bs->opaque;
|
||||
struct IscsiTask iTask;
|
||||
int r = 0;
|
||||
|
||||
iscsi_co_init_iscsitask(iscsilun, &iTask);
|
||||
qemu_mutex_lock(&iscsilun->mutex);
|
||||
@@ -892,13 +905,15 @@ retry:
|
||||
iTask.complete = 0;
|
||||
goto retry;
|
||||
}
|
||||
qemu_mutex_unlock(&iscsilun->mutex);
|
||||
|
||||
if (iTask.status != SCSI_STATUS_GOOD) {
|
||||
return iTask.err_code;
|
||||
error_report("iSCSI SYNCHRONIZECACHE10 failed: %s", iTask.err_str);
|
||||
r = iTask.err_code;
|
||||
}
|
||||
|
||||
return 0;
|
||||
qemu_mutex_unlock(&iscsilun->mutex);
|
||||
g_free(iTask.err_str);
|
||||
return r;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
@@ -1128,6 +1143,9 @@ retry:
|
||||
goto retry;
|
||||
}
|
||||
|
||||
iscsi_allocmap_set_invalid(iscsilun, offset >> BDRV_SECTOR_BITS,
|
||||
bytes >> BDRV_SECTOR_BITS);
|
||||
|
||||
if (iTask.status == SCSI_STATUS_CHECK_CONDITION) {
|
||||
/* the target might fail with a check condition if it
|
||||
is not happy with the alignment of the UNMAP request
|
||||
@@ -1136,15 +1154,15 @@ retry:
|
||||
}
|
||||
|
||||
if (iTask.status != SCSI_STATUS_GOOD) {
|
||||
error_report("iSCSI UNMAP failed at lba %" PRIu64 ": %s",
|
||||
list.lba, iTask.err_str);
|
||||
r = iTask.err_code;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
iscsi_allocmap_set_invalid(iscsilun, offset >> BDRV_SECTOR_BITS,
|
||||
bytes >> BDRV_SECTOR_BITS);
|
||||
|
||||
out_unlock:
|
||||
qemu_mutex_unlock(&iscsilun->mutex);
|
||||
g_free(iTask.err_str);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -1241,6 +1259,8 @@ retry:
|
||||
if (iTask.status != SCSI_STATUS_GOOD) {
|
||||
iscsi_allocmap_set_invalid(iscsilun, offset >> BDRV_SECTOR_BITS,
|
||||
bytes >> BDRV_SECTOR_BITS);
|
||||
error_report("iSCSI WRITESAME10/16 failed at lba %" PRIu64 ": %s",
|
||||
lba, iTask.err_str);
|
||||
r = iTask.err_code;
|
||||
goto out_unlock;
|
||||
}
|
||||
@@ -1255,6 +1275,7 @@ retry:
|
||||
|
||||
out_unlock:
|
||||
qemu_mutex_unlock(&iscsilun->mutex);
|
||||
g_free(iTask.err_str);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
+16
-34
@@ -18,10 +18,10 @@
|
||||
#include "qmp-commands.h"
|
||||
#include "block/nbd.h"
|
||||
#include "io/channel-socket.h"
|
||||
#include "io/net-listener.h"
|
||||
|
||||
typedef struct NBDServerData {
|
||||
QIOChannelSocket *listen_ioc;
|
||||
int watch;
|
||||
QIONetListener *listener;
|
||||
QCryptoTLSCreds *tlscreds;
|
||||
} NBDServerData;
|
||||
|
||||
@@ -32,27 +32,13 @@ static void nbd_blockdev_client_closed(NBDClient *client, bool ignored)
|
||||
nbd_client_put(client);
|
||||
}
|
||||
|
||||
static gboolean nbd_accept(QIOChannel *ioc, GIOCondition condition,
|
||||
gpointer opaque)
|
||||
static void nbd_accept(QIONetListener *listener, QIOChannelSocket *cioc,
|
||||
gpointer opaque)
|
||||
{
|
||||
QIOChannelSocket *cioc;
|
||||
|
||||
if (!nbd_server) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
cioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc),
|
||||
NULL);
|
||||
if (!cioc) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
qio_channel_set_name(QIO_CHANNEL(cioc), "nbd-server");
|
||||
nbd_client_new(NULL, cioc,
|
||||
nbd_server->tlscreds, NULL,
|
||||
nbd_blockdev_client_closed);
|
||||
object_unref(OBJECT(cioc));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
@@ -62,10 +48,8 @@ static void nbd_server_free(NBDServerData *server)
|
||||
return;
|
||||
}
|
||||
|
||||
if (server->watch != -1) {
|
||||
g_source_remove(server->watch);
|
||||
}
|
||||
object_unref(OBJECT(server->listen_ioc));
|
||||
qio_net_listener_disconnect(server->listener);
|
||||
object_unref(OBJECT(server->listener));
|
||||
if (server->tlscreds) {
|
||||
object_unref(OBJECT(server->tlscreds));
|
||||
}
|
||||
@@ -112,12 +96,12 @@ void nbd_server_start(SocketAddress *addr, const char *tls_creds,
|
||||
}
|
||||
|
||||
nbd_server = g_new0(NBDServerData, 1);
|
||||
nbd_server->watch = -1;
|
||||
nbd_server->listen_ioc = qio_channel_socket_new();
|
||||
qio_channel_set_name(QIO_CHANNEL(nbd_server->listen_ioc),
|
||||
"nbd-listener");
|
||||
if (qio_channel_socket_listen_sync(
|
||||
nbd_server->listen_ioc, addr, errp) < 0) {
|
||||
nbd_server->listener = qio_net_listener_new();
|
||||
|
||||
qio_net_listener_set_name(nbd_server->listener,
|
||||
"nbd-listener");
|
||||
|
||||
if (qio_net_listener_open_sync(nbd_server->listener, addr, errp) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
@@ -134,12 +118,10 @@ void nbd_server_start(SocketAddress *addr, const char *tls_creds,
|
||||
}
|
||||
}
|
||||
|
||||
nbd_server->watch = qio_channel_add_watch(
|
||||
QIO_CHANNEL(nbd_server->listen_ioc),
|
||||
G_IO_IN,
|
||||
nbd_accept,
|
||||
NULL,
|
||||
NULL);
|
||||
qio_net_listener_set_client_func(nbd_server->listener,
|
||||
nbd_accept,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
return;
|
||||
|
||||
|
||||
+7
-1
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* QEMU Baum Braille Device
|
||||
*
|
||||
* Copyright (c) 2008, 2010-2011, 2016 Samuel Thibault
|
||||
* Copyright (c) 2008, 2010-2011, 2016-2017 Samuel Thibault
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -239,6 +239,12 @@ static int baum_deferred_init(BaumChardev *baum)
|
||||
brlapi_perror("baum: brlapi__getDisplaySize");
|
||||
return 0;
|
||||
}
|
||||
if (baum->y > 1) {
|
||||
baum->y = 1;
|
||||
}
|
||||
if (baum->x > 84) {
|
||||
baum->x = 84;
|
||||
}
|
||||
|
||||
con = qemu_console_lookup_by_index(0);
|
||||
if (con && qemu_console_is_graphic(con)) {
|
||||
|
||||
@@ -123,6 +123,15 @@ static void mux_chr_send_event(MuxChardev *d, int mux_nr, int event)
|
||||
}
|
||||
}
|
||||
|
||||
static void mux_chr_be_event(Chardev *chr, int event)
|
||||
{
|
||||
MuxChardev *d = MUX_CHARDEV(chr);
|
||||
|
||||
if (d->focus != -1) {
|
||||
mux_chr_send_event(d, d->focus, event);
|
||||
}
|
||||
}
|
||||
|
||||
static int mux_proc_byte(Chardev *chr, MuxChardev *d, int ch)
|
||||
{
|
||||
if (d->term_got_escape) {
|
||||
@@ -346,6 +355,7 @@ static void char_mux_class_init(ObjectClass *oc, void *data)
|
||||
cc->chr_write = mux_chr_write;
|
||||
cc->chr_accept_input = mux_chr_accept_input;
|
||||
cc->chr_add_watch = mux_chr_add_watch;
|
||||
cc->chr_be_event = mux_chr_be_event;
|
||||
}
|
||||
|
||||
static const TypeInfo char_mux_type_info = {
|
||||
|
||||
+30
-43
@@ -25,6 +25,7 @@
|
||||
#include "chardev/char.h"
|
||||
#include "io/channel-socket.h"
|
||||
#include "io/channel-tls.h"
|
||||
#include "io/net-listener.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/clone-visitor.h"
|
||||
@@ -40,8 +41,7 @@ typedef struct {
|
||||
Chardev parent;
|
||||
QIOChannel *ioc; /* Client I/O channel */
|
||||
QIOChannelSocket *sioc; /* Client master channel */
|
||||
QIOChannelSocket *listen_ioc;
|
||||
guint listen_tag;
|
||||
QIONetListener *listener;
|
||||
QCryptoTLSCreds *tls_creds;
|
||||
int connected;
|
||||
int max_size;
|
||||
@@ -93,9 +93,9 @@ static void check_report_connect_error(Chardev *chr,
|
||||
qemu_chr_socket_restart_timer(chr);
|
||||
}
|
||||
|
||||
static gboolean tcp_chr_accept(QIOChannel *chan,
|
||||
GIOCondition cond,
|
||||
void *opaque);
|
||||
static void tcp_chr_accept(QIONetListener *listener,
|
||||
QIOChannelSocket *cioc,
|
||||
void *opaque);
|
||||
|
||||
static int tcp_chr_read_poll(void *opaque);
|
||||
static void tcp_chr_disconnect(Chardev *chr);
|
||||
@@ -401,9 +401,9 @@ static void tcp_chr_disconnect(Chardev *chr)
|
||||
|
||||
tcp_chr_free_connection(chr);
|
||||
|
||||
if (s->listen_ioc && s->listen_tag == 0) {
|
||||
s->listen_tag = qio_channel_add_watch(
|
||||
QIO_CHANNEL(s->listen_ioc), G_IO_IN, tcp_chr_accept, chr, NULL);
|
||||
if (s->listener) {
|
||||
qio_net_listener_set_client_func(s->listener, tcp_chr_accept,
|
||||
chr, NULL);
|
||||
}
|
||||
update_disconnected_filename(s);
|
||||
if (emit_close) {
|
||||
@@ -702,9 +702,8 @@ static int tcp_chr_new_client(Chardev *chr, QIOChannelSocket *sioc)
|
||||
if (s->do_nodelay) {
|
||||
qio_channel_set_delay(s->ioc, false);
|
||||
}
|
||||
if (s->listen_tag) {
|
||||
g_source_remove(s->listen_tag);
|
||||
s->listen_tag = 0;
|
||||
if (s->listener) {
|
||||
qio_net_listener_set_client_func(s->listener, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
if (s->tls_creds) {
|
||||
@@ -736,24 +735,14 @@ static int tcp_chr_add_client(Chardev *chr, int fd)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean tcp_chr_accept(QIOChannel *channel,
|
||||
GIOCondition cond,
|
||||
void *opaque)
|
||||
static void tcp_chr_accept(QIONetListener *listener,
|
||||
QIOChannelSocket *cioc,
|
||||
void *opaque)
|
||||
{
|
||||
Chardev *chr = CHARDEV(opaque);
|
||||
QIOChannelSocket *sioc;
|
||||
|
||||
sioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(channel),
|
||||
NULL);
|
||||
if (!sioc) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
tcp_chr_new_client(chr, sioc);
|
||||
|
||||
object_unref(OBJECT(sioc));
|
||||
|
||||
return TRUE;
|
||||
tcp_chr_set_client_ioc_name(chr, cioc);
|
||||
tcp_chr_new_client(chr, cioc);
|
||||
}
|
||||
|
||||
static int tcp_chr_wait_connected(Chardev *chr, Error **errp)
|
||||
@@ -767,9 +756,10 @@ static int tcp_chr_wait_connected(Chardev *chr, Error **errp)
|
||||
if (s->is_listen) {
|
||||
info_report("QEMU waiting for connection on: %s",
|
||||
chr->filename);
|
||||
qio_channel_set_blocking(QIO_CHANNEL(s->listen_ioc), true, NULL);
|
||||
tcp_chr_accept(QIO_CHANNEL(s->listen_ioc), G_IO_IN, chr);
|
||||
qio_channel_set_blocking(QIO_CHANNEL(s->listen_ioc), false, NULL);
|
||||
sioc = qio_net_listener_wait_client(s->listener);
|
||||
tcp_chr_set_client_ioc_name(chr, sioc);
|
||||
tcp_chr_new_client(chr, sioc);
|
||||
object_unref(OBJECT(sioc));
|
||||
} else {
|
||||
sioc = qio_channel_socket_new();
|
||||
tcp_chr_set_client_ioc_name(chr, sioc);
|
||||
@@ -797,12 +787,9 @@ static void char_socket_finalize(Object *obj)
|
||||
s->reconnect_timer = 0;
|
||||
}
|
||||
qapi_free_SocketAddress(s->addr);
|
||||
if (s->listen_tag) {
|
||||
g_source_remove(s->listen_tag);
|
||||
s->listen_tag = 0;
|
||||
}
|
||||
if (s->listen_ioc) {
|
||||
object_unref(OBJECT(s->listen_ioc));
|
||||
if (s->listener) {
|
||||
qio_net_listener_set_client_func(s->listener, NULL, NULL, NULL);
|
||||
object_unref(OBJECT(s->listener));
|
||||
}
|
||||
if (s->tls_creds) {
|
||||
object_unref(OBJECT(s->tls_creds));
|
||||
@@ -935,29 +922,29 @@ static void qmp_chardev_open_socket(Chardev *chr,
|
||||
} else {
|
||||
if (s->is_listen) {
|
||||
char *name;
|
||||
sioc = qio_channel_socket_new();
|
||||
s->listener = qio_net_listener_new();
|
||||
|
||||
name = g_strdup_printf("chardev-tcp-listener-%s", chr->label);
|
||||
qio_channel_set_name(QIO_CHANNEL(sioc), name);
|
||||
qio_net_listener_set_name(s->listener, name);
|
||||
g_free(name);
|
||||
|
||||
if (qio_channel_socket_listen_sync(sioc, s->addr, errp) < 0) {
|
||||
if (qio_net_listener_open_sync(s->listener, s->addr, errp) < 0) {
|
||||
object_unref(OBJECT(s->listener));
|
||||
s->listener = NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
qapi_free_SocketAddress(s->addr);
|
||||
s->addr = socket_local_address(sioc->fd, errp);
|
||||
s->addr = socket_local_address(s->listener->sioc[0]->fd, errp);
|
||||
update_disconnected_filename(s);
|
||||
|
||||
s->listen_ioc = sioc;
|
||||
if (is_waitconnect &&
|
||||
qemu_chr_wait_connected(chr, errp) < 0) {
|
||||
return;
|
||||
}
|
||||
if (!s->ioc) {
|
||||
s->listen_tag = qio_channel_add_watch(
|
||||
QIO_CHANNEL(s->listen_ioc), G_IO_IN,
|
||||
tcp_chr_accept, chr, NULL);
|
||||
qio_net_listener_set_client_func(s->listener, tcp_chr_accept,
|
||||
chr, NULL);
|
||||
}
|
||||
} else if (qemu_chr_wait_connected(chr, errp) < 0) {
|
||||
goto error;
|
||||
|
||||
+12
-6
@@ -43,10 +43,19 @@ static Object *get_chardevs_root(void)
|
||||
return container_get(object_get_root(), "/chardevs");
|
||||
}
|
||||
|
||||
void qemu_chr_be_event(Chardev *s, int event)
|
||||
static void chr_be_event(Chardev *s, int event)
|
||||
{
|
||||
CharBackend *be = s->be;
|
||||
|
||||
if (!be || !be->chr_event) {
|
||||
return;
|
||||
}
|
||||
|
||||
be->chr_event(be->opaque, event);
|
||||
}
|
||||
|
||||
void qemu_chr_be_event(Chardev *s, int event)
|
||||
{
|
||||
/* Keep track if the char device is open */
|
||||
switch (event) {
|
||||
case CHR_EVENT_OPENED:
|
||||
@@ -57,11 +66,7 @@ void qemu_chr_be_event(Chardev *s, int event)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!be || !be->chr_event) {
|
||||
return;
|
||||
}
|
||||
|
||||
be->chr_event(be->opaque, event);
|
||||
CHARDEV_GET_CLASS(s)->chr_be_event(s, event);
|
||||
}
|
||||
|
||||
/* Not reporting errors from writing to logfile, as logs are
|
||||
@@ -244,6 +249,7 @@ static void char_class_init(ObjectClass *oc, void *data)
|
||||
ChardevClass *cc = CHARDEV_CLASS(oc);
|
||||
|
||||
cc->chr_write = null_chr_write;
|
||||
cc->chr_be_event = chr_be_event;
|
||||
}
|
||||
|
||||
static void char_finalize(Object *obj)
|
||||
|
||||
@@ -426,6 +426,7 @@ vxhs=""
|
||||
supported_cpu="no"
|
||||
supported_os="no"
|
||||
bogus_os="no"
|
||||
malloc_trim=""
|
||||
|
||||
# parse CC options first
|
||||
for opt do
|
||||
@@ -1047,6 +1048,10 @@ for opt do
|
||||
;;
|
||||
--enable-tcg) tcg="yes"
|
||||
;;
|
||||
--disable-malloc-trim) malloc_trim="no"
|
||||
;;
|
||||
--enable-malloc-trim) malloc_trim="yes"
|
||||
;;
|
||||
--disable-spice) spice="no"
|
||||
;;
|
||||
--enable-spice) spice="yes"
|
||||
@@ -1466,6 +1471,7 @@ Advanced options (experts only):
|
||||
Default:trace-<pid>
|
||||
--disable-slirp disable SLIRP userspace network connectivity
|
||||
--enable-tcg-interpreter enable TCG with bytecode interpreter (TCI)
|
||||
--enable-malloc-trim enable libc malloc_trim() for memory optimization
|
||||
--oss-lib path to OSS library
|
||||
--cpu=CPU Build for host CPU [$cpu]
|
||||
--with-coroutine=BACKEND coroutine backend. Supported options:
|
||||
@@ -3860,6 +3866,30 @@ if test "$tcmalloc" = "yes" && test "$jemalloc" = "yes" ; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Even if malloc_trim() is available, these non-libc memory allocators
|
||||
# do not support it.
|
||||
if test "$tcmalloc" = "yes" || test "$jemalloc" = "yes" ; then
|
||||
if test "$malloc_trim" = "yes" ; then
|
||||
echo "Disabling malloc_trim with non-libc memory allocator"
|
||||
fi
|
||||
malloc_trim="no"
|
||||
fi
|
||||
|
||||
#######################################
|
||||
# malloc_trim
|
||||
|
||||
if test "$malloc_trim" != "no" ; then
|
||||
cat > $TMPC << EOF
|
||||
#include <malloc.h>
|
||||
int main(void) { malloc_trim(0); return 0; }
|
||||
EOF
|
||||
if compile_prog "" "" ; then
|
||||
malloc_trim="yes"
|
||||
else
|
||||
malloc_trim="no"
|
||||
fi
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# tcmalloc probe
|
||||
|
||||
@@ -3923,7 +3953,7 @@ fi
|
||||
# check if memfd is supported
|
||||
memfd=no
|
||||
cat > $TMPC << EOF
|
||||
#include <sys/memfd.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
@@ -5505,6 +5535,7 @@ if test "$tcg" = "yes" ; then
|
||||
echo "TCG debug enabled $debug_tcg"
|
||||
echo "TCG interpreter $tcg_interpreter"
|
||||
fi
|
||||
echo "malloc trim support $malloc_trim"
|
||||
echo "RDMA support $rdma"
|
||||
echo "fdt support $fdt"
|
||||
echo "preadv support $preadv"
|
||||
@@ -6015,6 +6046,10 @@ if test "$opengl" = "yes" ; then
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "$malloc_trim" = "yes" ; then
|
||||
echo "CONFIG_MALLOC_TRIM=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
if test "$avx2_opt" = "yes" ; then
|
||||
echo "CONFIG_AVX2_OPT=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
[Unit]
|
||||
Description=QEMU Guest Agent
|
||||
BindTo=dev-virtio\x2dports-org.qemu.guest_agent.0.device
|
||||
After=dev-virtio\x2dports-org.qemu.guest_agent.0.device
|
||||
|
||||
[Service]
|
||||
ExecStart=-/usr/bin/qemu-ga
|
||||
Restart=always
|
||||
RestartSec=0
|
||||
|
||||
[Install]
|
||||
@@ -0,0 +1,15 @@
|
||||
[Unit]
|
||||
Description=Persistent Reservation Daemon for QEMU
|
||||
|
||||
[Service]
|
||||
WorkingDirectory=/tmp
|
||||
Type=simple
|
||||
ExecStart=/usr/bin/qemu-pr-helper
|
||||
PrivateTmp=yes
|
||||
ProtectSystem=strict
|
||||
ReadWritePaths=/var/run
|
||||
RestrictAddressFamilies=AF_UNIX
|
||||
Restart=always
|
||||
RestartSec=0
|
||||
|
||||
[Install]
|
||||
@@ -0,0 +1,9 @@
|
||||
[Unit]
|
||||
Description=Persistent Reservation Daemon for QEMU
|
||||
|
||||
[Socket]
|
||||
ListenStream=/run/qemu-pr-helper.sock
|
||||
SocketMode=0600
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -1057,13 +1057,22 @@ static void qemu_tcg_destroy_vcpu(CPUState *cpu)
|
||||
{
|
||||
}
|
||||
|
||||
static void qemu_cpu_stop(CPUState *cpu, bool exit)
|
||||
{
|
||||
g_assert(qemu_cpu_is_self(cpu));
|
||||
cpu->stop = false;
|
||||
cpu->stopped = true;
|
||||
if (exit) {
|
||||
cpu_exit(cpu);
|
||||
}
|
||||
qemu_cond_broadcast(&qemu_pause_cond);
|
||||
}
|
||||
|
||||
static void qemu_wait_io_event_common(CPUState *cpu)
|
||||
{
|
||||
atomic_mb_set(&cpu->thread_kicked, false);
|
||||
if (cpu->stop) {
|
||||
cpu->stop = false;
|
||||
cpu->stopped = true;
|
||||
qemu_cond_broadcast(&qemu_pause_cond);
|
||||
qemu_cpu_stop(cpu, false);
|
||||
}
|
||||
process_queued_cpu_work(cpu);
|
||||
}
|
||||
@@ -1610,12 +1619,12 @@ void pause_all_vcpus(void)
|
||||
|
||||
qemu_clock_enable(QEMU_CLOCK_VIRTUAL, false);
|
||||
CPU_FOREACH(cpu) {
|
||||
cpu->stop = true;
|
||||
qemu_cpu_kick(cpu);
|
||||
}
|
||||
|
||||
if (qemu_in_vcpu_thread()) {
|
||||
cpu_stop_current();
|
||||
if (qemu_cpu_is_self(cpu)) {
|
||||
qemu_cpu_stop(cpu, true);
|
||||
} else {
|
||||
cpu->stop = true;
|
||||
qemu_cpu_kick(cpu);
|
||||
}
|
||||
}
|
||||
|
||||
while (!all_vcpus_paused()) {
|
||||
@@ -1778,11 +1787,8 @@ void qemu_init_vcpu(CPUState *cpu)
|
||||
/* If the target cpu hasn't set up any address spaces itself,
|
||||
* give it the default one.
|
||||
*/
|
||||
AddressSpace *as = g_new0(AddressSpace, 1);
|
||||
|
||||
address_space_init(as, cpu->memory, "cpu-memory");
|
||||
cpu->num_ases = 1;
|
||||
cpu_address_space_init(cpu, as, 0);
|
||||
cpu_address_space_init(cpu, 0, "cpu-memory", cpu->memory);
|
||||
}
|
||||
|
||||
if (kvm_enabled()) {
|
||||
@@ -1799,10 +1805,7 @@ void qemu_init_vcpu(CPUState *cpu)
|
||||
void cpu_stop_current(void)
|
||||
{
|
||||
if (current_cpu) {
|
||||
current_cpu->stop = false;
|
||||
current_cpu->stopped = true;
|
||||
cpu_exit(current_cpu);
|
||||
qemu_cond_broadcast(&qemu_pause_cond);
|
||||
qemu_cpu_stop(current_cpu, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -705,9 +705,17 @@ CPUState *qemu_get_cpu(int index)
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
void cpu_address_space_init(CPUState *cpu, AddressSpace *as, int asidx)
|
||||
void cpu_address_space_init(CPUState *cpu, int asidx,
|
||||
const char *prefix, MemoryRegion *mr)
|
||||
{
|
||||
CPUAddressSpace *newas;
|
||||
AddressSpace *as = g_new0(AddressSpace, 1);
|
||||
char *as_name;
|
||||
|
||||
assert(mr);
|
||||
as_name = g_strdup_printf("%s-%d", prefix, cpu->cpu_index);
|
||||
address_space_init(as, mr, as_name);
|
||||
g_free(as_name);
|
||||
|
||||
/* Target code should have set num_ases before calling us */
|
||||
assert(asidx < cpu->num_ases);
|
||||
@@ -2717,6 +2725,37 @@ static uint16_t dummy_section(PhysPageMap *map, FlatView *fv, MemoryRegion *mr)
|
||||
return phys_section_add(map, §ion);
|
||||
}
|
||||
|
||||
static void readonly_mem_write(void *opaque, hwaddr addr,
|
||||
uint64_t val, unsigned size)
|
||||
{
|
||||
/* Ignore any write to ROM. */
|
||||
}
|
||||
|
||||
static bool readonly_mem_accepts(void *opaque, hwaddr addr,
|
||||
unsigned size, bool is_write)
|
||||
{
|
||||
return is_write;
|
||||
}
|
||||
|
||||
/* This will only be used for writes, because reads are special cased
|
||||
* to directly access the underlying host ram.
|
||||
*/
|
||||
static const MemoryRegionOps readonly_mem_ops = {
|
||||
.write = readonly_mem_write,
|
||||
.valid.accepts = readonly_mem_accepts,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 1,
|
||||
.max_access_size = 8,
|
||||
.unaligned = false,
|
||||
},
|
||||
.impl = {
|
||||
.min_access_size = 1,
|
||||
.max_access_size = 8,
|
||||
.unaligned = false,
|
||||
},
|
||||
};
|
||||
|
||||
MemoryRegion *iotlb_to_region(CPUState *cpu, hwaddr index, MemTxAttrs attrs)
|
||||
{
|
||||
int asidx = cpu_asidx_from_attrs(cpu, attrs);
|
||||
@@ -2729,7 +2768,8 @@ MemoryRegion *iotlb_to_region(CPUState *cpu, hwaddr index, MemTxAttrs attrs)
|
||||
|
||||
static void io_mem_init(void)
|
||||
{
|
||||
memory_region_init_io(&io_mem_rom, NULL, &unassigned_mem_ops, NULL, NULL, UINT64_MAX);
|
||||
memory_region_init_io(&io_mem_rom, NULL, &readonly_mem_ops,
|
||||
NULL, NULL, UINT64_MAX);
|
||||
memory_region_init_io(&io_mem_unassigned, NULL, &unassigned_mem_ops, NULL,
|
||||
NULL, UINT64_MAX);
|
||||
|
||||
|
||||
@@ -111,6 +111,7 @@ static void kvm_pic_set_irq(void *opaque, int irq, int level)
|
||||
{
|
||||
int delivered;
|
||||
|
||||
pic_stat_update_irq(irq, level);
|
||||
delivered = kvm_set_irq(kvm_state, irq, level);
|
||||
apic_report_irq_delivered(delivered);
|
||||
}
|
||||
|
||||
@@ -113,3 +113,7 @@ amdvi_mode_invalid(uint8_t level, uint64_t addr)"error: translation level 0x%"PR
|
||||
amdvi_page_fault(uint64_t addr) "error: page fault accessing guest physical address 0x%"PRIx64
|
||||
amdvi_iotlb_hit(uint8_t bus, uint8_t slot, uint8_t func, uint64_t addr, uint64_t txaddr) "hit iotlb devid %02x:%02x.%x gpa 0x%"PRIx64" hpa 0x%"PRIx64
|
||||
amdvi_translation_result(uint8_t bus, uint8_t slot, uint8_t func, uint64_t addr, uint64_t txaddr) "devid: %02x:%02x.%x gpa 0x%"PRIx64" hpa 0x%"PRIx64
|
||||
|
||||
# hw/i386/vmport.c
|
||||
vmport_register(unsigned char command, void *func, void *opaque) "command: 0x%02x func: %p opaque: %p"
|
||||
vmport_command(unsigned char command) "command: 0x%02x"
|
||||
|
||||
+5
-9
@@ -27,8 +27,7 @@
|
||||
#include "hw/i386/pc.h"
|
||||
#include "sysemu/hw_accel.h"
|
||||
#include "hw/qdev.h"
|
||||
|
||||
/* #define VMPORT_DEBUG */
|
||||
#include "trace.h"
|
||||
|
||||
#define VMPORT_CMD_GETVERSION 0x0a
|
||||
#define VMPORT_CMD_GETRAMSIZE 0x14
|
||||
@@ -54,6 +53,7 @@ void vmport_register(unsigned char command, VMPortReadFunc *func, void *opaque)
|
||||
return;
|
||||
}
|
||||
|
||||
trace_vmport_register(command, func, opaque);
|
||||
port_state->func[command] = func;
|
||||
port_state->opaque[command] = opaque;
|
||||
}
|
||||
@@ -76,13 +76,9 @@ static uint64_t vmport_ioport_read(void *opaque, hwaddr addr,
|
||||
}
|
||||
|
||||
command = env->regs[R_ECX];
|
||||
if (command >= VMPORT_ENTRIES) {
|
||||
return eax;
|
||||
}
|
||||
if (!s->func[command]) {
|
||||
#ifdef VMPORT_DEBUG
|
||||
fprintf(stderr, "vmport: unknown command %x\n", command);
|
||||
#endif
|
||||
trace_vmport_command(command);
|
||||
if (command >= VMPORT_ENTRIES || !s->func[command]) {
|
||||
qemu_log_mask(LOG_UNIMP, "vmport: unknown command %x\n", command);
|
||||
return eax;
|
||||
}
|
||||
|
||||
|
||||
+12
-74
@@ -25,24 +25,15 @@
|
||||
#include "hw/hw.h"
|
||||
#include "hw/i386/pc.h"
|
||||
#include "hw/isa/isa.h"
|
||||
#include "monitor/monitor.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "qemu/log.h"
|
||||
#include "hw/isa/i8259_internal.h"
|
||||
#include "hw/intc/intc.h"
|
||||
#include "trace.h"
|
||||
|
||||
/* debug PIC */
|
||||
//#define DEBUG_PIC
|
||||
|
||||
#ifdef DEBUG_PIC
|
||||
#define DPRINTF(fmt, ...) \
|
||||
do { printf("pic: " fmt , ## __VA_ARGS__); } while (0)
|
||||
#else
|
||||
#define DPRINTF(fmt, ...)
|
||||
#endif
|
||||
|
||||
//#define DEBUG_IRQ_LATENCY
|
||||
//#define DEBUG_IRQ_COUNT
|
||||
|
||||
#define TYPE_I8259 "isa-i8259"
|
||||
#define PIC_CLASS(class) OBJECT_CLASS_CHECK(PICClass, (class), TYPE_I8259)
|
||||
@@ -58,12 +49,6 @@ typedef struct PICClass {
|
||||
DeviceRealize parent_realize;
|
||||
} PICClass;
|
||||
|
||||
#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
|
||||
static int irq_level[16];
|
||||
#endif
|
||||
#ifdef DEBUG_IRQ_COUNT
|
||||
static uint64_t irq_count[16];
|
||||
#endif
|
||||
#ifdef DEBUG_IRQ_LATENCY
|
||||
static int64_t irq_time[16];
|
||||
#endif
|
||||
@@ -122,8 +107,7 @@ static void pic_update_irq(PICCommonState *s)
|
||||
|
||||
irq = pic_get_irq(s);
|
||||
if (irq >= 0) {
|
||||
DPRINTF("pic%d: imr=%x irr=%x padd=%d\n",
|
||||
s->master ? 0 : 1, s->imr, s->irr, s->priority_add);
|
||||
trace_pic_update_irq(s->master, s->imr, s->irr, s->priority_add);
|
||||
qemu_irq_raise(s->int_out[0]);
|
||||
} else {
|
||||
qemu_irq_lower(s->int_out[0]);
|
||||
@@ -135,22 +119,11 @@ static void pic_set_irq(void *opaque, int irq, int level)
|
||||
{
|
||||
PICCommonState *s = opaque;
|
||||
int mask = 1 << irq;
|
||||
|
||||
#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT) || \
|
||||
defined(DEBUG_IRQ_LATENCY)
|
||||
int irq_index = s->master ? irq : irq + 8;
|
||||
#endif
|
||||
#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
|
||||
if (level != irq_level[irq_index]) {
|
||||
DPRINTF("pic_set_irq: irq=%d level=%d\n", irq_index, level);
|
||||
irq_level[irq_index] = level;
|
||||
#ifdef DEBUG_IRQ_COUNT
|
||||
if (level == 1) {
|
||||
irq_count[irq_index]++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
trace_pic_set_irq(s->master, irq, level);
|
||||
pic_stat_update_irq(irq_index, level);
|
||||
|
||||
#ifdef DEBUG_IRQ_LATENCY
|
||||
if (level) {
|
||||
irq_time[irq_index] = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
@@ -223,18 +196,18 @@ int pic_read_irq(DeviceState *d)
|
||||
intno = s->irq_base + irq;
|
||||
}
|
||||
|
||||
#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_LATENCY)
|
||||
if (irq == 2) {
|
||||
irq = irq2 + 8;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_IRQ_LATENCY
|
||||
printf("IRQ%d latency=%0.3fus\n",
|
||||
irq,
|
||||
(double)(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) -
|
||||
irq_time[irq]) * 1000000.0 / NANOSECONDS_PER_SECOND);
|
||||
#endif
|
||||
DPRINTF("pic_interrupt: irq=%d\n", irq);
|
||||
|
||||
trace_pic_interrupt(irq, intno);
|
||||
return intno;
|
||||
}
|
||||
|
||||
@@ -252,35 +225,6 @@ static void pic_reset(DeviceState *dev)
|
||||
pic_init_reset(s);
|
||||
}
|
||||
|
||||
static bool pic_get_statistics(InterruptStatsProvider *obj,
|
||||
uint64_t **irq_counts, unsigned int *nb_irqs)
|
||||
{
|
||||
PICCommonState *s = PIC_COMMON(obj);
|
||||
|
||||
if (s->master) {
|
||||
#ifdef DEBUG_IRQ_COUNT
|
||||
*irq_counts = irq_count;
|
||||
*nb_irqs = ARRAY_SIZE(irq_count);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
} else {
|
||||
*irq_counts = NULL;
|
||||
*nb_irqs = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void pic_print_info(InterruptStatsProvider *obj, Monitor *mon)
|
||||
{
|
||||
PICCommonState *s = PIC_COMMON(obj);
|
||||
monitor_printf(mon, "pic%d: irr=%02x imr=%02x isr=%02x hprio=%d "
|
||||
"irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n",
|
||||
s->master ? 0 : 1, s->irr, s->imr, s->isr, s->priority_add,
|
||||
s->irq_base, s->read_reg_select, s->elcr,
|
||||
s->special_fully_nested_mode);
|
||||
}
|
||||
|
||||
static void pic_ioport_write(void *opaque, hwaddr addr64,
|
||||
uint64_t val64, unsigned size)
|
||||
{
|
||||
@@ -289,7 +233,8 @@ static void pic_ioport_write(void *opaque, hwaddr addr64,
|
||||
uint32_t val = val64;
|
||||
int priority, cmd, irq;
|
||||
|
||||
DPRINTF("write: addr=0x%02x val=0x%02x\n", addr, val);
|
||||
trace_pic_ioport_write(s->master, addr, val);
|
||||
|
||||
if (addr == 0) {
|
||||
if (val & 0x10) {
|
||||
pic_init_reset(s);
|
||||
@@ -402,7 +347,7 @@ static uint64_t pic_ioport_read(void *opaque, hwaddr addr,
|
||||
ret = s->imr;
|
||||
}
|
||||
}
|
||||
DPRINTF("read: addr=0x%02" HWADDR_PRIx " val=0x%02x\n", addr, ret);
|
||||
trace_pic_ioport_read(s->master, addr, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -497,13 +442,10 @@ static void i8259_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
PICClass *k = PIC_CLASS(klass);
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass);
|
||||
|
||||
k->parent_realize = dc->realize;
|
||||
dc->realize = pic_realize;
|
||||
dc->reset = pic_reset;
|
||||
ic->get_statistics = pic_get_statistics;
|
||||
ic->print_info = pic_print_info;
|
||||
}
|
||||
|
||||
static const TypeInfo i8259_info = {
|
||||
@@ -512,10 +454,6 @@ static const TypeInfo i8259_info = {
|
||||
.parent = TYPE_PIC_COMMON,
|
||||
.class_init = i8259_class_init,
|
||||
.class_size = sizeof(PICClass),
|
||||
.interfaces = (InterfaceInfo[]) {
|
||||
{ TYPE_INTERRUPT_STATS_PROVIDER },
|
||||
{ }
|
||||
},
|
||||
};
|
||||
|
||||
static void pic_register_types(void)
|
||||
|
||||
@@ -25,6 +25,10 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/i386/pc.h"
|
||||
#include "hw/isa/i8259_internal.h"
|
||||
#include "monitor/monitor.h"
|
||||
|
||||
static int irq_level[16];
|
||||
static uint64_t irq_count[16];
|
||||
|
||||
void pic_reset_common(PICCommonState *s)
|
||||
{
|
||||
@@ -98,6 +102,44 @@ ISADevice *i8259_init_chip(const char *name, ISABus *bus, bool master)
|
||||
return isadev;
|
||||
}
|
||||
|
||||
void pic_stat_update_irq(int irq, int level)
|
||||
{
|
||||
if (level != irq_level[irq]) {
|
||||
irq_level[irq] = level;
|
||||
if (level == 1) {
|
||||
irq_count[irq]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool pic_get_statistics(InterruptStatsProvider *obj,
|
||||
uint64_t **irq_counts, unsigned int *nb_irqs)
|
||||
{
|
||||
PICCommonState *s = PIC_COMMON(obj);
|
||||
|
||||
if (s->master) {
|
||||
*irq_counts = irq_count;
|
||||
*nb_irqs = ARRAY_SIZE(irq_count);
|
||||
} else {
|
||||
*irq_counts = NULL;
|
||||
*nb_irqs = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void pic_print_info(InterruptStatsProvider *obj, Monitor *mon)
|
||||
{
|
||||
PICCommonState *s = PIC_COMMON(obj);
|
||||
|
||||
pic_dispatch_pre_save(s);
|
||||
monitor_printf(mon, "pic%d: irr=%02x imr=%02x isr=%02x hprio=%d "
|
||||
"irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n",
|
||||
s->master ? 0 : 1, s->irr, s->imr, s->isr, s->priority_add,
|
||||
s->irq_base, s->read_reg_select, s->elcr,
|
||||
s->special_fully_nested_mode);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_pic_common = {
|
||||
.name = "i8259",
|
||||
.version_id = 1,
|
||||
@@ -136,6 +178,7 @@ static Property pic_properties_common[] = {
|
||||
static void pic_common_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass);
|
||||
|
||||
dc->vmsd = &vmstate_pic_common;
|
||||
dc->props = pic_properties_common;
|
||||
@@ -147,6 +190,8 @@ static void pic_common_class_init(ObjectClass *klass, void *data)
|
||||
* code.
|
||||
*/
|
||||
dc->user_creatable = false;
|
||||
ic->get_statistics = pic_get_statistics;
|
||||
ic->print_info = pic_print_info;
|
||||
}
|
||||
|
||||
static const TypeInfo pic_common_type = {
|
||||
@@ -156,6 +201,10 @@ static const TypeInfo pic_common_type = {
|
||||
.class_size = sizeof(PICCommonClass),
|
||||
.class_init = pic_common_class_init,
|
||||
.abstract = true,
|
||||
.interfaces = (InterfaceInfo[]) {
|
||||
{ TYPE_INTERRUPT_STATS_PROVIDER },
|
||||
{ }
|
||||
},
|
||||
};
|
||||
|
||||
static void pic_common_register_types(void)
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# See docs/devel/tracing.txt for syntax documentation.
|
||||
|
||||
# hw/intc/i8259.c
|
||||
pic_update_irq(bool master, uint8_t imr, uint8_t irr, uint8_t padd) "master %d imr %"PRIu8" irr %"PRIu8" padd %"PRIu8
|
||||
pic_set_irq(bool master, int irq, int level) "master %d irq %d level %d"
|
||||
pic_interrupt(int irq, int intno) "irq %d intno %d"
|
||||
pic_ioport_write(bool master, uint64_t addr, uint64_t val) "master %d addr 0x%"PRIx64" val 0x%"PRIx64
|
||||
pic_ioport_read(bool master, uint64_t addr, int val) "master %d addr 0x%"PRIx64" val 0x%x"
|
||||
|
||||
# hw/intc/apic_common.c
|
||||
cpu_set_apic_base(uint64_t val) "0x%016"PRIx64
|
||||
cpu_get_apic_base(uint64_t val) "0x%016"PRIx64
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user