* gdbstub fixes (Alex)

* IOMMU MemoryRegion subclass (Alexey)
 * Chardev hotswap (Anton)
 * NBD_OPT_GO support (Eric)
 * Misc bugfixes
 * DEFINE_PROP_LINK (minus the ARM patches - Fam)
 * MAINTAINERS updates (Philippe)
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.22 (GNU/Linux)
 
 iQEcBAABAgAGBQJZaJejAAoJEL/70l94x66DwQ4H/0NUvh/Zfs64wE1iuZJACc24
 1za02fFaB50vFDwQKWbM0GkHzDxoXBHk4Rvn92p+VSxpKtaAX4GRwCvxRA5GeUtm
 GAYbdIJUe0UELepKExrlUVzQcK9VfljoJpK3dZkP5Zzx83L2PAI/SexrZRibN2Uf
 yRI60uvlsMWU12nenzdVnYORd+TWDNKele7BhMrX/FX9wxaS1PlnsnKZggy6CU7G
 8dwZJAZJ/s5tRGXyXyAQzLm5JZQCLnA6jxya540TbPeciFgbvvS2ydIitZ54vSPO
 VtmZ1rSWfTEbNF5xGD1Ztu8aAENr5/I05l6IjxZd45BdUCW3HxeJkc+7lE0K4uk=
 =wnVs
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging

* gdbstub fixes (Alex)
* IOMMU MemoryRegion subclass (Alexey)
* Chardev hotswap (Anton)
* NBD_OPT_GO support (Eric)
* Misc bugfixes
* DEFINE_PROP_LINK (minus the ARM patches - Fam)
* MAINTAINERS updates (Philippe)

# gpg: Signature made Fri 14 Jul 2017 11:06:27 BST
# 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: (55 commits)
  spapr_rng: Convert to DEFINE_PROP_LINK
  cpu: Convert to DEFINE_PROP_LINK
  mips_cmgcr: Convert to DEFINE_PROP_LINK
  ivshmem: Convert to DEFINE_PROP_LINK
  dimm: Convert to DEFINE_PROP_LINK
  virtio-crypto: Convert to DEFINE_PROP_LINK
  virtio-rng: Convert to DEFINE_PROP_LINK
  virtio-scsi: Convert to DEFINE_PROP_LINK
  virtio-blk: Convert to DEFINE_PROP_LINK
  qdev: Add const qualifier to PropertyInfo definitions
  qmp: Use ObjectProperty.type if present
  qdev: Introduce DEFINE_PROP_LINK
  qdev: Introduce PropertyInfo.create
  qom: enforce readonly nature of link's check callback
  translate-all: remove redundant !tcg_enabled check in dump_exec_info
  vl: fix breakage of -tb-size
  nbd: Implement NBD_INFO_BLOCK_SIZE on client
  nbd: Implement NBD_INFO_BLOCK_SIZE on server
  nbd: Implement NBD_OPT_GO on client
  nbd: Implement NBD_OPT_GO on server
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2017-07-14 12:16:09 +01:00
commit 6c6076662d
123 changed files with 2021 additions and 875 deletions

View File

@ -84,14 +84,10 @@ M: Paolo Bonzini <pbonzini@redhat.com>
M: Peter Crosthwaite <crosthwaite.peter@gmail.com> M: Peter Crosthwaite <crosthwaite.peter@gmail.com>
M: Richard Henderson <rth@twiddle.net> M: Richard Henderson <rth@twiddle.net>
S: Maintained S: Maintained
F: cpu-exec.c
F: cpu-exec-common.c
F: cpus.c F: cpus.c
F: cputlb.c
F: exec.c F: exec.c
F: softmmu_template.h F: softmmu_template.h
F: translate-all.* F: accel/tcg/
F: translate-common.c
F: include/exec/cpu*.h F: include/exec/cpu*.h
F: include/exec/exec-all.h F: include/exec/exec-all.h
F: include/exec/helper*.h F: include/exec/helper*.h
@ -277,8 +273,8 @@ Overall
M: Paolo Bonzini <pbonzini@redhat.com> M: Paolo Bonzini <pbonzini@redhat.com>
L: kvm@vger.kernel.org L: kvm@vger.kernel.org
S: Supported S: Supported
F: kvm-*
F: */kvm.* F: */kvm.*
F: accel/kvm/
F: include/sysemu/kvm*.h F: include/sysemu/kvm*.h
ARM ARM
@ -327,7 +323,6 @@ M: Stefano Stabellini <sstabellini@kernel.org>
M: Anthony Perard <anthony.perard@citrix.com> M: Anthony Perard <anthony.perard@citrix.com>
L: xen-devel@lists.xenproject.org L: xen-devel@lists.xenproject.org
S: Supported S: Supported
F: xen-*
F: */xen* F: */xen*
F: hw/9pfs/xen-9p-backend.c F: hw/9pfs/xen-9p-backend.c
F: hw/char/xen_console.c F: hw/char/xen_console.c
@ -1160,6 +1155,13 @@ F: docs/specs/vmgenid.txt
F: tests/vmgenid-test.c F: tests/vmgenid-test.c
F: stubs/vmgenid.c F: stubs/vmgenid.c
Unimplemented device
M: Peter Maydell <peter.maydell@linaro.org>
R: Philippe Mathieu-Daudé <f4bug@amsat.org>
S: Maintained
F: include/hw/misc/unimp.h
F: hw/misc/unimp.c
Subsystems Subsystems
---------- ----------
Audio Audio
@ -1650,7 +1652,7 @@ TCI target
M: Stefan Weil <sw@weilnetz.de> M: Stefan Weil <sw@weilnetz.de>
S: Maintained S: Maintained
F: tcg/tci/ F: tcg/tci/
F: tci.c F: tcg/tci.c
F: disas/tci.c F: disas/tci.c
Block drivers Block drivers

View File

@ -1851,11 +1851,6 @@ void dump_exec_info(FILE *f, fprintf_function cpu_fprintf)
tb_lock(); tb_lock();
if (!tcg_enabled()) {
cpu_fprintf(f, "TCG not enabled\n");
return;
}
target_code_size = 0; target_code_size = 0;
max_target_code_size = 0; max_target_code_size = 0;
cross_page = 0; cross_page = 0;

View File

@ -106,7 +106,7 @@ static void rng_egd_opened(RngBackend *b, Error **errp)
/* FIXME we should resubmit pending requests when the CDS reconnects. */ /* FIXME we should resubmit pending requests when the CDS reconnects. */
qemu_chr_fe_set_handlers(&s->chr, rng_egd_chr_can_read, qemu_chr_fe_set_handlers(&s->chr, rng_egd_chr_can_read,
rng_egd_chr_read, NULL, s, NULL, true); rng_egd_chr_read, NULL, NULL, s, NULL, true);
} }
static void rng_egd_set_chardev(Object *obj, const char *value, Error **errp) static void rng_egd_set_chardev(Object *obj, const char *value, Error **errp)

View File

@ -242,7 +242,7 @@ int nbd_client_co_pwritev(BlockDriverState *bs, uint64_t offset,
ssize_t ret; ssize_t ret;
if (flags & BDRV_REQ_FUA) { if (flags & BDRV_REQ_FUA) {
assert(client->nbdflags & NBD_FLAG_SEND_FUA); assert(client->info.flags & NBD_FLAG_SEND_FUA);
request.flags |= NBD_CMD_FLAG_FUA; request.flags |= NBD_CMD_FLAG_FUA;
} }
@ -270,12 +270,12 @@ int nbd_client_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
}; };
NBDReply reply; NBDReply reply;
if (!(client->nbdflags & NBD_FLAG_SEND_WRITE_ZEROES)) { if (!(client->info.flags & NBD_FLAG_SEND_WRITE_ZEROES)) {
return -ENOTSUP; return -ENOTSUP;
} }
if (flags & BDRV_REQ_FUA) { if (flags & BDRV_REQ_FUA) {
assert(client->nbdflags & NBD_FLAG_SEND_FUA); assert(client->info.flags & NBD_FLAG_SEND_FUA);
request.flags |= NBD_CMD_FLAG_FUA; request.flags |= NBD_CMD_FLAG_FUA;
} }
if (!(flags & BDRV_REQ_MAY_UNMAP)) { if (!(flags & BDRV_REQ_MAY_UNMAP)) {
@ -299,7 +299,7 @@ int nbd_client_co_flush(BlockDriverState *bs)
NBDReply reply; NBDReply reply;
ssize_t ret; ssize_t ret;
if (!(client->nbdflags & NBD_FLAG_SEND_FLUSH)) { if (!(client->info.flags & NBD_FLAG_SEND_FLUSH)) {
return 0; return 0;
} }
@ -327,7 +327,7 @@ int nbd_client_co_pdiscard(BlockDriverState *bs, int64_t offset, int bytes)
NBDReply reply; NBDReply reply;
ssize_t ret; ssize_t ret;
if (!(client->nbdflags & NBD_FLAG_SEND_TRIM)) { if (!(client->info.flags & NBD_FLAG_SEND_TRIM)) {
return 0; return 0;
} }
@ -384,22 +384,24 @@ int nbd_client_init(BlockDriverState *bs,
logout("session init %s\n", export); logout("session init %s\n", export);
qio_channel_set_blocking(QIO_CHANNEL(sioc), true, NULL); qio_channel_set_blocking(QIO_CHANNEL(sioc), true, NULL);
client->info.request_sizes = true;
ret = nbd_receive_negotiate(QIO_CHANNEL(sioc), export, ret = nbd_receive_negotiate(QIO_CHANNEL(sioc), export,
&client->nbdflags,
tlscreds, hostname, tlscreds, hostname,
&client->ioc, &client->ioc, &client->info, errp);
&client->size, errp);
if (ret < 0) { if (ret < 0) {
logout("Failed to negotiate with the NBD server\n"); logout("Failed to negotiate with the NBD server\n");
return ret; return ret;
} }
if (client->nbdflags & NBD_FLAG_SEND_FUA) { if (client->info.flags & NBD_FLAG_SEND_FUA) {
bs->supported_write_flags = BDRV_REQ_FUA; bs->supported_write_flags = BDRV_REQ_FUA;
bs->supported_zero_flags |= BDRV_REQ_FUA; bs->supported_zero_flags |= BDRV_REQ_FUA;
} }
if (client->nbdflags & NBD_FLAG_SEND_WRITE_ZEROES) { if (client->info.flags & NBD_FLAG_SEND_WRITE_ZEROES) {
bs->supported_zero_flags |= BDRV_REQ_MAY_UNMAP; bs->supported_zero_flags |= BDRV_REQ_MAY_UNMAP;
} }
if (client->info.min_block > bs->bl.request_alignment) {
bs->bl.request_alignment = client->info.min_block;
}
qemu_co_mutex_init(&client->send_mutex); qemu_co_mutex_init(&client->send_mutex);
qemu_co_queue_init(&client->free_sema); qemu_co_queue_init(&client->free_sema);

View File

@ -20,8 +20,7 @@
typedef struct NBDClientSession { typedef struct NBDClientSession {
QIOChannelSocket *sioc; /* The master data channel */ QIOChannelSocket *sioc; /* The master data channel */
QIOChannel *ioc; /* The current I/O channel which may differ (eg TLS) */ QIOChannel *ioc; /* The current I/O channel which may differ (eg TLS) */
uint16_t nbdflags; NBDExportInfo info;
off_t size;
CoMutex send_mutex; CoMutex send_mutex;
CoQueue free_sema; CoQueue free_sema;

View File

@ -472,9 +472,17 @@ static int nbd_co_flush(BlockDriverState *bs)
static void nbd_refresh_limits(BlockDriverState *bs, Error **errp) static void nbd_refresh_limits(BlockDriverState *bs, Error **errp)
{ {
bs->bl.max_pdiscard = NBD_MAX_BUFFER_SIZE; NBDClientSession *s = nbd_get_client_session(bs);
bs->bl.max_pwrite_zeroes = NBD_MAX_BUFFER_SIZE; uint32_t max = MIN_NON_ZERO(NBD_MAX_BUFFER_SIZE, s->info.max_block);
bs->bl.max_transfer = NBD_MAX_BUFFER_SIZE;
bs->bl.max_pdiscard = max;
bs->bl.max_pwrite_zeroes = max;
bs->bl.max_transfer = max;
if (s->info.opt_block &&
s->info.opt_block > bs->bl.opt_transfer) {
bs->bl.opt_transfer = s->info.opt_block;
}
} }
static void nbd_close(BlockDriverState *bs) static void nbd_close(BlockDriverState *bs)
@ -492,7 +500,7 @@ static int64_t nbd_getlength(BlockDriverState *bs)
{ {
BDRVNBDState *s = bs->opaque; BDRVNBDState *s = bs->opaque;
return s->client.size; return s->client.info.size;
} }
static void nbd_detach_aio_context(BlockDriverState *bs) static void nbd_detach_aio_context(BlockDriverState *bs)

View File

@ -85,6 +85,8 @@ struct emulated_sigtable {
/* NOTE: we force a big alignment so that the stack stored after is /* NOTE: we force a big alignment so that the stack stored after is
aligned too */ aligned too */
typedef struct TaskState { typedef struct TaskState {
pid_t ts_tid; /* tid (or pid) of this task */
struct TaskState *next; struct TaskState *next;
int used; /* non zero if used */ int used; /* non zero if used */
struct image_info *info; struct image_info *info;

View File

@ -179,9 +179,21 @@ void qemu_chr_fe_printf(CharBackend *be, const char *fmt, ...)
Chardev *qemu_chr_fe_get_driver(CharBackend *be) Chardev *qemu_chr_fe_get_driver(CharBackend *be)
{ {
/* this is unsafe for the users that support chardev hotswap */
assert(be->chr_be_change == NULL);
return be->chr; return be->chr;
} }
bool qemu_chr_fe_backend_connected(CharBackend *be)
{
return !!be->chr;
}
bool qemu_chr_fe_backend_open(CharBackend *be)
{
return be->chr && be->chr->be_open;
}
bool qemu_chr_fe_init(CharBackend *b, Chardev *s, Error **errp) bool qemu_chr_fe_init(CharBackend *b, Chardev *s, Error **errp)
{ {
int tag = 0; int tag = 0;
@ -216,7 +228,7 @@ void qemu_chr_fe_deinit(CharBackend *b, bool del)
assert(b); assert(b);
if (b->chr) { if (b->chr) {
qemu_chr_fe_set_handlers(b, NULL, NULL, NULL, NULL, NULL, true); qemu_chr_fe_set_handlers(b, NULL, NULL, NULL, NULL, NULL, NULL, true);
if (b->chr->be == b) { if (b->chr->be == b) {
b->chr->be = NULL; b->chr->be = NULL;
} }
@ -235,6 +247,7 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
IOCanReadHandler *fd_can_read, IOCanReadHandler *fd_can_read,
IOReadHandler *fd_read, IOReadHandler *fd_read,
IOEventHandler *fd_event, IOEventHandler *fd_event,
BackendChangeHandler *be_change,
void *opaque, void *opaque,
GMainContext *context, GMainContext *context,
bool set_open) bool set_open)
@ -258,6 +271,7 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
b->chr_can_read = fd_can_read; b->chr_can_read = fd_can_read;
b->chr_read = fd_read; b->chr_read = fd_read;
b->chr_event = fd_event; b->chr_event = fd_event;
b->chr_be_change = be_change;
b->opaque = opaque; b->opaque = opaque;
if (cc->chr_update_read_handler) { if (cc->chr_update_read_handler) {
cc->chr_update_read_handler(s, context); cc->chr_update_read_handler(s, context);

View File

@ -278,6 +278,7 @@ void mux_chr_set_handlers(Chardev *chr, GMainContext *context)
mux_chr_can_read, mux_chr_can_read,
mux_chr_read, mux_chr_read,
mux_chr_event, mux_chr_event,
NULL,
chr, chr,
context, true); context, true);
} }

View File

@ -454,7 +454,9 @@ static int tcp_chr_sync_read(Chardev *chr, const uint8_t *buf, int len)
return 0; return 0;
} }
qio_channel_set_blocking(s->ioc, true, NULL);
size = tcp_chr_recv(chr, (void *) buf, len); size = tcp_chr_recv(chr, (void *) buf, len);
qio_channel_set_blocking(s->ioc, false, NULL);
if (size == 0) { if (size == 0) {
/* connection closed */ /* connection closed */
tcp_chr_disconnect(chr); tcp_chr_disconnect(chr);

View File

@ -556,17 +556,23 @@ help_string_append(const char *name, void *opaque)
g_string_append_printf(str, "\n%s", name); g_string_append_printf(str, "\n%s", name);
} }
Chardev *qemu_chr_new_from_opts(QemuOpts *opts, static const char *chardev_alias_translate(const char *name)
Error **errp) {
int i;
for (i = 0; i < (int)ARRAY_SIZE(chardev_alias_table); i++) {
if (g_strcmp0(chardev_alias_table[i].alias, name) == 0) {
return chardev_alias_table[i].typename;
}
}
return name;
}
ChardevBackend *qemu_chr_parse_opts(QemuOpts *opts, Error **errp)
{ {
Error *local_err = NULL; Error *local_err = NULL;
const ChardevClass *cc; const ChardevClass *cc;
Chardev *chr;
int i;
ChardevBackend *backend = NULL; ChardevBackend *backend = NULL;
const char *name = qemu_opt_get(opts, "backend"); const char *name = chardev_alias_translate(qemu_opt_get(opts, "backend"));
const char *id = qemu_opts_id(opts);
char *bid = NULL;
if (name == NULL) { if (name == NULL) {
error_setg(errp, "chardev: \"%s\" missing backend", error_setg(errp, "chardev: \"%s\" missing backend",
@ -574,7 +580,40 @@ Chardev *qemu_chr_new_from_opts(QemuOpts *opts,
return NULL; return NULL;
} }
if (is_help_option(name)) { cc = char_get_class(name, errp);
if (cc == NULL) {
return NULL;
}
backend = g_new0(ChardevBackend, 1);
backend->type = CHARDEV_BACKEND_KIND_NULL;
if (cc->parse) {
cc->parse(opts, backend, &local_err);
if (local_err) {
error_propagate(errp, local_err);
qapi_free_ChardevBackend(backend);
return NULL;
}
} else {
ChardevCommon *ccom = g_new0(ChardevCommon, 1);
qemu_chr_parse_common(opts, ccom);
backend->u.null.data = ccom; /* Any ChardevCommon member would work */
}
return backend;
}
Chardev *qemu_chr_new_from_opts(QemuOpts *opts, Error **errp)
{
const ChardevClass *cc;
Chardev *chr = NULL;
ChardevBackend *backend = NULL;
const char *name = chardev_alias_translate(qemu_opt_get(opts, "backend"));
const char *id = qemu_opts_id(opts);
char *bid = NULL;
if (name && is_help_option(name)) {
GString *str = g_string_new(""); GString *str = g_string_new("");
chardev_name_foreach(help_string_append, str); chardev_name_foreach(help_string_append, str);
@ -589,38 +628,20 @@ Chardev *qemu_chr_new_from_opts(QemuOpts *opts,
return NULL; return NULL;
} }
for (i = 0; i < (int)ARRAY_SIZE(chardev_alias_table); i++) { backend = qemu_chr_parse_opts(opts, errp);
if (g_strcmp0(chardev_alias_table[i].alias, name) == 0) { if (backend == NULL) {
name = chardev_alias_table[i].typename; return NULL;
break;
}
} }
cc = char_get_class(name, errp); cc = char_get_class(name, errp);
if (cc == NULL) { if (cc == NULL) {
return NULL; goto out;
} }
backend = g_new0(ChardevBackend, 1);
backend->type = CHARDEV_BACKEND_KIND_NULL;
if (qemu_opt_get_bool(opts, "mux", 0)) { if (qemu_opt_get_bool(opts, "mux", 0)) {
bid = g_strdup_printf("%s-base", id); bid = g_strdup_printf("%s-base", id);
} }
chr = NULL;
if (cc->parse) {
cc->parse(opts, backend, &local_err);
if (local_err) {
error_propagate(errp, local_err);
goto out;
}
} else {
ChardevCommon *ccom = g_new0(ChardevCommon, 1);
qemu_chr_parse_common(opts, ccom);
backend->u.null.data = ccom; /* Any ChardevCommon member would work */
}
chr = qemu_chardev_new(bid ? bid : id, chr = qemu_chardev_new(bid ? bid : id,
object_class_get_name(OBJECT_CLASS(cc)), object_class_get_name(OBJECT_CLASS(cc)),
backend, errp); backend, errp);
@ -930,6 +951,89 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
return ret; return ret;
} }
ChardevReturn *qmp_chardev_change(const char *id, ChardevBackend *backend,
Error **errp)
{
CharBackend *be;
const ChardevClass *cc;
Chardev *chr, *chr_new;
bool closed_sent = false;
ChardevReturn *ret;
chr = qemu_chr_find(id);
if (!chr) {
error_setg(errp, "Chardev '%s' does not exist", id);
return NULL;
}
if (CHARDEV_IS_MUX(chr)) {
error_setg(errp, "Mux device hotswap not supported yet");
return NULL;
}
if (qemu_chr_replay(chr)) {
error_setg(errp,
"Chardev '%s' cannot be changed in record/replay mode", id);
return NULL;
}
be = chr->be;
if (!be) {
/* easy case */
object_unparent(OBJECT(chr));
return qmp_chardev_add(id, backend, errp);
}
if (!be->chr_be_change) {
error_setg(errp, "Chardev user does not support chardev hotswap");
return NULL;
}
cc = char_get_class(ChardevBackendKind_lookup[backend->type], errp);
if (!cc) {
return NULL;
}
chr_new = qemu_chardev_new(NULL, object_class_get_name(OBJECT_CLASS(cc)),
backend, errp);
if (!chr_new) {
return NULL;
}
chr_new->label = g_strdup(id);
if (chr->be_open && !chr_new->be_open) {
qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
closed_sent = true;
}
chr->be = NULL;
qemu_chr_fe_init(be, chr_new, &error_abort);
if (be->chr_be_change(be->opaque) < 0) {
error_setg(errp, "Chardev '%s' change failed", chr_new->label);
chr_new->be = NULL;
qemu_chr_fe_init(be, chr, &error_abort);
if (closed_sent) {
qemu_chr_be_event(chr, CHR_EVENT_OPENED);
}
object_unref(OBJECT(chr_new));
return NULL;
}
object_unparent(OBJECT(chr));
object_property_add_child(get_chardevs_root(), chr_new->label,
OBJECT(chr_new), &error_abort);
object_unref(OBJECT(chr_new));
ret = g_new0(ChardevReturn, 1);
if (CHARDEV_IS_PTY(chr_new)) {
ret->pty = g_strdup(chr_new->filename + 4);
ret->has_pty = true;
}
return ret;
}
void qmp_chardev_remove(const char *id, Error **errp) void qmp_chardev_remove(const char *id, Error **errp)
{ {
Chardev *chr; Chardev *chr;

2
configure vendored
View File

@ -1583,7 +1583,7 @@ gcc_flags="-Wold-style-declaration -Wold-style-definition -Wtype-limits"
gcc_flags="-Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers $gcc_flags" gcc_flags="-Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers $gcc_flags"
gcc_flags="-Wno-missing-include-dirs -Wempty-body -Wnested-externs $gcc_flags" gcc_flags="-Wno-missing-include-dirs -Wempty-body -Wnested-externs $gcc_flags"
gcc_flags="-Wendif-labels -Wno-shift-negative-value $gcc_flags" gcc_flags="-Wendif-labels -Wno-shift-negative-value $gcc_flags"
gcc_flags="-Wno-initializer-overrides $gcc_flags" gcc_flags="-Wno-initializer-overrides -Wexpansion-to-defined $gcc_flags"
gcc_flags="-Wno-string-plus-int $gcc_flags" gcc_flags="-Wno-string-plus-int $gcc_flags"
# Note that we do not add -Werror to gcc_flags here, because that would # Note that we do not add -Werror to gcc_flags here, because that would
# enable it for all configure tests. If a configure test failed due # enable it for all configure tests. If a configure test failed due

70
exec.c
View File

@ -27,6 +27,7 @@
#include "exec/target_page.h" #include "exec/target_page.h"
#include "tcg.h" #include "tcg.h"
#include "hw/qdev-core.h" #include "hw/qdev-core.h"
#include "hw/qdev-properties.h"
#if !defined(CONFIG_USER_ONLY) #if !defined(CONFIG_USER_ONLY)
#include "hw/boards.h" #include "hw/boards.h"
#include "hw/xen/xen.h" #include "hw/xen/xen.h"
@ -480,19 +481,21 @@ static MemoryRegionSection address_space_do_translate(AddressSpace *as,
{ {
IOMMUTLBEntry iotlb; IOMMUTLBEntry iotlb;
MemoryRegionSection *section; MemoryRegionSection *section;
MemoryRegion *mr; IOMMUMemoryRegion *iommu_mr;
IOMMUMemoryRegionClass *imrc;
for (;;) { for (;;) {
AddressSpaceDispatch *d = atomic_rcu_read(&as->dispatch); AddressSpaceDispatch *d = atomic_rcu_read(&as->dispatch);
section = address_space_translate_internal(d, addr, &addr, plen, is_mmio); section = address_space_translate_internal(d, addr, &addr, plen, is_mmio);
mr = section->mr;
if (!mr->iommu_ops) { iommu_mr = memory_region_get_iommu(section->mr);
if (!iommu_mr) {
break; break;
} }
imrc = memory_region_get_iommu_class_nocheck(iommu_mr);
iotlb = mr->iommu_ops->translate(mr, addr, is_write ? iotlb = imrc->translate(iommu_mr, addr, is_write ?
IOMMU_WO : IOMMU_RO); IOMMU_WO : IOMMU_RO);
addr = ((iotlb.translated_addr & ~iotlb.addr_mask) addr = ((iotlb.translated_addr & ~iotlb.addr_mask)
| (addr & iotlb.addr_mask)); | (addr & iotlb.addr_mask));
*plen = MIN(*plen, (addr | iotlb.addr_mask) - addr + 1); *plen = MIN(*plen, (addr | iotlb.addr_mask) - addr + 1);
@ -588,7 +591,7 @@ address_space_translate_for_iotlb(CPUState *cpu, int asidx, hwaddr addr,
section = address_space_translate_internal(d, addr, xlat, plen, false); section = address_space_translate_internal(d, addr, xlat, plen, false);
assert(!section->mr->iommu_ops); assert(!memory_region_is_iommu(section->mr));
return section; return section;
} }
#endif #endif
@ -735,6 +738,20 @@ void cpu_exec_unrealizefn(CPUState *cpu)
} }
} }
Property cpu_common_props[] = {
#ifndef CONFIG_USER_ONLY
/* Create a memory property for softmmu CPU object,
* so users can wire up its memory. (This can't go in qom/cpu.c
* because that file is compiled only once for both user-mode
* and system builds.) The default if no link is set up is to use
* the system address space.
*/
DEFINE_PROP_LINK("memory", CPUState, memory, TYPE_MEMORY_REGION,
MemoryRegion *),
#endif
DEFINE_PROP_END_OF_LIST(),
};
void cpu_exec_initfn(CPUState *cpu) void cpu_exec_initfn(CPUState *cpu)
{ {
cpu->as = NULL; cpu->as = NULL;
@ -742,18 +759,6 @@ void cpu_exec_initfn(CPUState *cpu)
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
cpu->thread_id = qemu_get_thread_id(); cpu->thread_id = qemu_get_thread_id();
/* This is a softmmu CPU object, so create a property for it
* so users can wire up its memory. (This can't go in qom/cpu.c
* because that file is compiled only once for both user-mode
* and system builds.) The default if no link is set up is to use
* the system address space.
*/
object_property_add_link(OBJECT(cpu), "memory", TYPE_MEMORY_REGION,
(Object **)&cpu->memory,
qdev_prop_allow_set_link_before_realize,
OBJ_PROP_LINK_UNREF_ON_RELEASE,
&error_abort);
cpu->memory = system_memory; cpu->memory = system_memory;
object_ref(OBJECT(cpu->memory)); object_ref(OBJECT(cpu->memory));
#endif #endif
@ -775,15 +780,28 @@ void cpu_exec_realizefn(CPUState *cpu, Error **errp)
#endif #endif
} }
#if defined(CONFIG_USER_ONLY)
static void breakpoint_invalidate(CPUState *cpu, target_ulong pc) static void breakpoint_invalidate(CPUState *cpu, target_ulong pc)
{ {
/* Flush the whole TB as this will not have race conditions mmap_lock();
* even if we don't have proper locking yet. tb_lock();
* Ideally we would just invalidate the TBs for the tb_invalidate_phys_page_range(pc, pc + 1, 0);
* specified PC. tb_unlock();
*/ mmap_unlock();
tb_flush(cpu);
} }
#else
static void breakpoint_invalidate(CPUState *cpu, target_ulong pc)
{
MemTxAttrs attrs;
hwaddr phys = cpu_get_phys_page_attrs_debug(cpu, pc, &attrs);
int asidx = cpu_asidx_from_attrs(cpu, attrs);
if (phys != -1) {
/* Locks grabbed by tb_invalidate_phys_addr */
tb_invalidate_phys_addr(cpu->cpu_ases[asidx].as,
phys | (pc & ~TARGET_PAGE_MASK));
}
}
#endif
#if defined(CONFIG_USER_ONLY) #if defined(CONFIG_USER_ONLY)
void cpu_watchpoint_remove_all(CPUState *cpu, int mask) void cpu_watchpoint_remove_all(CPUState *cpu, int mask)
@ -2929,7 +2947,7 @@ static MemTxResult address_space_write_continue(AddressSpace *as, hwaddr addr,
} }
} else { } else {
/* RAM case */ /* RAM case */
ptr = qemu_map_ram_ptr(mr->ram_block, addr1); ptr = qemu_ram_ptr_length(mr->ram_block, addr1, &l);
memcpy(ptr, buf, l); memcpy(ptr, buf, l);
invalidate_and_set_dirty(mr, addr1, l); invalidate_and_set_dirty(mr, addr1, l);
} }
@ -3020,7 +3038,7 @@ MemTxResult address_space_read_continue(AddressSpace *as, hwaddr addr,
} }
} else { } else {
/* RAM case */ /* RAM case */
ptr = qemu_map_ram_ptr(mr->ram_block, addr1); ptr = qemu_ram_ptr_length(mr->ram_block, addr1, &l);
memcpy(buf, ptr, l); memcpy(buf, ptr, l);
} }

121
gdbstub.c
View File

@ -56,6 +56,21 @@ static inline int target_memory_rw_debug(CPUState *cpu, target_ulong addr,
return cpu_memory_rw_debug(cpu, addr, buf, len, is_write); return cpu_memory_rw_debug(cpu, addr, buf, len, is_write);
} }
/* Return the GDB index for a given vCPU state.
*
* For user mode this is simply the thread id. In system mode GDB
* numbers CPUs from 1 as 0 is reserved as an "any cpu" index.
*/
static inline int cpu_gdb_index(CPUState *cpu)
{
#if defined(CONFIG_USER_ONLY)
TaskState *ts = (TaskState *) cpu->opaque;
return ts->ts_tid;
#else
return cpu->cpu_index + 1;
#endif
}
enum { enum {
GDB_SIGNAL_0 = 0, GDB_SIGNAL_0 = 0,
GDB_SIGNAL_INT = 2, GDB_SIGNAL_INT = 2,
@ -272,7 +287,20 @@ static int gdb_signal_to_target (int sig)
return -1; return -1;
} }
//#define DEBUG_GDB /* #define DEBUG_GDB */
#ifdef DEBUG_GDB
# define DEBUG_GDB_GATE 1
#else
# define DEBUG_GDB_GATE 0
#endif
#define gdb_debug(fmt, ...) do { \
if (DEBUG_GDB_GATE) { \
fprintf(stderr, "%s: " fmt, __func__, ## __VA_ARGS__); \
} \
} while (0)
typedef struct GDBRegisterState { typedef struct GDBRegisterState {
int base_reg; int base_reg;
@ -548,9 +576,7 @@ static int put_packet_binary(GDBState *s, const char *buf, int len)
/* return -1 if error, 0 if OK */ /* return -1 if error, 0 if OK */
static int put_packet(GDBState *s, const char *buf) static int put_packet(GDBState *s, const char *buf)
{ {
#ifdef DEBUG_GDB gdb_debug("reply='%s'\n", buf);
printf("reply='%s'\n", buf);
#endif
return put_packet_binary(s, buf, strlen(buf)); return put_packet_binary(s, buf, strlen(buf));
} }
@ -827,7 +853,7 @@ static CPUState *find_cpu(uint32_t thread_id)
CPUState *cpu; CPUState *cpu;
CPU_FOREACH(cpu) { CPU_FOREACH(cpu) {
if (cpu_index(cpu) == thread_id) { if (cpu_gdb_index(cpu) == thread_id) {
return cpu; return cpu;
} }
} }
@ -912,23 +938,16 @@ static int gdb_handle_vcont(GDBState *s, const char *p)
if (res) { if (res) {
goto out; goto out;
} }
idx = tmp;
/* 0 means any thread, so we pick the first valid CPU */
if (!idx) {
idx = cpu_index(first_cpu);
}
/* /* 0 means any thread, so we pick the first valid CPU */
* If we are in user mode, the thread specified is actually a cpu = tmp ? find_cpu(tmp) : first_cpu;
* thread id, and not an index. We need to find the actual
* CPU first, and only then we can use its index.
*/
cpu = find_cpu(idx);
/* invalid CPU/thread specified */ /* invalid CPU/thread specified */
if (!idx || !cpu) { if (!cpu) {
res = -EINVAL; res = -EINVAL;
goto out; goto out;
} }
/* only use if no previous match occourred */ /* only use if no previous match occourred */
if (newstates[cpu->cpu_index] == 1) { if (newstates[cpu->cpu_index] == 1) {
newstates[cpu->cpu_index] = cur_action; newstates[cpu->cpu_index] = cur_action;
@ -956,16 +975,16 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
uint8_t *registers; uint8_t *registers;
target_ulong addr, len; target_ulong addr, len;
#ifdef DEBUG_GDB
printf("command='%s'\n", line_buf); gdb_debug("command='%s'\n", line_buf);
#endif
p = line_buf; p = line_buf;
ch = *p++; ch = *p++;
switch(ch) { switch(ch) {
case '?': case '?':
/* TODO: Make this return the correct value for user-mode. */ /* TODO: Make this return the correct value for user-mode. */
snprintf(buf, sizeof(buf), "T%02xthread:%02x;", GDB_SIGNAL_TRAP, snprintf(buf, sizeof(buf), "T%02xthread:%02x;", GDB_SIGNAL_TRAP,
cpu_index(s->c_cpu)); cpu_gdb_index(s->c_cpu));
put_packet(s, buf); put_packet(s, buf);
/* Remove all the breakpoints when this query is issued, /* Remove all the breakpoints when this query is issued,
* because gdb is doing and initial connect and the state * because gdb is doing and initial connect and the state
@ -1233,7 +1252,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
} else if (strcmp(p,"sThreadInfo") == 0) { } else if (strcmp(p,"sThreadInfo") == 0) {
report_cpuinfo: report_cpuinfo:
if (s->query_cpu) { if (s->query_cpu) {
snprintf(buf, sizeof(buf), "m%x", cpu_index(s->query_cpu)); snprintf(buf, sizeof(buf), "m%x", cpu_gdb_index(s->query_cpu));
put_packet(s, buf); put_packet(s, buf);
s->query_cpu = CPU_NEXT(s->query_cpu); s->query_cpu = CPU_NEXT(s->query_cpu);
} else } else
@ -1390,7 +1409,7 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state)
} }
snprintf(buf, sizeof(buf), snprintf(buf, sizeof(buf),
"T%02xthread:%02x;%swatch:" TARGET_FMT_lx ";", "T%02xthread:%02x;%swatch:" TARGET_FMT_lx ";",
GDB_SIGNAL_TRAP, cpu_index(cpu), type, GDB_SIGNAL_TRAP, cpu_gdb_index(cpu), type,
(target_ulong)cpu->watchpoint_hit->vaddr); (target_ulong)cpu->watchpoint_hit->vaddr);
cpu->watchpoint_hit = NULL; cpu->watchpoint_hit = NULL;
goto send_packet; goto send_packet;
@ -1424,7 +1443,7 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state)
break; break;
} }
gdb_set_stop_cpu(cpu); gdb_set_stop_cpu(cpu);
snprintf(buf, sizeof(buf), "T%02xthread:%02x;", ret, cpu_index(cpu)); snprintf(buf, sizeof(buf), "T%02xthread:%02x;", ret, cpu_gdb_index(cpu));
send_packet: send_packet:
put_packet(s, buf); put_packet(s, buf);
@ -1519,17 +1538,14 @@ static void gdb_read_byte(GDBState *s, int ch)
/* Waiting for a response to the last packet. If we see the start /* Waiting for a response to the last packet. If we see the start
of a new command then abandon the previous response. */ of a new command then abandon the previous response. */
if (ch == '-') { if (ch == '-') {
#ifdef DEBUG_GDB gdb_debug("Got NACK, retransmitting\n");
printf("Got NACK, retransmitting\n");
#endif
put_buffer(s, (uint8_t *)s->last_packet, s->last_packet_len); put_buffer(s, (uint8_t *)s->last_packet, s->last_packet_len);
} else if (ch == '+') {
gdb_debug("Got ACK\n");
} else {
gdb_debug("Got '%c' when expecting ACK/NACK\n", ch);
} }
#ifdef DEBUG_GDB
else if (ch == '+')
printf("Got ACK\n");
else
printf("Got '%c' when expecting ACK/NACK\n", ch);
#endif
if (ch == '+' || ch == '$') if (ch == '+' || ch == '$')
s->last_packet_len = 0; s->last_packet_len = 0;
if (ch != '$') if (ch != '$')
@ -1550,9 +1566,7 @@ static void gdb_read_byte(GDBState *s, int ch)
s->line_sum = 0; s->line_sum = 0;
s->state = RS_GETLINE; s->state = RS_GETLINE;
} else { } else {
#ifdef DEBUG_GDB gdb_debug("received garbage between packets: 0x%x\n", ch);
printf("gdbstub received garbage between packets: 0x%x\n", ch);
#endif
} }
break; break;
case RS_GETLINE: case RS_GETLINE:
@ -1568,9 +1582,7 @@ static void gdb_read_byte(GDBState *s, int ch)
/* end of command, start of checksum*/ /* end of command, start of checksum*/
s->state = RS_CHKSUM1; s->state = RS_CHKSUM1;
} else if (s->line_buf_index >= sizeof(s->line_buf) - 1) { } else if (s->line_buf_index >= sizeof(s->line_buf) - 1) {
#ifdef DEBUG_GDB gdb_debug("command buffer overrun, dropping command\n");
printf("gdbstub command buffer overrun, dropping command\n");
#endif
s->state = RS_IDLE; s->state = RS_IDLE;
} else { } else {
/* unescaped command character */ /* unescaped command character */
@ -1584,9 +1596,7 @@ static void gdb_read_byte(GDBState *s, int ch)
s->state = RS_CHKSUM1; s->state = RS_CHKSUM1;
} else if (s->line_buf_index >= sizeof(s->line_buf) - 1) { } else if (s->line_buf_index >= sizeof(s->line_buf) - 1) {
/* command buffer overrun */ /* command buffer overrun */
#ifdef DEBUG_GDB gdb_debug("command buffer overrun, dropping command\n");
printf("gdbstub command buffer overrun, dropping command\n");
#endif
s->state = RS_IDLE; s->state = RS_IDLE;
} else { } else {
/* parse escaped character and leave escape state */ /* parse escaped character and leave escape state */
@ -1598,25 +1608,18 @@ static void gdb_read_byte(GDBState *s, int ch)
case RS_GETLINE_RLE: case RS_GETLINE_RLE:
if (ch < ' ') { if (ch < ' ') {
/* invalid RLE count encoding */ /* invalid RLE count encoding */
#ifdef DEBUG_GDB gdb_debug("got invalid RLE count: 0x%x\n", ch);
printf("gdbstub got invalid RLE count: 0x%x\n", ch);
#endif
s->state = RS_GETLINE; s->state = RS_GETLINE;
} else { } else {
/* decode repeat length */ /* decode repeat length */
int repeat = (unsigned char)ch - ' ' + 3; int repeat = (unsigned char)ch - ' ' + 3;
if (s->line_buf_index + repeat >= sizeof(s->line_buf) - 1) { if (s->line_buf_index + repeat >= sizeof(s->line_buf) - 1) {
/* that many repeats would overrun the command buffer */ /* that many repeats would overrun the command buffer */
#ifdef DEBUG_GDB gdb_debug("command buffer overrun, dropping command\n");
printf("gdbstub command buffer overrun,"
" dropping command\n");
#endif
s->state = RS_IDLE; s->state = RS_IDLE;
} else if (s->line_buf_index < 1) { } else if (s->line_buf_index < 1) {
/* got a repeat but we have nothing to repeat */ /* got a repeat but we have nothing to repeat */
#ifdef DEBUG_GDB gdb_debug("got invalid RLE sequence\n");
printf("gdbstub got invalid RLE sequence\n");
#endif
s->state = RS_GETLINE; s->state = RS_GETLINE;
} else { } else {
/* repeat the last character */ /* repeat the last character */
@ -1631,9 +1634,7 @@ static void gdb_read_byte(GDBState *s, int ch)
case RS_CHKSUM1: case RS_CHKSUM1:
/* get high hex digit of checksum */ /* get high hex digit of checksum */
if (!isxdigit(ch)) { if (!isxdigit(ch)) {
#ifdef DEBUG_GDB gdb_debug("got invalid command checksum digit\n");
printf("gdbstub got invalid command checksum digit\n");
#endif
s->state = RS_GETLINE; s->state = RS_GETLINE;
break; break;
} }
@ -1644,21 +1645,17 @@ static void gdb_read_byte(GDBState *s, int ch)
case RS_CHKSUM2: case RS_CHKSUM2:
/* get low hex digit of checksum */ /* get low hex digit of checksum */
if (!isxdigit(ch)) { if (!isxdigit(ch)) {
#ifdef DEBUG_GDB gdb_debug("got invalid command checksum digit\n");
printf("gdbstub got invalid command checksum digit\n");
#endif
s->state = RS_GETLINE; s->state = RS_GETLINE;
break; break;
} }
s->line_csum |= fromhex(ch); s->line_csum |= fromhex(ch);
if (s->line_csum != (s->line_sum & 0xff)) { if (s->line_csum != (s->line_sum & 0xff)) {
gdb_debug("got command packet with incorrect checksum\n");
/* send NAK reply */ /* send NAK reply */
reply = '-'; reply = '-';
put_buffer(s, &reply, 1); put_buffer(s, &reply, 1);
#ifdef DEBUG_GDB
printf("gdbstub got command packet with incorrect checksum\n");
#endif
s->state = RS_IDLE; s->state = RS_IDLE;
} else { } else {
/* send ACK reply */ /* send ACK reply */
@ -2003,7 +2000,7 @@ int gdbserver_start(const char *device)
if (chr) { if (chr) {
qemu_chr_fe_init(&s->chr, chr, &error_abort); qemu_chr_fe_init(&s->chr, chr, &error_abort);
qemu_chr_fe_set_handlers(&s->chr, gdb_chr_can_receive, gdb_chr_receive, qemu_chr_fe_set_handlers(&s->chr, gdb_chr_can_receive, gdb_chr_receive,
gdb_chr_event, NULL, NULL, true); gdb_chr_event, NULL, NULL, NULL, true);
} }
s->state = chr ? RS_IDLE : RS_INACTIVE; s->state = chr ? RS_IDLE : RS_INACTIVE;
s->mon_chr = mon_chr; s->mon_chr = mon_chr;

View File

@ -1726,7 +1726,23 @@ ETEXI
STEXI STEXI
@item chardev-add args @item chardev-add args
@findex chardev-add @findex chardev-add
chardev_add accepts the same parameters as the -chardev command line switch. chardev-add accepts the same parameters as the -chardev command line switch.
ETEXI
{
.name = "chardev-change",
.args_type = "id:s,args:s",
.params = "id args",
.help = "change chardev",
.cmd = hmp_chardev_change,
},
STEXI
@item chardev-change args
@findex chardev-change
chardev-change accepts existing chardev @var{id} and then the same arguments
as the -chardev command line switch (except for "id").
ETEXI ETEXI

34
hmp.c
View File

@ -2197,6 +2197,40 @@ void hmp_chardev_add(Monitor *mon, const QDict *qdict)
hmp_handle_error(mon, &err); hmp_handle_error(mon, &err);
} }
void hmp_chardev_change(Monitor *mon, const QDict *qdict)
{
const char *args = qdict_get_str(qdict, "args");
const char *id;
Error *err = NULL;
ChardevBackend *backend = NULL;
ChardevReturn *ret = NULL;
QemuOpts *opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"), args,
true);
if (!opts) {
error_setg(&err, "Parsing chardev args failed");
goto end;
}
id = qdict_get_str(qdict, "id");
if (qemu_opts_id(opts)) {
error_setg(&err, "Unexpected 'id' parameter");
goto end;
}
backend = qemu_chr_parse_opts(opts, &err);
if (!backend) {
goto end;
}
ret = qmp_chardev_change(id, backend, &err);
end:
qapi_free_ChardevReturn(ret);
qapi_free_ChardevBackend(backend);
qemu_opts_del(opts);
hmp_handle_error(mon, &err);
}
void hmp_chardev_remove(Monitor *mon, const QDict *qdict) void hmp_chardev_remove(Monitor *mon, const QDict *qdict)
{ {
Error *local_err = NULL; Error *local_err = NULL;

1
hmp.h
View File

@ -102,6 +102,7 @@ void hmp_nbd_server_start(Monitor *mon, const QDict *qdict);
void hmp_nbd_server_add(Monitor *mon, const QDict *qdict); void hmp_nbd_server_add(Monitor *mon, const QDict *qdict);
void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict); void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict);
void hmp_chardev_add(Monitor *mon, const QDict *qdict); void hmp_chardev_add(Monitor *mon, const QDict *qdict);
void hmp_chardev_change(Monitor *mon, const QDict *qdict);
void hmp_chardev_remove(Monitor *mon, const QDict *qdict); void hmp_chardev_remove(Monitor *mon, const QDict *qdict);
void hmp_chardev_send_break(Monitor *mon, const QDict *qdict); void hmp_chardev_send_break(Monitor *mon, const QDict *qdict);
void hmp_qemu_io(Monitor *mon, const QDict *qdict); void hmp_qemu_io(Monitor *mon, const QDict *qdict);

View File

@ -17,6 +17,7 @@
#define TYPE_TYPHOON_PCI_HOST_BRIDGE "typhoon-pcihost" #define TYPE_TYPHOON_PCI_HOST_BRIDGE "typhoon-pcihost"
#define TYPE_TYPHOON_IOMMU_MEMORY_REGION "typhoon-iommu-memory-region"
typedef struct TyphoonCchip { typedef struct TyphoonCchip {
MemoryRegion region; MemoryRegion region;
@ -41,7 +42,7 @@ typedef struct TyphoonPchip {
MemoryRegion reg_conf; MemoryRegion reg_conf;
AddressSpace iommu_as; AddressSpace iommu_as;
MemoryRegion iommu; IOMMUMemoryRegion iommu;
uint64_t ctl; uint64_t ctl;
TyphoonWindow win[4]; TyphoonWindow win[4];
@ -663,7 +664,8 @@ static bool window_translate(TyphoonWindow *win, hwaddr addr,
/* Handle PCI-to-system address translation. */ /* Handle PCI-to-system address translation. */
/* TODO: A translation failure here ought to set PCI error codes on the /* TODO: A translation failure here ought to set PCI error codes on the
Pchip and generate a machine check interrupt. */ Pchip and generate a machine check interrupt. */
static IOMMUTLBEntry typhoon_translate_iommu(MemoryRegion *iommu, hwaddr addr, static IOMMUTLBEntry typhoon_translate_iommu(IOMMUMemoryRegion *iommu,
hwaddr addr,
IOMMUAccessFlags flag) IOMMUAccessFlags flag)
{ {
TyphoonPchip *pchip = container_of(iommu, TyphoonPchip, iommu); TyphoonPchip *pchip = container_of(iommu, TyphoonPchip, iommu);
@ -724,10 +726,6 @@ static IOMMUTLBEntry typhoon_translate_iommu(MemoryRegion *iommu, hwaddr addr,
return ret; return ret;
} }
static const MemoryRegionIOMMUOps typhoon_iommu_ops = {
.translate = typhoon_translate_iommu,
};
static AddressSpace *typhoon_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn) static AddressSpace *typhoon_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn)
{ {
TyphoonState *s = opaque; TyphoonState *s = opaque;
@ -891,9 +889,11 @@ PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus,
qdev_init_nofail(dev); qdev_init_nofail(dev);
/* Host memory as seen from the PCI side, via the IOMMU. */ /* Host memory as seen from the PCI side, via the IOMMU. */
memory_region_init_iommu(&s->pchip.iommu, OBJECT(s), &typhoon_iommu_ops, memory_region_init_iommu(&s->pchip.iommu, sizeof(s->pchip.iommu),
TYPE_TYPHOON_IOMMU_MEMORY_REGION, OBJECT(s),
"iommu-typhoon", UINT64_MAX); "iommu-typhoon", UINT64_MAX);
address_space_init(&s->pchip.iommu_as, &s->pchip.iommu, "pchip0-pci"); address_space_init(&s->pchip.iommu_as, MEMORY_REGION(&s->pchip.iommu),
"pchip0-pci");
pci_setup_iommu(b, typhoon_pci_dma_iommu, s); pci_setup_iommu(b, typhoon_pci_dma_iommu, s);
/* Pchip0 PCI special/interrupt acknowledge, 0x801.F800.0000, 64MB. */ /* Pchip0 PCI special/interrupt acknowledge, 0x801.F800.0000, 64MB. */
@ -951,9 +951,24 @@ static const TypeInfo typhoon_pcihost_info = {
.class_init = typhoon_pcihost_class_init, .class_init = typhoon_pcihost_class_init,
}; };
static void typhoon_iommu_memory_region_class_init(ObjectClass *klass,
void *data)
{
IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
imrc->translate = typhoon_translate_iommu;
}
static const TypeInfo typhoon_iommu_memory_region_info = {
.parent = TYPE_IOMMU_MEMORY_REGION,
.name = TYPE_TYPHOON_IOMMU_MEMORY_REGION,
.class_init = typhoon_iommu_memory_region_class_init,
};
static void typhoon_register_types(void) static void typhoon_register_types(void)
{ {
type_register_static(&typhoon_pcihost_info); type_register_static(&typhoon_pcihost_info);
type_register_static(&typhoon_iommu_memory_region_info);
} }
type_init(typhoon_register_types) type_init(typhoon_register_types)

View File

@ -1970,7 +1970,8 @@ static void pxa2xx_fir_realize(DeviceState *dev, Error **errp)
PXA2xxFIrState *s = PXA2XX_FIR(dev); PXA2xxFIrState *s = PXA2XX_FIR(dev);
qemu_chr_fe_set_handlers(&s->chr, pxa2xx_fir_is_empty, qemu_chr_fe_set_handlers(&s->chr, pxa2xx_fir_is_empty,
pxa2xx_fir_rx, pxa2xx_fir_event, s, NULL, true); pxa2xx_fir_rx, pxa2xx_fir_event, NULL, s, NULL,
true);
} }
static bool pxa2xx_fir_vmstate_validate(void *opaque, int version_id) static bool pxa2xx_fir_vmstate_validate(void *opaque, int version_id)

View File

@ -1106,7 +1106,7 @@ static void strongarm_uart_tx(void *opaque)
if (s->utcr3 & UTCR3_LBM) /* loopback */ { if (s->utcr3 & UTCR3_LBM) /* loopback */ {
strongarm_uart_receive(s, &s->tx_fifo[s->tx_start], 1); strongarm_uart_receive(s, &s->tx_fifo[s->tx_start], 1);
} else if (qemu_chr_fe_get_driver(&s->chr)) { } else if (qemu_chr_fe_backend_connected(&s->chr)) {
/* XXX this blocks entire thread. Rewrite to use /* XXX this blocks entire thread. Rewrite to use
* qemu_chr_fe_write and background I/O callbacks */ * qemu_chr_fe_write and background I/O callbacks */
qemu_chr_fe_write_all(&s->chr, &s->tx_fifo[s->tx_start], 1); qemu_chr_fe_write_all(&s->chr, &s->tx_fifo[s->tx_start], 1);
@ -1247,7 +1247,7 @@ static void strongarm_uart_realize(DeviceState *dev, Error **errp)
strongarm_uart_can_receive, strongarm_uart_can_receive,
strongarm_uart_receive, strongarm_uart_receive,
strongarm_uart_event, strongarm_uart_event,
s, NULL, true); NULL, s, NULL, true);
} }
static void strongarm_uart_reset(DeviceState *dev) static void strongarm_uart_reset(DeviceState *dev)

View File

@ -983,10 +983,6 @@ static void virtio_blk_instance_init(Object *obj)
{ {
VirtIOBlock *s = VIRTIO_BLK(obj); VirtIOBlock *s = VIRTIO_BLK(obj);
object_property_add_link(obj, "iothread", TYPE_IOTHREAD,
(Object **)&s->conf.iothread,
qdev_prop_allow_set_link_before_realize,
OBJ_PROP_LINK_UNREF_ON_RELEASE, NULL);
device_add_bootindex_property(obj, &s->conf.conf.bootindex, device_add_bootindex_property(obj, &s->conf.conf.bootindex,
"bootindex", "/disk@0,0", "bootindex", "/disk@0,0",
DEVICE(obj), NULL); DEVICE(obj), NULL);
@ -1014,6 +1010,8 @@ static Property virtio_blk_properties[] = {
DEFINE_PROP_BIT("request-merging", VirtIOBlock, conf.request_merging, 0, DEFINE_PROP_BIT("request-merging", VirtIOBlock, conf.request_merging, 0,
true), true),
DEFINE_PROP_UINT16("num-queues", VirtIOBlock, conf.num_queues, 1), DEFINE_PROP_UINT16("num-queues", VirtIOBlock, conf.num_queues, 1),
DEFINE_PROP_LINK("iothread", VirtIOBlock, conf.iothread, TYPE_IOTHREAD,
IOThread *),
DEFINE_PROP_END_OF_LIST(), DEFINE_PROP_END_OF_LIST(),
}; };

View File

@ -279,7 +279,7 @@ static void bcm2835_aux_realize(DeviceState *dev, Error **errp)
BCM2835AuxState *s = BCM2835_AUX(dev); BCM2835AuxState *s = BCM2835_AUX(dev);
qemu_chr_fe_set_handlers(&s->chr, bcm2835_aux_can_receive, qemu_chr_fe_set_handlers(&s->chr, bcm2835_aux_can_receive,
bcm2835_aux_receive, NULL, s, NULL, true); bcm2835_aux_receive, NULL, NULL, s, NULL, true);
} }
static Property bcm2835_aux_props[] = { static Property bcm2835_aux_props[] = {

View File

@ -279,7 +279,7 @@ static gboolean cadence_uart_xmit(GIOChannel *chan, GIOCondition cond,
int ret; int ret;
/* instant drain the fifo when there's no back-end */ /* instant drain the fifo when there's no back-end */
if (!qemu_chr_fe_get_driver(&s->chr)) { if (!qemu_chr_fe_backend_connected(&s->chr)) {
s->tx_count = 0; s->tx_count = 0;
return FALSE; return FALSE;
} }
@ -485,7 +485,7 @@ static void cadence_uart_realize(DeviceState *dev, Error **errp)
fifo_trigger_update, s); fifo_trigger_update, s);
qemu_chr_fe_set_handlers(&s->chr, uart_can_receive, uart_receive, qemu_chr_fe_set_handlers(&s->chr, uart_can_receive, uart_receive,
uart_event, s, NULL, true); uart_event, NULL, s, NULL, true);
} }
static void cadence_uart_init(Object *obj) static void cadence_uart_init(Object *obj)

View File

@ -87,12 +87,12 @@ static const MemoryRegionOps debugcon_ops = {
static void debugcon_realize_core(DebugconState *s, Error **errp) static void debugcon_realize_core(DebugconState *s, Error **errp)
{ {
if (!qemu_chr_fe_get_driver(&s->chr)) { if (!qemu_chr_fe_backend_connected(&s->chr)) {
error_setg(errp, "Can't create debugcon device, empty char device"); error_setg(errp, "Can't create debugcon device, empty char device");
return; return;
} }
qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, NULL, s, NULL, true); qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, NULL, NULL, s, NULL, true);
} }
static void debugcon_isa_realizefn(DeviceState *dev, Error **errp) static void debugcon_isa_realizefn(DeviceState *dev, Error **errp)

View File

@ -146,7 +146,7 @@ static void digic_uart_realize(DeviceState *dev, Error **errp)
DigicUartState *s = DIGIC_UART(dev); DigicUartState *s = DIGIC_UART(dev);
qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx, qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx,
uart_event, s, NULL, true); uart_event, NULL, s, NULL, true);
} }
static void digic_uart_init(Object *obj) static void digic_uart_init(Object *obj)

View File

@ -417,7 +417,7 @@ static void escc_update_parameters(ChannelState *s)
int speed, parity, data_bits, stop_bits; int speed, parity, data_bits, stop_bits;
QEMUSerialSetParams ssp; QEMUSerialSetParams ssp;
if (!qemu_chr_fe_get_driver(&s->chr) || s->type != ser) if (!qemu_chr_fe_backend_connected(&s->chr) || s->type != ser)
return; return;
if (s->wregs[W_TXCTRL1] & TXCTRL1_PAREN) { if (s->wregs[W_TXCTRL1] & TXCTRL1_PAREN) {
@ -557,7 +557,7 @@ static void escc_mem_write(void *opaque, hwaddr addr,
trace_escc_mem_writeb_data(CHN_C(s), val); trace_escc_mem_writeb_data(CHN_C(s), val);
s->tx = val; s->tx = val;
if (s->wregs[W_TXCTRL2] & TXCTRL2_TXEN) { // tx enabled if (s->wregs[W_TXCTRL2] & TXCTRL2_TXEN) { // tx enabled
if (qemu_chr_fe_get_driver(&s->chr)) { if (qemu_chr_fe_backend_connected(&s->chr)) {
/* XXX this blocks entire thread. Rewrite to use /* XXX this blocks entire thread. Rewrite to use
* qemu_chr_fe_write and background I/O callbacks */ * qemu_chr_fe_write and background I/O callbacks */
qemu_chr_fe_write_all(&s->chr, &s->tx, 1); qemu_chr_fe_write_all(&s->chr, &s->tx, 1);
@ -1013,10 +1013,10 @@ static void escc_realize(DeviceState *dev, Error **errp)
ESCC_SIZE << s->it_shift); ESCC_SIZE << s->it_shift);
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
if (qemu_chr_fe_get_driver(&s->chn[i].chr)) { if (qemu_chr_fe_backend_connected(&s->chn[i].chr)) {
s->chn[i].clock = s->frequency / 2; s->chn[i].clock = s->frequency / 2;
qemu_chr_fe_set_handlers(&s->chn[i].chr, serial_can_receive, qemu_chr_fe_set_handlers(&s->chn[i].chr, serial_can_receive,
serial_receive1, serial_event, serial_receive1, serial_event, NULL,
&s->chn[i], NULL, true); &s->chn[i], NULL, true);
} }
} }

View File

@ -233,7 +233,7 @@ static void etraxfs_ser_realize(DeviceState *dev, Error **errp)
qemu_chr_fe_set_handlers(&s->chr, qemu_chr_fe_set_handlers(&s->chr,
serial_can_receive, serial_receive, serial_can_receive, serial_receive,
serial_event, s, NULL, true); serial_event, NULL, s, NULL, true);
} }
static void etraxfs_ser_class_init(ObjectClass *klass, void *data) static void etraxfs_ser_class_init(ObjectClass *klass, void *data)

View File

@ -380,7 +380,7 @@ static void exynos4210_uart_write(void *opaque, hwaddr offset,
break; break;
case UTXH: case UTXH:
if (qemu_chr_fe_get_driver(&s->chr)) { if (qemu_chr_fe_backend_connected(&s->chr)) {
s->reg[I_(UTRSTAT)] &= ~(UTRSTAT_TRANSMITTER_EMPTY | s->reg[I_(UTRSTAT)] &= ~(UTRSTAT_TRANSMITTER_EMPTY |
UTRSTAT_Tx_BUFFER_EMPTY); UTRSTAT_Tx_BUFFER_EMPTY);
ch = (uint8_t)val; ch = (uint8_t)val;
@ -645,7 +645,7 @@ static void exynos4210_uart_realize(DeviceState *dev, Error **errp)
qemu_chr_fe_set_handlers(&s->chr, exynos4210_uart_can_receive, qemu_chr_fe_set_handlers(&s->chr, exynos4210_uart_can_receive,
exynos4210_uart_receive, exynos4210_uart_event, exynos4210_uart_receive, exynos4210_uart_event,
s, NULL, true); NULL, s, NULL, true);
} }
static Property exynos4210_uart_properties[] = { static Property exynos4210_uart_properties[] = {

View File

@ -201,7 +201,7 @@ static void grlib_apbuart_write(void *opaque, hwaddr addr,
case DATA_OFFSET: case DATA_OFFSET:
case DATA_OFFSET + 3: /* When only one byte write */ case DATA_OFFSET + 3: /* When only one byte write */
/* Transmit when character device available and transmitter enabled */ /* Transmit when character device available and transmitter enabled */
if (qemu_chr_fe_get_driver(&uart->chr) && if (qemu_chr_fe_backend_connected(&uart->chr) &&
(uart->control & UART_TRANSMIT_ENABLE)) { (uart->control & UART_TRANSMIT_ENABLE)) {
c = value & 0xFF; c = value & 0xFF;
/* XXX this blocks entire thread. Rewrite to use /* XXX this blocks entire thread. Rewrite to use
@ -247,7 +247,7 @@ static int grlib_apbuart_init(SysBusDevice *dev)
grlib_apbuart_can_receive, grlib_apbuart_can_receive,
grlib_apbuart_receive, grlib_apbuart_receive,
grlib_apbuart_event, grlib_apbuart_event,
uart, NULL, true); NULL, uart, NULL, true);
sysbus_init_irq(dev, &uart->irq); sysbus_init_irq(dev, &uart->irq);

View File

@ -315,7 +315,7 @@ static void imx_serial_realize(DeviceState *dev, Error **errp)
DPRINTF("char dev for uart: %p\n", qemu_chr_fe_get_driver(&s->chr)); DPRINTF("char dev for uart: %p\n", qemu_chr_fe_get_driver(&s->chr));
qemu_chr_fe_set_handlers(&s->chr, imx_can_receive, imx_receive, qemu_chr_fe_set_handlers(&s->chr, imx_can_receive, imx_receive,
imx_event, s, NULL, true); imx_event, NULL, s, NULL, true);
} }
static void imx_serial_init(Object *obj) static void imx_serial_init(Object *obj)

View File

@ -542,10 +542,10 @@ static void ipoctal_realize(DeviceState *dev, Error **errp)
ch->ipoctal = s; ch->ipoctal = s;
/* Redirect IP-Octal channels to host character devices */ /* Redirect IP-Octal channels to host character devices */
if (qemu_chr_fe_get_driver(&ch->dev)) { if (qemu_chr_fe_backend_connected(&ch->dev)) {
qemu_chr_fe_set_handlers(&ch->dev, hostdev_can_receive, qemu_chr_fe_set_handlers(&ch->dev, hostdev_can_receive,
hostdev_receive, hostdev_event, hostdev_receive, hostdev_event,
ch, NULL, true); NULL, ch, NULL, true);
DPRINTF("Redirecting channel %u to %s\n", i, ch->dev->label); DPRINTF("Redirecting channel %u to %s\n", i, ch->dev->label);
} else { } else {
DPRINTF("Could not redirect channel %u, no chardev set\n", i); DPRINTF("Could not redirect channel %u, no chardev set\n", i);

View File

@ -119,7 +119,7 @@ static void lm32_juart_realize(DeviceState *dev, Error **errp)
LM32JuartState *s = LM32_JUART(dev); LM32JuartState *s = LM32_JUART(dev);
qemu_chr_fe_set_handlers(&s->chr, juart_can_rx, juart_rx, qemu_chr_fe_set_handlers(&s->chr, juart_can_rx, juart_rx,
juart_event, s, NULL, true); juart_event, NULL, s, NULL, true);
} }
static const VMStateDescription vmstate_lm32_juart = { static const VMStateDescription vmstate_lm32_juart = {

View File

@ -266,7 +266,7 @@ static void lm32_uart_realize(DeviceState *dev, Error **errp)
LM32UartState *s = LM32_UART(dev); LM32UartState *s = LM32_UART(dev);
qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx, qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx,
uart_event, s, NULL, true); uart_event, NULL, s, NULL, true);
} }
static const VMStateDescription vmstate_lm32_uart = { static const VMStateDescription vmstate_lm32_uart = {

View File

@ -305,7 +305,7 @@ static void mcf_uart_realize(DeviceState *dev, Error **errp)
mcf_uart_state *s = MCF_UART(dev); mcf_uart_state *s = MCF_UART(dev);
qemu_chr_fe_set_handlers(&s->chr, mcf_uart_can_receive, mcf_uart_receive, qemu_chr_fe_set_handlers(&s->chr, mcf_uart_can_receive, mcf_uart_receive,
mcf_uart_event, s, NULL, true); mcf_uart_event, NULL, s, NULL, true);
} }
static Property mcf_uart_properties[] = { static Property mcf_uart_properties[] = {

View File

@ -199,7 +199,7 @@ static void milkymist_uart_realize(DeviceState *dev, Error **errp)
MilkymistUartState *s = MILKYMIST_UART(dev); MilkymistUartState *s = MILKYMIST_UART(dev);
qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx, qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx,
uart_event, s, NULL, true); uart_event, NULL, s, NULL, true);
} }
static void milkymist_uart_init(Object *obj) static void milkymist_uart_init(Object *obj)

View File

@ -503,6 +503,10 @@ static const VMStateDescription vmstate_parallel_isa = {
} }
}; };
static int parallel_can_receive(void *opaque)
{
return 1;
}
static void parallel_isa_realizefn(DeviceState *dev, Error **errp) static void parallel_isa_realizefn(DeviceState *dev, Error **errp)
{ {
@ -513,7 +517,7 @@ static void parallel_isa_realizefn(DeviceState *dev, Error **errp)
int base; int base;
uint8_t dummy; uint8_t dummy;
if (!qemu_chr_fe_get_driver(&s->chr)) { if (!qemu_chr_fe_backend_connected(&s->chr)) {
error_setg(errp, "Can't create parallel device, empty char device"); error_setg(errp, "Can't create parallel device, empty char device");
return; return;
} }
@ -535,6 +539,8 @@ static void parallel_isa_realizefn(DeviceState *dev, Error **errp)
isa_init_irq(isadev, &s->irq, isa->isairq); isa_init_irq(isadev, &s->irq, isa->isairq);
qemu_register_reset(parallel_reset, s); qemu_register_reset(parallel_reset, s);
qemu_chr_fe_set_handlers(&s->chr, parallel_can_receive, NULL,
NULL, NULL, s, NULL, true);
if (qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_PP_READ_STATUS, &dummy) == 0) { if (qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_PP_READ_STATUS, &dummy) == 0) {
s->hw_driver = 1; s->hw_driver = 1;
s->status = dummy; s->status = dummy;

View File

@ -329,7 +329,7 @@ static void pl011_realize(DeviceState *dev, Error **errp)
PL011State *s = PL011(dev); PL011State *s = PL011(dev);
qemu_chr_fe_set_handlers(&s->chr, pl011_can_receive, pl011_receive, qemu_chr_fe_set_handlers(&s->chr, pl011_can_receive, pl011_receive,
pl011_event, s, NULL, true); pl011_event, NULL, s, NULL, true);
} }
static void pl011_class_init(ObjectClass *oc, void *data) static void pl011_class_init(ObjectClass *oc, void *data)

View File

@ -195,7 +195,7 @@ static int write_console_data(SCLPEvent *event, const uint8_t *buf, int len)
{ {
SCLPConsoleLM *scon = SCLPLM_CONSOLE(event); SCLPConsoleLM *scon = SCLPLM_CONSOLE(event);
if (!qemu_chr_fe_get_driver(&scon->chr)) { if (!qemu_chr_fe_backend_connected(&scon->chr)) {
/* If there's no backend, we can just say we consumed all data. */ /* If there's no backend, we can just say we consumed all data. */
return len; return len;
} }
@ -313,7 +313,7 @@ static int console_init(SCLPEvent *event)
console_available = true; console_available = true;
qemu_chr_fe_set_handlers(&scon->chr, chr_can_read, qemu_chr_fe_set_handlers(&scon->chr, chr_can_read,
chr_read, NULL, scon, NULL, true); chr_read, NULL, NULL, scon, NULL, true);
return 0; return 0;
} }

View File

@ -163,7 +163,7 @@ static ssize_t write_console_data(SCLPEvent *event, const uint8_t *buf,
{ {
SCLPConsole *scon = SCLP_CONSOLE(event); SCLPConsole *scon = SCLP_CONSOLE(event);
if (!qemu_chr_fe_get_driver(&scon->chr)) { if (!qemu_chr_fe_backend_connected(&scon->chr)) {
/* If there's no backend, we can just say we consumed all data. */ /* If there's no backend, we can just say we consumed all data. */
return len; return len;
} }
@ -228,7 +228,7 @@ static int console_init(SCLPEvent *event)
} }
console_available = true; console_available = true;
qemu_chr_fe_set_handlers(&scon->chr, chr_can_read, qemu_chr_fe_set_handlers(&scon->chr, chr_can_read,
chr_read, NULL, scon, NULL, true); chr_read, NULL, NULL, scon, NULL, true);
return 0; return 0;
} }

View File

@ -312,6 +312,24 @@ static void serial_write_fcr(SerialState *s, uint8_t val)
} }
} }
static void serial_update_tiocm(SerialState *s)
{
int flags;
qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_GET_TIOCM, &flags);
flags &= ~(CHR_TIOCM_RTS | CHR_TIOCM_DTR);
if (s->mcr & UART_MCR_RTS) {
flags |= CHR_TIOCM_RTS;
}
if (s->mcr & UART_MCR_DTR) {
flags |= CHR_TIOCM_DTR;
}
qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_TIOCM, &flags);
}
static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val, static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
unsigned size) unsigned size)
{ {
@ -426,24 +444,13 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
break; break;
case 4: case 4:
{ {
int flags;
int old_mcr = s->mcr; int old_mcr = s->mcr;
s->mcr = val & 0x1f; s->mcr = val & 0x1f;
if (val & UART_MCR_LOOP) if (val & UART_MCR_LOOP)
break; break;
if (s->poll_msl >= 0 && old_mcr != s->mcr) { if (s->poll_msl >= 0 && old_mcr != s->mcr) {
serial_update_tiocm(s);
qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_GET_TIOCM, &flags);
flags &= ~(CHR_TIOCM_RTS | CHR_TIOCM_DTR);
if (val & UART_MCR_RTS)
flags |= CHR_TIOCM_RTS;
if (val & UART_MCR_DTR)
flags |= CHR_TIOCM_DTR;
qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_TIOCM, &flags);
/* Update the modem status after a one-character-send wait-time, since there may be a response /* Update the modem status after a one-character-send wait-time, since there may be a response
from the device/computer at the other end of the serial line */ from the device/computer at the other end of the serial line */
timer_mod(s->modem_status_poll, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->char_transmit_time); timer_mod(s->modem_status_poll, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->char_transmit_time);
@ -884,9 +891,37 @@ static void serial_reset(void *opaque)
s->msr &= ~UART_MSR_ANY_DELTA; s->msr &= ~UART_MSR_ANY_DELTA;
} }
static int serial_be_change(void *opaque)
{
SerialState *s = opaque;
qemu_chr_fe_set_handlers(&s->chr, serial_can_receive1, serial_receive1,
serial_event, serial_be_change, s, NULL, true);
serial_update_parameters(s);
qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_BREAK,
&s->last_break_enable);
s->poll_msl = (s->ier & UART_IER_MSI) ? 1 : 0;
serial_update_msl(s);
if (s->poll_msl >= 0 && !(s->mcr & UART_MCR_LOOP)) {
serial_update_tiocm(s);
}
if (s->watch_tag > 0) {
g_source_remove(s->watch_tag);
s->watch_tag = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
serial_watch_cb, s);
}
return 0;
}
void serial_realize_core(SerialState *s, Error **errp) void serial_realize_core(SerialState *s, Error **errp)
{ {
if (!qemu_chr_fe_get_driver(&s->chr)) { if (!qemu_chr_fe_backend_connected(&s->chr)) {
error_setg(errp, "Can't create serial device, empty char device"); error_setg(errp, "Can't create serial device, empty char device");
return; return;
} }
@ -897,7 +932,7 @@ void serial_realize_core(SerialState *s, Error **errp)
qemu_register_reset(serial_reset, s); qemu_register_reset(serial_reset, s);
qemu_chr_fe_set_handlers(&s->chr, serial_can_receive1, serial_receive1, qemu_chr_fe_set_handlers(&s->chr, serial_can_receive1, serial_receive1,
serial_event, s, NULL, true); serial_event, serial_be_change, s, NULL, true);
fifo8_create(&s->recv_fifo, UART_FIFO_LENGTH); fifo8_create(&s->recv_fifo, UART_FIFO_LENGTH);
fifo8_create(&s->xmit_fifo, UART_FIFO_LENGTH); fifo8_create(&s->xmit_fifo, UART_FIFO_LENGTH);
serial_reset(s); serial_reset(s);

View File

@ -110,7 +110,7 @@ static void sh_serial_write(void *opaque, hwaddr offs,
} }
return; return;
case 0x0c: /* FTDR / TDR */ case 0x0c: /* FTDR / TDR */
if (qemu_chr_fe_get_driver(&s->chr)) { if (qemu_chr_fe_backend_connected(&s->chr)) {
ch = val; ch = val;
/* XXX this blocks entire thread. Rewrite to use /* XXX this blocks entire thread. Rewrite to use
* qemu_chr_fe_write and background I/O callbacks */ * qemu_chr_fe_write and background I/O callbacks */
@ -400,7 +400,7 @@ void sh_serial_init(MemoryRegion *sysmem,
qemu_chr_fe_init(&s->chr, chr, &error_abort); qemu_chr_fe_init(&s->chr, chr, &error_abort);
qemu_chr_fe_set_handlers(&s->chr, sh_serial_can_receive1, qemu_chr_fe_set_handlers(&s->chr, sh_serial_can_receive1,
sh_serial_receive1, sh_serial_receive1,
sh_serial_event, s, NULL, true); sh_serial_event, NULL, s, NULL, true);
} }
s->eri = eri_source; s->eri = eri_source;

View File

@ -78,13 +78,13 @@ static void spapr_vty_realize(VIOsPAPRDevice *sdev, Error **errp)
{ {
VIOsPAPRVTYDevice *dev = VIO_SPAPR_VTY_DEVICE(sdev); VIOsPAPRVTYDevice *dev = VIO_SPAPR_VTY_DEVICE(sdev);
if (!qemu_chr_fe_get_driver(&dev->chardev)) { if (!qemu_chr_fe_backend_connected(&dev->chardev)) {
error_setg(errp, "chardev property not set"); error_setg(errp, "chardev property not set");
return; return;
} }
qemu_chr_fe_set_handlers(&dev->chardev, vty_can_receive, qemu_chr_fe_set_handlers(&dev->chardev, vty_can_receive,
vty_receive, NULL, dev, NULL, true); vty_receive, NULL, NULL, dev, NULL, true);
} }
/* Forward declaration */ /* Forward declaration */

View File

@ -207,7 +207,8 @@ static void stm32f2xx_usart_realize(DeviceState *dev, Error **errp)
STM32F2XXUsartState *s = STM32F2XX_USART(dev); STM32F2XXUsartState *s = STM32F2XX_USART(dev);
qemu_chr_fe_set_handlers(&s->chr, stm32f2xx_usart_can_receive, qemu_chr_fe_set_handlers(&s->chr, stm32f2xx_usart_can_receive,
stm32f2xx_usart_receive, NULL, s, NULL, true); stm32f2xx_usart_receive, NULL, NULL,
s, NULL, true);
} }
static void stm32f2xx_usart_class_init(ObjectClass *klass, void *data) static void stm32f2xx_usart_class_init(ObjectClass *klass, void *data)

View File

@ -179,7 +179,7 @@ static void terminal_init(EmulatedCcw3270Device *dev, Error **errp)
} }
terminal_available = true; terminal_available = true;
qemu_chr_fe_set_handlers(&t->chr, terminal_can_read, qemu_chr_fe_set_handlers(&t->chr, terminal_can_read,
terminal_read, chr_event, t, NULL, true); terminal_read, chr_event, NULL, t, NULL, true);
} }
static int read_payload_3270(EmulatedCcw3270Device *dev, uint32_t cda, static int read_payload_3270(EmulatedCcw3270Device *dev, uint32_t cda,
@ -239,7 +239,7 @@ static int write_payload_3270(EmulatedCcw3270Device *dev, uint8_t cmd,
return 0; return 0;
} }
} }
if (!qemu_chr_fe_get_driver(&t->chr)) { if (!qemu_chr_fe_backend_connected(&t->chr)) {
/* We just say we consumed all data if there's no backend. */ /* We just say we consumed all data if there's no backend. */
return count; return count;
} }

View File

@ -49,7 +49,7 @@ static ssize_t flush_buf(VirtIOSerialPort *port,
VirtConsole *vcon = VIRTIO_CONSOLE(port); VirtConsole *vcon = VIRTIO_CONSOLE(port);
ssize_t ret; ssize_t ret;
if (!qemu_chr_fe_get_driver(&vcon->chr)) { if (!qemu_chr_fe_backend_connected(&vcon->chr)) {
/* If there's no backend, we can just say we consumed all data. */ /* If there's no backend, we can just say we consumed all data. */
return len; return len;
} }
@ -163,12 +163,35 @@ static void chr_event(void *opaque, int event)
} }
} }
static int chr_be_change(void *opaque)
{
VirtConsole *vcon = opaque;
VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(vcon);
VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port);
if (k->is_console) {
qemu_chr_fe_set_handlers(&vcon->chr, chr_can_read, chr_read,
NULL, chr_be_change, vcon, NULL, true);
} else {
qemu_chr_fe_set_handlers(&vcon->chr, chr_can_read, chr_read,
chr_event, chr_be_change, vcon, NULL, false);
}
if (vcon->watch) {
g_source_remove(vcon->watch);
vcon->watch = qemu_chr_fe_add_watch(&vcon->chr,
G_IO_OUT | G_IO_HUP,
chr_write_unblocked, vcon);
}
return 0;
}
static void virtconsole_realize(DeviceState *dev, Error **errp) static void virtconsole_realize(DeviceState *dev, Error **errp)
{ {
VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(dev); VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(dev);
VirtConsole *vcon = VIRTIO_CONSOLE(dev); VirtConsole *vcon = VIRTIO_CONSOLE(dev);
VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(dev); VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(dev);
Chardev *chr = qemu_chr_fe_get_driver(&vcon->chr);
if (port->id == 0 && !k->is_console) { if (port->id == 0 && !k->is_console) {
error_setg(errp, "Port number 0 on virtio-serial devices reserved " error_setg(errp, "Port number 0 on virtio-serial devices reserved "
@ -176,7 +199,7 @@ static void virtconsole_realize(DeviceState *dev, Error **errp)
return; return;
} }
if (chr) { if (qemu_chr_fe_backend_connected(&vcon->chr)) {
/* /*
* For consoles we don't block guest data transfer just * For consoles we don't block guest data transfer just
* because nothing is connected - we'll just let it go * because nothing is connected - we'll just let it go
@ -188,11 +211,13 @@ static void virtconsole_realize(DeviceState *dev, Error **errp)
*/ */
if (k->is_console) { if (k->is_console) {
qemu_chr_fe_set_handlers(&vcon->chr, chr_can_read, chr_read, qemu_chr_fe_set_handlers(&vcon->chr, chr_can_read, chr_read,
NULL, vcon, NULL, true); NULL, chr_be_change,
vcon, NULL, true);
virtio_serial_open(port); virtio_serial_open(port);
} else { } else {
qemu_chr_fe_set_handlers(&vcon->chr, chr_can_read, chr_read, qemu_chr_fe_set_handlers(&vcon->chr, chr_can_read, chr_read,
chr_event, vcon, NULL, false); chr_event, chr_be_change,
vcon, NULL, false);
} }
} }
} }

View File

@ -150,7 +150,7 @@ static void xencons_send(struct XenConsole *con)
ssize_t len, size; ssize_t len, size;
size = con->buffer.size - con->buffer.consumed; size = con->buffer.size - con->buffer.consumed;
if (qemu_chr_fe_get_driver(&con->chr)) { if (qemu_chr_fe_backend_connected(&con->chr)) {
len = qemu_chr_fe_write(&con->chr, len = qemu_chr_fe_write(&con->chr,
con->buffer.data + con->buffer.consumed, con->buffer.data + con->buffer.consumed,
size); size);
@ -246,7 +246,7 @@ static int con_initialise(struct XenDevice *xendev)
xen_be_bind_evtchn(&con->xendev); xen_be_bind_evtchn(&con->xendev);
qemu_chr_fe_set_handlers(&con->chr, xencons_can_receive, qemu_chr_fe_set_handlers(&con->chr, xencons_can_receive,
xencons_receive, NULL, con, NULL, true); xencons_receive, NULL, NULL, con, NULL, true);
xen_pv_printf(xendev, 1, xen_pv_printf(xendev, 1,
"ring mfn %d, remote port %d, local port %d, limit %zd\n", "ring mfn %d, remote port %d, local port %d, limit %zd\n",

View File

@ -212,7 +212,7 @@ static void xilinx_uartlite_realize(DeviceState *dev, Error **errp)
XilinxUARTLite *s = XILINX_UARTLITE(dev); XilinxUARTLite *s = XILINX_UARTLITE(dev);
qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx, qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx,
uart_event, s, NULL, true); uart_event, NULL, s, NULL, true);
} }
static void xilinx_uartlite_init(Object *obj) static void xilinx_uartlite_init(Object *obj)

View File

@ -159,7 +159,7 @@ static void set_drive(Object *obj, Visitor *v, const char *name, void *opaque,
set_pointer(obj, v, opaque, parse_drive, name, errp); set_pointer(obj, v, opaque, parse_drive, name, errp);
} }
PropertyInfo qdev_prop_drive = { const PropertyInfo qdev_prop_drive = {
.name = "str", .name = "str",
.description = "Node name or ID of a block device to use as a backend", .description = "Node name or ID of a block device to use as a backend",
.get = get_drive, .get = get_drive,
@ -228,7 +228,7 @@ static void release_chr(Object *obj, const char *name, void *opaque)
qemu_chr_fe_deinit(be, false); qemu_chr_fe_deinit(be, false);
} }
PropertyInfo qdev_prop_chr = { const PropertyInfo qdev_prop_chr = {
.name = "str", .name = "str",
.description = "ID of a chardev to use as a backend", .description = "ID of a chardev to use as a backend",
.get = get_chr, .get = get_chr,
@ -313,7 +313,7 @@ out:
g_free(str); g_free(str);
} }
PropertyInfo qdev_prop_netdev = { const PropertyInfo qdev_prop_netdev = {
.name = "str", .name = "str",
.description = "ID of a netdev to use as a backend", .description = "ID of a netdev to use as a backend",
.get = get_netdev, .get = get_netdev,
@ -393,7 +393,7 @@ static void set_vlan(Object *obj, Visitor *v, const char *name, void *opaque,
*ptr = hubport; *ptr = hubport;
} }
PropertyInfo qdev_prop_vlan = { const PropertyInfo qdev_prop_vlan = {
.name = "int32", .name = "int32",
.description = "Integer VLAN id to connect to", .description = "Integer VLAN id to connect to",
.print = print_vlan, .print = print_vlan,

View File

@ -25,7 +25,8 @@ void qdev_prop_set_after_realize(DeviceState *dev, const char *name,
} }
} }
void qdev_prop_allow_set_link_before_realize(Object *obj, const char *name, void qdev_prop_allow_set_link_before_realize(const Object *obj,
const char *name,
Object *val, Error **errp) Object *val, Error **errp)
{ {
DeviceState *dev = DEVICE(obj); DeviceState *dev = DEVICE(obj);
@ -131,7 +132,7 @@ static void set_default_value_bool(Object *obj, const Property *prop)
object_property_set_bool(obj, prop->defval.u, prop->name, &error_abort); object_property_set_bool(obj, prop->defval.u, prop->name, &error_abort);
} }
PropertyInfo qdev_prop_bit = { const PropertyInfo qdev_prop_bit = {
.name = "bool", .name = "bool",
.description = "on/off", .description = "on/off",
.get = prop_get_bit, .get = prop_get_bit,
@ -190,7 +191,7 @@ static void prop_set_bit64(Object *obj, Visitor *v, const char *name,
bit64_prop_set(dev, prop, value); bit64_prop_set(dev, prop, value);
} }
PropertyInfo qdev_prop_bit64 = { const PropertyInfo qdev_prop_bit64 = {
.name = "bool", .name = "bool",
.description = "on/off", .description = "on/off",
.get = prop_get_bit64, .get = prop_get_bit64,
@ -225,7 +226,7 @@ static void set_bool(Object *obj, Visitor *v, const char *name, void *opaque,
visit_type_bool(v, name, ptr, errp); visit_type_bool(v, name, ptr, errp);
} }
PropertyInfo qdev_prop_bool = { const PropertyInfo qdev_prop_bool = {
.name = "bool", .name = "bool",
.get = get_bool, .get = get_bool,
.set = set_bool, .set = set_bool,
@ -269,7 +270,7 @@ static void set_default_value_uint(Object *obj, const Property *prop)
object_property_set_uint(obj, prop->defval.u, prop->name, &error_abort); object_property_set_uint(obj, prop->defval.u, prop->name, &error_abort);
} }
PropertyInfo qdev_prop_uint8 = { const PropertyInfo qdev_prop_uint8 = {
.name = "uint8", .name = "uint8",
.get = get_uint8, .get = get_uint8,
.set = set_uint8, .set = set_uint8,
@ -303,7 +304,7 @@ static void set_uint16(Object *obj, Visitor *v, const char *name,
visit_type_uint16(v, name, ptr, errp); visit_type_uint16(v, name, ptr, errp);
} }
PropertyInfo qdev_prop_uint16 = { const PropertyInfo qdev_prop_uint16 = {
.name = "uint16", .name = "uint16",
.get = get_uint16, .get = get_uint16,
.set = set_uint16, .set = set_uint16,
@ -362,14 +363,14 @@ static void set_int32(Object *obj, Visitor *v, const char *name, void *opaque,
visit_type_int32(v, name, ptr, errp); visit_type_int32(v, name, ptr, errp);
} }
PropertyInfo qdev_prop_uint32 = { const PropertyInfo qdev_prop_uint32 = {
.name = "uint32", .name = "uint32",
.get = get_uint32, .get = get_uint32,
.set = set_uint32, .set = set_uint32,
.set_default_value = set_default_value_uint, .set_default_value = set_default_value_uint,
}; };
PropertyInfo qdev_prop_int32 = { const PropertyInfo qdev_prop_int32 = {
.name = "int32", .name = "int32",
.get = get_int32, .get = get_int32,
.set = set_int32, .set = set_int32,
@ -403,7 +404,7 @@ static void set_uint64(Object *obj, Visitor *v, const char *name,
visit_type_uint64(v, name, ptr, errp); visit_type_uint64(v, name, ptr, errp);
} }
PropertyInfo qdev_prop_uint64 = { const PropertyInfo qdev_prop_uint64 = {
.name = "uint64", .name = "uint64",
.get = get_uint64, .get = get_uint64,
.set = set_uint64, .set = set_uint64,
@ -456,7 +457,7 @@ static void set_string(Object *obj, Visitor *v, const char *name,
*ptr = str; *ptr = str;
} }
PropertyInfo qdev_prop_string = { const PropertyInfo qdev_prop_string = {
.name = "str", .name = "str",
.release = release_string, .release = release_string,
.get = get_string, .get = get_string,
@ -466,7 +467,7 @@ PropertyInfo qdev_prop_string = {
/* --- pointer --- */ /* --- pointer --- */
/* Not a proper property, just for dirty hacks. TODO Remove it! */ /* Not a proper property, just for dirty hacks. TODO Remove it! */
PropertyInfo qdev_prop_ptr = { const PropertyInfo qdev_prop_ptr = {
.name = "ptr", .name = "ptr",
}; };
@ -540,7 +541,7 @@ inval:
g_free(str); g_free(str);
} }
PropertyInfo qdev_prop_macaddr = { const PropertyInfo qdev_prop_macaddr = {
.name = "str", .name = "str",
.description = "Ethernet 6-byte MAC Address, example: 52:54:00:12:34:56", .description = "Ethernet 6-byte MAC Address, example: 52:54:00:12:34:56",
.get = get_mac, .get = get_mac,
@ -549,7 +550,7 @@ PropertyInfo qdev_prop_macaddr = {
/* --- on/off/auto --- */ /* --- on/off/auto --- */
PropertyInfo qdev_prop_on_off_auto = { const PropertyInfo qdev_prop_on_off_auto = {
.name = "OnOffAuto", .name = "OnOffAuto",
.description = "on/off/auto", .description = "on/off/auto",
.enum_table = OnOffAuto_lookup, .enum_table = OnOffAuto_lookup,
@ -562,7 +563,7 @@ PropertyInfo qdev_prop_on_off_auto = {
QEMU_BUILD_BUG_ON(sizeof(LostTickPolicy) != sizeof(int)); QEMU_BUILD_BUG_ON(sizeof(LostTickPolicy) != sizeof(int));
PropertyInfo qdev_prop_losttickpolicy = { const PropertyInfo qdev_prop_losttickpolicy = {
.name = "LostTickPolicy", .name = "LostTickPolicy",
.enum_table = LostTickPolicy_lookup, .enum_table = LostTickPolicy_lookup,
.get = get_enum, .get = get_enum,
@ -574,7 +575,7 @@ PropertyInfo qdev_prop_losttickpolicy = {
QEMU_BUILD_BUG_ON(sizeof(BlockdevOnError) != sizeof(int)); QEMU_BUILD_BUG_ON(sizeof(BlockdevOnError) != sizeof(int));
PropertyInfo qdev_prop_blockdev_on_error = { const PropertyInfo qdev_prop_blockdev_on_error = {
.name = "BlockdevOnError", .name = "BlockdevOnError",
.description = "Error handling policy, " .description = "Error handling policy, "
"report/ignore/enospc/stop/auto", "report/ignore/enospc/stop/auto",
@ -588,7 +589,7 @@ PropertyInfo qdev_prop_blockdev_on_error = {
QEMU_BUILD_BUG_ON(sizeof(BiosAtaTranslation) != sizeof(int)); QEMU_BUILD_BUG_ON(sizeof(BiosAtaTranslation) != sizeof(int));
PropertyInfo qdev_prop_bios_chs_trans = { const PropertyInfo qdev_prop_bios_chs_trans = {
.name = "BiosAtaTranslation", .name = "BiosAtaTranslation",
.description = "Logical CHS translation algorithm, " .description = "Logical CHS translation algorithm, "
"auto/none/lba/large/rechs", "auto/none/lba/large/rechs",
@ -600,7 +601,7 @@ PropertyInfo qdev_prop_bios_chs_trans = {
/* --- FDC default drive types */ /* --- FDC default drive types */
PropertyInfo qdev_prop_fdc_drive_type = { const PropertyInfo qdev_prop_fdc_drive_type = {
.name = "FdcDriveType", .name = "FdcDriveType",
.description = "FDC drive type, " .description = "FDC drive type, "
"144/288/120/none/auto", "144/288/120/none/auto",
@ -676,7 +677,7 @@ static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest,
} }
} }
PropertyInfo qdev_prop_pci_devfn = { const PropertyInfo qdev_prop_pci_devfn = {
.name = "int32", .name = "int32",
.description = "Slot and optional function number, example: 06.0 or 06", .description = "Slot and optional function number, example: 06.0 or 06",
.print = print_pci_devfn, .print = print_pci_devfn,
@ -725,7 +726,7 @@ static void set_blocksize(Object *obj, Visitor *v, const char *name,
*ptr = value; *ptr = value;
} }
PropertyInfo qdev_prop_blocksize = { const PropertyInfo qdev_prop_blocksize = {
.name = "uint16", .name = "uint16",
.description = "A power of two between 512 and 32768", .description = "A power of two between 512 and 32768",
.get = get_uint16, .get = get_uint16,
@ -840,7 +841,7 @@ inval:
g_free(str); g_free(str);
} }
PropertyInfo qdev_prop_pci_host_devaddr = { const PropertyInfo qdev_prop_pci_host_devaddr = {
.name = "str", .name = "str",
.description = "Address (bus/device/function) of " .description = "Address (bus/device/function) of "
"the host device, example: 04:10.0", "the host device, example: 04:10.0",
@ -949,7 +950,7 @@ static void set_prop_arraylen(Object *obj, Visitor *v, const char *name,
} }
} }
PropertyInfo qdev_prop_arraylen = { const PropertyInfo qdev_prop_arraylen = {
.name = "uint32", .name = "uint32",
.get = get_uint32, .get = get_uint32,
.set = set_prop_arraylen, .set = set_prop_arraylen,
@ -1207,9 +1208,27 @@ static void set_size(Object *obj, Visitor *v, const char *name, void *opaque,
visit_type_size(v, name, ptr, errp); visit_type_size(v, name, ptr, errp);
} }
PropertyInfo qdev_prop_size = { const PropertyInfo qdev_prop_size = {
.name = "size", .name = "size",
.get = get_size, .get = get_size,
.set = set_size, .set = set_size,
.set_default_value = set_default_value_uint, .set_default_value = set_default_value_uint,
}; };
/* --- object link property --- */
static void create_link_property(Object *obj, Property *prop, Error **errp)
{
Object **child = qdev_get_prop_ptr(DEVICE(obj), prop);
object_property_add_link(obj, prop->name, prop->link_type,
child,
qdev_prop_allow_set_link_before_realize,
OBJ_PROP_LINK_UNREF_ON_RELEASE,
errp);
}
const PropertyInfo qdev_prop_link = {
.name = "link",
.create = create_link_property,
};

View File

@ -744,6 +744,10 @@ static void qdev_property_add_legacy(DeviceState *dev, Property *prop,
return; return;
} }
if (prop->info->create) {
return;
}
name = g_strdup_printf("legacy-%s", prop->name); name = g_strdup_printf("legacy-%s", prop->name);
object_property_add(OBJECT(dev), name, "str", object_property_add(OBJECT(dev), name, "str",
prop->info->print ? qdev_get_legacy_property : prop->info->get, prop->info->print ? qdev_get_legacy_property : prop->info->get,
@ -770,20 +774,23 @@ void qdev_property_add_static(DeviceState *dev, Property *prop,
Error *local_err = NULL; Error *local_err = NULL;
Object *obj = OBJECT(dev); Object *obj = OBJECT(dev);
/* if (prop->info->create) {
* TODO qdev_prop_ptr does not have getters or setters. It must prop->info->create(obj, prop, &local_err);
* go now that it can be replaced with links. The test should be } else {
* removed along with it: all static properties are read/write. /*
*/ * TODO qdev_prop_ptr does not have getters or setters. It must
if (!prop->info->get && !prop->info->set) { * go now that it can be replaced with links. The test should be
return; * removed along with it: all static properties are read/write.
*/
if (!prop->info->get && !prop->info->set) {
return;
}
object_property_add(obj, prop->name, prop->info->name,
prop->info->get, prop->info->set,
prop->info->release,
prop, &local_err);
} }
object_property_add(obj, prop->name, prop->info->name,
prop->info->get, prop->info->set,
prop->info->release,
prop, &local_err);
if (local_err) { if (local_err) {
error_propagate(errp, local_err); error_propagate(errp, local_err);
return; return;

View File

@ -515,7 +515,7 @@ static void xlnx_dp_aux_set_command(XlnxDPState *s, uint32_t value)
s->core_registers[DP_INTERRUPT_SIGNAL_STATE] |= 0x04; s->core_registers[DP_INTERRUPT_SIGNAL_STATE] |= 0x04;
} }
static void xlnx_dp_set_dpdma(Object *obj, const char *name, Object *val, static void xlnx_dp_set_dpdma(const Object *obj, const char *name, Object *val,
Error **errp) Error **errp)
{ {
XlnxDPState *s = XLNX_DP(obj); XlnxDPState *s = XLNX_DP(obj);

View File

@ -54,6 +54,8 @@ typedef struct dma_pagetable_entry {
#define RC4030(obj) \ #define RC4030(obj) \
OBJECT_CHECK(rc4030State, (obj), TYPE_RC4030) OBJECT_CHECK(rc4030State, (obj), TYPE_RC4030)
#define TYPE_RC4030_IOMMU_MEMORY_REGION "rc4030-iommu-memory-region"
typedef struct rc4030State typedef struct rc4030State
{ {
SysBusDevice parent; SysBusDevice parent;
@ -90,7 +92,7 @@ typedef struct rc4030State
qemu_irq jazz_bus_irq; qemu_irq jazz_bus_irq;
/* whole DMA memory region, root of DMA address space */ /* whole DMA memory region, root of DMA address space */
MemoryRegion dma_mr; IOMMUMemoryRegion dma_mr;
AddressSpace dma_as; AddressSpace dma_as;
MemoryRegion iomem_chipset; MemoryRegion iomem_chipset;
@ -488,7 +490,7 @@ static const MemoryRegionOps jazzio_ops = {
.endianness = DEVICE_NATIVE_ENDIAN, .endianness = DEVICE_NATIVE_ENDIAN,
}; };
static IOMMUTLBEntry rc4030_dma_translate(MemoryRegion *iommu, hwaddr addr, static IOMMUTLBEntry rc4030_dma_translate(IOMMUMemoryRegion *iommu, hwaddr addr,
IOMMUAccessFlags flag) IOMMUAccessFlags flag)
{ {
rc4030State *s = container_of(iommu, rc4030State, dma_mr); rc4030State *s = container_of(iommu, rc4030State, dma_mr);
@ -516,10 +518,6 @@ static IOMMUTLBEntry rc4030_dma_translate(MemoryRegion *iommu, hwaddr addr,
return ret; return ret;
} }
static const MemoryRegionIOMMUOps rc4030_dma_ops = {
.translate = rc4030_dma_translate,
};
static void rc4030_reset(DeviceState *dev) static void rc4030_reset(DeviceState *dev)
{ {
rc4030State *s = RC4030(dev); rc4030State *s = RC4030(dev);
@ -677,9 +675,10 @@ static void rc4030_realize(DeviceState *dev, Error **errp)
memory_region_init_io(&s->iomem_jazzio, NULL, &jazzio_ops, s, memory_region_init_io(&s->iomem_jazzio, NULL, &jazzio_ops, s,
"rc4030.jazzio", 0x00001000); "rc4030.jazzio", 0x00001000);
memory_region_init_iommu(&s->dma_mr, o, &rc4030_dma_ops, memory_region_init_iommu(&s->dma_mr, sizeof(s->dma_mr),
"rc4030.dma", UINT32_MAX); TYPE_RC4030_IOMMU_MEMORY_REGION,
address_space_init(&s->dma_as, &s->dma_mr, "rc4030-dma"); o, "rc4030.dma", UINT32_MAX);
address_space_init(&s->dma_as, MEMORY_REGION(&s->dma_mr), "rc4030-dma");
} }
static void rc4030_unrealize(DeviceState *dev, Error **errp) static void rc4030_unrealize(DeviceState *dev, Error **errp)
@ -710,14 +709,29 @@ static const TypeInfo rc4030_info = {
.class_init = rc4030_class_init, .class_init = rc4030_class_init,
}; };
static void rc4030_iommu_memory_region_class_init(ObjectClass *klass,
void *data)
{
IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
imrc->translate = rc4030_dma_translate;
}
static const TypeInfo rc4030_iommu_memory_region_info = {
.parent = TYPE_IOMMU_MEMORY_REGION,
.name = TYPE_RC4030_IOMMU_MEMORY_REGION,
.class_init = rc4030_iommu_memory_region_class_init,
};
static void rc4030_register_types(void) static void rc4030_register_types(void)
{ {
type_register_static(&rc4030_info); type_register_static(&rc4030_info);
type_register_static(&rc4030_iommu_memory_region_info);
} }
type_init(rc4030_register_types) type_init(rc4030_register_types)
DeviceState *rc4030_init(rc4030_dma **dmas, MemoryRegion **dma_mr) DeviceState *rc4030_init(rc4030_dma **dmas, IOMMUMemoryRegion **dma_mr)
{ {
DeviceState *dev; DeviceState *dev;

View File

@ -52,7 +52,7 @@ struct AMDVIAddressSpace {
uint8_t bus_num; /* bus number */ uint8_t bus_num; /* bus number */
uint8_t devfn; /* device function */ uint8_t devfn; /* device function */
AMDVIState *iommu_state; /* AMDVI - one per machine */ AMDVIState *iommu_state; /* AMDVI - one per machine */
MemoryRegion iommu; /* Device's address translation region */ IOMMUMemoryRegion iommu; /* Device's address translation region */
MemoryRegion iommu_ir; /* Device's interrupt remapping region */ MemoryRegion iommu_ir; /* Device's interrupt remapping region */
AddressSpace as; /* device's corresponding address space */ AddressSpace as; /* device's corresponding address space */
}; };
@ -987,7 +987,7 @@ static inline bool amdvi_is_interrupt_addr(hwaddr addr)
return addr >= AMDVI_INT_ADDR_FIRST && addr <= AMDVI_INT_ADDR_LAST; return addr >= AMDVI_INT_ADDR_FIRST && addr <= AMDVI_INT_ADDR_LAST;
} }
static IOMMUTLBEntry amdvi_translate(MemoryRegion *iommu, hwaddr addr, static IOMMUTLBEntry amdvi_translate(IOMMUMemoryRegion *iommu, hwaddr addr,
IOMMUAccessFlags flag) IOMMUAccessFlags flag)
{ {
AMDVIAddressSpace *as = container_of(iommu, AMDVIAddressSpace, iommu); AMDVIAddressSpace *as = container_of(iommu, AMDVIAddressSpace, iommu);
@ -1044,9 +1044,13 @@ static AddressSpace *amdvi_host_dma_iommu(PCIBus *bus, void *opaque, int devfn)
iommu_as[devfn]->devfn = (uint8_t)devfn; iommu_as[devfn]->devfn = (uint8_t)devfn;
iommu_as[devfn]->iommu_state = s; iommu_as[devfn]->iommu_state = s;
memory_region_init_iommu(&iommu_as[devfn]->iommu, OBJECT(s), memory_region_init_iommu(&iommu_as[devfn]->iommu,
&s->iommu_ops, "amd-iommu", UINT64_MAX); sizeof(iommu_as[devfn]->iommu),
address_space_init(&iommu_as[devfn]->as, &iommu_as[devfn]->iommu, TYPE_AMD_IOMMU_MEMORY_REGION,
OBJECT(s),
"amd-iommu", UINT64_MAX);
address_space_init(&iommu_as[devfn]->as,
MEMORY_REGION(&iommu_as[devfn]->iommu),
"amd-iommu"); "amd-iommu");
} }
return &iommu_as[devfn]->as; return &iommu_as[devfn]->as;
@ -1067,7 +1071,7 @@ static const MemoryRegionOps mmio_mem_ops = {
} }
}; };
static void amdvi_iommu_notify_flag_changed(MemoryRegion *iommu, static void amdvi_iommu_notify_flag_changed(IOMMUMemoryRegion *iommu,
IOMMUNotifierFlag old, IOMMUNotifierFlag old,
IOMMUNotifierFlag new) IOMMUNotifierFlag new)
{ {
@ -1085,8 +1089,6 @@ static void amdvi_init(AMDVIState *s)
{ {
amdvi_iotlb_reset(s); amdvi_iotlb_reset(s);
s->iommu_ops.translate = amdvi_translate;
s->iommu_ops.notify_flag_changed = amdvi_iommu_notify_flag_changed;
s->devtab_len = 0; s->devtab_len = 0;
s->cmdbuf_len = 0; s->cmdbuf_len = 0;
s->cmdbuf_head = 0; s->cmdbuf_head = 0;
@ -1227,10 +1229,25 @@ static const TypeInfo amdviPCI = {
.instance_size = sizeof(AMDVIPCIState), .instance_size = sizeof(AMDVIPCIState),
}; };
static void amdvi_iommu_memory_region_class_init(ObjectClass *klass, void *data)
{
IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
imrc->translate = amdvi_translate;
imrc->notify_flag_changed = amdvi_iommu_notify_flag_changed;
}
static const TypeInfo amdvi_iommu_memory_region_info = {
.parent = TYPE_IOMMU_MEMORY_REGION,
.name = TYPE_AMD_IOMMU_MEMORY_REGION,
.class_init = amdvi_iommu_memory_region_class_init,
};
static void amdviPCI_register_types(void) static void amdviPCI_register_types(void)
{ {
type_register_static(&amdviPCI); type_register_static(&amdviPCI);
type_register_static(&amdvi); type_register_static(&amdvi);
type_register_static(&amdvi_iommu_memory_region_info);
} }
type_init(amdviPCI_register_types); type_init(amdviPCI_register_types);

View File

@ -220,6 +220,8 @@
#define TYPE_AMD_IOMMU_PCI "AMDVI-PCI" #define TYPE_AMD_IOMMU_PCI "AMDVI-PCI"
#define TYPE_AMD_IOMMU_MEMORY_REGION "amd-iommu-iommu-memory-region"
typedef struct AMDVIAddressSpace AMDVIAddressSpace; typedef struct AMDVIAddressSpace AMDVIAddressSpace;
/* functions to steal PCI config space */ /* functions to steal PCI config space */
@ -276,9 +278,6 @@ typedef struct AMDVIState {
uint8_t romask[AMDVI_MMIO_SIZE]; /* MMIO read/only mask */ uint8_t romask[AMDVI_MMIO_SIZE]; /* MMIO read/only mask */
bool mmio_enabled; bool mmio_enabled;
/* IOMMU function */
MemoryRegionIOMMUOps iommu_ops;
/* for each served device */ /* for each served device */
AMDVIAddressSpace **address_spaces[PCI_BUS_MAX]; AMDVIAddressSpace **address_spaces[PCI_BUS_MAX];

View File

@ -972,9 +972,9 @@ static bool vtd_switch_address_space(VTDAddressSpace *as)
/* Turn off first then on the other */ /* Turn off first then on the other */
if (use_iommu) { if (use_iommu) {
memory_region_set_enabled(&as->sys_alias, false); memory_region_set_enabled(&as->sys_alias, false);
memory_region_set_enabled(&as->iommu, true); memory_region_set_enabled(MEMORY_REGION(&as->iommu), true);
} else { } else {
memory_region_set_enabled(&as->iommu, false); memory_region_set_enabled(MEMORY_REGION(&as->iommu), false);
memory_region_set_enabled(&as->sys_alias, true); memory_region_set_enabled(&as->sys_alias, true);
} }
@ -1366,7 +1366,7 @@ static void vtd_iotlb_domain_invalidate(IntelIOMMUState *s, uint16_t domain_id)
static int vtd_page_invalidate_notify_hook(IOMMUTLBEntry *entry, static int vtd_page_invalidate_notify_hook(IOMMUTLBEntry *entry,
void *private) void *private)
{ {
memory_region_notify_iommu((MemoryRegion *)private, *entry); memory_region_notify_iommu((IOMMUMemoryRegion *)private, *entry);
return 0; return 0;
} }
@ -2264,7 +2264,7 @@ static void vtd_mem_write(void *opaque, hwaddr addr,
} }
} }
static IOMMUTLBEntry vtd_iommu_translate(MemoryRegion *iommu, hwaddr addr, static IOMMUTLBEntry vtd_iommu_translate(IOMMUMemoryRegion *iommu, hwaddr addr,
IOMMUAccessFlags flag) IOMMUAccessFlags flag)
{ {
VTDAddressSpace *vtd_as = container_of(iommu, VTDAddressSpace, iommu); VTDAddressSpace *vtd_as = container_of(iommu, VTDAddressSpace, iommu);
@ -2303,7 +2303,7 @@ static IOMMUTLBEntry vtd_iommu_translate(MemoryRegion *iommu, hwaddr addr,
return iotlb; return iotlb;
} }
static void vtd_iommu_notify_flag_changed(MemoryRegion *iommu, static void vtd_iommu_notify_flag_changed(IOMMUMemoryRegion *iommu,
IOMMUNotifierFlag old, IOMMUNotifierFlag old,
IOMMUNotifierFlag new) IOMMUNotifierFlag new)
{ {
@ -2718,8 +2718,9 @@ VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn)
* vtd_sys_alias and intel_iommu regions. IR region is always * vtd_sys_alias and intel_iommu regions. IR region is always
* enabled. * enabled.
*/ */
memory_region_init_iommu(&vtd_dev_as->iommu, OBJECT(s), memory_region_init_iommu(&vtd_dev_as->iommu, sizeof(vtd_dev_as->iommu),
&s->iommu_ops, "intel_iommu_dmar", TYPE_INTEL_IOMMU_MEMORY_REGION, OBJECT(s),
"intel_iommu_dmar",
UINT64_MAX); UINT64_MAX);
memory_region_init_alias(&vtd_dev_as->sys_alias, OBJECT(s), memory_region_init_alias(&vtd_dev_as->sys_alias, OBJECT(s),
"vtd_sys_alias", get_system_memory(), "vtd_sys_alias", get_system_memory(),
@ -2736,7 +2737,8 @@ VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn)
memory_region_add_subregion_overlap(&vtd_dev_as->root, 0, memory_region_add_subregion_overlap(&vtd_dev_as->root, 0,
&vtd_dev_as->sys_alias, 1); &vtd_dev_as->sys_alias, 1);
memory_region_add_subregion_overlap(&vtd_dev_as->root, 0, memory_region_add_subregion_overlap(&vtd_dev_as->root, 0,
&vtd_dev_as->iommu, 1); MEMORY_REGION(&vtd_dev_as->iommu),
1);
vtd_switch_address_space(vtd_dev_as); vtd_switch_address_space(vtd_dev_as);
} }
return vtd_dev_as; return vtd_dev_as;
@ -2816,9 +2818,9 @@ static int vtd_replay_hook(IOMMUTLBEntry *entry, void *private)
return 0; return 0;
} }
static void vtd_iommu_replay(MemoryRegion *mr, IOMMUNotifier *n) static void vtd_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n)
{ {
VTDAddressSpace *vtd_as = container_of(mr, VTDAddressSpace, iommu); VTDAddressSpace *vtd_as = container_of(iommu_mr, VTDAddressSpace, iommu);
IntelIOMMUState *s = vtd_as->iommu_state; IntelIOMMUState *s = vtd_as->iommu_state;
uint8_t bus_n = pci_bus_num(vtd_as->bus); uint8_t bus_n = pci_bus_num(vtd_as->bus);
VTDContextEntry ce; VTDContextEntry ce;
@ -2856,9 +2858,6 @@ static void vtd_init(IntelIOMMUState *s)
memset(s->w1cmask, 0, DMAR_REG_SIZE); memset(s->w1cmask, 0, DMAR_REG_SIZE);
memset(s->womask, 0, DMAR_REG_SIZE); memset(s->womask, 0, DMAR_REG_SIZE);
s->iommu_ops.translate = vtd_iommu_translate;
s->iommu_ops.notify_flag_changed = vtd_iommu_notify_flag_changed;
s->iommu_ops.replay = vtd_iommu_replay;
s->root = 0; s->root = 0;
s->root_extended = false; s->root_extended = false;
s->dmar_enabled = false; s->dmar_enabled = false;
@ -3073,9 +3072,26 @@ static const TypeInfo vtd_info = {
.class_init = vtd_class_init, .class_init = vtd_class_init,
}; };
static void vtd_iommu_memory_region_class_init(ObjectClass *klass,
void *data)
{
IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
imrc->translate = vtd_iommu_translate;
imrc->notify_flag_changed = vtd_iommu_notify_flag_changed;
imrc->replay = vtd_iommu_replay;
}
static const TypeInfo vtd_iommu_memory_region_info = {
.parent = TYPE_IOMMU_MEMORY_REGION,
.name = TYPE_INTEL_IOMMU_MEMORY_REGION,
.class_init = vtd_iommu_memory_region_class_init,
};
static void vtd_register_types(void) static void vtd_register_types(void)
{ {
type_register_static(&vtd_info); type_register_static(&vtd_info);
type_register_static(&vtd_iommu_memory_region_info);
} }
type_init(vtd_register_types) type_init(vtd_register_types)

View File

@ -383,8 +383,7 @@ static void patch_byte(X86CPU *cpu, target_ulong addr, uint8_t byte)
cpu_memory_rw_debug(CPU(cpu), addr, &byte, 1, 1); cpu_memory_rw_debug(CPU(cpu), addr, &byte, 1, 1);
} }
static void patch_call(VAPICROMState *s, X86CPU *cpu, target_ulong ip, static void patch_call(X86CPU *cpu, target_ulong ip, uint32_t target)
uint32_t target)
{ {
uint32_t offset; uint32_t offset;
@ -393,16 +392,59 @@ static void patch_call(VAPICROMState *s, X86CPU *cpu, target_ulong ip,
cpu_memory_rw_debug(CPU(cpu), ip + 1, (void *)&offset, sizeof(offset), 1); cpu_memory_rw_debug(CPU(cpu), ip + 1, (void *)&offset, sizeof(offset), 1);
} }
typedef struct PatchInfo {
VAPICHandlers *handler;
target_ulong ip;
} PatchInfo;
static void do_patch_instruction(CPUState *cs, run_on_cpu_data data)
{
X86CPU *x86_cpu = X86_CPU(cs);
PatchInfo *info = (PatchInfo *) data.host_ptr;
VAPICHandlers *handlers = info->handler;
target_ulong ip = info->ip;
uint8_t opcode[2];
uint32_t imm32 = 0;
cpu_memory_rw_debug(cs, ip, opcode, sizeof(opcode), 0);
switch (opcode[0]) {
case 0x89: /* mov r32 to r/m32 */
patch_byte(x86_cpu, ip, 0x50 + modrm_reg(opcode[1])); /* push reg */
patch_call(x86_cpu, ip + 1, handlers->set_tpr);
break;
case 0x8b: /* mov r/m32 to r32 */
patch_byte(x86_cpu, ip, 0x90);
patch_call(x86_cpu, ip + 1, handlers->get_tpr[modrm_reg(opcode[1])]);
break;
case 0xa1: /* mov abs to eax */
patch_call(x86_cpu, ip, handlers->get_tpr[0]);
break;
case 0xa3: /* mov eax to abs */
patch_call(x86_cpu, ip, handlers->set_tpr_eax);
break;
case 0xc7: /* mov imm32, r/m32 (c7/0) */
patch_byte(x86_cpu, ip, 0x68); /* push imm32 */
cpu_memory_rw_debug(cs, ip + 6, (void *)&imm32, sizeof(imm32), 0);
cpu_memory_rw_debug(cs, ip + 1, (void *)&imm32, sizeof(imm32), 1);
patch_call(x86_cpu, ip + 5, handlers->set_tpr);
break;
case 0xff: /* push r/m32 */
patch_byte(x86_cpu, ip, 0x50); /* push eax */
patch_call(x86_cpu, ip + 1, handlers->get_tpr_stack);
break;
default:
abort();
}
g_free(info);
}
static void patch_instruction(VAPICROMState *s, X86CPU *cpu, target_ulong ip) static void patch_instruction(VAPICROMState *s, X86CPU *cpu, target_ulong ip)
{ {
CPUState *cs = CPU(cpu); CPUState *cs = CPU(cpu);
CPUX86State *env = &cpu->env;
VAPICHandlers *handlers; VAPICHandlers *handlers;
uint8_t opcode[2]; PatchInfo *info;
uint32_t imm32 = 0;
target_ulong current_pc = 0;
target_ulong current_cs_base = 0;
uint32_t current_flags = 0;
if (smp_cpus == 1) { if (smp_cpus == 1) {
handlers = &s->rom_state.up; handlers = &s->rom_state.up;
@ -410,60 +452,11 @@ static void patch_instruction(VAPICROMState *s, X86CPU *cpu, target_ulong ip)
handlers = &s->rom_state.mp; handlers = &s->rom_state.mp;
} }
if (tcg_enabled()) { info = g_new(PatchInfo, 1);
cpu_restore_state(cs, cs->mem_io_pc); info->handler = handlers;
cpu_get_tb_cpu_state(env, &current_pc, &current_cs_base, info->ip = ip;
&current_flags);
/* Account this instruction, because we will exit the tb.
This is the first instruction in the block. Therefore
there is no need in restoring CPU state. */
if (use_icount) {
--cs->icount_decr.u16.low;
}
}
pause_all_vcpus(); async_safe_run_on_cpu(cs, do_patch_instruction, RUN_ON_CPU_HOST_PTR(info));
cpu_memory_rw_debug(cs, ip, opcode, sizeof(opcode), 0);
switch (opcode[0]) {
case 0x89: /* mov r32 to r/m32 */
patch_byte(cpu, ip, 0x50 + modrm_reg(opcode[1])); /* push reg */
patch_call(s, cpu, ip + 1, handlers->set_tpr);
break;
case 0x8b: /* mov r/m32 to r32 */
patch_byte(cpu, ip, 0x90);
patch_call(s, cpu, ip + 1, handlers->get_tpr[modrm_reg(opcode[1])]);
break;
case 0xa1: /* mov abs to eax */
patch_call(s, cpu, ip, handlers->get_tpr[0]);
break;
case 0xa3: /* mov eax to abs */
patch_call(s, cpu, ip, handlers->set_tpr_eax);
break;
case 0xc7: /* mov imm32, r/m32 (c7/0) */
patch_byte(cpu, ip, 0x68); /* push imm32 */
cpu_memory_rw_debug(cs, ip + 6, (void *)&imm32, sizeof(imm32), 0);
cpu_memory_rw_debug(cs, ip + 1, (void *)&imm32, sizeof(imm32), 1);
patch_call(s, cpu, ip + 5, handlers->set_tpr);
break;
case 0xff: /* push r/m32 */
patch_byte(cpu, ip, 0x50); /* push eax */
patch_call(s, cpu, ip + 1, handlers->get_tpr_stack);
break;
default:
abort();
}
resume_all_vcpus();
if (tcg_enabled()) {
/* Both tb_lock and iothread_mutex will be reset when
* longjmps back into the cpu_exec loop. */
tb_lock();
tb_gen_code(cs, current_pc, current_cs_base, current_flags, 1);
cpu_loop_exit_noexc(cs);
}
} }
void vapic_report_tpr_access(DeviceState *dev, CPUState *cs, target_ulong ip, void vapic_report_tpr_access(DeviceState *dev, CPUState *cs, target_ulong ip,

View File

@ -90,7 +90,7 @@ static TypeInfo ipmi_interface_type_info = {
.class_init = ipmi_interface_class_init, .class_init = ipmi_interface_class_init,
}; };
static void isa_ipmi_bmc_check(Object *obj, const char *name, static void isa_ipmi_bmc_check(const Object *obj, const char *name,
Object *val, Error **errp) Object *val, Error **errp)
{ {
IPMIBmc *bmc = IPMI_BMC(val); IPMIBmc *bmc = IPMI_BMC(val);

View File

@ -447,13 +447,13 @@ static void ipmi_bmc_extern_realize(DeviceState *dev, Error **errp)
{ {
IPMIBmcExtern *ibe = IPMI_BMC_EXTERN(dev); IPMIBmcExtern *ibe = IPMI_BMC_EXTERN(dev);
if (!qemu_chr_fe_get_driver(&ibe->chr)) { if (!qemu_chr_fe_backend_connected(&ibe->chr)) {
error_setg(errp, "IPMI external bmc requires chardev attribute"); error_setg(errp, "IPMI external bmc requires chardev attribute");
return; return;
} }
qemu_chr_fe_set_handlers(&ibe->chr, can_receive, receive, qemu_chr_fe_set_handlers(&ibe->chr, can_receive, receive,
chr_event, ibe, NULL, true); chr_event, NULL, ibe, NULL, true);
} }
static int ipmi_bmc_extern_post_migrate(void *opaque, int version_id) static int ipmi_bmc_extern_post_migrate(void *opaque, int version_id)

View File

@ -350,6 +350,8 @@ static Property pc_dimm_properties[] = {
DEFINE_PROP_UINT32(PC_DIMM_NODE_PROP, PCDIMMDevice, node, 0), DEFINE_PROP_UINT32(PC_DIMM_NODE_PROP, PCDIMMDevice, node, 0),
DEFINE_PROP_INT32(PC_DIMM_SLOT_PROP, PCDIMMDevice, slot, DEFINE_PROP_INT32(PC_DIMM_SLOT_PROP, PCDIMMDevice, slot,
PC_DIMM_UNASSIGNED_SLOT), PC_DIMM_UNASSIGNED_SLOT),
DEFINE_PROP_LINK(PC_DIMM_MEMDEV_PROP, PCDIMMDevice, hostmem,
TYPE_MEMORY_BACKEND, HostMemoryBackend *),
DEFINE_PROP_END_OF_LIST(), DEFINE_PROP_END_OF_LIST(),
}; };
@ -367,33 +369,10 @@ static void pc_dimm_get_size(Object *obj, Visitor *v, const char *name,
visit_type_uint64(v, name, &value, errp); visit_type_uint64(v, name, &value, errp);
} }
static void pc_dimm_check_memdev_is_busy(Object *obj, const char *name,
Object *val, Error **errp)
{
Error *local_err = NULL;
if (host_memory_backend_is_mapped(MEMORY_BACKEND(val))) {
char *path = object_get_canonical_path_component(val);
error_setg(&local_err, "can't use already busy memdev: %s", path);
g_free(path);
} else {
qdev_prop_allow_set_link_before_realize(obj, name, val, &local_err);
}
error_propagate(errp, local_err);
}
static void pc_dimm_init(Object *obj) static void pc_dimm_init(Object *obj)
{ {
PCDIMMDevice *dimm = PC_DIMM(obj);
object_property_add(obj, PC_DIMM_SIZE_PROP, "uint64", pc_dimm_get_size, object_property_add(obj, PC_DIMM_SIZE_PROP, "uint64", pc_dimm_get_size,
NULL, NULL, NULL, &error_abort); NULL, NULL, NULL, &error_abort);
object_property_add_link(obj, PC_DIMM_MEMDEV_PROP, TYPE_MEMORY_BACKEND,
(Object **)&dimm->hostmem,
pc_dimm_check_memdev_is_busy,
OBJ_PROP_LINK_UNREF_ON_RELEASE,
&error_abort);
} }
static void pc_dimm_realize(DeviceState *dev, Error **errp) static void pc_dimm_realize(DeviceState *dev, Error **errp)
@ -404,6 +383,11 @@ static void pc_dimm_realize(DeviceState *dev, Error **errp)
if (!dimm->hostmem) { if (!dimm->hostmem) {
error_setg(errp, "'" PC_DIMM_MEMDEV_PROP "' property is not set"); error_setg(errp, "'" PC_DIMM_MEMDEV_PROP "' property is not set");
return; return;
} else if (host_memory_backend_is_mapped(dimm->hostmem)) {
char *path = object_get_canonical_path_component(OBJECT(dimm->hostmem));
error_setg(errp, "can't use already busy memdev: %s", path);
g_free(path);
return;
} }
if (((nb_numa_nodes > 0) && (dimm->node >= nb_numa_nodes)) || if (((nb_numa_nodes > 0) && (dimm->node >= nb_numa_nodes)) ||
(!nb_numa_nodes && dimm->node)) { (!nb_numa_nodes && dimm->node)) {

View File

@ -533,7 +533,7 @@ static void boston_mach_init(MachineState *machine)
chr = qemu_chr_new("lcd", "vc:320x240"); chr = qemu_chr_new("lcd", "vc:320x240");
qemu_chr_fe_init(&s->lcd_display, chr, NULL); qemu_chr_fe_init(&s->lcd_display, chr, NULL);
qemu_chr_fe_set_handlers(&s->lcd_display, NULL, NULL, qemu_chr_fe_set_handlers(&s->lcd_display, NULL, NULL,
boston_lcd_event, s, NULL, true); boston_lcd_event, NULL, s, NULL, true);
ahci = pci_create_simple_multifunction(&PCI_BRIDGE(&pcie2->root)->sec_bus, ahci = pci_create_simple_multifunction(&PCI_BRIDGE(&pcie2->root)->sec_bus,
PCI_DEVFN(0, 0), PCI_DEVFN(0, 0),

View File

@ -130,7 +130,7 @@ static void mips_jazz_init(MachineState *machine,
CPUMIPSState *env; CPUMIPSState *env;
qemu_irq *i8259; qemu_irq *i8259;
rc4030_dma *dmas; rc4030_dma *dmas;
MemoryRegion *rc4030_dma_mr; IOMMUMemoryRegion *rc4030_dma_mr;
MemoryRegion *isa_mem = g_new(MemoryRegion, 1); MemoryRegion *isa_mem = g_new(MemoryRegion, 1);
MemoryRegion *isa_io = g_new(MemoryRegion, 1); MemoryRegion *isa_io = g_new(MemoryRegion, 1);
MemoryRegion *rtc = g_new(MemoryRegion, 1); MemoryRegion *rtc = g_new(MemoryRegion, 1);

View File

@ -570,7 +570,7 @@ static MaltaFPGAState *malta_fpga_init(MemoryRegion *address_space,
chr = qemu_chr_new("fpga", "vc:320x200"); chr = qemu_chr_new("fpga", "vc:320x200");
qemu_chr_fe_init(&s->display, chr, NULL); qemu_chr_fe_init(&s->display, chr, NULL);
qemu_chr_fe_set_handlers(&s->display, NULL, NULL, qemu_chr_fe_set_handlers(&s->display, NULL, NULL,
malta_fgpa_display_event, s, NULL, true); malta_fgpa_display_event, NULL, s, NULL, true);
s->uart = serial_mm_init(address_space, base + 0x900, 3, uart_irq, s->uart = serial_mm_init(address_space, base + 0x900, 3, uart_irq,
230400, uart_chr, DEVICE_NATIVE_ENDIAN); 230400, uart_chr, DEVICE_NATIVE_ENDIAN);

View File

@ -894,7 +894,7 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp)
} }
qemu_chr_fe_set_handlers(&s->server_chr, ivshmem_can_receive, qemu_chr_fe_set_handlers(&s->server_chr, ivshmem_can_receive,
ivshmem_read, NULL, s, NULL, true); ivshmem_read, NULL, NULL, s, NULL, true);
if (ivshmem_setup_interrupts(s, errp) < 0) { if (ivshmem_setup_interrupts(s, errp) < 0) {
error_prepend(errp, "Failed to initialize interrupts: "); error_prepend(errp, "Failed to initialize interrupts: ");
@ -1009,18 +1009,6 @@ static const TypeInfo ivshmem_common_info = {
.class_init = ivshmem_common_class_init, .class_init = ivshmem_common_class_init,
}; };
static void ivshmem_check_memdev_is_busy(Object *obj, const char *name,
Object *val, Error **errp)
{
if (host_memory_backend_is_mapped(MEMORY_BACKEND(val))) {
char *path = object_get_canonical_path_component(val);
error_setg(errp, "can't use already busy memdev: %s", path);
g_free(path);
} else {
qdev_prop_allow_set_link_before_realize(obj, name, val, errp);
}
}
static const VMStateDescription ivshmem_plain_vmsd = { static const VMStateDescription ivshmem_plain_vmsd = {
.name = TYPE_IVSHMEM_PLAIN, .name = TYPE_IVSHMEM_PLAIN,
.version_id = 0, .version_id = 0,
@ -1037,6 +1025,8 @@ static const VMStateDescription ivshmem_plain_vmsd = {
static Property ivshmem_plain_properties[] = { static Property ivshmem_plain_properties[] = {
DEFINE_PROP_ON_OFF_AUTO("master", IVShmemState, master, ON_OFF_AUTO_OFF), DEFINE_PROP_ON_OFF_AUTO("master", IVShmemState, master, ON_OFF_AUTO_OFF),
DEFINE_PROP_LINK("memdev", IVShmemState, hostmem, TYPE_MEMORY_BACKEND,
HostMemoryBackend *),
DEFINE_PROP_END_OF_LIST(), DEFINE_PROP_END_OF_LIST(),
}; };
@ -1044,11 +1034,6 @@ static void ivshmem_plain_init(Object *obj)
{ {
IVShmemState *s = IVSHMEM_PLAIN(obj); IVShmemState *s = IVSHMEM_PLAIN(obj);
object_property_add_link(obj, "memdev", TYPE_MEMORY_BACKEND,
(Object **)&s->hostmem,
ivshmem_check_memdev_is_busy,
OBJ_PROP_LINK_UNREF_ON_RELEASE,
&error_abort);
s->not_legacy_32bit = 1; s->not_legacy_32bit = 1;
} }
@ -1059,6 +1044,11 @@ static void ivshmem_plain_realize(PCIDevice *dev, Error **errp)
if (!s->hostmem) { if (!s->hostmem) {
error_setg(errp, "You must specify a 'memdev'"); error_setg(errp, "You must specify a 'memdev'");
return; return;
} else if (host_memory_backend_is_mapped(s->hostmem)) {
char *path = object_get_canonical_path_component(OBJECT(s->hostmem));
error_setg(errp, "can't use already busy memdev: %s", path);
g_free(path);
return;
} }
ivshmem_common_realize(dev, errp); ivshmem_common_realize(dev, errp);
@ -1128,7 +1118,7 @@ static void ivshmem_doorbell_realize(PCIDevice *dev, Error **errp)
{ {
IVShmemState *s = IVSHMEM_COMMON(dev); IVShmemState *s = IVSHMEM_COMMON(dev);
if (!qemu_chr_fe_get_driver(&s->server_chr)) { if (!qemu_chr_fe_backend_connected(&s->server_chr)) {
error_setg(errp, "You must specify a 'chardev'"); error_setg(errp, "You must specify a 'chardev'");
return; return;
} }
@ -1257,7 +1247,7 @@ static void ivshmem_realize(PCIDevice *dev, Error **errp)
" or ivshmem-doorbell instead"); " or ivshmem-doorbell instead");
} }
if (!!qemu_chr_fe_get_driver(&s->server_chr) + !!s->shmobj != 1) { if (qemu_chr_fe_backend_connected(&s->server_chr) + !!s->shmobj != 1) {
error_setg(errp, "You must specify either 'shm' or 'chardev'"); error_setg(errp, "You must specify either 'shm' or 'chardev'");
return; return;
} }

View File

@ -181,18 +181,6 @@ static void mips_gcr_init(Object *obj)
SysBusDevice *sbd = SYS_BUS_DEVICE(obj); SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
MIPSGCRState *s = MIPS_GCR(obj); MIPSGCRState *s = MIPS_GCR(obj);
object_property_add_link(obj, "gic", TYPE_MEMORY_REGION,
(Object **)&s->gic_mr,
qdev_prop_allow_set_link_before_realize,
OBJ_PROP_LINK_UNREF_ON_RELEASE,
&error_abort);
object_property_add_link(obj, "cpc", TYPE_MEMORY_REGION,
(Object **)&s->cpc_mr,
qdev_prop_allow_set_link_before_realize,
OBJ_PROP_LINK_UNREF_ON_RELEASE,
&error_abort);
memory_region_init_io(&s->iomem, OBJECT(s), &gcr_ops, s, memory_region_init_io(&s->iomem, OBJECT(s), &gcr_ops, s,
"mips-gcr", GCR_ADDRSPACE_SZ); "mips-gcr", GCR_ADDRSPACE_SZ);
sysbus_init_mmio(sbd, &s->iomem); sysbus_init_mmio(sbd, &s->iomem);
@ -227,6 +215,10 @@ static Property mips_gcr_properties[] = {
DEFINE_PROP_INT32("num-vp", MIPSGCRState, num_vps, 1), DEFINE_PROP_INT32("num-vp", MIPSGCRState, num_vps, 1),
DEFINE_PROP_INT32("gcr-rev", MIPSGCRState, gcr_rev, 0x800), DEFINE_PROP_INT32("gcr-rev", MIPSGCRState, gcr_rev, 0x800),
DEFINE_PROP_UINT64("gcr-base", MIPSGCRState, gcr_base, GCR_BASE_ADDR), DEFINE_PROP_UINT64("gcr-base", MIPSGCRState, gcr_base, GCR_BASE_ADDR),
DEFINE_PROP_LINK("gic", MIPSGCRState, gic_mr, TYPE_MEMORY_REGION,
MemoryRegion *),
DEFINE_PROP_LINK("cpc", MIPSGCRState, cpc_mr, TYPE_MEMORY_REGION,
MemoryRegion *),
DEFINE_PROP_END_OF_LIST(), DEFINE_PROP_END_OF_LIST(),
}; };

View File

@ -123,7 +123,7 @@ do { printf("IOMMU: " fmt , ## __VA_ARGS__); } while (0)
typedef struct IOMMUState { typedef struct IOMMUState {
AddressSpace iommu_as; AddressSpace iommu_as;
MemoryRegion iommu; IOMMUMemoryRegion iommu;
uint64_t regs[IOMMU_NREGS]; uint64_t regs[IOMMU_NREGS];
} IOMMUState; } IOMMUState;
@ -133,6 +133,8 @@ typedef struct IOMMUState {
#define APB_DEVICE(obj) \ #define APB_DEVICE(obj) \
OBJECT_CHECK(APBState, (obj), TYPE_APB) OBJECT_CHECK(APBState, (obj), TYPE_APB)
#define TYPE_APB_IOMMU_MEMORY_REGION "pbm-iommu-memory-region"
typedef struct APBState { typedef struct APBState {
PCIHostState parent_obj; PCIHostState parent_obj;
@ -208,7 +210,7 @@ static AddressSpace *pbm_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn)
} }
/* Called from RCU critical section */ /* Called from RCU critical section */
static IOMMUTLBEntry pbm_translate_iommu(MemoryRegion *iommu, hwaddr addr, static IOMMUTLBEntry pbm_translate_iommu(IOMMUMemoryRegion *iommu, hwaddr addr,
IOMMUAccessFlags flag) IOMMUAccessFlags flag)
{ {
IOMMUState *is = container_of(iommu, IOMMUState, iommu); IOMMUState *is = container_of(iommu, IOMMUState, iommu);
@ -322,10 +324,6 @@ static IOMMUTLBEntry pbm_translate_iommu(MemoryRegion *iommu, hwaddr addr,
return ret; return ret;
} }
static MemoryRegionIOMMUOps pbm_iommu_ops = {
.translate = pbm_translate_iommu,
};
static void iommu_config_write(void *opaque, hwaddr addr, static void iommu_config_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size) uint64_t val, unsigned size)
{ {
@ -697,9 +695,10 @@ PCIBus *pci_apb_init(hwaddr special_base,
is = &d->iommu; is = &d->iommu;
memset(is, 0, sizeof(IOMMUState)); memset(is, 0, sizeof(IOMMUState));
memory_region_init_iommu(&is->iommu, OBJECT(dev), &pbm_iommu_ops, memory_region_init_iommu(&is->iommu, sizeof(is->iommu),
TYPE_APB_IOMMU_MEMORY_REGION, OBJECT(dev),
"iommu-apb", UINT64_MAX); "iommu-apb", UINT64_MAX);
address_space_init(&is->iommu_as, &is->iommu, "pbm-as"); address_space_init(&is->iommu_as, MEMORY_REGION(&is->iommu), "pbm-as");
pci_setup_iommu(phb->bus, pbm_pci_dma_iommu, is); pci_setup_iommu(phb->bus, pbm_pci_dma_iommu, is);
/* APB secondary busses */ /* APB secondary busses */
@ -860,11 +859,25 @@ static const TypeInfo pbm_pci_bridge_info = {
.class_init = pbm_pci_bridge_class_init, .class_init = pbm_pci_bridge_class_init,
}; };
static void pbm_iommu_memory_region_class_init(ObjectClass *klass, void *data)
{
IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
imrc->translate = pbm_translate_iommu;
}
static const TypeInfo pbm_iommu_memory_region_info = {
.parent = TYPE_IOMMU_MEMORY_REGION,
.name = TYPE_APB_IOMMU_MEMORY_REGION,
.class_init = pbm_iommu_memory_region_class_init,
};
static void pbm_register_types(void) static void pbm_register_types(void)
{ {
type_register_static(&pbm_host_info); type_register_static(&pbm_host_info);
type_register_static(&pbm_pci_host_info); type_register_static(&pbm_pci_host_info);
type_register_static(&pbm_pci_bridge_info); type_register_static(&pbm_pci_bridge_info);
type_register_static(&pbm_iommu_memory_region_info);
} }
type_init(pbm_register_types) type_init(pbm_register_types)

View File

@ -110,7 +110,8 @@ static void spapr_tce_free_table(uint64_t *table, int fd, uint32_t nb_table)
} }
/* Called from RCU critical section */ /* Called from RCU critical section */
static IOMMUTLBEntry spapr_tce_translate_iommu(MemoryRegion *iommu, hwaddr addr, static IOMMUTLBEntry spapr_tce_translate_iommu(IOMMUMemoryRegion *iommu,
hwaddr addr,
IOMMUAccessFlags flag) IOMMUAccessFlags flag)
{ {
sPAPRTCETable *tcet = container_of(iommu, sPAPRTCETable, iommu); sPAPRTCETable *tcet = container_of(iommu, sPAPRTCETable, iommu);
@ -150,14 +151,14 @@ static void spapr_tce_table_pre_save(void *opaque)
tcet->bus_offset, tcet->page_shift); tcet->bus_offset, tcet->page_shift);
} }
static uint64_t spapr_tce_get_min_page_size(MemoryRegion *iommu) static uint64_t spapr_tce_get_min_page_size(IOMMUMemoryRegion *iommu)
{ {
sPAPRTCETable *tcet = container_of(iommu, sPAPRTCETable, iommu); sPAPRTCETable *tcet = container_of(iommu, sPAPRTCETable, iommu);
return 1ULL << tcet->page_shift; return 1ULL << tcet->page_shift;
} }
static void spapr_tce_notify_flag_changed(MemoryRegion *iommu, static void spapr_tce_notify_flag_changed(IOMMUMemoryRegion *iommu,
IOMMUNotifierFlag old, IOMMUNotifierFlag old,
IOMMUNotifierFlag new) IOMMUNotifierFlag new)
{ {
@ -247,12 +248,6 @@ static const VMStateDescription vmstate_spapr_tce_table = {
} }
}; };
static MemoryRegionIOMMUOps spapr_iommu_ops = {
.translate = spapr_tce_translate_iommu,
.get_min_page_size = spapr_tce_get_min_page_size,
.notify_flag_changed = spapr_tce_notify_flag_changed,
};
static int spapr_tce_table_realize(DeviceState *dev) static int spapr_tce_table_realize(DeviceState *dev)
{ {
sPAPRTCETable *tcet = SPAPR_TCE_TABLE(dev); sPAPRTCETable *tcet = SPAPR_TCE_TABLE(dev);
@ -265,7 +260,9 @@ static int spapr_tce_table_realize(DeviceState *dev)
memory_region_init(&tcet->root, tcetobj, tmp, UINT64_MAX); memory_region_init(&tcet->root, tcetobj, tmp, UINT64_MAX);
snprintf(tmp, sizeof(tmp), "tce-iommu-%x", tcet->liobn); snprintf(tmp, sizeof(tmp), "tce-iommu-%x", tcet->liobn);
memory_region_init_iommu(&tcet->iommu, tcetobj, &spapr_iommu_ops, tmp, 0); memory_region_init_iommu(&tcet->iommu, sizeof(tcet->iommu),
TYPE_SPAPR_IOMMU_MEMORY_REGION,
tcetobj, tmp, 0);
QLIST_INSERT_HEAD(&spapr_tce_tables, tcet, list); QLIST_INSERT_HEAD(&spapr_tce_tables, tcet, list);
@ -348,9 +345,10 @@ void spapr_tce_table_enable(sPAPRTCETable *tcet,
&tcet->fd, &tcet->fd,
tcet->need_vfio); tcet->need_vfio);
memory_region_set_size(&tcet->iommu, memory_region_set_size(MEMORY_REGION(&tcet->iommu),
(uint64_t)tcet->nb_table << tcet->page_shift); (uint64_t)tcet->nb_table << tcet->page_shift);
memory_region_add_subregion(&tcet->root, tcet->bus_offset, &tcet->iommu); memory_region_add_subregion(&tcet->root, tcet->bus_offset,
MEMORY_REGION(&tcet->iommu));
} }
void spapr_tce_table_disable(sPAPRTCETable *tcet) void spapr_tce_table_disable(sPAPRTCETable *tcet)
@ -359,8 +357,8 @@ void spapr_tce_table_disable(sPAPRTCETable *tcet)
return; return;
} }
memory_region_del_subregion(&tcet->root, &tcet->iommu); memory_region_del_subregion(&tcet->root, MEMORY_REGION(&tcet->iommu));
memory_region_set_size(&tcet->iommu, 0); memory_region_set_size(MEMORY_REGION(&tcet->iommu), 0);
spapr_tce_free_table(tcet->table, tcet->fd, tcet->nb_table); spapr_tce_free_table(tcet->table, tcet->fd, tcet->nb_table);
tcet->fd = -1; tcet->fd = -1;
@ -637,9 +635,25 @@ static TypeInfo spapr_tce_table_info = {
.class_init = spapr_tce_table_class_init, .class_init = spapr_tce_table_class_init,
}; };
static void spapr_iommu_memory_region_class_init(ObjectClass *klass, void *data)
{
IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
imrc->translate = spapr_tce_translate_iommu;
imrc->get_min_page_size = spapr_tce_get_min_page_size;
imrc->notify_flag_changed = spapr_tce_notify_flag_changed;
}
static const TypeInfo spapr_iommu_memory_region_info = {
.parent = TYPE_IOMMU_MEMORY_REGION,
.name = TYPE_SPAPR_IOMMU_MEMORY_REGION,
.class_init = spapr_iommu_memory_region_class_init,
};
static void register_types(void) static void register_types(void)
{ {
type_register_static(&spapr_tce_table_info); type_register_static(&spapr_tce_table_info);
type_register_static(&spapr_iommu_memory_region_info);
} }
type_init(register_types); type_init(register_types);

View File

@ -96,17 +96,11 @@ static target_ulong h_random(PowerPCCPU *cpu, sPAPRMachineState *spapr,
static void spapr_rng_instance_init(Object *obj) static void spapr_rng_instance_init(Object *obj)
{ {
sPAPRRngState *rngstate = SPAPR_RNG(obj);
if (object_resolve_path_type("", TYPE_SPAPR_RNG, NULL) != NULL) { if (object_resolve_path_type("", TYPE_SPAPR_RNG, NULL) != NULL) {
error_report("spapr-rng can not be instantiated twice!"); error_report("spapr-rng can not be instantiated twice!");
return; return;
} }
object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
(Object **)&rngstate->backend,
object_property_allow_set_link,
OBJ_PROP_LINK_UNREF_ON_RELEASE, NULL);
object_property_set_description(obj, "rng", object_property_set_description(obj, "rng",
"ID of the random number generator backend", "ID of the random number generator backend",
NULL); NULL);
@ -163,6 +157,8 @@ int spapr_rng_populate_dt(void *fdt)
static Property spapr_rng_properties[] = { static Property spapr_rng_properties[] = {
DEFINE_PROP_BOOL("use-kvm", sPAPRRngState, use_kvm, false), DEFINE_PROP_BOOL("use-kvm", sPAPRRngState, use_kvm, false),
DEFINE_PROP_LINK("rng", sPAPRRngState, backend, TYPE_RNG_BACKEND,
RngBackend *),
DEFINE_PROP_END_OF_LIST(), DEFINE_PROP_END_OF_LIST(),
}; };

View File

@ -2095,7 +2095,7 @@ out:
g_free(str); g_free(str);
} }
PropertyInfo css_devid_propinfo = { const PropertyInfo css_devid_propinfo = {
.name = "str", .name = "str",
.description = "Identifier of an I/O device in the channel " .description = "Identifier of an I/O device in the channel "
"subsystem, example: fe.1.23ab", "subsystem, example: fe.1.23ab",
@ -2103,7 +2103,7 @@ PropertyInfo css_devid_propinfo = {
.set = set_css_devid, .set = set_css_devid,
}; };
PropertyInfo css_devid_ro_propinfo = { const PropertyInfo css_devid_ro_propinfo = {
.name = "str", .name = "str",
.description = "Read-only identifier of an I/O device in the channel " .description = "Read-only identifier of an I/O device in the channel "
"subsystem, example: fe.1.23ab", "subsystem, example: fe.1.23ab",

View File

@ -356,7 +356,7 @@ out:
return pte; return pte;
} }
static IOMMUTLBEntry s390_translate_iommu(MemoryRegion *mr, hwaddr addr, static IOMMUTLBEntry s390_translate_iommu(IOMMUMemoryRegion *mr, hwaddr addr,
IOMMUAccessFlags flag) IOMMUAccessFlags flag)
{ {
uint64_t pte; uint64_t pte;
@ -407,10 +407,6 @@ static IOMMUTLBEntry s390_translate_iommu(MemoryRegion *mr, hwaddr addr,
return ret; return ret;
} }
static const MemoryRegionIOMMUOps s390_iommu_ops = {
.translate = s390_translate_iommu,
};
static S390PCIIOMMU *s390_pci_get_iommu(S390pciState *s, PCIBus *bus, static S390PCIIOMMU *s390_pci_get_iommu(S390pciState *s, PCIBus *bus,
int devfn) int devfn)
{ {
@ -522,17 +518,18 @@ static const MemoryRegionOps s390_msi_ctrl_ops = {
void s390_pci_iommu_enable(S390PCIIOMMU *iommu) void s390_pci_iommu_enable(S390PCIIOMMU *iommu)
{ {
char *name = g_strdup_printf("iommu-s390-%04x", iommu->pbdev->uid); char *name = g_strdup_printf("iommu-s390-%04x", iommu->pbdev->uid);
memory_region_init_iommu(&iommu->iommu_mr, OBJECT(&iommu->mr), memory_region_init_iommu(&iommu->iommu_mr, sizeof(iommu->iommu_mr),
&s390_iommu_ops, name, iommu->pal + 1); TYPE_S390_IOMMU_MEMORY_REGION, OBJECT(&iommu->mr),
name, iommu->pal + 1);
iommu->enabled = true; iommu->enabled = true;
memory_region_add_subregion(&iommu->mr, 0, &iommu->iommu_mr); memory_region_add_subregion(&iommu->mr, 0, MEMORY_REGION(&iommu->iommu_mr));
g_free(name); g_free(name);
} }
void s390_pci_iommu_disable(S390PCIIOMMU *iommu) void s390_pci_iommu_disable(S390PCIIOMMU *iommu)
{ {
iommu->enabled = false; iommu->enabled = false;
memory_region_del_subregion(&iommu->mr, &iommu->iommu_mr); memory_region_del_subregion(&iommu->mr, MEMORY_REGION(&iommu->iommu_mr));
object_unparent(OBJECT(&iommu->iommu_mr)); object_unparent(OBJECT(&iommu->iommu_mr));
} }
@ -1018,7 +1015,7 @@ static void s390_pci_set_fid(Object *obj, Visitor *v, const char *name,
zpci->fid_defined = true; zpci->fid_defined = true;
} }
static PropertyInfo s390_pci_fid_propinfo = { static const PropertyInfo s390_pci_fid_propinfo = {
.name = "zpci_fid", .name = "zpci_fid",
.get = s390_pci_get_fid, .get = s390_pci_get_fid,
.set = s390_pci_set_fid, .set = s390_pci_set_fid,
@ -1058,12 +1055,26 @@ static TypeInfo s390_pci_iommu_info = {
.instance_size = sizeof(S390PCIIOMMU), .instance_size = sizeof(S390PCIIOMMU),
}; };
static void s390_iommu_memory_region_class_init(ObjectClass *klass, void *data)
{
IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
imrc->translate = s390_translate_iommu;
}
static const TypeInfo s390_iommu_memory_region_info = {
.parent = TYPE_IOMMU_MEMORY_REGION,
.name = TYPE_S390_IOMMU_MEMORY_REGION,
.class_init = s390_iommu_memory_region_class_init,
};
static void s390_pci_register_types(void) static void s390_pci_register_types(void)
{ {
type_register_static(&s390_pcihost_info); type_register_static(&s390_pcihost_info);
type_register_static(&s390_pcibus_info); type_register_static(&s390_pcibus_info);
type_register_static(&s390_pci_device_info); type_register_static(&s390_pci_device_info);
type_register_static(&s390_pci_iommu_info); type_register_static(&s390_pci_iommu_info);
type_register_static(&s390_iommu_memory_region_info);
} }
type_init(s390_pci_register_types) type_init(s390_pci_register_types)

View File

@ -24,6 +24,7 @@
#define TYPE_S390_PCI_BUS "s390-pcibus" #define TYPE_S390_PCI_BUS "s390-pcibus"
#define TYPE_S390_PCI_DEVICE "zpci" #define TYPE_S390_PCI_DEVICE "zpci"
#define TYPE_S390_PCI_IOMMU "s390-pci-iommu" #define TYPE_S390_PCI_IOMMU "s390-pci-iommu"
#define TYPE_S390_IOMMU_MEMORY_REGION "s390-iommu-memory-region"
#define FH_MASK_ENABLE 0x80000000 #define FH_MASK_ENABLE 0x80000000
#define FH_MASK_INSTANCE 0x7f000000 #define FH_MASK_INSTANCE 0x7f000000
#define FH_MASK_SHM 0x00ff0000 #define FH_MASK_SHM 0x00ff0000
@ -266,7 +267,7 @@ typedef struct S390PCIIOMMU {
S390PCIBusDevice *pbdev; S390PCIBusDevice *pbdev;
AddressSpace as; AddressSpace as;
MemoryRegion mr; MemoryRegion mr;
MemoryRegion iommu_mr; IOMMUMemoryRegion iommu_mr;
bool enabled; bool enabled;
uint64_t g_iota; uint64_t g_iota;
uint64_t pba; uint64_t pba;

View File

@ -563,7 +563,8 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
S390PCIIOMMU *iommu; S390PCIIOMMU *iommu;
hwaddr start, end; hwaddr start, end;
IOMMUTLBEntry entry; IOMMUTLBEntry entry;
MemoryRegion *mr; IOMMUMemoryRegion *iommu_mr;
IOMMUMemoryRegionClass *imrc;
cpu_synchronize_state(CPU(cpu)); cpu_synchronize_state(CPU(cpu));
@ -622,9 +623,11 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
goto out; goto out;
} }
mr = &iommu->iommu_mr; iommu_mr = &iommu->iommu_mr;
imrc = IOMMU_MEMORY_REGION_GET_CLASS(iommu_mr);
while (start < end) { while (start < end) {
entry = mr->iommu_ops->translate(mr, start, IOMMU_NONE); entry = imrc->translate(iommu_mr, start, IOMMU_NONE);
if (!entry.translated_addr) { if (!entry.translated_addr) {
pbdev->state = ZPCI_FS_ERROR; pbdev->state = ZPCI_FS_ERROR;
@ -635,7 +638,7 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
goto out; goto out;
} }
memory_region_notify_iommu(mr, entry); memory_region_notify_iommu(iommu_mr, entry);
start += entry.addr_mask + 1; start += entry.addr_mask + 1;
} }

View File

@ -867,8 +867,6 @@ static void virtio_ccw_blk_instance_init(Object *obj)
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
TYPE_VIRTIO_BLK); TYPE_VIRTIO_BLK);
object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev),"iothread",
&error_abort);
object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev), object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
"bootindex", &error_abort); "bootindex", &error_abort);
} }
@ -952,8 +950,6 @@ static void virtio_ccw_scsi_instance_init(Object *obj)
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
TYPE_VIRTIO_SCSI); TYPE_VIRTIO_SCSI);
object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev), "iothread",
&error_abort);
} }
#ifdef CONFIG_VHOST_SCSI #ifdef CONFIG_VHOST_SCSI
@ -1552,8 +1548,6 @@ static void virtio_ccw_rng_instance_init(Object *obj)
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
TYPE_VIRTIO_RNG); TYPE_VIRTIO_RNG);
object_property_add_alias(obj, "rng", OBJECT(&dev->vdev),
"rng", &error_abort);
} }
static Property virtio_ccw_rng_properties[] = { static Property virtio_ccw_rng_properties[] = {
@ -1600,9 +1594,6 @@ static void virtio_ccw_crypto_instance_init(Object *obj)
ccw_dev->force_revision_1 = true; ccw_dev->force_revision_1 = true;
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
TYPE_VIRTIO_CRYPTO); TYPE_VIRTIO_CRYPTO);
object_property_add_alias(obj, "cryptodev", OBJECT(&dev->vdev),
"cryptodev", &error_abort);
} }
static void virtio_ccw_crypto_class_init(ObjectClass *klass, void *data) static void virtio_ccw_crypto_class_init(ObjectClass *klass, void *data)

View File

@ -898,16 +898,6 @@ static void virtio_scsi_device_realize(DeviceState *dev, Error **errp)
virtio_scsi_dataplane_setup(s, errp); virtio_scsi_dataplane_setup(s, errp);
} }
static void virtio_scsi_instance_init(Object *obj)
{
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(obj);
object_property_add_link(obj, "iothread", TYPE_IOTHREAD,
(Object **)&vs->conf.iothread,
qdev_prop_allow_set_link_before_realize,
OBJ_PROP_LINK_UNREF_ON_RELEASE, &error_abort);
}
void virtio_scsi_common_unrealize(DeviceState *dev, Error **errp) void virtio_scsi_common_unrealize(DeviceState *dev, Error **errp)
{ {
VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIODevice *vdev = VIRTIO_DEVICE(dev);
@ -935,6 +925,8 @@ static Property virtio_scsi_properties[] = {
VIRTIO_SCSI_F_HOTPLUG, true), VIRTIO_SCSI_F_HOTPLUG, true),
DEFINE_PROP_BIT("param_change", VirtIOSCSI, host_features, DEFINE_PROP_BIT("param_change", VirtIOSCSI, host_features,
VIRTIO_SCSI_F_CHANGE, true), VIRTIO_SCSI_F_CHANGE, true),
DEFINE_PROP_LINK("iothread", VirtIOSCSI, parent_obj.conf.iothread,
TYPE_IOTHREAD, IOThread *),
DEFINE_PROP_END_OF_LIST(), DEFINE_PROP_END_OF_LIST(),
}; };
@ -989,7 +981,6 @@ static const TypeInfo virtio_scsi_info = {
.name = TYPE_VIRTIO_SCSI, .name = TYPE_VIRTIO_SCSI,
.parent = TYPE_VIRTIO_SCSI_COMMON, .parent = TYPE_VIRTIO_SCSI_COMMON,
.instance_size = sizeof(VirtIOSCSI), .instance_size = sizeof(VirtIOSCSI),
.instance_init = virtio_scsi_instance_init,
.class_init = virtio_scsi_class_init, .class_init = virtio_scsi_class_init,
.interfaces = (InterfaceInfo[]) { .interfaces = (InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER }, { TYPE_HOTPLUG_HANDLER },

View File

@ -322,7 +322,7 @@ static void passthru_apdu_from_guest(
{ {
PassthruState *card = PASSTHRU_CCID_CARD(base); PassthruState *card = PASSTHRU_CCID_CARD(base);
if (!qemu_chr_fe_get_driver(&card->cs)) { if (!qemu_chr_fe_backend_connected(&card->cs)) {
printf("ccid-passthru: no chardev, discarding apdu length %d\n", len); printf("ccid-passthru: no chardev, discarding apdu length %d\n", len);
return; return;
} }
@ -343,12 +343,12 @@ static int passthru_initfn(CCIDCardState *base)
card->vscard_in_pos = 0; card->vscard_in_pos = 0;
card->vscard_in_hdr = 0; card->vscard_in_hdr = 0;
if (qemu_chr_fe_get_driver(&card->cs)) { if (qemu_chr_fe_backend_connected(&card->cs)) {
DPRINTF(card, D_INFO, "initing chardev\n"); DPRINTF(card, D_INFO, "initing chardev\n");
qemu_chr_fe_set_handlers(&card->cs, qemu_chr_fe_set_handlers(&card->cs,
ccid_card_vscard_can_read, ccid_card_vscard_can_read,
ccid_card_vscard_read, ccid_card_vscard_read,
ccid_card_vscard_event, card, NULL, true); ccid_card_vscard_event, NULL, card, NULL, true);
ccid_card_vscard_send_init(card); ccid_card_vscard_send_init(card);
} else { } else {
error_report("missing chardev"); error_report("missing chardev");

View File

@ -484,13 +484,12 @@ static void usb_serial_realize(USBDevice *dev, Error **errp)
{ {
USBSerialState *s = USB_SERIAL_DEV(dev); USBSerialState *s = USB_SERIAL_DEV(dev);
Error *local_err = NULL; Error *local_err = NULL;
Chardev *chr = qemu_chr_fe_get_driver(&s->cs);
usb_desc_create_serial(dev); usb_desc_create_serial(dev);
usb_desc_init(dev); usb_desc_init(dev);
dev->auto_attach = 0; dev->auto_attach = 0;
if (!chr) { if (!qemu_chr_fe_backend_connected(&s->cs)) {
error_setg(errp, "Property chardev is required"); error_setg(errp, "Property chardev is required");
return; return;
} }
@ -502,10 +501,10 @@ static void usb_serial_realize(USBDevice *dev, Error **errp)
} }
qemu_chr_fe_set_handlers(&s->cs, usb_serial_can_read, usb_serial_read, qemu_chr_fe_set_handlers(&s->cs, usb_serial_can_read, usb_serial_read,
usb_serial_event, s, NULL, true); usb_serial_event, NULL, s, NULL, true);
usb_serial_handle_reset(dev); usb_serial_handle_reset(dev);
if (chr->be_open && !dev->attached) { if (qemu_chr_fe_backend_open(&s->cs) && !dev->attached) {
usb_device_attach(dev, &error_abort); usb_device_attach(dev, &error_abort);
} }
} }

View File

@ -273,10 +273,9 @@ static gboolean usbredir_write_unblocked(GIOChannel *chan, GIOCondition cond,
static int usbredir_write(void *priv, uint8_t *data, int count) static int usbredir_write(void *priv, uint8_t *data, int count)
{ {
USBRedirDevice *dev = priv; USBRedirDevice *dev = priv;
Chardev *chr = qemu_chr_fe_get_driver(&dev->cs);
int r; int r;
if (!chr->be_open) { if (!qemu_chr_fe_backend_open(&dev->cs)) {
return 0; return 0;
} }
@ -1366,7 +1365,7 @@ static void usbredir_realize(USBDevice *udev, Error **errp)
USBRedirDevice *dev = USB_REDIRECT(udev); USBRedirDevice *dev = USB_REDIRECT(udev);
int i; int i;
if (!qemu_chr_fe_get_driver(&dev->cs)) { if (!qemu_chr_fe_backend_connected(&dev->cs)) {
error_setg(errp, QERR_MISSING_PARAMETER, "chardev"); error_setg(errp, QERR_MISSING_PARAMETER, "chardev");
return; return;
} }
@ -1399,7 +1398,7 @@ static void usbredir_realize(USBDevice *udev, Error **errp)
/* Let the backend know we are ready */ /* Let the backend know we are ready */
qemu_chr_fe_set_handlers(&dev->cs, usbredir_chardev_can_read, qemu_chr_fe_set_handlers(&dev->cs, usbredir_chardev_can_read,
usbredir_chardev_read, usbredir_chardev_event, usbredir_chardev_read, usbredir_chardev_event,
dev, NULL, true); NULL, dev, NULL, true);
dev->vmstate = dev->vmstate =
qemu_add_vm_change_state_handler(usbredir_vm_state_change, dev); qemu_add_vm_change_state_handler(usbredir_vm_state_change, dev);

View File

@ -479,6 +479,7 @@ static void vfio_listener_region_add(MemoryListener *listener,
if (memory_region_is_iommu(section->mr)) { if (memory_region_is_iommu(section->mr)) {
VFIOGuestIOMMU *giommu; VFIOGuestIOMMU *giommu;
IOMMUMemoryRegion *iommu_mr = IOMMU_MEMORY_REGION(section->mr);
trace_vfio_listener_region_add_iommu(iova, end); trace_vfio_listener_region_add_iommu(iova, end);
/* /*
@ -488,7 +489,7 @@ static void vfio_listener_region_add(MemoryListener *listener,
* device emulation the VFIO iommu handles to use). * device emulation the VFIO iommu handles to use).
*/ */
giommu = g_malloc0(sizeof(*giommu)); giommu = g_malloc0(sizeof(*giommu));
giommu->iommu = section->mr; giommu->iommu = iommu_mr;
giommu->iommu_offset = section->offset_within_address_space - giommu->iommu_offset = section->offset_within_address_space -
section->offset_within_region; section->offset_within_region;
giommu->container = container; giommu->container = container;
@ -501,7 +502,7 @@ static void vfio_listener_region_add(MemoryListener *listener,
int128_get64(llend)); int128_get64(llend));
QLIST_INSERT_HEAD(&container->giommu_list, giommu, giommu_next); QLIST_INSERT_HEAD(&container->giommu_list, giommu, giommu_next);
memory_region_register_iommu_notifier(giommu->iommu, &giommu->n); memory_region_register_iommu_notifier(section->mr, &giommu->n);
memory_region_iommu_replay(giommu->iommu, &giommu->n); memory_region_iommu_replay(giommu->iommu, &giommu->n);
return; return;
@ -569,9 +570,9 @@ static void vfio_listener_region_del(MemoryListener *listener,
VFIOGuestIOMMU *giommu; VFIOGuestIOMMU *giommu;
QLIST_FOREACH(giommu, &container->giommu_list, giommu_next) { QLIST_FOREACH(giommu, &container->giommu_list, giommu_next) {
if (giommu->iommu == section->mr && if (MEMORY_REGION(giommu->iommu) == section->mr &&
giommu->n.start == section->offset_within_region) { giommu->n.start == section->offset_within_region) {
memory_region_unregister_iommu_notifier(giommu->iommu, memory_region_unregister_iommu_notifier(section->mr,
&giommu->n); &giommu->n);
QLIST_REMOVE(giommu, giommu_next); QLIST_REMOVE(giommu, giommu_next);
g_free(giommu); g_free(giommu);
@ -1163,7 +1164,8 @@ static void vfio_disconnect_container(VFIOGroup *group)
QLIST_REMOVE(container, next); QLIST_REMOVE(container, next);
QLIST_FOREACH_SAFE(giommu, &container->giommu_list, giommu_next, tmp) { QLIST_FOREACH_SAFE(giommu, &container->giommu_list, giommu_next, tmp) {
memory_region_unregister_iommu_notifier(giommu->iommu, &giommu->n); memory_region_unregister_iommu_notifier(
MEMORY_REGION(giommu->iommu), &giommu->n);
QLIST_REMOVE(giommu, giommu_next); QLIST_REMOVE(giommu, giommu_next);
g_free(giommu); g_free(giommu);
} }

View File

@ -143,7 +143,8 @@ int vfio_spapr_create_window(VFIOContainer *container,
hwaddr *pgsize) hwaddr *pgsize)
{ {
int ret; int ret;
unsigned pagesize = memory_region_iommu_get_min_page_size(section->mr); IOMMUMemoryRegion *iommu_mr = IOMMU_MEMORY_REGION(section->mr);
unsigned pagesize = memory_region_iommu_get_min_page_size(iommu_mr);
unsigned entries, pages; unsigned entries, pages;
struct vfio_iommu_spapr_tce_create create = { .argsz = sizeof(create) }; struct vfio_iommu_spapr_tce_create create = { .argsz = sizeof(create) };

View File

@ -62,8 +62,6 @@ static void virtio_crypto_initfn(Object *obj)
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
TYPE_VIRTIO_CRYPTO); TYPE_VIRTIO_CRYPTO);
object_property_add_alias(obj, "cryptodev", OBJECT(&dev->vdev),
"cryptodev", &error_abort);
} }
static const TypeInfo virtio_crypto_pci_info = { static const TypeInfo virtio_crypto_pci_info = {

View File

@ -781,6 +781,11 @@ static void virtio_crypto_device_realize(DeviceState *dev, Error **errp)
if (vcrypto->cryptodev == NULL) { if (vcrypto->cryptodev == NULL) {
error_setg(errp, "'cryptodev' parameter expects a valid object"); error_setg(errp, "'cryptodev' parameter expects a valid object");
return; return;
} else if (cryptodev_backend_is_used(vcrypto->cryptodev)) {
char *path = object_get_canonical_path_component(OBJECT(vcrypto->conf.cryptodev));
error_setg(errp, "can't use already used cryptodev backend: %s", path);
g_free(path);
return;
} }
vcrypto->max_queues = MAX(vcrypto->cryptodev->conf.peers.queues, 1); vcrypto->max_queues = MAX(vcrypto->cryptodev->conf.peers.queues, 1);
@ -845,6 +850,8 @@ static const VMStateDescription vmstate_virtio_crypto = {
}; };
static Property virtio_crypto_properties[] = { static Property virtio_crypto_properties[] = {
DEFINE_PROP_LINK("cryptodev", VirtIOCrypto, conf.cryptodev,
TYPE_CRYPTODEV_BACKEND, CryptoDevBackend *),
DEFINE_PROP_END_OF_LIST(), DEFINE_PROP_END_OF_LIST(),
}; };
@ -888,20 +895,6 @@ static void virtio_crypto_class_init(ObjectClass *klass, void *data)
vdc->reset = virtio_crypto_reset; vdc->reset = virtio_crypto_reset;
} }
static void
virtio_crypto_check_cryptodev_is_used(Object *obj, const char *name,
Object *val, Error **errp)
{
if (cryptodev_backend_is_used(CRYPTODEV_BACKEND(val))) {
char *path = object_get_canonical_path_component(val);
error_setg(errp,
"can't use already used cryptodev backend: %s", path);
g_free(path);
} else {
qdev_prop_allow_set_link_before_realize(obj, name, val, errp);
}
}
static void virtio_crypto_instance_init(Object *obj) static void virtio_crypto_instance_init(Object *obj)
{ {
VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(obj); VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(obj);
@ -911,12 +904,6 @@ static void virtio_crypto_instance_init(Object *obj)
* Can be overriden with virtio_crypto_set_config_size. * Can be overriden with virtio_crypto_set_config_size.
*/ */
vcrypto->config_size = sizeof(struct virtio_crypto_config); vcrypto->config_size = sizeof(struct virtio_crypto_config);
object_property_add_link(obj, "cryptodev",
TYPE_CRYPTODEV_BACKEND,
(Object **)&vcrypto->conf.cryptodev,
virtio_crypto_check_cryptodev_is_used,
OBJ_PROP_LINK_UNREF_ON_RELEASE, NULL);
} }
static const TypeInfo virtio_crypto_info = { static const TypeInfo virtio_crypto_info = {

View File

@ -2000,8 +2000,6 @@ static void virtio_blk_pci_instance_init(Object *obj)
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
TYPE_VIRTIO_BLK); TYPE_VIRTIO_BLK);
object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev),"iothread",
&error_abort);
object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev), object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
"bootindex", &error_abort); "bootindex", &error_abort);
} }
@ -2071,8 +2069,6 @@ static void virtio_scsi_pci_instance_init(Object *obj)
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
TYPE_VIRTIO_SCSI); TYPE_VIRTIO_SCSI);
object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev), "iothread",
&error_abort);
} }
static const TypeInfo virtio_scsi_pci_info = { static const TypeInfo virtio_scsi_pci_info = {
@ -2467,8 +2463,6 @@ static void virtio_rng_initfn(Object *obj)
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
TYPE_VIRTIO_RNG); TYPE_VIRTIO_RNG);
object_property_add_alias(obj, "rng", OBJECT(&dev->vdev), "rng",
&error_abort);
} }
static const TypeInfo virtio_rng_pci_info = { static const TypeInfo virtio_rng_pci_info = {

View File

@ -246,6 +246,7 @@ static Property virtio_rng_properties[] = {
*/ */
DEFINE_PROP_UINT64("max-bytes", VirtIORNG, conf.max_bytes, INT64_MAX), DEFINE_PROP_UINT64("max-bytes", VirtIORNG, conf.max_bytes, INT64_MAX),
DEFINE_PROP_UINT32("period", VirtIORNG, conf.period_ms, 1 << 16), DEFINE_PROP_UINT32("period", VirtIORNG, conf.period_ms, 1 << 16),
DEFINE_PROP_LINK("rng", VirtIORNG, conf.rng, TYPE_RNG_BACKEND, RngBackend *),
DEFINE_PROP_END_OF_LIST(), DEFINE_PROP_END_OF_LIST(),
}; };
@ -262,21 +263,10 @@ static void virtio_rng_class_init(ObjectClass *klass, void *data)
vdc->get_features = get_features; vdc->get_features = get_features;
} }
static void virtio_rng_initfn(Object *obj)
{
VirtIORNG *vrng = VIRTIO_RNG(obj);
object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
(Object **)&vrng->conf.rng,
qdev_prop_allow_set_link_before_realize,
OBJ_PROP_LINK_UNREF_ON_RELEASE, NULL);
}
static const TypeInfo virtio_rng_info = { static const TypeInfo virtio_rng_info = {
.name = TYPE_VIRTIO_RNG, .name = TYPE_VIRTIO_RNG,
.parent = TYPE_VIRTIO_DEVICE, .parent = TYPE_VIRTIO_DEVICE,
.instance_size = sizeof(VirtIORNG), .instance_size = sizeof(VirtIORNG),
.instance_init = virtio_rng_initfn,
.class_init = virtio_rng_class_init, .class_init = virtio_rng_class_init,
}; };

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2016 Red Hat, Inc. * Copyright (C) 2016-2017 Red Hat, Inc.
* Copyright (C) 2005 Anthony Liguori <anthony@codemonkey.ws> * Copyright (C) 2005 Anthony Liguori <anthony@codemonkey.ws>
* *
* Network Block Device * Network Block Device
@ -83,18 +83,37 @@ typedef struct NBDReply NBDReply;
#define NBD_FLAG_C_FIXED_NEWSTYLE (1 << 0) /* Fixed newstyle protocol. */ #define NBD_FLAG_C_FIXED_NEWSTYLE (1 << 0) /* Fixed newstyle protocol. */
#define NBD_FLAG_C_NO_ZEROES (1 << 1) /* End handshake without zeroes. */ #define NBD_FLAG_C_NO_ZEROES (1 << 1) /* End handshake without zeroes. */
/* Reply types. */ /* Option requests. */
#define NBD_OPT_EXPORT_NAME (1)
#define NBD_OPT_ABORT (2)
#define NBD_OPT_LIST (3)
/* #define NBD_OPT_PEEK_EXPORT (4) not in use */
#define NBD_OPT_STARTTLS (5)
#define NBD_OPT_INFO (6)
#define NBD_OPT_GO (7)
#define NBD_OPT_STRUCTURED_REPLY (8)
/* Option reply types. */
#define NBD_REP_ERR(value) ((UINT32_C(1) << 31) | (value)) #define NBD_REP_ERR(value) ((UINT32_C(1) << 31) | (value))
#define NBD_REP_ACK (1) /* Data sending finished. */ #define NBD_REP_ACK (1) /* Data sending finished. */
#define NBD_REP_SERVER (2) /* Export description. */ #define NBD_REP_SERVER (2) /* Export description. */
#define NBD_REP_INFO (3) /* NBD_OPT_INFO/GO. */
#define NBD_REP_ERR_UNSUP NBD_REP_ERR(1) /* Unknown option */ #define NBD_REP_ERR_UNSUP NBD_REP_ERR(1) /* Unknown option */
#define NBD_REP_ERR_POLICY NBD_REP_ERR(2) /* Server denied */ #define NBD_REP_ERR_POLICY NBD_REP_ERR(2) /* Server denied */
#define NBD_REP_ERR_INVALID NBD_REP_ERR(3) /* Invalid length */ #define NBD_REP_ERR_INVALID NBD_REP_ERR(3) /* Invalid length */
#define NBD_REP_ERR_PLATFORM NBD_REP_ERR(4) /* Not compiled in */ #define NBD_REP_ERR_PLATFORM NBD_REP_ERR(4) /* Not compiled in */
#define NBD_REP_ERR_TLS_REQD NBD_REP_ERR(5) /* TLS required */ #define NBD_REP_ERR_TLS_REQD NBD_REP_ERR(5) /* TLS required */
#define NBD_REP_ERR_SHUTDOWN NBD_REP_ERR(7) /* Server shutting down */ #define NBD_REP_ERR_UNKNOWN NBD_REP_ERR(6) /* Export unknown */
#define NBD_REP_ERR_SHUTDOWN NBD_REP_ERR(7) /* Server shutting down */
#define NBD_REP_ERR_BLOCK_SIZE_REQD NBD_REP_ERR(8) /* Need INFO_BLOCK_SIZE */
/* Info types, used during NBD_REP_INFO */
#define NBD_INFO_EXPORT 0
#define NBD_INFO_NAME 1
#define NBD_INFO_DESCRIPTION 2
#define NBD_INFO_BLOCK_SIZE 3
/* Request flags, sent from client to server during transmission phase */ /* Request flags, sent from client to server during transmission phase */
#define NBD_CMD_FLAG_FUA (1 << 0) /* 'force unit access' during write */ #define NBD_CMD_FLAG_FUA (1 << 0) /* 'force unit access' during write */
@ -123,13 +142,26 @@ enum {
* aren't overflowing some other buffer. */ * aren't overflowing some other buffer. */
#define NBD_MAX_NAME_SIZE 256 #define NBD_MAX_NAME_SIZE 256
/* Details collected by NBD_OPT_EXPORT_NAME and NBD_OPT_GO */
struct NBDExportInfo {
/* Set by client before nbd_receive_negotiate() */
bool request_sizes;
/* Set by server results during nbd_receive_negotiate() */
uint64_t size;
uint16_t flags;
uint32_t min_block;
uint32_t opt_block;
uint32_t max_block;
};
typedef struct NBDExportInfo NBDExportInfo;
ssize_t nbd_rwv(QIOChannel *ioc, struct iovec *iov, size_t niov, size_t length, ssize_t nbd_rwv(QIOChannel *ioc, struct iovec *iov, size_t niov, size_t length,
bool do_read, Error **errp); bool do_read, Error **errp);
int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags, int nbd_receive_negotiate(QIOChannel *ioc, const char *name,
QCryptoTLSCreds *tlscreds, const char *hostname, QCryptoTLSCreds *tlscreds, const char *hostname,
QIOChannel **outioc, QIOChannel **outioc, NBDExportInfo *info,
off_t *size, Error **errp); Error **errp);
int nbd_init(int fd, QIOChannelSocket *sioc, uint16_t flags, off_t size, int nbd_init(int fd, QIOChannelSocket *sioc, NBDExportInfo *info,
Error **errp); Error **errp);
ssize_t nbd_send_request(QIOChannel *ioc, NBDRequest *request); ssize_t nbd_send_request(QIOChannel *ioc, NBDRequest *request);
ssize_t nbd_receive_reply(QIOChannel *ioc, NBDReply *reply, Error **errp); ssize_t nbd_receive_reply(QIOChannel *ioc, NBDReply *reply, Error **errp);

View File

@ -4,6 +4,7 @@
#include "chardev/char.h" #include "chardev/char.h"
typedef void IOEventHandler(void *opaque, int event); typedef void IOEventHandler(void *opaque, int event);
typedef int BackendChangeHandler(void *opaque);
/* This is the backend as seen by frontend, the actual backend is /* This is the backend as seen by frontend, the actual backend is
* Chardev */ * Chardev */
@ -12,6 +13,7 @@ struct CharBackend {
IOEventHandler *chr_event; IOEventHandler *chr_event;
IOCanReadHandler *chr_can_read; IOCanReadHandler *chr_can_read;
IOReadHandler *chr_read; IOReadHandler *chr_read;
BackendChangeHandler *chr_be_change;
void *opaque; void *opaque;
int tag; int tag;
int fe_open; int fe_open;
@ -44,9 +46,26 @@ void qemu_chr_fe_deinit(CharBackend *b, bool del);
* *
* Returns the driver associated with a CharBackend or NULL if no * Returns the driver associated with a CharBackend or NULL if no
* associated Chardev. * associated Chardev.
* Note: avoid this function as the driver should never be accessed directly,
* especially by the frontends that support chardevice hotswap.
* Consider qemu_chr_fe_backend_connected() to check for driver existence
*/ */
Chardev *qemu_chr_fe_get_driver(CharBackend *be); Chardev *qemu_chr_fe_get_driver(CharBackend *be);
/**
* @qemu_chr_fe_backend_connected:
*
* Returns true if there is a chardevice associated with @be.
*/
bool qemu_chr_fe_backend_connected(CharBackend *be);
/**
* @qemu_chr_fe_backend_open:
*
* Returns true if chardevice associated with @be is open.
*/
bool qemu_chr_fe_backend_open(CharBackend *be);
/** /**
* @qemu_chr_fe_set_handlers: * @qemu_chr_fe_set_handlers:
* @b: a CharBackend * @b: a CharBackend
@ -54,6 +73,8 @@ Chardev *qemu_chr_fe_get_driver(CharBackend *be);
* receive * receive
* @fd_read: callback to receive data from char * @fd_read: callback to receive data from char
* @fd_event: event callback * @fd_event: event callback
* @be_change: backend change callback; passing NULL means hot backend change
* is not supported and will not be attempted
* @opaque: an opaque pointer for the callbacks * @opaque: an opaque pointer for the callbacks
* @context: a main loop context or NULL for the default * @context: a main loop context or NULL for the default
* @set_open: whether to call qemu_chr_fe_set_open() implicitely when * @set_open: whether to call qemu_chr_fe_set_open() implicitely when
@ -68,6 +89,7 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
IOCanReadHandler *fd_can_read, IOCanReadHandler *fd_can_read,
IOReadHandler *fd_read, IOReadHandler *fd_read,
IOEventHandler *fd_event, IOEventHandler *fd_event,
BackendChangeHandler *be_change,
void *opaque, void *opaque,
GMainContext *context, GMainContext *context,
bool set_open); bool set_open);

View File

@ -80,6 +80,16 @@ Chardev *qemu_chr_new_from_opts(QemuOpts *opts,
*/ */
void qemu_chr_parse_common(QemuOpts *opts, ChardevCommon *backend); void qemu_chr_parse_common(QemuOpts *opts, ChardevCommon *backend);
/**
* @qemu_chr_parse_opts:
*
* Parse the options to the ChardevBackend struct.
*
* Returns: a new backend or NULL on error
*/
ChardevBackend *qemu_chr_parse_opts(QemuOpts *opts,
Error **errp);
/** /**
* @qemu_chr_new: * @qemu_chr_new:
* *
@ -92,6 +102,15 @@ void qemu_chr_parse_common(QemuOpts *opts, ChardevCommon *backend);
*/ */
Chardev *qemu_chr_new(const char *label, const char *filename); Chardev *qemu_chr_new(const char *label, const char *filename);
/**
* @qemu_chr_change:
*
* Change an existing character backend
*
* @opts the new backend options
*/
void qemu_chr_change(QemuOpts *opts, Error **errp);
/** /**
* @qemu_chr_cleanup: * @qemu_chr_cleanup:
* *

View File

@ -290,6 +290,9 @@ static inline void tlb_flush_by_mmuidx_all_cpus_synced(CPUState *cpu,
uint16_t idxmap) uint16_t idxmap)
{ {
} }
static inline void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr)
{
}
#endif #endif
#define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */ #define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */

View File

@ -58,15 +58,6 @@ void gdb_register_coprocessor(CPUState *cpu,
gdb_reg_cb get_reg, gdb_reg_cb set_reg, gdb_reg_cb get_reg, gdb_reg_cb set_reg,
int num_regs, const char *xml, int g_pos); int num_regs, const char *xml, int g_pos);
static inline int cpu_index(CPUState *cpu)
{
#if defined(CONFIG_USER_ONLY)
return cpu->host_tid;
#else
return cpu->cpu_index + 1;
#endif
}
/* The GDB remote protocol transfers values in target byte order. This means /* The GDB remote protocol transfers values in target byte order. This means
* we can use the raw memory access routines to access the value buffer. * we can use the raw memory access routines to access the value buffer.
* Conveniently, these also handle the case where the buffer is mis-aligned. * Conveniently, these also handle the case where the buffer is mis-aligned.

View File

@ -25,6 +25,7 @@
#include "qemu/notify.h" #include "qemu/notify.h"
#include "qom/object.h" #include "qom/object.h"
#include "qemu/rcu.h" #include "qemu/rcu.h"
#include "hw/qdev-core.h"
#define RAM_ADDR_INVALID (~(ram_addr_t)0) #define RAM_ADDR_INVALID (~(ram_addr_t)0)
@ -35,6 +36,16 @@
#define MEMORY_REGION(obj) \ #define MEMORY_REGION(obj) \
OBJECT_CHECK(MemoryRegion, (obj), TYPE_MEMORY_REGION) OBJECT_CHECK(MemoryRegion, (obj), TYPE_MEMORY_REGION)
#define TYPE_IOMMU_MEMORY_REGION "qemu:iommu-memory-region"
#define IOMMU_MEMORY_REGION(obj) \
OBJECT_CHECK(IOMMUMemoryRegion, (obj), TYPE_IOMMU_MEMORY_REGION)
#define IOMMU_MEMORY_REGION_CLASS(klass) \
OBJECT_CLASS_CHECK(IOMMUMemoryRegionClass, (klass), \
TYPE_IOMMU_MEMORY_REGION)
#define IOMMU_MEMORY_REGION_GET_CLASS(obj) \
OBJECT_GET_CLASS(IOMMUMemoryRegionClass, (obj), \
TYPE_IOMMU_MEMORY_REGION)
typedef struct MemoryRegionOps MemoryRegionOps; typedef struct MemoryRegionOps MemoryRegionOps;
typedef struct MemoryRegionMmio MemoryRegionMmio; typedef struct MemoryRegionMmio MemoryRegionMmio;
@ -189,26 +200,27 @@ struct MemoryRegionOps {
const MemoryRegionMmio old_mmio; const MemoryRegionMmio old_mmio;
}; };
typedef struct MemoryRegionIOMMUOps MemoryRegionIOMMUOps; typedef struct IOMMUMemoryRegionClass {
/* private */
struct DeviceClass parent_class;
struct MemoryRegionIOMMUOps {
/* /*
* Return a TLB entry that contains a given address. Flag should * Return a TLB entry that contains a given address. Flag should
* be the access permission of this translation operation. We can * be the access permission of this translation operation. We can
* set flag to IOMMU_NONE to mean that we don't need any * set flag to IOMMU_NONE to mean that we don't need any
* read/write permission checks, like, when for region replay. * read/write permission checks, like, when for region replay.
*/ */
IOMMUTLBEntry (*translate)(MemoryRegion *iommu, hwaddr addr, IOMMUTLBEntry (*translate)(IOMMUMemoryRegion *iommu, hwaddr addr,
IOMMUAccessFlags flag); IOMMUAccessFlags flag);
/* Returns minimum supported page size */ /* Returns minimum supported page size */
uint64_t (*get_min_page_size)(MemoryRegion *iommu); uint64_t (*get_min_page_size)(IOMMUMemoryRegion *iommu);
/* Called when IOMMU Notifier flag changed */ /* Called when IOMMU Notifier flag changed */
void (*notify_flag_changed)(MemoryRegion *iommu, void (*notify_flag_changed)(IOMMUMemoryRegion *iommu,
IOMMUNotifierFlag old_flags, IOMMUNotifierFlag old_flags,
IOMMUNotifierFlag new_flags); IOMMUNotifierFlag new_flags);
/* Set this up to provide customized IOMMU replay function */ /* Set this up to provide customized IOMMU replay function */
void (*replay)(MemoryRegion *iommu, IOMMUNotifier *notifier); void (*replay)(IOMMUMemoryRegion *iommu, IOMMUNotifier *notifier);
}; } IOMMUMemoryRegionClass;
typedef struct CoalescedMemoryRange CoalescedMemoryRange; typedef struct CoalescedMemoryRange CoalescedMemoryRange;
typedef struct MemoryRegionIoeventfd MemoryRegionIoeventfd; typedef struct MemoryRegionIoeventfd MemoryRegionIoeventfd;
@ -227,9 +239,9 @@ struct MemoryRegion {
bool flush_coalesced_mmio; bool flush_coalesced_mmio;
bool global_locking; bool global_locking;
uint8_t dirty_log_mask; uint8_t dirty_log_mask;
bool is_iommu;
RAMBlock *ram_block; RAMBlock *ram_block;
Object *owner; Object *owner;
const MemoryRegionIOMMUOps *iommu_ops;
const MemoryRegionOps *ops; const MemoryRegionOps *ops;
void *opaque; void *opaque;
@ -252,6 +264,11 @@ struct MemoryRegion {
const char *name; const char *name;
unsigned ioeventfd_nb; unsigned ioeventfd_nb;
MemoryRegionIoeventfd *ioeventfds; MemoryRegionIoeventfd *ioeventfds;
};
struct IOMMUMemoryRegion {
MemoryRegion parent_obj;
QLIST_HEAD(, IOMMUNotifier) iommu_notify; QLIST_HEAD(, IOMMUNotifier) iommu_notify;
IOMMUNotifierFlag iommu_notify_flags; IOMMUNotifierFlag iommu_notify_flags;
}; };
@ -612,21 +629,24 @@ static inline void memory_region_init_reservation(MemoryRegion *mr,
} }
/** /**
* memory_region_init_iommu: Initialize a memory region that translates * memory_region_init_iommu: Initialize a memory region of a custom type
* addresses * that translates addresses
* *
* An IOMMU region translates addresses and forwards accesses to a target * An IOMMU region translates addresses and forwards accesses to a target
* memory region. * memory region.
* *
* @mr: the #MemoryRegion to be initialized * @typename: QOM class name
* @_iommu_mr: the #IOMMUMemoryRegion to be initialized
* @instance_size: the IOMMUMemoryRegion subclass instance size
* @owner: the object that tracks the region's reference count * @owner: the object that tracks the region's reference count
* @ops: a function that translates addresses into the @target region * @ops: a function that translates addresses into the @target region
* @name: used for debugging; not visible to the user or ABI * @name: used for debugging; not visible to the user or ABI
* @size: size of the region. * @size: size of the region.
*/ */
void memory_region_init_iommu(MemoryRegion *mr, void memory_region_init_iommu(void *_iommu_mr,
struct Object *owner, size_t instance_size,
const MemoryRegionIOMMUOps *ops, const char *mrtypename,
Object *owner,
const char *name, const char *name,
uint64_t size); uint64_t size);
@ -679,20 +699,40 @@ static inline bool memory_region_is_romd(MemoryRegion *mr)
} }
/** /**
* memory_region_is_iommu: check whether a memory region is an iommu * memory_region_get_iommu: check whether a memory region is an iommu
* *
* Returns %true is a memory region is an iommu. * Returns pointer to IOMMUMemoryRegion if a memory region is an iommu,
* otherwise NULL.
* *
* @mr: the memory region being queried * @mr: the memory region being queried
*/ */
static inline bool memory_region_is_iommu(MemoryRegion *mr) static inline IOMMUMemoryRegion *memory_region_get_iommu(MemoryRegion *mr)
{ {
if (mr->alias) { if (mr->alias) {
return memory_region_is_iommu(mr->alias); return memory_region_get_iommu(mr->alias);
} }
return mr->iommu_ops; if (mr->is_iommu) {
return (IOMMUMemoryRegion *) mr;
}
return NULL;
} }
/**
* memory_region_get_iommu_class_nocheck: returns iommu memory region class
* if an iommu or NULL if not
*
* Returns pointer to IOMMUMemoryRegioniClass if a memory region is an iommu,
* otherwise NULL. This is fast path avoinding QOM checking, use with caution.
*
* @mr: the memory region being queried
*/
static inline IOMMUMemoryRegionClass *memory_region_get_iommu_class_nocheck(
IOMMUMemoryRegion *iommu_mr)
{
return (IOMMUMemoryRegionClass *) (((Object *)iommu_mr)->class);
}
#define memory_region_is_iommu(mr) (memory_region_get_iommu(mr) != NULL)
/** /**
* memory_region_iommu_get_min_page_size: get minimum supported page size * memory_region_iommu_get_min_page_size: get minimum supported page size
@ -700,9 +740,9 @@ static inline bool memory_region_is_iommu(MemoryRegion *mr)
* *
* Returns minimum supported page size for an iommu. * Returns minimum supported page size for an iommu.
* *
* @mr: the memory region being queried * @iommu_mr: the memory region being queried
*/ */
uint64_t memory_region_iommu_get_min_page_size(MemoryRegion *mr); uint64_t memory_region_iommu_get_min_page_size(IOMMUMemoryRegion *iommu_mr);
/** /**
* memory_region_notify_iommu: notify a change in an IOMMU translation entry. * memory_region_notify_iommu: notify a change in an IOMMU translation entry.
@ -716,12 +756,12 @@ uint64_t memory_region_iommu_get_min_page_size(MemoryRegion *mr);
* Note: for any IOMMU implementation, an in-place mapping change * Note: for any IOMMU implementation, an in-place mapping change
* should be notified with an UNMAP followed by a MAP. * should be notified with an UNMAP followed by a MAP.
* *
* @mr: the memory region that was changed * @iommu_mr: the memory region that was changed
* @entry: the new entry in the IOMMU translation table. The entry * @entry: the new entry in the IOMMU translation table. The entry
* replaces all old entries for the same virtual I/O address range. * replaces all old entries for the same virtual I/O address range.
* Deleted entries have .@perm == 0. * Deleted entries have .@perm == 0.
*/ */
void memory_region_notify_iommu(MemoryRegion *mr, void memory_region_notify_iommu(IOMMUMemoryRegion *iommu_mr,
IOMMUTLBEntry entry); IOMMUTLBEntry entry);
/** /**
@ -756,18 +796,18 @@ void memory_region_register_iommu_notifier(MemoryRegion *mr,
* a notifier with the minimum page granularity returned by * a notifier with the minimum page granularity returned by
* mr->iommu_ops->get_page_size(). * mr->iommu_ops->get_page_size().
* *
* @mr: the memory region to observe * @iommu_mr: the memory region to observe
* @n: the notifier to which to replay iommu mappings * @n: the notifier to which to replay iommu mappings
*/ */
void memory_region_iommu_replay(MemoryRegion *mr, IOMMUNotifier *n); void memory_region_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n);
/** /**
* memory_region_iommu_replay_all: replay existing IOMMU translations * memory_region_iommu_replay_all: replay existing IOMMU translations
* to all the notifiers registered. * to all the notifiers registered.
* *
* @mr: the memory region to observe * @iommu_mr: the memory region to observe
*/ */
void memory_region_iommu_replay_all(MemoryRegion *mr); void memory_region_iommu_replay_all(IOMMUMemoryRegion *iommu_mr);
/** /**
* memory_region_unregister_iommu_notifier: unregister a notifier for * memory_region_unregister_iommu_notifier: unregister a notifier for

View File

@ -32,6 +32,8 @@
#define INTEL_IOMMU_DEVICE(obj) \ #define INTEL_IOMMU_DEVICE(obj) \
OBJECT_CHECK(IntelIOMMUState, (obj), TYPE_INTEL_IOMMU_DEVICE) OBJECT_CHECK(IntelIOMMUState, (obj), TYPE_INTEL_IOMMU_DEVICE)
#define TYPE_INTEL_IOMMU_MEMORY_REGION "intel-iommu-iommu-memory-region"
/* DMAR Hardware Unit Definition address (IOMMU unit) */ /* DMAR Hardware Unit Definition address (IOMMU unit) */
#define Q35_HOST_BRIDGE_IOMMU_ADDR 0xfed90000ULL #define Q35_HOST_BRIDGE_IOMMU_ADDR 0xfed90000ULL
@ -83,7 +85,7 @@ struct VTDAddressSpace {
PCIBus *bus; PCIBus *bus;
uint8_t devfn; uint8_t devfn;
AddressSpace as; AddressSpace as;
MemoryRegion iommu; IOMMUMemoryRegion iommu;
MemoryRegion root; MemoryRegion root;
MemoryRegion sys_alias; MemoryRegion sys_alias;
MemoryRegion iommu_ir; /* Interrupt region: 0xfeeXXXXX */ MemoryRegion iommu_ir; /* Interrupt region: 0xfeeXXXXX */
@ -289,7 +291,6 @@ struct IntelIOMMUState {
uint32_t context_cache_gen; /* Should be in [1,MAX] */ uint32_t context_cache_gen; /* Should be in [1,MAX] */
GHashTable *iotlb; /* IOTLB */ GHashTable *iotlb; /* IOTLB */
MemoryRegionIOMMUOps iommu_ops;
GHashTable *vtd_as_by_busptr; /* VTDBus objects indexed by PCIBus* reference */ GHashTable *vtd_as_by_busptr; /* VTDBus objects indexed by PCIBus* reference */
VTDBus *vtd_as_by_bus_num[VTD_PCI_BUS_MAX]; /* VTDBus objects indexed by bus number */ VTDBus *vtd_as_by_bus_num[VTD_PCI_BUS_MAX]; /* VTDBus objects indexed by bus number */
/* list of registered notifiers */ /* list of registered notifiers */

View File

@ -19,6 +19,6 @@ typedef struct rc4030DMAState *rc4030_dma;
void rc4030_dma_read(void *dma, uint8_t *buf, int len); void rc4030_dma_read(void *dma, uint8_t *buf, int len);
void rc4030_dma_write(void *dma, uint8_t *buf, int len); void rc4030_dma_write(void *dma, uint8_t *buf, int len);
DeviceState *rc4030_init(rc4030_dma **dmas, MemoryRegion **dma_mr); DeviceState *rc4030_init(rc4030_dma **dmas, IOMMUMemoryRegion **dma_mr);
#endif #endif

View File

@ -582,6 +582,10 @@ typedef struct sPAPRTCETable sPAPRTCETable;
#define SPAPR_TCE_TABLE(obj) \ #define SPAPR_TCE_TABLE(obj) \
OBJECT_CHECK(sPAPRTCETable, (obj), TYPE_SPAPR_TCE_TABLE) OBJECT_CHECK(sPAPRTCETable, (obj), TYPE_SPAPR_TCE_TABLE)
#define TYPE_SPAPR_IOMMU_MEMORY_REGION "spapr-iommu-memory-region"
#define SPAPR_IOMMU_MEMORY_REGION(obj) \
OBJECT_CHECK(IOMMUMemoryRegion, (obj), TYPE_SPAPR_IOMMU_MEMORY_REGION)
struct sPAPRTCETable { struct sPAPRTCETable {
DeviceState parent; DeviceState parent;
uint32_t liobn; uint32_t liobn;
@ -594,7 +598,8 @@ struct sPAPRTCETable {
bool bypass; bool bypass;
bool need_vfio; bool need_vfio;
int fd; int fd;
MemoryRegion root, iommu; MemoryRegion root;
IOMMUMemoryRegion iommu;
struct VIOsPAPRDevice *vdev; /* for @bypass migration compatibility only */ struct VIOsPAPRDevice *vdev; /* for @bypass migration compatibility only */
QLIST_ENTRY(sPAPRTCETable) list; QLIST_ENTRY(sPAPRTCETable) list;
}; };

View File

@ -223,7 +223,7 @@ struct BusState {
struct Property { struct Property {
const char *name; const char *name;
PropertyInfo *info; const PropertyInfo *info;
ptrdiff_t offset; ptrdiff_t offset;
uint8_t bitnr; uint8_t bitnr;
union { union {
@ -231,8 +231,9 @@ struct Property {
uint64_t u; uint64_t u;
} defval; } defval;
int arrayoffset; int arrayoffset;
PropertyInfo *arrayinfo; const PropertyInfo *arrayinfo;
int arrayfieldsize; int arrayfieldsize;
const char *link_type;
}; };
struct PropertyInfo { struct PropertyInfo {
@ -241,6 +242,7 @@ struct PropertyInfo {
const char * const *enum_table; const char * const *enum_table;
int (*print)(DeviceState *dev, Property *prop, char *dest, size_t len); int (*print)(DeviceState *dev, Property *prop, char *dest, size_t len);
void (*set_default_value)(Object *obj, const Property *prop); void (*set_default_value)(Object *obj, const Property *prop);
void (*create)(Object *obj, Property *prop, Error **errp);
ObjectPropertyAccessor *get; ObjectPropertyAccessor *get;
ObjectPropertyAccessor *set; ObjectPropertyAccessor *set;
ObjectPropertyRelease *release; ObjectPropertyRelease *release;

View File

@ -5,31 +5,32 @@
/*** qdev-properties.c ***/ /*** qdev-properties.c ***/
extern PropertyInfo qdev_prop_bit; extern const PropertyInfo qdev_prop_bit;
extern PropertyInfo qdev_prop_bit64; extern const PropertyInfo qdev_prop_bit64;
extern PropertyInfo qdev_prop_bool; extern const PropertyInfo qdev_prop_bool;
extern PropertyInfo qdev_prop_uint8; extern const PropertyInfo qdev_prop_uint8;
extern PropertyInfo qdev_prop_uint16; extern const PropertyInfo qdev_prop_uint16;
extern PropertyInfo qdev_prop_uint32; extern const PropertyInfo qdev_prop_uint32;
extern PropertyInfo qdev_prop_int32; extern const PropertyInfo qdev_prop_int32;
extern PropertyInfo qdev_prop_uint64; extern const PropertyInfo qdev_prop_uint64;
extern PropertyInfo qdev_prop_size; extern const PropertyInfo qdev_prop_size;
extern PropertyInfo qdev_prop_string; extern const PropertyInfo qdev_prop_string;
extern PropertyInfo qdev_prop_chr; extern const PropertyInfo qdev_prop_chr;
extern PropertyInfo qdev_prop_ptr; extern const PropertyInfo qdev_prop_ptr;
extern PropertyInfo qdev_prop_macaddr; extern const PropertyInfo qdev_prop_macaddr;
extern PropertyInfo qdev_prop_on_off_auto; extern const PropertyInfo qdev_prop_on_off_auto;
extern PropertyInfo qdev_prop_losttickpolicy; extern const PropertyInfo qdev_prop_losttickpolicy;
extern PropertyInfo qdev_prop_blockdev_on_error; extern const PropertyInfo qdev_prop_blockdev_on_error;
extern PropertyInfo qdev_prop_bios_chs_trans; extern const PropertyInfo qdev_prop_bios_chs_trans;
extern PropertyInfo qdev_prop_fdc_drive_type; extern const PropertyInfo qdev_prop_fdc_drive_type;
extern PropertyInfo qdev_prop_drive; extern const PropertyInfo qdev_prop_drive;
extern PropertyInfo qdev_prop_netdev; extern const PropertyInfo qdev_prop_netdev;
extern PropertyInfo qdev_prop_vlan; extern const PropertyInfo qdev_prop_vlan;
extern PropertyInfo qdev_prop_pci_devfn; extern const PropertyInfo qdev_prop_pci_devfn;
extern PropertyInfo qdev_prop_blocksize; extern const PropertyInfo qdev_prop_blocksize;
extern PropertyInfo qdev_prop_pci_host_devaddr; extern const PropertyInfo qdev_prop_pci_host_devaddr;
extern PropertyInfo qdev_prop_arraylen; extern const PropertyInfo qdev_prop_arraylen;
extern const PropertyInfo qdev_prop_link;
#define DEFINE_PROP(_name, _state, _field, _prop, _type) { \ #define DEFINE_PROP(_name, _state, _field, _prop, _type) { \
.name = (_name), \ .name = (_name), \
@ -117,6 +118,14 @@ extern PropertyInfo qdev_prop_arraylen;
.arrayoffset = offsetof(_state, _arrayfield), \ .arrayoffset = offsetof(_state, _arrayfield), \
} }
#define DEFINE_PROP_LINK(_name, _state, _field, _type, _ptr_type) { \
.name = (_name), \
.info = &(qdev_prop_link), \
.offset = offsetof(_state, _field) \
+ type_check(_ptr_type, typeof_field(_state, _field)), \
.link_type = _type, \
}
#define DEFINE_PROP_UINT8(_n, _s, _f, _d) \ #define DEFINE_PROP_UINT8(_n, _s, _f, _d) \
DEFINE_PROP_UNSIGNED(_n, _s, _f, _d, qdev_prop_uint8, uint8_t) DEFINE_PROP_UNSIGNED(_n, _s, _f, _d, qdev_prop_uint8, uint8_t)
#define DEFINE_PROP_UINT16(_n, _s, _f, _d) \ #define DEFINE_PROP_UINT16(_n, _s, _f, _d) \
@ -272,7 +281,8 @@ void qdev_prop_set_after_realize(DeviceState *dev, const char *name,
* This function should be used as the check() argument to * This function should be used as the check() argument to
* object_property_add_link(). * object_property_add_link().
*/ */
void qdev_prop_allow_set_link_before_realize(Object *obj, const char *name, void qdev_prop_allow_set_link_before_realize(const Object *obj,
const char *name,
Object *val, Error **errp); Object *val, Error **errp);
#endif #endif

View File

@ -112,7 +112,7 @@ typedef struct CssDevId {
bool valid; bool valid;
} CssDevId; } CssDevId;
extern PropertyInfo css_devid_propinfo; extern const PropertyInfo css_devid_propinfo;
#define DEFINE_PROP_CSS_DEV_ID(_n, _s, _f) \ #define DEFINE_PROP_CSS_DEV_ID(_n, _s, _f) \
DEFINE_PROP(_n, _s, _f, css_devid_propinfo, CssDevId) DEFINE_PROP(_n, _s, _f, css_devid_propinfo, CssDevId)
@ -196,7 +196,7 @@ int css_do_rchp(uint8_t cssid, uint8_t chpid);
bool css_present(uint8_t cssid); bool css_present(uint8_t cssid);
#endif #endif
extern PropertyInfo css_devid_ro_propinfo; extern const PropertyInfo css_devid_ro_propinfo;
#define DEFINE_PROP_CSS_DEV_ID_RO(_n, _s, _f) \ #define DEFINE_PROP_CSS_DEV_ID_RO(_n, _s, _f) \
DEFINE_PROP(_n, _s, _f, css_devid_ro_propinfo, CssDevId) DEFINE_PROP(_n, _s, _f, css_devid_ro_propinfo, CssDevId)

View File

@ -95,7 +95,7 @@ typedef struct VFIOContainer {
typedef struct VFIOGuestIOMMU { typedef struct VFIOGuestIOMMU {
VFIOContainer *container; VFIOContainer *container;
MemoryRegion *iommu; IOMMUMemoryRegion *iommu;
hwaddr iommu_offset; hwaddr iommu_offset;
IOMMUNotifier n; IOMMUNotifier n;
QLIST_ENTRY(VFIOGuestIOMMU) giommu_next; QLIST_ENTRY(VFIOGuestIOMMU) giommu_next;

View File

@ -45,6 +45,7 @@ typedef struct MachineState MachineState;
typedef struct MemoryListener MemoryListener; typedef struct MemoryListener MemoryListener;
typedef struct MemoryMappingList MemoryMappingList; typedef struct MemoryMappingList MemoryMappingList;
typedef struct MemoryRegion MemoryRegion; typedef struct MemoryRegion MemoryRegion;
typedef struct IOMMUMemoryRegion IOMMUMemoryRegion;
typedef struct MemoryRegionCache MemoryRegionCache; typedef struct MemoryRegionCache MemoryRegionCache;
typedef struct MemoryRegionSection MemoryRegionSection; typedef struct MemoryRegionSection MemoryRegionSection;
typedef struct MigrationIncomingState MigrationIncomingState; typedef struct MigrationIncomingState MigrationIncomingState;

View File

@ -265,7 +265,6 @@ struct qemu_work_item;
* @cpu_index: CPU index (informative). * @cpu_index: CPU index (informative).
* @nr_cores: Number of cores within this CPU package. * @nr_cores: Number of cores within this CPU package.
* @nr_threads: Number of threads within this CPU. * @nr_threads: Number of threads within this CPU.
* @host_tid: Host thread ID.
* @running: #true if CPU is currently running (lockless). * @running: #true if CPU is currently running (lockless).
* @has_waiter: #true if a CPU is currently waiting for the cpu_exec_end; * @has_waiter: #true if a CPU is currently waiting for the cpu_exec_end;
* valid under cpu_list_lock. * valid under cpu_list_lock.
@ -319,7 +318,6 @@ struct CPUState {
HANDLE hThread; HANDLE hThread;
#endif #endif
int thread_id; int thread_id;
uint32_t host_tid;
bool running, has_waiter; bool running, has_waiter;
struct QemuCond *halt_cond; struct QemuCond *halt_cond;
bool thread_kicked; bool thread_kicked;
@ -1015,6 +1013,7 @@ AddressSpace *cpu_get_address_space(CPUState *cpu, int asidx);
void QEMU_NORETURN cpu_abort(CPUState *cpu, const char *fmt, ...) void QEMU_NORETURN cpu_abort(CPUState *cpu, const char *fmt, ...)
GCC_FMT_ATTR(2, 3); GCC_FMT_ATTR(2, 3);
extern Property cpu_common_props[];
void cpu_exec_initfn(CPUState *cpu); void cpu_exec_initfn(CPUState *cpu);
void cpu_exec_realizefn(CPUState *cpu, Error **errp); void cpu_exec_realizefn(CPUState *cpu, Error **errp);
void cpu_exec_unrealizefn(CPUState *cpu); void cpu_exec_unrealizefn(CPUState *cpu);

View File

@ -764,7 +764,7 @@ ObjectClass *object_get_class(Object *obj);
* *
* Returns: The QOM typename of @obj. * Returns: The QOM typename of @obj.
*/ */
const char *object_get_typename(Object *obj); const char *object_get_typename(const Object *obj);
/** /**
* type_register_static: * type_register_static:
@ -1319,7 +1319,7 @@ typedef enum {
* callback function. It allows the link property to be set and never returns * callback function. It allows the link property to be set and never returns
* an error. * an error.
*/ */
void object_property_allow_set_link(Object *, const char *, void object_property_allow_set_link(const Object *, const char *,
Object *, Error **); Object *, Error **);
/** /**
@ -1352,7 +1352,7 @@ void object_property_allow_set_link(Object *, const char *,
*/ */
void object_property_add_link(Object *obj, const char *name, void object_property_add_link(Object *obj, const char *name,
const char *type, Object **child, const char *type, Object **child,
void (*check)(Object *obj, const char *name, void (*check)(const Object *obj, const char *name,
Object *val, Error **errp), Object *val, Error **errp),
ObjectPropertyLinkFlags flags, ObjectPropertyLinkFlags flags,
Error **errp); Error **errp);

View File

@ -6219,7 +6219,6 @@ static void *clone_func(void *arg)
thread_cpu = cpu; thread_cpu = cpu;
ts = (TaskState *)cpu->opaque; ts = (TaskState *)cpu->opaque;
info->tid = gettid(); info->tid = gettid();
cpu->host_tid = info->tid;
task_settid(ts); task_settid(ts);
if (info->child_tidptr) if (info->child_tidptr)
put_user_u32(info->tid, info->child_tidptr); put_user_u32(info->tid, info->child_tidptr);

113
memory.c
View File

@ -977,12 +977,11 @@ static char *memory_region_escape_name(const char *name)
return escaped; return escaped;
} }
void memory_region_init(MemoryRegion *mr, static void memory_region_do_init(MemoryRegion *mr,
Object *owner, Object *owner,
const char *name, const char *name,
uint64_t size) uint64_t size)
{ {
object_initialize(mr, sizeof(*mr), TYPE_MEMORY_REGION);
mr->size = int128_make64(size); mr->size = int128_make64(size);
if (size == UINT64_MAX) { if (size == UINT64_MAX) {
mr->size = int128_2_64(); mr->size = int128_2_64();
@ -1006,6 +1005,15 @@ void memory_region_init(MemoryRegion *mr,
} }
} }
void memory_region_init(MemoryRegion *mr,
Object *owner,
const char *name,
uint64_t size)
{
object_initialize(mr, sizeof(*mr), TYPE_MEMORY_REGION);
memory_region_do_init(mr, owner, name, size);
}
static void memory_region_get_addr(Object *obj, Visitor *v, const char *name, static void memory_region_get_addr(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp) void *opaque, Error **errp)
{ {
@ -1092,6 +1100,13 @@ static void memory_region_initfn(Object *obj)
NULL, NULL, &error_abort); NULL, NULL, &error_abort);
} }
static void iommu_memory_region_initfn(Object *obj)
{
MemoryRegion *mr = MEMORY_REGION(obj);
mr->is_iommu = true;
}
static uint64_t unassigned_mem_read(void *opaque, hwaddr addr, static uint64_t unassigned_mem_read(void *opaque, hwaddr addr,
unsigned size) unsigned size)
{ {
@ -1491,17 +1506,23 @@ void memory_region_init_rom_device(MemoryRegion *mr,
mr->ram_block = qemu_ram_alloc(size, mr, errp); mr->ram_block = qemu_ram_alloc(size, mr, errp);
} }
void memory_region_init_iommu(MemoryRegion *mr, void memory_region_init_iommu(void *_iommu_mr,
size_t instance_size,
const char *mrtypename,
Object *owner, Object *owner,
const MemoryRegionIOMMUOps *ops,
const char *name, const char *name,
uint64_t size) uint64_t size)
{ {
memory_region_init(mr, owner, name, size); struct IOMMUMemoryRegion *iommu_mr;
mr->iommu_ops = ops, struct MemoryRegion *mr;
object_initialize(_iommu_mr, instance_size, mrtypename);
mr = MEMORY_REGION(_iommu_mr);
memory_region_do_init(mr, owner, name, size);
iommu_mr = IOMMU_MEMORY_REGION(mr);
mr->terminates = true; /* then re-forwards */ mr->terminates = true; /* then re-forwards */
QLIST_INIT(&mr->iommu_notify); QLIST_INIT(&iommu_mr->iommu_notify);
mr->iommu_notify_flags = IOMMU_NOTIFIER_NONE; iommu_mr->iommu_notify_flags = IOMMU_NOTIFIER_NONE;
} }
static void memory_region_finalize(Object *obj) static void memory_region_finalize(Object *obj)
@ -1596,63 +1617,70 @@ bool memory_region_is_logging(MemoryRegion *mr, uint8_t client)
return memory_region_get_dirty_log_mask(mr) & (1 << client); return memory_region_get_dirty_log_mask(mr) & (1 << client);
} }
static void memory_region_update_iommu_notify_flags(MemoryRegion *mr) static void memory_region_update_iommu_notify_flags(IOMMUMemoryRegion *iommu_mr)
{ {
IOMMUNotifierFlag flags = IOMMU_NOTIFIER_NONE; IOMMUNotifierFlag flags = IOMMU_NOTIFIER_NONE;
IOMMUNotifier *iommu_notifier; IOMMUNotifier *iommu_notifier;
IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_GET_CLASS(iommu_mr);
IOMMU_NOTIFIER_FOREACH(iommu_notifier, mr) { IOMMU_NOTIFIER_FOREACH(iommu_notifier, iommu_mr) {
flags |= iommu_notifier->notifier_flags; flags |= iommu_notifier->notifier_flags;
} }
if (flags != mr->iommu_notify_flags && if (flags != iommu_mr->iommu_notify_flags && imrc->notify_flag_changed) {
mr->iommu_ops->notify_flag_changed) { imrc->notify_flag_changed(iommu_mr,
mr->iommu_ops->notify_flag_changed(mr, mr->iommu_notify_flags, iommu_mr->iommu_notify_flags,
flags); flags);
} }
mr->iommu_notify_flags = flags; iommu_mr->iommu_notify_flags = flags;
} }
void memory_region_register_iommu_notifier(MemoryRegion *mr, void memory_region_register_iommu_notifier(MemoryRegion *mr,
IOMMUNotifier *n) IOMMUNotifier *n)
{ {
IOMMUMemoryRegion *iommu_mr;
if (mr->alias) { if (mr->alias) {
memory_region_register_iommu_notifier(mr->alias, n); memory_region_register_iommu_notifier(mr->alias, n);
return; return;
} }
/* We need to register for at least one bitfield */ /* We need to register for at least one bitfield */
iommu_mr = IOMMU_MEMORY_REGION(mr);
assert(n->notifier_flags != IOMMU_NOTIFIER_NONE); assert(n->notifier_flags != IOMMU_NOTIFIER_NONE);
assert(n->start <= n->end); assert(n->start <= n->end);
QLIST_INSERT_HEAD(&mr->iommu_notify, n, node); QLIST_INSERT_HEAD(&iommu_mr->iommu_notify, n, node);
memory_region_update_iommu_notify_flags(mr); memory_region_update_iommu_notify_flags(iommu_mr);
} }
uint64_t memory_region_iommu_get_min_page_size(MemoryRegion *mr) uint64_t memory_region_iommu_get_min_page_size(IOMMUMemoryRegion *iommu_mr)
{ {
assert(memory_region_is_iommu(mr)); IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_GET_CLASS(iommu_mr);
if (mr->iommu_ops && mr->iommu_ops->get_min_page_size) {
return mr->iommu_ops->get_min_page_size(mr); if (imrc->get_min_page_size) {
return imrc->get_min_page_size(iommu_mr);
} }
return TARGET_PAGE_SIZE; return TARGET_PAGE_SIZE;
} }
void memory_region_iommu_replay(MemoryRegion *mr, IOMMUNotifier *n) void memory_region_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n)
{ {
MemoryRegion *mr = MEMORY_REGION(iommu_mr);
IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_GET_CLASS(iommu_mr);
hwaddr addr, granularity; hwaddr addr, granularity;
IOMMUTLBEntry iotlb; IOMMUTLBEntry iotlb;
/* If the IOMMU has its own replay callback, override */ /* If the IOMMU has its own replay callback, override */
if (mr->iommu_ops->replay) { if (imrc->replay) {
mr->iommu_ops->replay(mr, n); imrc->replay(iommu_mr, n);
return; return;
} }
granularity = memory_region_iommu_get_min_page_size(mr); granularity = memory_region_iommu_get_min_page_size(iommu_mr);
for (addr = 0; addr < memory_region_size(mr); addr += granularity) { for (addr = 0; addr < memory_region_size(mr); addr += granularity) {
iotlb = mr->iommu_ops->translate(mr, addr, IOMMU_NONE); iotlb = imrc->translate(iommu_mr, addr, IOMMU_NONE);
if (iotlb.perm != IOMMU_NONE) { if (iotlb.perm != IOMMU_NONE) {
n->notify(n, &iotlb); n->notify(n, &iotlb);
} }
@ -1665,24 +1693,27 @@ void memory_region_iommu_replay(MemoryRegion *mr, IOMMUNotifier *n)
} }
} }
void memory_region_iommu_replay_all(MemoryRegion *mr) void memory_region_iommu_replay_all(IOMMUMemoryRegion *iommu_mr)
{ {
IOMMUNotifier *notifier; IOMMUNotifier *notifier;
IOMMU_NOTIFIER_FOREACH(notifier, mr) { IOMMU_NOTIFIER_FOREACH(notifier, iommu_mr) {
memory_region_iommu_replay(mr, notifier); memory_region_iommu_replay(iommu_mr, notifier);
} }
} }
void memory_region_unregister_iommu_notifier(MemoryRegion *mr, void memory_region_unregister_iommu_notifier(MemoryRegion *mr,
IOMMUNotifier *n) IOMMUNotifier *n)
{ {
IOMMUMemoryRegion *iommu_mr;
if (mr->alias) { if (mr->alias) {
memory_region_unregister_iommu_notifier(mr->alias, n); memory_region_unregister_iommu_notifier(mr->alias, n);
return; return;
} }
QLIST_REMOVE(n, node); QLIST_REMOVE(n, node);
memory_region_update_iommu_notify_flags(mr); iommu_mr = IOMMU_MEMORY_REGION(mr);
memory_region_update_iommu_notify_flags(iommu_mr);
} }
void memory_region_notify_one(IOMMUNotifier *notifier, void memory_region_notify_one(IOMMUNotifier *notifier,
@ -1710,14 +1741,14 @@ void memory_region_notify_one(IOMMUNotifier *notifier,
} }
} }
void memory_region_notify_iommu(MemoryRegion *mr, void memory_region_notify_iommu(IOMMUMemoryRegion *iommu_mr,
IOMMUTLBEntry entry) IOMMUTLBEntry entry)
{ {
IOMMUNotifier *iommu_notifier; IOMMUNotifier *iommu_notifier;
assert(memory_region_is_iommu(mr)); assert(memory_region_is_iommu(MEMORY_REGION(iommu_mr)));
IOMMU_NOTIFIER_FOREACH(iommu_notifier, mr) { IOMMU_NOTIFIER_FOREACH(iommu_notifier, iommu_mr) {
memory_region_notify_one(iommu_notifier, &entry); memory_region_notify_one(iommu_notifier, &entry);
} }
} }
@ -2825,9 +2856,19 @@ static const TypeInfo memory_region_info = {
.instance_finalize = memory_region_finalize, .instance_finalize = memory_region_finalize,
}; };
static const TypeInfo iommu_memory_region_info = {
.parent = TYPE_MEMORY_REGION,
.name = TYPE_IOMMU_MEMORY_REGION,
.class_size = sizeof(IOMMUMemoryRegionClass),
.instance_size = sizeof(IOMMUMemoryRegion),
.instance_init = iommu_memory_region_initfn,
.abstract = true,
};
static void memory_register_types(void) static void memory_register_types(void)
{ {
type_register_static(&memory_region_info); type_register_static(&memory_region_info);
type_register_static(&iommu_memory_region_info);
} }
type_init(memory_register_types) type_init(memory_register_types)

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