mirror of
https://github.com/qemu/qemu.git
synced 2024-11-23 19:03:38 +08:00
* 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:
commit
6c6076662d
18
MAINTAINERS
18
MAINTAINERS
@ -84,14 +84,10 @@ M: Paolo Bonzini <pbonzini@redhat.com>
|
||||
M: Peter Crosthwaite <crosthwaite.peter@gmail.com>
|
||||
M: Richard Henderson <rth@twiddle.net>
|
||||
S: Maintained
|
||||
F: cpu-exec.c
|
||||
F: cpu-exec-common.c
|
||||
F: cpus.c
|
||||
F: cputlb.c
|
||||
F: exec.c
|
||||
F: softmmu_template.h
|
||||
F: translate-all.*
|
||||
F: translate-common.c
|
||||
F: accel/tcg/
|
||||
F: include/exec/cpu*.h
|
||||
F: include/exec/exec-all.h
|
||||
F: include/exec/helper*.h
|
||||
@ -277,8 +273,8 @@ Overall
|
||||
M: Paolo Bonzini <pbonzini@redhat.com>
|
||||
L: kvm@vger.kernel.org
|
||||
S: Supported
|
||||
F: kvm-*
|
||||
F: */kvm.*
|
||||
F: accel/kvm/
|
||||
F: include/sysemu/kvm*.h
|
||||
|
||||
ARM
|
||||
@ -327,7 +323,6 @@ M: Stefano Stabellini <sstabellini@kernel.org>
|
||||
M: Anthony Perard <anthony.perard@citrix.com>
|
||||
L: xen-devel@lists.xenproject.org
|
||||
S: Supported
|
||||
F: xen-*
|
||||
F: */xen*
|
||||
F: hw/9pfs/xen-9p-backend.c
|
||||
F: hw/char/xen_console.c
|
||||
@ -1160,6 +1155,13 @@ F: docs/specs/vmgenid.txt
|
||||
F: tests/vmgenid-test.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
|
||||
----------
|
||||
Audio
|
||||
@ -1650,7 +1652,7 @@ TCI target
|
||||
M: Stefan Weil <sw@weilnetz.de>
|
||||
S: Maintained
|
||||
F: tcg/tci/
|
||||
F: tci.c
|
||||
F: tcg/tci.c
|
||||
F: disas/tci.c
|
||||
|
||||
Block drivers
|
||||
|
@ -1851,11 +1851,6 @@ void dump_exec_info(FILE *f, fprintf_function cpu_fprintf)
|
||||
|
||||
tb_lock();
|
||||
|
||||
if (!tcg_enabled()) {
|
||||
cpu_fprintf(f, "TCG not enabled\n");
|
||||
return;
|
||||
}
|
||||
|
||||
target_code_size = 0;
|
||||
max_target_code_size = 0;
|
||||
cross_page = 0;
|
||||
|
@ -106,7 +106,7 @@ static void rng_egd_opened(RngBackend *b, Error **errp)
|
||||
|
||||
/* FIXME we should resubmit pending requests when the CDS reconnects. */
|
||||
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)
|
||||
|
@ -242,7 +242,7 @@ int nbd_client_co_pwritev(BlockDriverState *bs, uint64_t offset,
|
||||
ssize_t ret;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -270,12 +270,12 @@ int nbd_client_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
|
||||
};
|
||||
NBDReply reply;
|
||||
|
||||
if (!(client->nbdflags & NBD_FLAG_SEND_WRITE_ZEROES)) {
|
||||
if (!(client->info.flags & NBD_FLAG_SEND_WRITE_ZEROES)) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
if (!(flags & BDRV_REQ_MAY_UNMAP)) {
|
||||
@ -299,7 +299,7 @@ int nbd_client_co_flush(BlockDriverState *bs)
|
||||
NBDReply reply;
|
||||
ssize_t ret;
|
||||
|
||||
if (!(client->nbdflags & NBD_FLAG_SEND_FLUSH)) {
|
||||
if (!(client->info.flags & NBD_FLAG_SEND_FLUSH)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -327,7 +327,7 @@ int nbd_client_co_pdiscard(BlockDriverState *bs, int64_t offset, int bytes)
|
||||
NBDReply reply;
|
||||
ssize_t ret;
|
||||
|
||||
if (!(client->nbdflags & NBD_FLAG_SEND_TRIM)) {
|
||||
if (!(client->info.flags & NBD_FLAG_SEND_TRIM)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -384,22 +384,24 @@ int nbd_client_init(BlockDriverState *bs,
|
||||
logout("session init %s\n", export);
|
||||
qio_channel_set_blocking(QIO_CHANNEL(sioc), true, NULL);
|
||||
|
||||
client->info.request_sizes = true;
|
||||
ret = nbd_receive_negotiate(QIO_CHANNEL(sioc), export,
|
||||
&client->nbdflags,
|
||||
tlscreds, hostname,
|
||||
&client->ioc,
|
||||
&client->size, errp);
|
||||
&client->ioc, &client->info, errp);
|
||||
if (ret < 0) {
|
||||
logout("Failed to negotiate with the NBD server\n");
|
||||
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_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;
|
||||
}
|
||||
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_queue_init(&client->free_sema);
|
||||
|
@ -20,8 +20,7 @@
|
||||
typedef struct NBDClientSession {
|
||||
QIOChannelSocket *sioc; /* The master data channel */
|
||||
QIOChannel *ioc; /* The current I/O channel which may differ (eg TLS) */
|
||||
uint16_t nbdflags;
|
||||
off_t size;
|
||||
NBDExportInfo info;
|
||||
|
||||
CoMutex send_mutex;
|
||||
CoQueue free_sema;
|
||||
|
16
block/nbd.c
16
block/nbd.c
@ -472,9 +472,17 @@ static int nbd_co_flush(BlockDriverState *bs)
|
||||
|
||||
static void nbd_refresh_limits(BlockDriverState *bs, Error **errp)
|
||||
{
|
||||
bs->bl.max_pdiscard = NBD_MAX_BUFFER_SIZE;
|
||||
bs->bl.max_pwrite_zeroes = NBD_MAX_BUFFER_SIZE;
|
||||
bs->bl.max_transfer = NBD_MAX_BUFFER_SIZE;
|
||||
NBDClientSession *s = nbd_get_client_session(bs);
|
||||
uint32_t max = MIN_NON_ZERO(NBD_MAX_BUFFER_SIZE, s->info.max_block);
|
||||
|
||||
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)
|
||||
@ -492,7 +500,7 @@ static int64_t nbd_getlength(BlockDriverState *bs)
|
||||
{
|
||||
BDRVNBDState *s = bs->opaque;
|
||||
|
||||
return s->client.size;
|
||||
return s->client.info.size;
|
||||
}
|
||||
|
||||
static void nbd_detach_aio_context(BlockDriverState *bs)
|
||||
|
@ -85,6 +85,8 @@ struct emulated_sigtable {
|
||||
/* NOTE: we force a big alignment so that the stack stored after is
|
||||
aligned too */
|
||||
typedef struct TaskState {
|
||||
pid_t ts_tid; /* tid (or pid) of this task */
|
||||
|
||||
struct TaskState *next;
|
||||
int used; /* non zero if used */
|
||||
struct image_info *info;
|
||||
|
@ -179,9 +179,21 @@ void qemu_chr_fe_printf(CharBackend *be, const char *fmt, ...)
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
int tag = 0;
|
||||
@ -216,7 +228,7 @@ void qemu_chr_fe_deinit(CharBackend *b, bool del)
|
||||
assert(b);
|
||||
|
||||
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) {
|
||||
b->chr->be = NULL;
|
||||
}
|
||||
@ -235,6 +247,7 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
|
||||
IOCanReadHandler *fd_can_read,
|
||||
IOReadHandler *fd_read,
|
||||
IOEventHandler *fd_event,
|
||||
BackendChangeHandler *be_change,
|
||||
void *opaque,
|
||||
GMainContext *context,
|
||||
bool set_open)
|
||||
@ -258,6 +271,7 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
|
||||
b->chr_can_read = fd_can_read;
|
||||
b->chr_read = fd_read;
|
||||
b->chr_event = fd_event;
|
||||
b->chr_be_change = be_change;
|
||||
b->opaque = opaque;
|
||||
if (cc->chr_update_read_handler) {
|
||||
cc->chr_update_read_handler(s, context);
|
||||
|
@ -278,6 +278,7 @@ void mux_chr_set_handlers(Chardev *chr, GMainContext *context)
|
||||
mux_chr_can_read,
|
||||
mux_chr_read,
|
||||
mux_chr_event,
|
||||
NULL,
|
||||
chr,
|
||||
context, true);
|
||||
}
|
||||
|
@ -454,7 +454,9 @@ static int tcp_chr_sync_read(Chardev *chr, const uint8_t *buf, int len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
qio_channel_set_blocking(s->ioc, true, NULL);
|
||||
size = tcp_chr_recv(chr, (void *) buf, len);
|
||||
qio_channel_set_blocking(s->ioc, false, NULL);
|
||||
if (size == 0) {
|
||||
/* connection closed */
|
||||
tcp_chr_disconnect(chr);
|
||||
|
164
chardev/char.c
164
chardev/char.c
@ -556,17 +556,23 @@ help_string_append(const char *name, void *opaque)
|
||||
g_string_append_printf(str, "\n%s", name);
|
||||
}
|
||||
|
||||
Chardev *qemu_chr_new_from_opts(QemuOpts *opts,
|
||||
Error **errp)
|
||||
static const char *chardev_alias_translate(const char *name)
|
||||
{
|
||||
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;
|
||||
const ChardevClass *cc;
|
||||
Chardev *chr;
|
||||
int i;
|
||||
ChardevBackend *backend = NULL;
|
||||
const char *name = qemu_opt_get(opts, "backend");
|
||||
const char *id = qemu_opts_id(opts);
|
||||
char *bid = NULL;
|
||||
const char *name = chardev_alias_translate(qemu_opt_get(opts, "backend"));
|
||||
|
||||
if (name == NULL) {
|
||||
error_setg(errp, "chardev: \"%s\" missing backend",
|
||||
@ -574,7 +580,40 @@ Chardev *qemu_chr_new_from_opts(QemuOpts *opts,
|
||||
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("");
|
||||
|
||||
chardev_name_foreach(help_string_append, str);
|
||||
@ -589,38 +628,20 @@ Chardev *qemu_chr_new_from_opts(QemuOpts *opts,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < (int)ARRAY_SIZE(chardev_alias_table); i++) {
|
||||
if (g_strcmp0(chardev_alias_table[i].alias, name) == 0) {
|
||||
name = chardev_alias_table[i].typename;
|
||||
break;
|
||||
}
|
||||
backend = qemu_chr_parse_opts(opts, errp);
|
||||
if (backend == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cc = char_get_class(name, errp);
|
||||
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)) {
|
||||
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,
|
||||
object_class_get_name(OBJECT_CLASS(cc)),
|
||||
backend, errp);
|
||||
@ -930,6 +951,89 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
|
||||
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)
|
||||
{
|
||||
Chardev *chr;
|
||||
|
2
configure
vendored
2
configure
vendored
@ -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="-Wno-missing-include-dirs -Wempty-body -Wnested-externs $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"
|
||||
# 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
|
||||
|
70
exec.c
70
exec.c
@ -27,6 +27,7 @@
|
||||
#include "exec/target_page.h"
|
||||
#include "tcg.h"
|
||||
#include "hw/qdev-core.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
#include "hw/boards.h"
|
||||
#include "hw/xen/xen.h"
|
||||
@ -480,19 +481,21 @@ static MemoryRegionSection address_space_do_translate(AddressSpace *as,
|
||||
{
|
||||
IOMMUTLBEntry iotlb;
|
||||
MemoryRegionSection *section;
|
||||
MemoryRegion *mr;
|
||||
IOMMUMemoryRegion *iommu_mr;
|
||||
IOMMUMemoryRegionClass *imrc;
|
||||
|
||||
for (;;) {
|
||||
AddressSpaceDispatch *d = atomic_rcu_read(&as->dispatch);
|
||||
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;
|
||||
}
|
||||
imrc = memory_region_get_iommu_class_nocheck(iommu_mr);
|
||||
|
||||
iotlb = mr->iommu_ops->translate(mr, addr, is_write ?
|
||||
IOMMU_WO : IOMMU_RO);
|
||||
iotlb = imrc->translate(iommu_mr, addr, is_write ?
|
||||
IOMMU_WO : IOMMU_RO);
|
||||
addr = ((iotlb.translated_addr & ~iotlb.addr_mask)
|
||||
| (addr & iotlb.addr_mask));
|
||||
*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);
|
||||
|
||||
assert(!section->mr->iommu_ops);
|
||||
assert(!memory_region_is_iommu(section->mr));
|
||||
return section;
|
||||
}
|
||||
#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)
|
||||
{
|
||||
cpu->as = NULL;
|
||||
@ -742,18 +759,6 @@ void cpu_exec_initfn(CPUState *cpu)
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
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;
|
||||
object_ref(OBJECT(cpu->memory));
|
||||
#endif
|
||||
@ -775,15 +780,28 @@ void cpu_exec_realizefn(CPUState *cpu, Error **errp)
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
static void breakpoint_invalidate(CPUState *cpu, target_ulong pc)
|
||||
{
|
||||
/* Flush the whole TB as this will not have race conditions
|
||||
* even if we don't have proper locking yet.
|
||||
* Ideally we would just invalidate the TBs for the
|
||||
* specified PC.
|
||||
*/
|
||||
tb_flush(cpu);
|
||||
mmap_lock();
|
||||
tb_lock();
|
||||
tb_invalidate_phys_page_range(pc, pc + 1, 0);
|
||||
tb_unlock();
|
||||
mmap_unlock();
|
||||
}
|
||||
#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)
|
||||
void cpu_watchpoint_remove_all(CPUState *cpu, int mask)
|
||||
@ -2929,7 +2947,7 @@ static MemTxResult address_space_write_continue(AddressSpace *as, hwaddr addr,
|
||||
}
|
||||
} else {
|
||||
/* 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);
|
||||
invalidate_and_set_dirty(mr, addr1, l);
|
||||
}
|
||||
@ -3020,7 +3038,7 @@ MemTxResult address_space_read_continue(AddressSpace *as, hwaddr addr,
|
||||
}
|
||||
} else {
|
||||
/* 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);
|
||||
}
|
||||
|
||||
|
121
gdbstub.c
121
gdbstub.c
@ -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 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 {
|
||||
GDB_SIGNAL_0 = 0,
|
||||
GDB_SIGNAL_INT = 2,
|
||||
@ -272,7 +287,20 @@ static int gdb_signal_to_target (int sig)
|
||||
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 {
|
||||
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 */
|
||||
static int put_packet(GDBState *s, const char *buf)
|
||||
{
|
||||
#ifdef DEBUG_GDB
|
||||
printf("reply='%s'\n", buf);
|
||||
#endif
|
||||
gdb_debug("reply='%s'\n", buf);
|
||||
|
||||
return put_packet_binary(s, buf, strlen(buf));
|
||||
}
|
||||
@ -827,7 +853,7 @@ static CPUState *find_cpu(uint32_t thread_id)
|
||||
CPUState *cpu;
|
||||
|
||||
CPU_FOREACH(cpu) {
|
||||
if (cpu_index(cpu) == thread_id) {
|
||||
if (cpu_gdb_index(cpu) == thread_id) {
|
||||
return cpu;
|
||||
}
|
||||
}
|
||||
@ -912,23 +938,16 @@ static int gdb_handle_vcont(GDBState *s, const char *p)
|
||||
if (res) {
|
||||
goto out;
|
||||
}
|
||||
idx = tmp;
|
||||
/* 0 means any thread, so we pick the first valid CPU */
|
||||
if (!idx) {
|
||||
idx = cpu_index(first_cpu);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we are in user mode, the thread specified is actually a
|
||||
* 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);
|
||||
/* 0 means any thread, so we pick the first valid CPU */
|
||||
cpu = tmp ? find_cpu(tmp) : first_cpu;
|
||||
|
||||
/* invalid CPU/thread specified */
|
||||
if (!idx || !cpu) {
|
||||
if (!cpu) {
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* only use if no previous match occourred */
|
||||
if (newstates[cpu->cpu_index] == 1) {
|
||||
newstates[cpu->cpu_index] = cur_action;
|
||||
@ -956,16 +975,16 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
|
||||
uint8_t *registers;
|
||||
target_ulong addr, len;
|
||||
|
||||
#ifdef DEBUG_GDB
|
||||
printf("command='%s'\n", line_buf);
|
||||
#endif
|
||||
|
||||
gdb_debug("command='%s'\n", line_buf);
|
||||
|
||||
p = line_buf;
|
||||
ch = *p++;
|
||||
switch(ch) {
|
||||
case '?':
|
||||
/* TODO: Make this return the correct value for user-mode. */
|
||||
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);
|
||||
/* Remove all the breakpoints when this query is issued,
|
||||
* 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) {
|
||||
report_cpuinfo:
|
||||
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);
|
||||
s->query_cpu = CPU_NEXT(s->query_cpu);
|
||||
} else
|
||||
@ -1390,7 +1409,7 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state)
|
||||
}
|
||||
snprintf(buf, sizeof(buf),
|
||||
"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);
|
||||
cpu->watchpoint_hit = NULL;
|
||||
goto send_packet;
|
||||
@ -1424,7 +1443,7 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state)
|
||||
break;
|
||||
}
|
||||
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:
|
||||
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
|
||||
of a new command then abandon the previous response. */
|
||||
if (ch == '-') {
|
||||
#ifdef DEBUG_GDB
|
||||
printf("Got NACK, retransmitting\n");
|
||||
#endif
|
||||
gdb_debug("Got NACK, retransmitting\n");
|
||||
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 == '$')
|
||||
s->last_packet_len = 0;
|
||||
if (ch != '$')
|
||||
@ -1550,9 +1566,7 @@ static void gdb_read_byte(GDBState *s, int ch)
|
||||
s->line_sum = 0;
|
||||
s->state = RS_GETLINE;
|
||||
} else {
|
||||
#ifdef DEBUG_GDB
|
||||
printf("gdbstub received garbage between packets: 0x%x\n", ch);
|
||||
#endif
|
||||
gdb_debug("received garbage between packets: 0x%x\n", ch);
|
||||
}
|
||||
break;
|
||||
case RS_GETLINE:
|
||||
@ -1568,9 +1582,7 @@ static void gdb_read_byte(GDBState *s, int ch)
|
||||
/* end of command, start of checksum*/
|
||||
s->state = RS_CHKSUM1;
|
||||
} else if (s->line_buf_index >= sizeof(s->line_buf) - 1) {
|
||||
#ifdef DEBUG_GDB
|
||||
printf("gdbstub command buffer overrun, dropping command\n");
|
||||
#endif
|
||||
gdb_debug("command buffer overrun, dropping command\n");
|
||||
s->state = RS_IDLE;
|
||||
} else {
|
||||
/* unescaped command character */
|
||||
@ -1584,9 +1596,7 @@ static void gdb_read_byte(GDBState *s, int ch)
|
||||
s->state = RS_CHKSUM1;
|
||||
} else if (s->line_buf_index >= sizeof(s->line_buf) - 1) {
|
||||
/* command buffer overrun */
|
||||
#ifdef DEBUG_GDB
|
||||
printf("gdbstub command buffer overrun, dropping command\n");
|
||||
#endif
|
||||
gdb_debug("command buffer overrun, dropping command\n");
|
||||
s->state = RS_IDLE;
|
||||
} else {
|
||||
/* parse escaped character and leave escape state */
|
||||
@ -1598,25 +1608,18 @@ static void gdb_read_byte(GDBState *s, int ch)
|
||||
case RS_GETLINE_RLE:
|
||||
if (ch < ' ') {
|
||||
/* invalid RLE count encoding */
|
||||
#ifdef DEBUG_GDB
|
||||
printf("gdbstub got invalid RLE count: 0x%x\n", ch);
|
||||
#endif
|
||||
gdb_debug("got invalid RLE count: 0x%x\n", ch);
|
||||
s->state = RS_GETLINE;
|
||||
} else {
|
||||
/* decode repeat length */
|
||||
int repeat = (unsigned char)ch - ' ' + 3;
|
||||
if (s->line_buf_index + repeat >= sizeof(s->line_buf) - 1) {
|
||||
/* that many repeats would overrun the command buffer */
|
||||
#ifdef DEBUG_GDB
|
||||
printf("gdbstub command buffer overrun,"
|
||||
" dropping command\n");
|
||||
#endif
|
||||
gdb_debug("command buffer overrun, dropping command\n");
|
||||
s->state = RS_IDLE;
|
||||
} else if (s->line_buf_index < 1) {
|
||||
/* got a repeat but we have nothing to repeat */
|
||||
#ifdef DEBUG_GDB
|
||||
printf("gdbstub got invalid RLE sequence\n");
|
||||
#endif
|
||||
gdb_debug("got invalid RLE sequence\n");
|
||||
s->state = RS_GETLINE;
|
||||
} else {
|
||||
/* repeat the last character */
|
||||
@ -1631,9 +1634,7 @@ static void gdb_read_byte(GDBState *s, int ch)
|
||||
case RS_CHKSUM1:
|
||||
/* get high hex digit of checksum */
|
||||
if (!isxdigit(ch)) {
|
||||
#ifdef DEBUG_GDB
|
||||
printf("gdbstub got invalid command checksum digit\n");
|
||||
#endif
|
||||
gdb_debug("got invalid command checksum digit\n");
|
||||
s->state = RS_GETLINE;
|
||||
break;
|
||||
}
|
||||
@ -1644,21 +1645,17 @@ static void gdb_read_byte(GDBState *s, int ch)
|
||||
case RS_CHKSUM2:
|
||||
/* get low hex digit of checksum */
|
||||
if (!isxdigit(ch)) {
|
||||
#ifdef DEBUG_GDB
|
||||
printf("gdbstub got invalid command checksum digit\n");
|
||||
#endif
|
||||
gdb_debug("got invalid command checksum digit\n");
|
||||
s->state = RS_GETLINE;
|
||||
break;
|
||||
}
|
||||
s->line_csum |= fromhex(ch);
|
||||
|
||||
if (s->line_csum != (s->line_sum & 0xff)) {
|
||||
gdb_debug("got command packet with incorrect checksum\n");
|
||||
/* send NAK reply */
|
||||
reply = '-';
|
||||
put_buffer(s, &reply, 1);
|
||||
#ifdef DEBUG_GDB
|
||||
printf("gdbstub got command packet with incorrect checksum\n");
|
||||
#endif
|
||||
s->state = RS_IDLE;
|
||||
} else {
|
||||
/* send ACK reply */
|
||||
@ -2003,7 +2000,7 @@ int gdbserver_start(const char *device)
|
||||
if (chr) {
|
||||
qemu_chr_fe_init(&s->chr, chr, &error_abort);
|
||||
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->mon_chr = mon_chr;
|
||||
|
@ -1726,7 +1726,23 @@ ETEXI
|
||||
STEXI
|
||||
@item chardev-add args
|
||||
@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
|
||||
|
||||
|
34
hmp.c
34
hmp.c
@ -2197,6 +2197,40 @@ void hmp_chardev_add(Monitor *mon, const QDict *qdict)
|
||||
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)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
|
1
hmp.h
1
hmp.h
@ -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_stop(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_send_break(Monitor *mon, const QDict *qdict);
|
||||
void hmp_qemu_io(Monitor *mon, const QDict *qdict);
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
|
||||
#define TYPE_TYPHOON_PCI_HOST_BRIDGE "typhoon-pcihost"
|
||||
#define TYPE_TYPHOON_IOMMU_MEMORY_REGION "typhoon-iommu-memory-region"
|
||||
|
||||
typedef struct TyphoonCchip {
|
||||
MemoryRegion region;
|
||||
@ -41,7 +42,7 @@ typedef struct TyphoonPchip {
|
||||
MemoryRegion reg_conf;
|
||||
|
||||
AddressSpace iommu_as;
|
||||
MemoryRegion iommu;
|
||||
IOMMUMemoryRegion iommu;
|
||||
|
||||
uint64_t ctl;
|
||||
TyphoonWindow win[4];
|
||||
@ -663,7 +664,8 @@ static bool window_translate(TyphoonWindow *win, hwaddr addr,
|
||||
/* Handle PCI-to-system address translation. */
|
||||
/* TODO: A translation failure here ought to set PCI error codes on the
|
||||
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)
|
||||
{
|
||||
TyphoonPchip *pchip = container_of(iommu, TyphoonPchip, iommu);
|
||||
@ -724,10 +726,6 @@ static IOMMUTLBEntry typhoon_translate_iommu(MemoryRegion *iommu, hwaddr addr,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const MemoryRegionIOMMUOps typhoon_iommu_ops = {
|
||||
.translate = typhoon_translate_iommu,
|
||||
};
|
||||
|
||||
static AddressSpace *typhoon_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn)
|
||||
{
|
||||
TyphoonState *s = opaque;
|
||||
@ -891,9 +889,11 @@ PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus,
|
||||
qdev_init_nofail(dev);
|
||||
|
||||
/* 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);
|
||||
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);
|
||||
|
||||
/* 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,
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
type_register_static(&typhoon_pcihost_info);
|
||||
type_register_static(&typhoon_iommu_memory_region_info);
|
||||
}
|
||||
|
||||
type_init(typhoon_register_types)
|
||||
|
@ -1970,7 +1970,8 @@ static void pxa2xx_fir_realize(DeviceState *dev, Error **errp)
|
||||
PXA2xxFIrState *s = PXA2XX_FIR(dev);
|
||||
|
||||
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)
|
||||
|
@ -1106,7 +1106,7 @@ static void strongarm_uart_tx(void *opaque)
|
||||
|
||||
if (s->utcr3 & UTCR3_LBM) /* loopback */ {
|
||||
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
|
||||
* qemu_chr_fe_write and background I/O callbacks */
|
||||
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_receive,
|
||||
strongarm_uart_event,
|
||||
s, NULL, true);
|
||||
NULL, s, NULL, true);
|
||||
}
|
||||
|
||||
static void strongarm_uart_reset(DeviceState *dev)
|
||||
|
@ -983,10 +983,6 @@ static void virtio_blk_instance_init(Object *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,
|
||||
"bootindex", "/disk@0,0",
|
||||
DEVICE(obj), NULL);
|
||||
@ -1014,6 +1010,8 @@ static Property virtio_blk_properties[] = {
|
||||
DEFINE_PROP_BIT("request-merging", VirtIOBlock, conf.request_merging, 0,
|
||||
true),
|
||||
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(),
|
||||
};
|
||||
|
||||
|
@ -279,7 +279,7 @@ static void bcm2835_aux_realize(DeviceState *dev, Error **errp)
|
||||
BCM2835AuxState *s = BCM2835_AUX(dev);
|
||||
|
||||
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[] = {
|
||||
|
@ -279,7 +279,7 @@ static gboolean cadence_uart_xmit(GIOChannel *chan, GIOCondition cond,
|
||||
int ret;
|
||||
|
||||
/* 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;
|
||||
return FALSE;
|
||||
}
|
||||
@ -485,7 +485,7 @@ static void cadence_uart_realize(DeviceState *dev, Error **errp)
|
||||
fifo_trigger_update, s);
|
||||
|
||||
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)
|
||||
|
@ -87,12 +87,12 @@ static const MemoryRegionOps debugcon_ops = {
|
||||
|
||||
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");
|
||||
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)
|
||||
|
@ -146,7 +146,7 @@ static void digic_uart_realize(DeviceState *dev, Error **errp)
|
||||
DigicUartState *s = DIGIC_UART(dev);
|
||||
|
||||
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)
|
||||
|
@ -417,7 +417,7 @@ static void escc_update_parameters(ChannelState *s)
|
||||
int speed, parity, data_bits, stop_bits;
|
||||
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;
|
||||
|
||||
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);
|
||||
s->tx = val;
|
||||
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
|
||||
* qemu_chr_fe_write and background I/O callbacks */
|
||||
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);
|
||||
|
||||
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;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -233,7 +233,7 @@ static void etraxfs_ser_realize(DeviceState *dev, Error **errp)
|
||||
|
||||
qemu_chr_fe_set_handlers(&s->chr,
|
||||
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)
|
||||
|
@ -380,7 +380,7 @@ static void exynos4210_uart_write(void *opaque, hwaddr offset,
|
||||
break;
|
||||
|
||||
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 |
|
||||
UTRSTAT_Tx_BUFFER_EMPTY);
|
||||
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,
|
||||
exynos4210_uart_receive, exynos4210_uart_event,
|
||||
s, NULL, true);
|
||||
NULL, s, NULL, true);
|
||||
}
|
||||
|
||||
static Property exynos4210_uart_properties[] = {
|
||||
|
@ -201,7 +201,7 @@ static void grlib_apbuart_write(void *opaque, hwaddr addr,
|
||||
case DATA_OFFSET:
|
||||
case DATA_OFFSET + 3: /* When only one byte write */
|
||||
/* 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)) {
|
||||
c = value & 0xFF;
|
||||
/* 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_receive,
|
||||
grlib_apbuart_event,
|
||||
uart, NULL, true);
|
||||
NULL, uart, NULL, true);
|
||||
|
||||
sysbus_init_irq(dev, &uart->irq);
|
||||
|
||||
|
@ -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));
|
||||
|
||||
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)
|
||||
|
@ -542,10 +542,10 @@ static void ipoctal_realize(DeviceState *dev, Error **errp)
|
||||
ch->ipoctal = s;
|
||||
|
||||
/* 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,
|
||||
hostdev_receive, hostdev_event,
|
||||
ch, NULL, true);
|
||||
NULL, ch, NULL, true);
|
||||
DPRINTF("Redirecting channel %u to %s\n", i, ch->dev->label);
|
||||
} else {
|
||||
DPRINTF("Could not redirect channel %u, no chardev set\n", i);
|
||||
|
@ -119,7 +119,7 @@ static void lm32_juart_realize(DeviceState *dev, Error **errp)
|
||||
LM32JuartState *s = LM32_JUART(dev);
|
||||
|
||||
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 = {
|
||||
|
@ -266,7 +266,7 @@ static void lm32_uart_realize(DeviceState *dev, Error **errp)
|
||||
LM32UartState *s = LM32_UART(dev);
|
||||
|
||||
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 = {
|
||||
|
@ -305,7 +305,7 @@ static void mcf_uart_realize(DeviceState *dev, Error **errp)
|
||||
mcf_uart_state *s = MCF_UART(dev);
|
||||
|
||||
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[] = {
|
||||
|
@ -199,7 +199,7 @@ static void milkymist_uart_realize(DeviceState *dev, Error **errp)
|
||||
MilkymistUartState *s = MILKYMIST_UART(dev);
|
||||
|
||||
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)
|
||||
|
@ -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)
|
||||
{
|
||||
@ -513,7 +517,7 @@ static void parallel_isa_realizefn(DeviceState *dev, Error **errp)
|
||||
int base;
|
||||
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");
|
||||
return;
|
||||
}
|
||||
@ -535,6 +539,8 @@ static void parallel_isa_realizefn(DeviceState *dev, Error **errp)
|
||||
isa_init_irq(isadev, &s->irq, isa->isairq);
|
||||
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) {
|
||||
s->hw_driver = 1;
|
||||
s->status = dummy;
|
||||
|
@ -329,7 +329,7 @@ static void pl011_realize(DeviceState *dev, Error **errp)
|
||||
PL011State *s = PL011(dev);
|
||||
|
||||
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)
|
||||
|
@ -195,7 +195,7 @@ static int write_console_data(SCLPEvent *event, const uint8_t *buf, int len)
|
||||
{
|
||||
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. */
|
||||
return len;
|
||||
}
|
||||
@ -313,7 +313,7 @@ static int console_init(SCLPEvent *event)
|
||||
console_available = true;
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -163,7 +163,7 @@ static ssize_t write_console_data(SCLPEvent *event, const uint8_t *buf,
|
||||
{
|
||||
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. */
|
||||
return len;
|
||||
}
|
||||
@ -228,7 +228,7 @@ static int console_init(SCLPEvent *event)
|
||||
}
|
||||
console_available = true;
|
||||
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;
|
||||
}
|
||||
|
@ -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,
|
||||
unsigned size)
|
||||
{
|
||||
@ -426,24 +444,13 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
|
||||
break;
|
||||
case 4:
|
||||
{
|
||||
int flags;
|
||||
int old_mcr = s->mcr;
|
||||
s->mcr = val & 0x1f;
|
||||
if (val & UART_MCR_LOOP)
|
||||
break;
|
||||
|
||||
if (s->poll_msl >= 0 && old_mcr != s->mcr) {
|
||||
|
||||
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);
|
||||
serial_update_tiocm(s);
|
||||
/* 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 */
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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");
|
||||
return;
|
||||
}
|
||||
@ -897,7 +932,7 @@ void serial_realize_core(SerialState *s, Error **errp)
|
||||
qemu_register_reset(serial_reset, s);
|
||||
|
||||
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->xmit_fifo, UART_FIFO_LENGTH);
|
||||
serial_reset(s);
|
||||
|
@ -110,7 +110,7 @@ static void sh_serial_write(void *opaque, hwaddr offs,
|
||||
}
|
||||
return;
|
||||
case 0x0c: /* FTDR / TDR */
|
||||
if (qemu_chr_fe_get_driver(&s->chr)) {
|
||||
if (qemu_chr_fe_backend_connected(&s->chr)) {
|
||||
ch = val;
|
||||
/* XXX this blocks entire thread. Rewrite to use
|
||||
* 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_set_handlers(&s->chr, sh_serial_can_receive1,
|
||||
sh_serial_receive1,
|
||||
sh_serial_event, s, NULL, true);
|
||||
sh_serial_event, NULL, s, NULL, true);
|
||||
}
|
||||
|
||||
s->eri = eri_source;
|
||||
|
@ -78,13 +78,13 @@ static void spapr_vty_realize(VIOsPAPRDevice *sdev, Error **errp)
|
||||
{
|
||||
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");
|
||||
return;
|
||||
}
|
||||
|
||||
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 */
|
||||
|
@ -207,7 +207,8 @@ static void stm32f2xx_usart_realize(DeviceState *dev, Error **errp)
|
||||
STM32F2XXUsartState *s = STM32F2XX_USART(dev);
|
||||
|
||||
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)
|
||||
|
@ -179,7 +179,7 @@ static void terminal_init(EmulatedCcw3270Device *dev, Error **errp)
|
||||
}
|
||||
terminal_available = true;
|
||||
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,
|
||||
@ -239,7 +239,7 @@ static int write_payload_3270(EmulatedCcw3270Device *dev, uint8_t cmd,
|
||||
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. */
|
||||
return count;
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ static ssize_t flush_buf(VirtIOSerialPort *port,
|
||||
VirtConsole *vcon = VIRTIO_CONSOLE(port);
|
||||
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. */
|
||||
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)
|
||||
{
|
||||
VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(dev);
|
||||
VirtConsole *vcon = VIRTIO_CONSOLE(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) {
|
||||
error_setg(errp, "Port number 0 on virtio-serial devices reserved "
|
||||
@ -176,7 +199,7 @@ static void virtconsole_realize(DeviceState *dev, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
if (chr) {
|
||||
if (qemu_chr_fe_backend_connected(&vcon->chr)) {
|
||||
/*
|
||||
* For consoles we don't block guest data transfer just
|
||||
* 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) {
|
||||
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);
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -150,7 +150,7 @@ static void xencons_send(struct XenConsole *con)
|
||||
ssize_t len, size;
|
||||
|
||||
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,
|
||||
con->buffer.data + con->buffer.consumed,
|
||||
size);
|
||||
@ -246,7 +246,7 @@ static int con_initialise(struct XenDevice *xendev)
|
||||
|
||||
xen_be_bind_evtchn(&con->xendev);
|
||||
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,
|
||||
"ring mfn %d, remote port %d, local port %d, limit %zd\n",
|
||||
|
@ -212,7 +212,7 @@ static void xilinx_uartlite_realize(DeviceState *dev, Error **errp)
|
||||
XilinxUARTLite *s = XILINX_UARTLITE(dev);
|
||||
|
||||
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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
PropertyInfo qdev_prop_drive = {
|
||||
const PropertyInfo qdev_prop_drive = {
|
||||
.name = "str",
|
||||
.description = "Node name or ID of a block device to use as a backend",
|
||||
.get = get_drive,
|
||||
@ -228,7 +228,7 @@ static void release_chr(Object *obj, const char *name, void *opaque)
|
||||
qemu_chr_fe_deinit(be, false);
|
||||
}
|
||||
|
||||
PropertyInfo qdev_prop_chr = {
|
||||
const PropertyInfo qdev_prop_chr = {
|
||||
.name = "str",
|
||||
.description = "ID of a chardev to use as a backend",
|
||||
.get = get_chr,
|
||||
@ -313,7 +313,7 @@ out:
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
PropertyInfo qdev_prop_netdev = {
|
||||
const PropertyInfo qdev_prop_netdev = {
|
||||
.name = "str",
|
||||
.description = "ID of a netdev to use as a backend",
|
||||
.get = get_netdev,
|
||||
@ -393,7 +393,7 @@ static void set_vlan(Object *obj, Visitor *v, const char *name, void *opaque,
|
||||
*ptr = hubport;
|
||||
}
|
||||
|
||||
PropertyInfo qdev_prop_vlan = {
|
||||
const PropertyInfo qdev_prop_vlan = {
|
||||
.name = "int32",
|
||||
.description = "Integer VLAN id to connect to",
|
||||
.print = print_vlan,
|
||||
|
@ -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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
PropertyInfo qdev_prop_bit = {
|
||||
const PropertyInfo qdev_prop_bit = {
|
||||
.name = "bool",
|
||||
.description = "on/off",
|
||||
.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);
|
||||
}
|
||||
|
||||
PropertyInfo qdev_prop_bit64 = {
|
||||
const PropertyInfo qdev_prop_bit64 = {
|
||||
.name = "bool",
|
||||
.description = "on/off",
|
||||
.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);
|
||||
}
|
||||
|
||||
PropertyInfo qdev_prop_bool = {
|
||||
const PropertyInfo qdev_prop_bool = {
|
||||
.name = "bool",
|
||||
.get = get_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);
|
||||
}
|
||||
|
||||
PropertyInfo qdev_prop_uint8 = {
|
||||
const PropertyInfo qdev_prop_uint8 = {
|
||||
.name = "uint8",
|
||||
.get = get_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);
|
||||
}
|
||||
|
||||
PropertyInfo qdev_prop_uint16 = {
|
||||
const PropertyInfo qdev_prop_uint16 = {
|
||||
.name = "uint16",
|
||||
.get = get_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);
|
||||
}
|
||||
|
||||
PropertyInfo qdev_prop_uint32 = {
|
||||
const PropertyInfo qdev_prop_uint32 = {
|
||||
.name = "uint32",
|
||||
.get = get_uint32,
|
||||
.set = set_uint32,
|
||||
.set_default_value = set_default_value_uint,
|
||||
};
|
||||
|
||||
PropertyInfo qdev_prop_int32 = {
|
||||
const PropertyInfo qdev_prop_int32 = {
|
||||
.name = "int32",
|
||||
.get = get_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);
|
||||
}
|
||||
|
||||
PropertyInfo qdev_prop_uint64 = {
|
||||
const PropertyInfo qdev_prop_uint64 = {
|
||||
.name = "uint64",
|
||||
.get = get_uint64,
|
||||
.set = set_uint64,
|
||||
@ -456,7 +457,7 @@ static void set_string(Object *obj, Visitor *v, const char *name,
|
||||
*ptr = str;
|
||||
}
|
||||
|
||||
PropertyInfo qdev_prop_string = {
|
||||
const PropertyInfo qdev_prop_string = {
|
||||
.name = "str",
|
||||
.release = release_string,
|
||||
.get = get_string,
|
||||
@ -466,7 +467,7 @@ PropertyInfo qdev_prop_string = {
|
||||
/* --- pointer --- */
|
||||
|
||||
/* Not a proper property, just for dirty hacks. TODO Remove it! */
|
||||
PropertyInfo qdev_prop_ptr = {
|
||||
const PropertyInfo qdev_prop_ptr = {
|
||||
.name = "ptr",
|
||||
};
|
||||
|
||||
@ -540,7 +541,7 @@ inval:
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
PropertyInfo qdev_prop_macaddr = {
|
||||
const PropertyInfo qdev_prop_macaddr = {
|
||||
.name = "str",
|
||||
.description = "Ethernet 6-byte MAC Address, example: 52:54:00:12:34:56",
|
||||
.get = get_mac,
|
||||
@ -549,7 +550,7 @@ PropertyInfo qdev_prop_macaddr = {
|
||||
|
||||
/* --- on/off/auto --- */
|
||||
|
||||
PropertyInfo qdev_prop_on_off_auto = {
|
||||
const PropertyInfo qdev_prop_on_off_auto = {
|
||||
.name = "OnOffAuto",
|
||||
.description = "on/off/auto",
|
||||
.enum_table = OnOffAuto_lookup,
|
||||
@ -562,7 +563,7 @@ PropertyInfo qdev_prop_on_off_auto = {
|
||||
|
||||
QEMU_BUILD_BUG_ON(sizeof(LostTickPolicy) != sizeof(int));
|
||||
|
||||
PropertyInfo qdev_prop_losttickpolicy = {
|
||||
const PropertyInfo qdev_prop_losttickpolicy = {
|
||||
.name = "LostTickPolicy",
|
||||
.enum_table = LostTickPolicy_lookup,
|
||||
.get = get_enum,
|
||||
@ -574,7 +575,7 @@ PropertyInfo qdev_prop_losttickpolicy = {
|
||||
|
||||
QEMU_BUILD_BUG_ON(sizeof(BlockdevOnError) != sizeof(int));
|
||||
|
||||
PropertyInfo qdev_prop_blockdev_on_error = {
|
||||
const PropertyInfo qdev_prop_blockdev_on_error = {
|
||||
.name = "BlockdevOnError",
|
||||
.description = "Error handling policy, "
|
||||
"report/ignore/enospc/stop/auto",
|
||||
@ -588,7 +589,7 @@ PropertyInfo qdev_prop_blockdev_on_error = {
|
||||
|
||||
QEMU_BUILD_BUG_ON(sizeof(BiosAtaTranslation) != sizeof(int));
|
||||
|
||||
PropertyInfo qdev_prop_bios_chs_trans = {
|
||||
const PropertyInfo qdev_prop_bios_chs_trans = {
|
||||
.name = "BiosAtaTranslation",
|
||||
.description = "Logical CHS translation algorithm, "
|
||||
"auto/none/lba/large/rechs",
|
||||
@ -600,7 +601,7 @@ PropertyInfo qdev_prop_bios_chs_trans = {
|
||||
|
||||
/* --- FDC default drive types */
|
||||
|
||||
PropertyInfo qdev_prop_fdc_drive_type = {
|
||||
const PropertyInfo qdev_prop_fdc_drive_type = {
|
||||
.name = "FdcDriveType",
|
||||
.description = "FDC drive type, "
|
||||
"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",
|
||||
.description = "Slot and optional function number, example: 06.0 or 06",
|
||||
.print = print_pci_devfn,
|
||||
@ -725,7 +726,7 @@ static void set_blocksize(Object *obj, Visitor *v, const char *name,
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
PropertyInfo qdev_prop_blocksize = {
|
||||
const PropertyInfo qdev_prop_blocksize = {
|
||||
.name = "uint16",
|
||||
.description = "A power of two between 512 and 32768",
|
||||
.get = get_uint16,
|
||||
@ -840,7 +841,7 @@ inval:
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
PropertyInfo qdev_prop_pci_host_devaddr = {
|
||||
const PropertyInfo qdev_prop_pci_host_devaddr = {
|
||||
.name = "str",
|
||||
.description = "Address (bus/device/function) of "
|
||||
"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",
|
||||
.get = get_uint32,
|
||||
.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);
|
||||
}
|
||||
|
||||
PropertyInfo qdev_prop_size = {
|
||||
const PropertyInfo qdev_prop_size = {
|
||||
.name = "size",
|
||||
.get = get_size,
|
||||
.set = set_size,
|
||||
.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,
|
||||
};
|
||||
|
@ -744,6 +744,10 @@ static void qdev_property_add_legacy(DeviceState *dev, Property *prop,
|
||||
return;
|
||||
}
|
||||
|
||||
if (prop->info->create) {
|
||||
return;
|
||||
}
|
||||
|
||||
name = g_strdup_printf("legacy-%s", prop->name);
|
||||
object_property_add(OBJECT(dev), name, "str",
|
||||
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;
|
||||
Object *obj = OBJECT(dev);
|
||||
|
||||
/*
|
||||
* TODO qdev_prop_ptr does not have getters or setters. It must
|
||||
* go now that it can be replaced with links. The test should be
|
||||
* removed along with it: all static properties are read/write.
|
||||
*/
|
||||
if (!prop->info->get && !prop->info->set) {
|
||||
return;
|
||||
if (prop->info->create) {
|
||||
prop->info->create(obj, prop, &local_err);
|
||||
} else {
|
||||
/*
|
||||
* TODO qdev_prop_ptr does not have getters or setters. It must
|
||||
* go now that it can be replaced with links. The test should be
|
||||
* 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) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
|
@ -515,7 +515,7 @@ static void xlnx_dp_aux_set_command(XlnxDPState *s, uint32_t value)
|
||||
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)
|
||||
{
|
||||
XlnxDPState *s = XLNX_DP(obj);
|
||||
|
@ -54,6 +54,8 @@ typedef struct dma_pagetable_entry {
|
||||
#define RC4030(obj) \
|
||||
OBJECT_CHECK(rc4030State, (obj), TYPE_RC4030)
|
||||
|
||||
#define TYPE_RC4030_IOMMU_MEMORY_REGION "rc4030-iommu-memory-region"
|
||||
|
||||
typedef struct rc4030State
|
||||
{
|
||||
SysBusDevice parent;
|
||||
@ -90,7 +92,7 @@ typedef struct rc4030State
|
||||
qemu_irq jazz_bus_irq;
|
||||
|
||||
/* whole DMA memory region, root of DMA address space */
|
||||
MemoryRegion dma_mr;
|
||||
IOMMUMemoryRegion dma_mr;
|
||||
AddressSpace dma_as;
|
||||
|
||||
MemoryRegion iomem_chipset;
|
||||
@ -488,7 +490,7 @@ static const MemoryRegionOps jazzio_ops = {
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static IOMMUTLBEntry rc4030_dma_translate(MemoryRegion *iommu, hwaddr addr,
|
||||
static IOMMUTLBEntry rc4030_dma_translate(IOMMUMemoryRegion *iommu, hwaddr addr,
|
||||
IOMMUAccessFlags flag)
|
||||
{
|
||||
rc4030State *s = container_of(iommu, rc4030State, dma_mr);
|
||||
@ -516,10 +518,6 @@ static IOMMUTLBEntry rc4030_dma_translate(MemoryRegion *iommu, hwaddr addr,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const MemoryRegionIOMMUOps rc4030_dma_ops = {
|
||||
.translate = rc4030_dma_translate,
|
||||
};
|
||||
|
||||
static void rc4030_reset(DeviceState *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,
|
||||
"rc4030.jazzio", 0x00001000);
|
||||
|
||||
memory_region_init_iommu(&s->dma_mr, o, &rc4030_dma_ops,
|
||||
"rc4030.dma", UINT32_MAX);
|
||||
address_space_init(&s->dma_as, &s->dma_mr, "rc4030-dma");
|
||||
memory_region_init_iommu(&s->dma_mr, sizeof(s->dma_mr),
|
||||
TYPE_RC4030_IOMMU_MEMORY_REGION,
|
||||
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)
|
||||
@ -710,14 +709,29 @@ static const TypeInfo rc4030_info = {
|
||||
.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)
|
||||
{
|
||||
type_register_static(&rc4030_info);
|
||||
type_register_static(&rc4030_iommu_memory_region_info);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
@ -52,7 +52,7 @@ struct AMDVIAddressSpace {
|
||||
uint8_t bus_num; /* bus number */
|
||||
uint8_t devfn; /* device function */
|
||||
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 */
|
||||
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;
|
||||
}
|
||||
|
||||
static IOMMUTLBEntry amdvi_translate(MemoryRegion *iommu, hwaddr addr,
|
||||
static IOMMUTLBEntry amdvi_translate(IOMMUMemoryRegion *iommu, hwaddr addr,
|
||||
IOMMUAccessFlags flag)
|
||||
{
|
||||
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]->iommu_state = s;
|
||||
|
||||
memory_region_init_iommu(&iommu_as[devfn]->iommu, OBJECT(s),
|
||||
&s->iommu_ops, "amd-iommu", UINT64_MAX);
|
||||
address_space_init(&iommu_as[devfn]->as, &iommu_as[devfn]->iommu,
|
||||
memory_region_init_iommu(&iommu_as[devfn]->iommu,
|
||||
sizeof(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");
|
||||
}
|
||||
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 new)
|
||||
{
|
||||
@ -1085,8 +1089,6 @@ static void amdvi_init(AMDVIState *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->cmdbuf_len = 0;
|
||||
s->cmdbuf_head = 0;
|
||||
@ -1227,10 +1229,25 @@ static const TypeInfo amdviPCI = {
|
||||
.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)
|
||||
{
|
||||
type_register_static(&amdviPCI);
|
||||
type_register_static(&amdvi);
|
||||
type_register_static(&amdvi_iommu_memory_region_info);
|
||||
}
|
||||
|
||||
type_init(amdviPCI_register_types);
|
||||
|
@ -220,6 +220,8 @@
|
||||
|
||||
#define TYPE_AMD_IOMMU_PCI "AMDVI-PCI"
|
||||
|
||||
#define TYPE_AMD_IOMMU_MEMORY_REGION "amd-iommu-iommu-memory-region"
|
||||
|
||||
typedef struct AMDVIAddressSpace AMDVIAddressSpace;
|
||||
|
||||
/* functions to steal PCI config space */
|
||||
@ -276,9 +278,6 @@ typedef struct AMDVIState {
|
||||
uint8_t romask[AMDVI_MMIO_SIZE]; /* MMIO read/only mask */
|
||||
bool mmio_enabled;
|
||||
|
||||
/* IOMMU function */
|
||||
MemoryRegionIOMMUOps iommu_ops;
|
||||
|
||||
/* for each served device */
|
||||
AMDVIAddressSpace **address_spaces[PCI_BUS_MAX];
|
||||
|
||||
|
@ -972,9 +972,9 @@ static bool vtd_switch_address_space(VTDAddressSpace *as)
|
||||
/* Turn off first then on the other */
|
||||
if (use_iommu) {
|
||||
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 {
|
||||
memory_region_set_enabled(&as->iommu, false);
|
||||
memory_region_set_enabled(MEMORY_REGION(&as->iommu), false);
|
||||
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,
|
||||
void *private)
|
||||
{
|
||||
memory_region_notify_iommu((MemoryRegion *)private, *entry);
|
||||
memory_region_notify_iommu((IOMMUMemoryRegion *)private, *entry);
|
||||
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)
|
||||
{
|
||||
VTDAddressSpace *vtd_as = container_of(iommu, VTDAddressSpace, iommu);
|
||||
@ -2303,7 +2303,7 @@ static IOMMUTLBEntry vtd_iommu_translate(MemoryRegion *iommu, hwaddr addr,
|
||||
return iotlb;
|
||||
}
|
||||
|
||||
static void vtd_iommu_notify_flag_changed(MemoryRegion *iommu,
|
||||
static void vtd_iommu_notify_flag_changed(IOMMUMemoryRegion *iommu,
|
||||
IOMMUNotifierFlag old,
|
||||
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
|
||||
* enabled.
|
||||
*/
|
||||
memory_region_init_iommu(&vtd_dev_as->iommu, OBJECT(s),
|
||||
&s->iommu_ops, "intel_iommu_dmar",
|
||||
memory_region_init_iommu(&vtd_dev_as->iommu, sizeof(vtd_dev_as->iommu),
|
||||
TYPE_INTEL_IOMMU_MEMORY_REGION, OBJECT(s),
|
||||
"intel_iommu_dmar",
|
||||
UINT64_MAX);
|
||||
memory_region_init_alias(&vtd_dev_as->sys_alias, OBJECT(s),
|
||||
"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,
|
||||
&vtd_dev_as->sys_alias, 1);
|
||||
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);
|
||||
}
|
||||
return vtd_dev_as;
|
||||
@ -2816,9 +2818,9 @@ static int vtd_replay_hook(IOMMUTLBEntry *entry, void *private)
|
||||
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;
|
||||
uint8_t bus_n = pci_bus_num(vtd_as->bus);
|
||||
VTDContextEntry ce;
|
||||
@ -2856,9 +2858,6 @@ static void vtd_init(IntelIOMMUState *s)
|
||||
memset(s->w1cmask, 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_extended = false;
|
||||
s->dmar_enabled = false;
|
||||
@ -3073,9 +3072,26 @@ static const TypeInfo vtd_info = {
|
||||
.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)
|
||||
{
|
||||
type_register_static(&vtd_info);
|
||||
type_register_static(&vtd_iommu_memory_region_info);
|
||||
}
|
||||
|
||||
type_init(vtd_register_types)
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
static void patch_call(VAPICROMState *s, X86CPU *cpu, target_ulong ip,
|
||||
uint32_t target)
|
||||
static void patch_call(X86CPU *cpu, target_ulong ip, uint32_t target)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
CPUState *cs = CPU(cpu);
|
||||
CPUX86State *env = &cpu->env;
|
||||
VAPICHandlers *handlers;
|
||||
uint8_t opcode[2];
|
||||
uint32_t imm32 = 0;
|
||||
target_ulong current_pc = 0;
|
||||
target_ulong current_cs_base = 0;
|
||||
uint32_t current_flags = 0;
|
||||
PatchInfo *info;
|
||||
|
||||
if (smp_cpus == 1) {
|
||||
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;
|
||||
}
|
||||
|
||||
if (tcg_enabled()) {
|
||||
cpu_restore_state(cs, cs->mem_io_pc);
|
||||
cpu_get_tb_cpu_state(env, ¤t_pc, ¤t_cs_base,
|
||||
¤t_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;
|
||||
}
|
||||
}
|
||||
info = g_new(PatchInfo, 1);
|
||||
info->handler = handlers;
|
||||
info->ip = ip;
|
||||
|
||||
pause_all_vcpus();
|
||||
|
||||
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);
|
||||
}
|
||||
async_safe_run_on_cpu(cs, do_patch_instruction, RUN_ON_CPU_HOST_PTR(info));
|
||||
}
|
||||
|
||||
void vapic_report_tpr_access(DeviceState *dev, CPUState *cs, target_ulong ip,
|
||||
|
@ -90,7 +90,7 @@ static TypeInfo ipmi_interface_type_info = {
|
||||
.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)
|
||||
{
|
||||
IPMIBmc *bmc = IPMI_BMC(val);
|
||||
|
@ -447,13 +447,13 @@ static void ipmi_bmc_extern_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
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");
|
||||
return;
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -350,6 +350,8 @@ static Property pc_dimm_properties[] = {
|
||||
DEFINE_PROP_UINT32(PC_DIMM_NODE_PROP, PCDIMMDevice, node, 0),
|
||||
DEFINE_PROP_INT32(PC_DIMM_SLOT_PROP, PCDIMMDevice, slot,
|
||||
PC_DIMM_UNASSIGNED_SLOT),
|
||||
DEFINE_PROP_LINK(PC_DIMM_MEMDEV_PROP, PCDIMMDevice, hostmem,
|
||||
TYPE_MEMORY_BACKEND, HostMemoryBackend *),
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
PCDIMMDevice *dimm = PC_DIMM(obj);
|
||||
|
||||
object_property_add(obj, PC_DIMM_SIZE_PROP, "uint64", pc_dimm_get_size,
|
||||
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)
|
||||
@ -404,6 +383,11 @@ static void pc_dimm_realize(DeviceState *dev, Error **errp)
|
||||
if (!dimm->hostmem) {
|
||||
error_setg(errp, "'" PC_DIMM_MEMDEV_PROP "' property is not set");
|
||||
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)) ||
|
||||
(!nb_numa_nodes && dimm->node)) {
|
||||
|
@ -533,7 +533,7 @@ static void boston_mach_init(MachineState *machine)
|
||||
chr = qemu_chr_new("lcd", "vc:320x240");
|
||||
qemu_chr_fe_init(&s->lcd_display, chr, 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,
|
||||
PCI_DEVFN(0, 0),
|
||||
|
@ -130,7 +130,7 @@ static void mips_jazz_init(MachineState *machine,
|
||||
CPUMIPSState *env;
|
||||
qemu_irq *i8259;
|
||||
rc4030_dma *dmas;
|
||||
MemoryRegion *rc4030_dma_mr;
|
||||
IOMMUMemoryRegion *rc4030_dma_mr;
|
||||
MemoryRegion *isa_mem = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *isa_io = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *rtc = g_new(MemoryRegion, 1);
|
||||
|
@ -570,7 +570,7 @@ static MaltaFPGAState *malta_fpga_init(MemoryRegion *address_space,
|
||||
chr = qemu_chr_new("fpga", "vc:320x200");
|
||||
qemu_chr_fe_init(&s->display, chr, 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,
|
||||
230400, uart_chr, DEVICE_NATIVE_ENDIAN);
|
||||
|
@ -894,7 +894,7 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp)
|
||||
}
|
||||
|
||||
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) {
|
||||
error_prepend(errp, "Failed to initialize interrupts: ");
|
||||
@ -1009,18 +1009,6 @@ static const TypeInfo ivshmem_common_info = {
|
||||
.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 = {
|
||||
.name = TYPE_IVSHMEM_PLAIN,
|
||||
.version_id = 0,
|
||||
@ -1037,6 +1025,8 @@ static const VMStateDescription ivshmem_plain_vmsd = {
|
||||
|
||||
static Property ivshmem_plain_properties[] = {
|
||||
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(),
|
||||
};
|
||||
|
||||
@ -1044,11 +1034,6 @@ static void ivshmem_plain_init(Object *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;
|
||||
}
|
||||
|
||||
@ -1059,6 +1044,11 @@ static void ivshmem_plain_realize(PCIDevice *dev, Error **errp)
|
||||
if (!s->hostmem) {
|
||||
error_setg(errp, "You must specify a 'memdev'");
|
||||
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);
|
||||
@ -1128,7 +1118,7 @@ static void ivshmem_doorbell_realize(PCIDevice *dev, Error **errp)
|
||||
{
|
||||
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'");
|
||||
return;
|
||||
}
|
||||
@ -1257,7 +1247,7 @@ static void ivshmem_realize(PCIDevice *dev, Error **errp)
|
||||
" 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'");
|
||||
return;
|
||||
}
|
||||
|
@ -181,18 +181,6 @@ static void mips_gcr_init(Object *obj)
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(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,
|
||||
"mips-gcr", GCR_ADDRSPACE_SZ);
|
||||
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("gcr-rev", MIPSGCRState, gcr_rev, 0x800),
|
||||
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(),
|
||||
};
|
||||
|
||||
|
@ -123,7 +123,7 @@ do { printf("IOMMU: " fmt , ## __VA_ARGS__); } while (0)
|
||||
|
||||
typedef struct IOMMUState {
|
||||
AddressSpace iommu_as;
|
||||
MemoryRegion iommu;
|
||||
IOMMUMemoryRegion iommu;
|
||||
|
||||
uint64_t regs[IOMMU_NREGS];
|
||||
} IOMMUState;
|
||||
@ -133,6 +133,8 @@ typedef struct IOMMUState {
|
||||
#define APB_DEVICE(obj) \
|
||||
OBJECT_CHECK(APBState, (obj), TYPE_APB)
|
||||
|
||||
#define TYPE_APB_IOMMU_MEMORY_REGION "pbm-iommu-memory-region"
|
||||
|
||||
typedef struct APBState {
|
||||
PCIHostState parent_obj;
|
||||
|
||||
@ -208,7 +210,7 @@ static AddressSpace *pbm_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn)
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
IOMMUState *is = container_of(iommu, IOMMUState, iommu);
|
||||
@ -322,10 +324,6 @@ static IOMMUTLBEntry pbm_translate_iommu(MemoryRegion *iommu, hwaddr addr,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static MemoryRegionIOMMUOps pbm_iommu_ops = {
|
||||
.translate = pbm_translate_iommu,
|
||||
};
|
||||
|
||||
static void iommu_config_write(void *opaque, hwaddr addr,
|
||||
uint64_t val, unsigned size)
|
||||
{
|
||||
@ -697,9 +695,10 @@ PCIBus *pci_apb_init(hwaddr special_base,
|
||||
is = &d->iommu;
|
||||
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);
|
||||
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);
|
||||
|
||||
/* APB secondary busses */
|
||||
@ -860,11 +859,25 @@ static const TypeInfo pbm_pci_bridge_info = {
|
||||
.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)
|
||||
{
|
||||
type_register_static(&pbm_host_info);
|
||||
type_register_static(&pbm_pci_host_info);
|
||||
type_register_static(&pbm_pci_bridge_info);
|
||||
type_register_static(&pbm_iommu_memory_region_info);
|
||||
}
|
||||
|
||||
type_init(pbm_register_types)
|
||||
|
@ -110,7 +110,8 @@ static void spapr_tce_free_table(uint64_t *table, int fd, uint32_t nb_table)
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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 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)
|
||||
{
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
@ -348,9 +345,10 @@ void spapr_tce_table_enable(sPAPRTCETable *tcet,
|
||||
&tcet->fd,
|
||||
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);
|
||||
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)
|
||||
@ -359,8 +357,8 @@ void spapr_tce_table_disable(sPAPRTCETable *tcet)
|
||||
return;
|
||||
}
|
||||
|
||||
memory_region_del_subregion(&tcet->root, &tcet->iommu);
|
||||
memory_region_set_size(&tcet->iommu, 0);
|
||||
memory_region_del_subregion(&tcet->root, MEMORY_REGION(&tcet->iommu));
|
||||
memory_region_set_size(MEMORY_REGION(&tcet->iommu), 0);
|
||||
|
||||
spapr_tce_free_table(tcet->table, tcet->fd, tcet->nb_table);
|
||||
tcet->fd = -1;
|
||||
@ -637,9 +635,25 @@ static TypeInfo spapr_tce_table_info = {
|
||||
.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)
|
||||
{
|
||||
type_register_static(&spapr_tce_table_info);
|
||||
type_register_static(&spapr_iommu_memory_region_info);
|
||||
}
|
||||
|
||||
type_init(register_types);
|
||||
|
@ -96,17 +96,11 @@ static target_ulong h_random(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||
|
||||
static void spapr_rng_instance_init(Object *obj)
|
||||
{
|
||||
sPAPRRngState *rngstate = SPAPR_RNG(obj);
|
||||
|
||||
if (object_resolve_path_type("", TYPE_SPAPR_RNG, NULL) != NULL) {
|
||||
error_report("spapr-rng can not be instantiated twice!");
|
||||
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",
|
||||
"ID of the random number generator backend",
|
||||
NULL);
|
||||
@ -163,6 +157,8 @@ int spapr_rng_populate_dt(void *fdt)
|
||||
|
||||
static Property spapr_rng_properties[] = {
|
||||
DEFINE_PROP_BOOL("use-kvm", sPAPRRngState, use_kvm, false),
|
||||
DEFINE_PROP_LINK("rng", sPAPRRngState, backend, TYPE_RNG_BACKEND,
|
||||
RngBackend *),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
|
@ -2095,7 +2095,7 @@ out:
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
PropertyInfo css_devid_propinfo = {
|
||||
const PropertyInfo css_devid_propinfo = {
|
||||
.name = "str",
|
||||
.description = "Identifier of an I/O device in the channel "
|
||||
"subsystem, example: fe.1.23ab",
|
||||
@ -2103,7 +2103,7 @@ PropertyInfo css_devid_propinfo = {
|
||||
.set = set_css_devid,
|
||||
};
|
||||
|
||||
PropertyInfo css_devid_ro_propinfo = {
|
||||
const PropertyInfo css_devid_ro_propinfo = {
|
||||
.name = "str",
|
||||
.description = "Read-only identifier of an I/O device in the channel "
|
||||
"subsystem, example: fe.1.23ab",
|
||||
|
@ -356,7 +356,7 @@ out:
|
||||
return pte;
|
||||
}
|
||||
|
||||
static IOMMUTLBEntry s390_translate_iommu(MemoryRegion *mr, hwaddr addr,
|
||||
static IOMMUTLBEntry s390_translate_iommu(IOMMUMemoryRegion *mr, hwaddr addr,
|
||||
IOMMUAccessFlags flag)
|
||||
{
|
||||
uint64_t pte;
|
||||
@ -407,10 +407,6 @@ static IOMMUTLBEntry s390_translate_iommu(MemoryRegion *mr, hwaddr addr,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const MemoryRegionIOMMUOps s390_iommu_ops = {
|
||||
.translate = s390_translate_iommu,
|
||||
};
|
||||
|
||||
static S390PCIIOMMU *s390_pci_get_iommu(S390pciState *s, PCIBus *bus,
|
||||
int devfn)
|
||||
{
|
||||
@ -522,17 +518,18 @@ static const MemoryRegionOps s390_msi_ctrl_ops = {
|
||||
void s390_pci_iommu_enable(S390PCIIOMMU *iommu)
|
||||
{
|
||||
char *name = g_strdup_printf("iommu-s390-%04x", iommu->pbdev->uid);
|
||||
memory_region_init_iommu(&iommu->iommu_mr, OBJECT(&iommu->mr),
|
||||
&s390_iommu_ops, name, iommu->pal + 1);
|
||||
memory_region_init_iommu(&iommu->iommu_mr, sizeof(iommu->iommu_mr),
|
||||
TYPE_S390_IOMMU_MEMORY_REGION, OBJECT(&iommu->mr),
|
||||
name, iommu->pal + 1);
|
||||
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);
|
||||
}
|
||||
|
||||
void s390_pci_iommu_disable(S390PCIIOMMU *iommu)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
@ -1018,7 +1015,7 @@ static void s390_pci_set_fid(Object *obj, Visitor *v, const char *name,
|
||||
zpci->fid_defined = true;
|
||||
}
|
||||
|
||||
static PropertyInfo s390_pci_fid_propinfo = {
|
||||
static const PropertyInfo s390_pci_fid_propinfo = {
|
||||
.name = "zpci_fid",
|
||||
.get = s390_pci_get_fid,
|
||||
.set = s390_pci_set_fid,
|
||||
@ -1058,12 +1055,26 @@ static TypeInfo s390_pci_iommu_info = {
|
||||
.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)
|
||||
{
|
||||
type_register_static(&s390_pcihost_info);
|
||||
type_register_static(&s390_pcibus_info);
|
||||
type_register_static(&s390_pci_device_info);
|
||||
type_register_static(&s390_pci_iommu_info);
|
||||
type_register_static(&s390_iommu_memory_region_info);
|
||||
}
|
||||
|
||||
type_init(s390_pci_register_types)
|
||||
|
@ -24,6 +24,7 @@
|
||||
#define TYPE_S390_PCI_BUS "s390-pcibus"
|
||||
#define TYPE_S390_PCI_DEVICE "zpci"
|
||||
#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_INSTANCE 0x7f000000
|
||||
#define FH_MASK_SHM 0x00ff0000
|
||||
@ -266,7 +267,7 @@ typedef struct S390PCIIOMMU {
|
||||
S390PCIBusDevice *pbdev;
|
||||
AddressSpace as;
|
||||
MemoryRegion mr;
|
||||
MemoryRegion iommu_mr;
|
||||
IOMMUMemoryRegion iommu_mr;
|
||||
bool enabled;
|
||||
uint64_t g_iota;
|
||||
uint64_t pba;
|
||||
|
@ -563,7 +563,8 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
|
||||
S390PCIIOMMU *iommu;
|
||||
hwaddr start, end;
|
||||
IOMMUTLBEntry entry;
|
||||
MemoryRegion *mr;
|
||||
IOMMUMemoryRegion *iommu_mr;
|
||||
IOMMUMemoryRegionClass *imrc;
|
||||
|
||||
cpu_synchronize_state(CPU(cpu));
|
||||
|
||||
@ -622,9 +623,11 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
|
||||
goto out;
|
||||
}
|
||||
|
||||
mr = &iommu->iommu_mr;
|
||||
iommu_mr = &iommu->iommu_mr;
|
||||
imrc = IOMMU_MEMORY_REGION_GET_CLASS(iommu_mr);
|
||||
|
||||
while (start < end) {
|
||||
entry = mr->iommu_ops->translate(mr, start, IOMMU_NONE);
|
||||
entry = imrc->translate(iommu_mr, start, IOMMU_NONE);
|
||||
|
||||
if (!entry.translated_addr) {
|
||||
pbdev->state = ZPCI_FS_ERROR;
|
||||
@ -635,7 +638,7 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
|
||||
goto out;
|
||||
}
|
||||
|
||||
memory_region_notify_iommu(mr, entry);
|
||||
memory_region_notify_iommu(iommu_mr, entry);
|
||||
start += entry.addr_mask + 1;
|
||||
}
|
||||
|
||||
|
@ -867,8 +867,6 @@ static void virtio_ccw_blk_instance_init(Object *obj)
|
||||
|
||||
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
|
||||
TYPE_VIRTIO_BLK);
|
||||
object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev),"iothread",
|
||||
&error_abort);
|
||||
object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
|
||||
"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),
|
||||
TYPE_VIRTIO_SCSI);
|
||||
object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev), "iothread",
|
||||
&error_abort);
|
||||
}
|
||||
|
||||
#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),
|
||||
TYPE_VIRTIO_RNG);
|
||||
object_property_add_alias(obj, "rng", OBJECT(&dev->vdev),
|
||||
"rng", &error_abort);
|
||||
}
|
||||
|
||||
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;
|
||||
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
|
||||
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)
|
||||
|
@ -898,16 +898,6 @@ static void virtio_scsi_device_realize(DeviceState *dev, Error **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)
|
||||
{
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
|
||||
@ -935,6 +925,8 @@ static Property virtio_scsi_properties[] = {
|
||||
VIRTIO_SCSI_F_HOTPLUG, true),
|
||||
DEFINE_PROP_BIT("param_change", VirtIOSCSI, host_features,
|
||||
VIRTIO_SCSI_F_CHANGE, true),
|
||||
DEFINE_PROP_LINK("iothread", VirtIOSCSI, parent_obj.conf.iothread,
|
||||
TYPE_IOTHREAD, IOThread *),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
@ -989,7 +981,6 @@ static const TypeInfo virtio_scsi_info = {
|
||||
.name = TYPE_VIRTIO_SCSI,
|
||||
.parent = TYPE_VIRTIO_SCSI_COMMON,
|
||||
.instance_size = sizeof(VirtIOSCSI),
|
||||
.instance_init = virtio_scsi_instance_init,
|
||||
.class_init = virtio_scsi_class_init,
|
||||
.interfaces = (InterfaceInfo[]) {
|
||||
{ TYPE_HOTPLUG_HANDLER },
|
||||
|
@ -322,7 +322,7 @@ static void passthru_apdu_from_guest(
|
||||
{
|
||||
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);
|
||||
return;
|
||||
}
|
||||
@ -343,12 +343,12 @@ static int passthru_initfn(CCIDCardState *base)
|
||||
|
||||
card->vscard_in_pos = 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");
|
||||
qemu_chr_fe_set_handlers(&card->cs,
|
||||
ccid_card_vscard_can_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);
|
||||
} else {
|
||||
error_report("missing chardev");
|
||||
|
@ -484,13 +484,12 @@ static void usb_serial_realize(USBDevice *dev, Error **errp)
|
||||
{
|
||||
USBSerialState *s = USB_SERIAL_DEV(dev);
|
||||
Error *local_err = NULL;
|
||||
Chardev *chr = qemu_chr_fe_get_driver(&s->cs);
|
||||
|
||||
usb_desc_create_serial(dev);
|
||||
usb_desc_init(dev);
|
||||
dev->auto_attach = 0;
|
||||
|
||||
if (!chr) {
|
||||
if (!qemu_chr_fe_backend_connected(&s->cs)) {
|
||||
error_setg(errp, "Property chardev is required");
|
||||
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,
|
||||
usb_serial_event, s, NULL, true);
|
||||
usb_serial_event, NULL, s, NULL, true);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -273,10 +273,9 @@ static gboolean usbredir_write_unblocked(GIOChannel *chan, GIOCondition cond,
|
||||
static int usbredir_write(void *priv, uint8_t *data, int count)
|
||||
{
|
||||
USBRedirDevice *dev = priv;
|
||||
Chardev *chr = qemu_chr_fe_get_driver(&dev->cs);
|
||||
int r;
|
||||
|
||||
if (!chr->be_open) {
|
||||
if (!qemu_chr_fe_backend_open(&dev->cs)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1366,7 +1365,7 @@ static void usbredir_realize(USBDevice *udev, Error **errp)
|
||||
USBRedirDevice *dev = USB_REDIRECT(udev);
|
||||
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");
|
||||
return;
|
||||
}
|
||||
@ -1399,7 +1398,7 @@ static void usbredir_realize(USBDevice *udev, Error **errp)
|
||||
/* Let the backend know we are ready */
|
||||
qemu_chr_fe_set_handlers(&dev->cs, usbredir_chardev_can_read,
|
||||
usbredir_chardev_read, usbredir_chardev_event,
|
||||
dev, NULL, true);
|
||||
NULL, dev, NULL, true);
|
||||
|
||||
dev->vmstate =
|
||||
qemu_add_vm_change_state_handler(usbredir_vm_state_change, dev);
|
||||
|
@ -479,6 +479,7 @@ static void vfio_listener_region_add(MemoryListener *listener,
|
||||
|
||||
if (memory_region_is_iommu(section->mr)) {
|
||||
VFIOGuestIOMMU *giommu;
|
||||
IOMMUMemoryRegion *iommu_mr = IOMMU_MEMORY_REGION(section->mr);
|
||||
|
||||
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).
|
||||
*/
|
||||
giommu = g_malloc0(sizeof(*giommu));
|
||||
giommu->iommu = section->mr;
|
||||
giommu->iommu = iommu_mr;
|
||||
giommu->iommu_offset = section->offset_within_address_space -
|
||||
section->offset_within_region;
|
||||
giommu->container = container;
|
||||
@ -501,7 +502,7 @@ static void vfio_listener_region_add(MemoryListener *listener,
|
||||
int128_get64(llend));
|
||||
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);
|
||||
|
||||
return;
|
||||
@ -569,9 +570,9 @@ static void vfio_listener_region_del(MemoryListener *listener,
|
||||
VFIOGuestIOMMU *giommu;
|
||||
|
||||
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) {
|
||||
memory_region_unregister_iommu_notifier(giommu->iommu,
|
||||
memory_region_unregister_iommu_notifier(section->mr,
|
||||
&giommu->n);
|
||||
QLIST_REMOVE(giommu, giommu_next);
|
||||
g_free(giommu);
|
||||
@ -1163,7 +1164,8 @@ static void vfio_disconnect_container(VFIOGroup *group)
|
||||
QLIST_REMOVE(container, next);
|
||||
|
||||
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);
|
||||
g_free(giommu);
|
||||
}
|
||||
|
@ -143,7 +143,8 @@ int vfio_spapr_create_window(VFIOContainer *container,
|
||||
hwaddr *pgsize)
|
||||
{
|
||||
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;
|
||||
struct vfio_iommu_spapr_tce_create create = { .argsz = sizeof(create) };
|
||||
|
||||
|
@ -62,8 +62,6 @@ static void virtio_crypto_initfn(Object *obj)
|
||||
|
||||
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
|
||||
TYPE_VIRTIO_CRYPTO);
|
||||
object_property_add_alias(obj, "cryptodev", OBJECT(&dev->vdev),
|
||||
"cryptodev", &error_abort);
|
||||
}
|
||||
|
||||
static const TypeInfo virtio_crypto_pci_info = {
|
||||
|
@ -781,6 +781,11 @@ static void virtio_crypto_device_realize(DeviceState *dev, Error **errp)
|
||||
if (vcrypto->cryptodev == NULL) {
|
||||
error_setg(errp, "'cryptodev' parameter expects a valid object");
|
||||
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);
|
||||
@ -845,6 +850,8 @@ static const VMStateDescription vmstate_virtio_crypto = {
|
||||
};
|
||||
|
||||
static Property virtio_crypto_properties[] = {
|
||||
DEFINE_PROP_LINK("cryptodev", VirtIOCrypto, conf.cryptodev,
|
||||
TYPE_CRYPTODEV_BACKEND, CryptoDevBackend *),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
@ -888,20 +895,6 @@ static void virtio_crypto_class_init(ObjectClass *klass, void *data)
|
||||
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)
|
||||
{
|
||||
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.
|
||||
*/
|
||||
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 = {
|
||||
|
@ -2000,8 +2000,6 @@ static void virtio_blk_pci_instance_init(Object *obj)
|
||||
|
||||
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
|
||||
TYPE_VIRTIO_BLK);
|
||||
object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev),"iothread",
|
||||
&error_abort);
|
||||
object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
|
||||
"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),
|
||||
TYPE_VIRTIO_SCSI);
|
||||
object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev), "iothread",
|
||||
&error_abort);
|
||||
}
|
||||
|
||||
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),
|
||||
TYPE_VIRTIO_RNG);
|
||||
object_property_add_alias(obj, "rng", OBJECT(&dev->vdev), "rng",
|
||||
&error_abort);
|
||||
}
|
||||
|
||||
static const TypeInfo virtio_rng_pci_info = {
|
||||
|
@ -246,6 +246,7 @@ static Property virtio_rng_properties[] = {
|
||||
*/
|
||||
DEFINE_PROP_UINT64("max-bytes", VirtIORNG, conf.max_bytes, INT64_MAX),
|
||||
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(),
|
||||
};
|
||||
|
||||
@ -262,21 +263,10 @@ static void virtio_rng_class_init(ObjectClass *klass, void *data)
|
||||
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 = {
|
||||
.name = TYPE_VIRTIO_RNG,
|
||||
.parent = TYPE_VIRTIO_DEVICE,
|
||||
.instance_size = sizeof(VirtIORNG),
|
||||
.instance_init = virtio_rng_initfn,
|
||||
.class_init = virtio_rng_class_init,
|
||||
};
|
||||
|
||||
|
@ -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>
|
||||
*
|
||||
* 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_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_ACK (1) /* Data sending finished. */
|
||||
#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_POLICY NBD_REP_ERR(2) /* Server denied */
|
||||
#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_TLS_REQD NBD_REP_ERR(5) /* TLS required */
|
||||
#define NBD_REP_ERR_SHUTDOWN NBD_REP_ERR(7) /* Server shutting down */
|
||||
#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_INVALID NBD_REP_ERR(3) /* Invalid length */
|
||||
#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_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 */
|
||||
#define NBD_CMD_FLAG_FUA (1 << 0) /* 'force unit access' during write */
|
||||
@ -123,13 +142,26 @@ enum {
|
||||
* aren't overflowing some other buffer. */
|
||||
#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,
|
||||
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,
|
||||
QIOChannel **outioc,
|
||||
off_t *size, Error **errp);
|
||||
int nbd_init(int fd, QIOChannelSocket *sioc, uint16_t flags, off_t size,
|
||||
QIOChannel **outioc, NBDExportInfo *info,
|
||||
Error **errp);
|
||||
int nbd_init(int fd, QIOChannelSocket *sioc, NBDExportInfo *info,
|
||||
Error **errp);
|
||||
ssize_t nbd_send_request(QIOChannel *ioc, NBDRequest *request);
|
||||
ssize_t nbd_receive_reply(QIOChannel *ioc, NBDReply *reply, Error **errp);
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "chardev/char.h"
|
||||
|
||||
typedef void IOEventHandler(void *opaque, int event);
|
||||
typedef int BackendChangeHandler(void *opaque);
|
||||
|
||||
/* This is the backend as seen by frontend, the actual backend is
|
||||
* Chardev */
|
||||
@ -12,6 +13,7 @@ struct CharBackend {
|
||||
IOEventHandler *chr_event;
|
||||
IOCanReadHandler *chr_can_read;
|
||||
IOReadHandler *chr_read;
|
||||
BackendChangeHandler *chr_be_change;
|
||||
void *opaque;
|
||||
int tag;
|
||||
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
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* @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:
|
||||
* @b: a CharBackend
|
||||
@ -54,6 +73,8 @@ Chardev *qemu_chr_fe_get_driver(CharBackend *be);
|
||||
* receive
|
||||
* @fd_read: callback to receive data from char
|
||||
* @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
|
||||
* @context: a main loop context or NULL for the default
|
||||
* @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,
|
||||
IOReadHandler *fd_read,
|
||||
IOEventHandler *fd_event,
|
||||
BackendChangeHandler *be_change,
|
||||
void *opaque,
|
||||
GMainContext *context,
|
||||
bool set_open);
|
||||
|
@ -80,6 +80,16 @@ Chardev *qemu_chr_new_from_opts(QemuOpts *opts,
|
||||
*/
|
||||
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:
|
||||
*
|
||||
@ -92,6 +102,15 @@ void qemu_chr_parse_common(QemuOpts *opts, ChardevCommon *backend);
|
||||
*/
|
||||
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:
|
||||
*
|
||||
|
@ -290,6 +290,9 @@ static inline void tlb_flush_by_mmuidx_all_cpus_synced(CPUState *cpu,
|
||||
uint16_t idxmap)
|
||||
{
|
||||
}
|
||||
static inline void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */
|
||||
|
@ -58,15 +58,6 @@ void gdb_register_coprocessor(CPUState *cpu,
|
||||
gdb_reg_cb get_reg, gdb_reg_cb set_reg,
|
||||
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
|
||||
* 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.
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "qemu/notify.h"
|
||||
#include "qom/object.h"
|
||||
#include "qemu/rcu.h"
|
||||
#include "hw/qdev-core.h"
|
||||
|
||||
#define RAM_ADDR_INVALID (~(ram_addr_t)0)
|
||||
|
||||
@ -35,6 +36,16 @@
|
||||
#define MEMORY_REGION(obj) \
|
||||
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 MemoryRegionMmio MemoryRegionMmio;
|
||||
|
||||
@ -189,26 +200,27 @@ struct MemoryRegionOps {
|
||||
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
|
||||
* be the access permission of this translation operation. We can
|
||||
* set flag to IOMMU_NONE to mean that we don't need any
|
||||
* read/write permission checks, like, when for region replay.
|
||||
*/
|
||||
IOMMUTLBEntry (*translate)(MemoryRegion *iommu, hwaddr addr,
|
||||
IOMMUTLBEntry (*translate)(IOMMUMemoryRegion *iommu, hwaddr addr,
|
||||
IOMMUAccessFlags flag);
|
||||
/* 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 */
|
||||
void (*notify_flag_changed)(MemoryRegion *iommu,
|
||||
void (*notify_flag_changed)(IOMMUMemoryRegion *iommu,
|
||||
IOMMUNotifierFlag old_flags,
|
||||
IOMMUNotifierFlag new_flags);
|
||||
/* 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 MemoryRegionIoeventfd MemoryRegionIoeventfd;
|
||||
@ -227,9 +239,9 @@ struct MemoryRegion {
|
||||
bool flush_coalesced_mmio;
|
||||
bool global_locking;
|
||||
uint8_t dirty_log_mask;
|
||||
bool is_iommu;
|
||||
RAMBlock *ram_block;
|
||||
Object *owner;
|
||||
const MemoryRegionIOMMUOps *iommu_ops;
|
||||
|
||||
const MemoryRegionOps *ops;
|
||||
void *opaque;
|
||||
@ -252,6 +264,11 @@ struct MemoryRegion {
|
||||
const char *name;
|
||||
unsigned ioeventfd_nb;
|
||||
MemoryRegionIoeventfd *ioeventfds;
|
||||
};
|
||||
|
||||
struct IOMMUMemoryRegion {
|
||||
MemoryRegion parent_obj;
|
||||
|
||||
QLIST_HEAD(, IOMMUNotifier) iommu_notify;
|
||||
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
|
||||
* addresses
|
||||
* memory_region_init_iommu: Initialize a memory region of a custom type
|
||||
* that translates addresses
|
||||
*
|
||||
* An IOMMU region translates addresses and forwards accesses to a target
|
||||
* 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
|
||||
* @ops: a function that translates addresses into the @target region
|
||||
* @name: used for debugging; not visible to the user or ABI
|
||||
* @size: size of the region.
|
||||
*/
|
||||
void memory_region_init_iommu(MemoryRegion *mr,
|
||||
struct Object *owner,
|
||||
const MemoryRegionIOMMUOps *ops,
|
||||
void memory_region_init_iommu(void *_iommu_mr,
|
||||
size_t instance_size,
|
||||
const char *mrtypename,
|
||||
Object *owner,
|
||||
const char *name,
|
||||
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
|
||||
*/
|
||||
static inline bool memory_region_is_iommu(MemoryRegion *mr)
|
||||
static inline IOMMUMemoryRegion *memory_region_get_iommu(MemoryRegion *mr)
|
||||
{
|
||||
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
|
||||
@ -700,9 +740,9 @@ static inline bool memory_region_is_iommu(MemoryRegion *mr)
|
||||
*
|
||||
* 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.
|
||||
@ -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
|
||||
* 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
|
||||
* replaces all old entries for the same virtual I/O address range.
|
||||
* Deleted entries have .@perm == 0.
|
||||
*/
|
||||
void memory_region_notify_iommu(MemoryRegion *mr,
|
||||
void memory_region_notify_iommu(IOMMUMemoryRegion *iommu_mr,
|
||||
IOMMUTLBEntry entry);
|
||||
|
||||
/**
|
||||
@ -756,18 +796,18 @@ void memory_region_register_iommu_notifier(MemoryRegion *mr,
|
||||
* a notifier with the minimum page granularity returned by
|
||||
* 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
|
||||
*/
|
||||
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
|
||||
* 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
|
||||
|
@ -32,6 +32,8 @@
|
||||
#define INTEL_IOMMU_DEVICE(obj) \
|
||||
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) */
|
||||
#define Q35_HOST_BRIDGE_IOMMU_ADDR 0xfed90000ULL
|
||||
|
||||
@ -83,7 +85,7 @@ struct VTDAddressSpace {
|
||||
PCIBus *bus;
|
||||
uint8_t devfn;
|
||||
AddressSpace as;
|
||||
MemoryRegion iommu;
|
||||
IOMMUMemoryRegion iommu;
|
||||
MemoryRegion root;
|
||||
MemoryRegion sys_alias;
|
||||
MemoryRegion iommu_ir; /* Interrupt region: 0xfeeXXXXX */
|
||||
@ -289,7 +291,6 @@ struct IntelIOMMUState {
|
||||
uint32_t context_cache_gen; /* Should be in [1,MAX] */
|
||||
GHashTable *iotlb; /* IOTLB */
|
||||
|
||||
MemoryRegionIOMMUOps iommu_ops;
|
||||
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 */
|
||||
/* list of registered notifiers */
|
||||
|
@ -19,6 +19,6 @@ typedef struct rc4030DMAState *rc4030_dma;
|
||||
void rc4030_dma_read(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
|
||||
|
@ -582,6 +582,10 @@ typedef struct sPAPRTCETable sPAPRTCETable;
|
||||
#define SPAPR_TCE_TABLE(obj) \
|
||||
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 {
|
||||
DeviceState parent;
|
||||
uint32_t liobn;
|
||||
@ -594,7 +598,8 @@ struct sPAPRTCETable {
|
||||
bool bypass;
|
||||
bool need_vfio;
|
||||
int fd;
|
||||
MemoryRegion root, iommu;
|
||||
MemoryRegion root;
|
||||
IOMMUMemoryRegion iommu;
|
||||
struct VIOsPAPRDevice *vdev; /* for @bypass migration compatibility only */
|
||||
QLIST_ENTRY(sPAPRTCETable) list;
|
||||
};
|
||||
|
@ -223,7 +223,7 @@ struct BusState {
|
||||
|
||||
struct Property {
|
||||
const char *name;
|
||||
PropertyInfo *info;
|
||||
const PropertyInfo *info;
|
||||
ptrdiff_t offset;
|
||||
uint8_t bitnr;
|
||||
union {
|
||||
@ -231,8 +231,9 @@ struct Property {
|
||||
uint64_t u;
|
||||
} defval;
|
||||
int arrayoffset;
|
||||
PropertyInfo *arrayinfo;
|
||||
const PropertyInfo *arrayinfo;
|
||||
int arrayfieldsize;
|
||||
const char *link_type;
|
||||
};
|
||||
|
||||
struct PropertyInfo {
|
||||
@ -241,6 +242,7 @@ struct PropertyInfo {
|
||||
const char * const *enum_table;
|
||||
int (*print)(DeviceState *dev, Property *prop, char *dest, size_t len);
|
||||
void (*set_default_value)(Object *obj, const Property *prop);
|
||||
void (*create)(Object *obj, Property *prop, Error **errp);
|
||||
ObjectPropertyAccessor *get;
|
||||
ObjectPropertyAccessor *set;
|
||||
ObjectPropertyRelease *release;
|
||||
|
@ -5,31 +5,32 @@
|
||||
|
||||
/*** qdev-properties.c ***/
|
||||
|
||||
extern PropertyInfo qdev_prop_bit;
|
||||
extern PropertyInfo qdev_prop_bit64;
|
||||
extern PropertyInfo qdev_prop_bool;
|
||||
extern PropertyInfo qdev_prop_uint8;
|
||||
extern PropertyInfo qdev_prop_uint16;
|
||||
extern PropertyInfo qdev_prop_uint32;
|
||||
extern PropertyInfo qdev_prop_int32;
|
||||
extern PropertyInfo qdev_prop_uint64;
|
||||
extern PropertyInfo qdev_prop_size;
|
||||
extern PropertyInfo qdev_prop_string;
|
||||
extern PropertyInfo qdev_prop_chr;
|
||||
extern PropertyInfo qdev_prop_ptr;
|
||||
extern PropertyInfo qdev_prop_macaddr;
|
||||
extern PropertyInfo qdev_prop_on_off_auto;
|
||||
extern PropertyInfo qdev_prop_losttickpolicy;
|
||||
extern PropertyInfo qdev_prop_blockdev_on_error;
|
||||
extern PropertyInfo qdev_prop_bios_chs_trans;
|
||||
extern PropertyInfo qdev_prop_fdc_drive_type;
|
||||
extern PropertyInfo qdev_prop_drive;
|
||||
extern PropertyInfo qdev_prop_netdev;
|
||||
extern PropertyInfo qdev_prop_vlan;
|
||||
extern PropertyInfo qdev_prop_pci_devfn;
|
||||
extern PropertyInfo qdev_prop_blocksize;
|
||||
extern PropertyInfo qdev_prop_pci_host_devaddr;
|
||||
extern PropertyInfo qdev_prop_arraylen;
|
||||
extern const PropertyInfo qdev_prop_bit;
|
||||
extern const PropertyInfo qdev_prop_bit64;
|
||||
extern const PropertyInfo qdev_prop_bool;
|
||||
extern const PropertyInfo qdev_prop_uint8;
|
||||
extern const PropertyInfo qdev_prop_uint16;
|
||||
extern const PropertyInfo qdev_prop_uint32;
|
||||
extern const PropertyInfo qdev_prop_int32;
|
||||
extern const PropertyInfo qdev_prop_uint64;
|
||||
extern const PropertyInfo qdev_prop_size;
|
||||
extern const PropertyInfo qdev_prop_string;
|
||||
extern const PropertyInfo qdev_prop_chr;
|
||||
extern const PropertyInfo qdev_prop_ptr;
|
||||
extern const PropertyInfo qdev_prop_macaddr;
|
||||
extern const PropertyInfo qdev_prop_on_off_auto;
|
||||
extern const PropertyInfo qdev_prop_losttickpolicy;
|
||||
extern const PropertyInfo qdev_prop_blockdev_on_error;
|
||||
extern const PropertyInfo qdev_prop_bios_chs_trans;
|
||||
extern const PropertyInfo qdev_prop_fdc_drive_type;
|
||||
extern const PropertyInfo qdev_prop_drive;
|
||||
extern const PropertyInfo qdev_prop_netdev;
|
||||
extern const PropertyInfo qdev_prop_vlan;
|
||||
extern const PropertyInfo qdev_prop_pci_devfn;
|
||||
extern const PropertyInfo qdev_prop_blocksize;
|
||||
extern const PropertyInfo qdev_prop_pci_host_devaddr;
|
||||
extern const PropertyInfo qdev_prop_arraylen;
|
||||
extern const PropertyInfo qdev_prop_link;
|
||||
|
||||
#define DEFINE_PROP(_name, _state, _field, _prop, _type) { \
|
||||
.name = (_name), \
|
||||
@ -117,6 +118,14 @@ extern PropertyInfo qdev_prop_arraylen;
|
||||
.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_PROP_UNSIGNED(_n, _s, _f, _d, qdev_prop_uint8, uint8_t)
|
||||
#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
|
||||
* 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);
|
||||
|
||||
#endif
|
||||
|
@ -112,7 +112,7 @@ typedef struct CssDevId {
|
||||
bool valid;
|
||||
} CssDevId;
|
||||
|
||||
extern PropertyInfo css_devid_propinfo;
|
||||
extern const PropertyInfo css_devid_propinfo;
|
||||
|
||||
#define DEFINE_PROP_CSS_DEV_ID(_n, _s, _f) \
|
||||
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);
|
||||
#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_PROP(_n, _s, _f, css_devid_ro_propinfo, CssDevId)
|
||||
|
@ -95,7 +95,7 @@ typedef struct VFIOContainer {
|
||||
|
||||
typedef struct VFIOGuestIOMMU {
|
||||
VFIOContainer *container;
|
||||
MemoryRegion *iommu;
|
||||
IOMMUMemoryRegion *iommu;
|
||||
hwaddr iommu_offset;
|
||||
IOMMUNotifier n;
|
||||
QLIST_ENTRY(VFIOGuestIOMMU) giommu_next;
|
||||
|
@ -45,6 +45,7 @@ typedef struct MachineState MachineState;
|
||||
typedef struct MemoryListener MemoryListener;
|
||||
typedef struct MemoryMappingList MemoryMappingList;
|
||||
typedef struct MemoryRegion MemoryRegion;
|
||||
typedef struct IOMMUMemoryRegion IOMMUMemoryRegion;
|
||||
typedef struct MemoryRegionCache MemoryRegionCache;
|
||||
typedef struct MemoryRegionSection MemoryRegionSection;
|
||||
typedef struct MigrationIncomingState MigrationIncomingState;
|
||||
|
@ -265,7 +265,6 @@ struct qemu_work_item;
|
||||
* @cpu_index: CPU index (informative).
|
||||
* @nr_cores: Number of cores within this CPU package.
|
||||
* @nr_threads: Number of threads within this CPU.
|
||||
* @host_tid: Host thread ID.
|
||||
* @running: #true if CPU is currently running (lockless).
|
||||
* @has_waiter: #true if a CPU is currently waiting for the cpu_exec_end;
|
||||
* valid under cpu_list_lock.
|
||||
@ -319,7 +318,6 @@ struct CPUState {
|
||||
HANDLE hThread;
|
||||
#endif
|
||||
int thread_id;
|
||||
uint32_t host_tid;
|
||||
bool running, has_waiter;
|
||||
struct QemuCond *halt_cond;
|
||||
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, ...)
|
||||
GCC_FMT_ATTR(2, 3);
|
||||
extern Property cpu_common_props[];
|
||||
void cpu_exec_initfn(CPUState *cpu);
|
||||
void cpu_exec_realizefn(CPUState *cpu, Error **errp);
|
||||
void cpu_exec_unrealizefn(CPUState *cpu);
|
||||
|
@ -764,7 +764,7 @@ ObjectClass *object_get_class(Object *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:
|
||||
@ -1319,7 +1319,7 @@ typedef enum {
|
||||
* callback function. It allows the link property to be set and never returns
|
||||
* an error.
|
||||
*/
|
||||
void object_property_allow_set_link(Object *, const char *,
|
||||
void object_property_allow_set_link(const Object *, const char *,
|
||||
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,
|
||||
const char *type, Object **child,
|
||||
void (*check)(Object *obj, const char *name,
|
||||
void (*check)(const Object *obj, const char *name,
|
||||
Object *val, Error **errp),
|
||||
ObjectPropertyLinkFlags flags,
|
||||
Error **errp);
|
||||
|
@ -6219,7 +6219,6 @@ static void *clone_func(void *arg)
|
||||
thread_cpu = cpu;
|
||||
ts = (TaskState *)cpu->opaque;
|
||||
info->tid = gettid();
|
||||
cpu->host_tid = info->tid;
|
||||
task_settid(ts);
|
||||
if (info->child_tidptr)
|
||||
put_user_u32(info->tid, info->child_tidptr);
|
||||
|
113
memory.c
113
memory.c
@ -977,12 +977,11 @@ static char *memory_region_escape_name(const char *name)
|
||||
return escaped;
|
||||
}
|
||||
|
||||
void memory_region_init(MemoryRegion *mr,
|
||||
Object *owner,
|
||||
const char *name,
|
||||
uint64_t size)
|
||||
static void memory_region_do_init(MemoryRegion *mr,
|
||||
Object *owner,
|
||||
const char *name,
|
||||
uint64_t size)
|
||||
{
|
||||
object_initialize(mr, sizeof(*mr), TYPE_MEMORY_REGION);
|
||||
mr->size = int128_make64(size);
|
||||
if (size == UINT64_MAX) {
|
||||
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,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
@ -1092,6 +1100,13 @@ static void memory_region_initfn(Object *obj)
|
||||
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,
|
||||
unsigned size)
|
||||
{
|
||||
@ -1491,17 +1506,23 @@ void memory_region_init_rom_device(MemoryRegion *mr,
|
||||
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,
|
||||
const MemoryRegionIOMMUOps *ops,
|
||||
const char *name,
|
||||
uint64_t size)
|
||||
{
|
||||
memory_region_init(mr, owner, name, size);
|
||||
mr->iommu_ops = ops,
|
||||
struct IOMMUMemoryRegion *iommu_mr;
|
||||
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 */
|
||||
QLIST_INIT(&mr->iommu_notify);
|
||||
mr->iommu_notify_flags = IOMMU_NOTIFIER_NONE;
|
||||
QLIST_INIT(&iommu_mr->iommu_notify);
|
||||
iommu_mr->iommu_notify_flags = IOMMU_NOTIFIER_NONE;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
if (flags != mr->iommu_notify_flags &&
|
||||
mr->iommu_ops->notify_flag_changed) {
|
||||
mr->iommu_ops->notify_flag_changed(mr, mr->iommu_notify_flags,
|
||||
flags);
|
||||
if (flags != iommu_mr->iommu_notify_flags && imrc->notify_flag_changed) {
|
||||
imrc->notify_flag_changed(iommu_mr,
|
||||
iommu_mr->iommu_notify_flags,
|
||||
flags);
|
||||
}
|
||||
|
||||
mr->iommu_notify_flags = flags;
|
||||
iommu_mr->iommu_notify_flags = flags;
|
||||
}
|
||||
|
||||
void memory_region_register_iommu_notifier(MemoryRegion *mr,
|
||||
IOMMUNotifier *n)
|
||||
{
|
||||
IOMMUMemoryRegion *iommu_mr;
|
||||
|
||||
if (mr->alias) {
|
||||
memory_region_register_iommu_notifier(mr->alias, n);
|
||||
return;
|
||||
}
|
||||
|
||||
/* We need to register for at least one bitfield */
|
||||
iommu_mr = IOMMU_MEMORY_REGION(mr);
|
||||
assert(n->notifier_flags != IOMMU_NOTIFIER_NONE);
|
||||
assert(n->start <= n->end);
|
||||
QLIST_INSERT_HEAD(&mr->iommu_notify, n, node);
|
||||
memory_region_update_iommu_notify_flags(mr);
|
||||
QLIST_INSERT_HEAD(&iommu_mr->iommu_notify, n, node);
|
||||
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));
|
||||
if (mr->iommu_ops && mr->iommu_ops->get_min_page_size) {
|
||||
return mr->iommu_ops->get_min_page_size(mr);
|
||||
IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_GET_CLASS(iommu_mr);
|
||||
|
||||
if (imrc->get_min_page_size) {
|
||||
return imrc->get_min_page_size(iommu_mr);
|
||||
}
|
||||
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;
|
||||
IOMMUTLBEntry iotlb;
|
||||
|
||||
/* If the IOMMU has its own replay callback, override */
|
||||
if (mr->iommu_ops->replay) {
|
||||
mr->iommu_ops->replay(mr, n);
|
||||
if (imrc->replay) {
|
||||
imrc->replay(iommu_mr, n);
|
||||
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) {
|
||||
iotlb = mr->iommu_ops->translate(mr, addr, IOMMU_NONE);
|
||||
iotlb = imrc->translate(iommu_mr, addr, IOMMU_NONE);
|
||||
if (iotlb.perm != IOMMU_NONE) {
|
||||
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;
|
||||
|
||||
IOMMU_NOTIFIER_FOREACH(notifier, mr) {
|
||||
memory_region_iommu_replay(mr, notifier);
|
||||
IOMMU_NOTIFIER_FOREACH(notifier, iommu_mr) {
|
||||
memory_region_iommu_replay(iommu_mr, notifier);
|
||||
}
|
||||
}
|
||||
|
||||
void memory_region_unregister_iommu_notifier(MemoryRegion *mr,
|
||||
IOMMUNotifier *n)
|
||||
{
|
||||
IOMMUMemoryRegion *iommu_mr;
|
||||
|
||||
if (mr->alias) {
|
||||
memory_region_unregister_iommu_notifier(mr->alias, n);
|
||||
return;
|
||||
}
|
||||
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,
|
||||
@ -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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -2825,9 +2856,19 @@ static const TypeInfo memory_region_info = {
|
||||
.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)
|
||||
{
|
||||
type_register_static(&memory_region_info);
|
||||
type_register_static(&iommu_memory_region_info);
|
||||
}
|
||||
|
||||
type_init(memory_register_types)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user