* KVM run_on_cpu fix (Alex)

* atomic usage fixes (Emilio, me)
 * hugetlbfs alignment fix (Haozhong)
 * CharBackend refactoring (Marc-André)
 * test-i386 fixes (me)
 * MemoryListener optimizations (me)
 * Miscellaneous bugfixes (me)
 * iSER support (Roy)
 * --version formatting (Thomas)
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.22 (GNU/Linux)
 
 iQEcBAABAgAGBQJYDhCrAAoJEL/70l94x66DBbMH/iM6Z8Kp9tXImqdnVBLCIFW9
 MhxeiaEJ5erILHpOajK8kHTg9Uuqj2Z3sY7n04IU0uvRhvOtwKd28m8AoC2El1j6
 JAHLk2IAfoepfYPVl0s9quQJhxQXlGjMojdbVP4GD3GzIN27x9IrWUSv14gcjf11
 sJr049KXoIphckXBq9JOCEXRSz9Bn9nAc4KzUAbLpH7p8P02Tiox5eW8W6Bn7E3F
 z1J+3XdFl29afjDFvtVLwU5lPM8KR6XC6qyZmD4PO7dzdYMmXxSSL0E/d746x9sp
 4fVmLpoPSSMvmssMz45WZLiMNJQp0HB44rsYVaTjWdn1xprS8cj8JDfvNUQxwr0=
 =/2n2
 -----END PGP SIGNATURE-----

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

* KVM run_on_cpu fix (Alex)
* atomic usage fixes (Emilio, me)
* hugetlbfs alignment fix (Haozhong)
* CharBackend refactoring (Marc-André)
* test-i386 fixes (me)
* MemoryListener optimizations (me)
* Miscellaneous bugfixes (me)
* iSER support (Roy)
* --version formatting (Thomas)

# gpg: Signature made Mon 24 Oct 2016 14:46:19 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: (50 commits)
  exec.c: workaround regression caused by alignment change in d2f39ad
  char: remove explicit_be_open from CharDriverState
  char: use common error path in qmp_chardev_add
  char: replace avail_connections
  char: remove unused qemu_chr_fe_event
  char: use an enum for CHR_EVENT
  char: remove unused CHR_EVENT_FOCUS
  char: move fe_open in CharBackend
  char: remove explicit_fe_open, use a set_handlers argument
  char: rename chr_close/chr_free
  char: move front end handlers in CharBackend
  tests: start chardev unit tests
  char: make some qemu_chr_fe skip if no driver
  char: replace qemu_chr_claim/release with qemu_chr_fe_init/deinit
  vhost-user: only initialize queue 0 CharBackend
  char: fold qemu_chr_set_handlers in qemu_chr_fe_set_handlers
  char: use qemu_chr_fe* functions with CharBackend argument
  colo: claim in find_and_check_chardev
  char: rename some frontend functions
  char: remaining switch to CharBackend in frontend
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2016-10-24 15:03:09 +01:00
commit a3ae21ec3f
96 changed files with 1738 additions and 1229 deletions

View File

@ -551,7 +551,7 @@ static void baum_chr_read(void *opaque)
} }
} }
static void baum_close(struct CharDriverState *chr) static void baum_free(struct CharDriverState *chr)
{ {
BaumDriverState *baum = chr->opaque; BaumDriverState *baum = chr->opaque;
@ -566,6 +566,7 @@ static void baum_close(struct CharDriverState *chr)
static CharDriverState *chr_baum_init(const char *id, static CharDriverState *chr_baum_init(const char *id,
ChardevBackend *backend, ChardevBackend *backend,
ChardevReturn *ret, ChardevReturn *ret,
bool *be_opened,
Error **errp) Error **errp)
{ {
ChardevCommon *common = backend->u.braille.data; ChardevCommon *common = backend->u.braille.data;
@ -589,7 +590,7 @@ static CharDriverState *chr_baum_init(const char *id,
chr->opaque = baum; chr->opaque = baum;
chr->chr_write = baum_write; chr->chr_write = baum_write;
chr->chr_accept_input = baum_accept_input; chr->chr_accept_input = baum_accept_input;
chr->chr_close = baum_close; chr->chr_free = baum_free;
handle = g_malloc0(brlapi_getHandleSize()); handle = g_malloc0(brlapi_getHandleSize());
baum->brlapi = handle; baum->brlapi = handle;

View File

@ -133,7 +133,7 @@ static int msmouse_chr_write (struct CharDriverState *s, const uint8_t *buf, int
return len; return len;
} }
static void msmouse_chr_close (struct CharDriverState *chr) static void msmouse_chr_free(struct CharDriverState *chr)
{ {
MouseState *mouse = chr->opaque; MouseState *mouse = chr->opaque;
@ -151,6 +151,7 @@ static QemuInputHandler msmouse_handler = {
static CharDriverState *qemu_chr_open_msmouse(const char *id, static CharDriverState *qemu_chr_open_msmouse(const char *id,
ChardevBackend *backend, ChardevBackend *backend,
ChardevReturn *ret, ChardevReturn *ret,
bool *be_opened,
Error **errp) Error **errp)
{ {
ChardevCommon *common = backend->u.msmouse.data; ChardevCommon *common = backend->u.msmouse.data;
@ -162,9 +163,9 @@ static CharDriverState *qemu_chr_open_msmouse(const char *id,
return NULL; return NULL;
} }
chr->chr_write = msmouse_chr_write; chr->chr_write = msmouse_chr_write;
chr->chr_close = msmouse_chr_close; chr->chr_free = msmouse_chr_free;
chr->chr_accept_input = msmouse_chr_accept_input; chr->chr_accept_input = msmouse_chr_accept_input;
chr->explicit_be_open = true; *be_opened = false;
mouse = g_new0(MouseState, 1); mouse = g_new0(MouseState, 1);
mouse->hs = qemu_input_handler_register((DeviceState *)mouse, mouse->hs = qemu_input_handler_register((DeviceState *)mouse,

View File

@ -15,7 +15,6 @@
#include "sysemu/char.h" #include "sysemu/char.h"
#include "qapi/error.h" #include "qapi/error.h"
#include "qapi/qmp/qerror.h" #include "qapi/qmp/qerror.h"
#include "hw/qdev.h" /* just for DEFINE_PROP_CHR */
#define TYPE_RNG_EGD "rng-egd" #define TYPE_RNG_EGD "rng-egd"
#define RNG_EGD(obj) OBJECT_CHECK(RngEgd, (obj), TYPE_RNG_EGD) #define RNG_EGD(obj) OBJECT_CHECK(RngEgd, (obj), TYPE_RNG_EGD)
@ -24,7 +23,7 @@ typedef struct RngEgd
{ {
RngBackend parent; RngBackend parent;
CharDriverState *chr; CharBackend chr;
char *chr_name; char *chr_name;
} RngEgd; } RngEgd;
@ -43,7 +42,7 @@ static void rng_egd_request_entropy(RngBackend *b, RngRequest *req)
/* XXX this blocks entire thread. Rewrite to use /* XXX this blocks entire thread. Rewrite to use
* qemu_chr_fe_write and background I/O callbacks */ * qemu_chr_fe_write and background I/O callbacks */
qemu_chr_fe_write_all(s->chr, header, sizeof(header)); qemu_chr_fe_write_all(&s->chr, header, sizeof(header));
size -= len; size -= len;
} }
@ -87,6 +86,7 @@ static void rng_egd_chr_read(void *opaque, const uint8_t *buf, int size)
static void rng_egd_opened(RngBackend *b, Error **errp) static void rng_egd_opened(RngBackend *b, Error **errp)
{ {
RngEgd *s = RNG_EGD(b); RngEgd *s = RNG_EGD(b);
CharDriverState *chr;
if (s->chr_name == NULL) { if (s->chr_name == NULL) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
@ -94,21 +94,19 @@ static void rng_egd_opened(RngBackend *b, Error **errp)
return; return;
} }
s->chr = qemu_chr_find(s->chr_name); chr = qemu_chr_find(s->chr_name);
if (s->chr == NULL) { if (chr == NULL) {
error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
"Device '%s' not found", s->chr_name); "Device '%s' not found", s->chr_name);
return; return;
} }
if (!qemu_chr_fe_init(&s->chr, chr, errp)) {
if (qemu_chr_fe_claim(s->chr) != 0) {
error_setg(errp, QERR_DEVICE_IN_USE, s->chr_name);
return; return;
} }
/* FIXME we should resubmit pending requests when the CDS reconnects. */ /* FIXME we should resubmit pending requests when the CDS reconnects. */
qemu_chr_add_handlers(s->chr, rng_egd_chr_can_read, rng_egd_chr_read, qemu_chr_fe_set_handlers(&s->chr, rng_egd_chr_can_read,
NULL, s); rng_egd_chr_read, NULL, s, NULL, true);
} }
static void rng_egd_set_chardev(Object *obj, const char *value, Error **errp) static void rng_egd_set_chardev(Object *obj, const char *value, Error **errp)
@ -127,9 +125,10 @@ static void rng_egd_set_chardev(Object *obj, const char *value, Error **errp)
static char *rng_egd_get_chardev(Object *obj, Error **errp) static char *rng_egd_get_chardev(Object *obj, Error **errp)
{ {
RngEgd *s = RNG_EGD(obj); RngEgd *s = RNG_EGD(obj);
CharDriverState *chr = qemu_chr_fe_get_driver(&s->chr);
if (s->chr && s->chr->label) { if (chr && chr->label) {
return g_strdup(s->chr->label); return g_strdup(chr->label);
} }
return NULL; return NULL;
@ -146,11 +145,7 @@ static void rng_egd_finalize(Object *obj)
{ {
RngEgd *s = RNG_EGD(obj); RngEgd *s = RNG_EGD(obj);
if (s->chr) { qemu_chr_fe_deinit(&s->chr);
qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, NULL);
qemu_chr_fe_release(s->chr);
}
g_free(s->chr_name); g_free(s->chr_name);
} }

View File

@ -102,7 +102,7 @@ static int testdev_write(CharDriverState *chr, const uint8_t *buf, int len)
return orig_len; return orig_len;
} }
static void testdev_close(struct CharDriverState *chr) static void testdev_free(struct CharDriverState *chr)
{ {
TestdevCharState *testdev = chr->opaque; TestdevCharState *testdev = chr->opaque;
@ -112,6 +112,7 @@ static void testdev_close(struct CharDriverState *chr)
static CharDriverState *chr_testdev_init(const char *id, static CharDriverState *chr_testdev_init(const char *id,
ChardevBackend *backend, ChardevBackend *backend,
ChardevReturn *ret, ChardevReturn *ret,
bool *be_opened,
Error **errp) Error **errp)
{ {
TestdevCharState *testdev; TestdevCharState *testdev;
@ -122,7 +123,7 @@ static CharDriverState *chr_testdev_init(const char *id,
chr->opaque = testdev; chr->opaque = testdev;
chr->chr_write = testdev_write; chr->chr_write = testdev_write;
chr->chr_close = testdev_close; chr->chr_free = testdev_free;
return chr; return chr;
} }

View File

@ -202,6 +202,10 @@ static inline unsigned exp_random(double mean)
#define SCSI_SENSE_ASCQ_PARAMETER_LIST_LENGTH_ERROR 0x1a00 #define SCSI_SENSE_ASCQ_PARAMETER_LIST_LENGTH_ERROR 0x1a00
#endif #endif
#ifndef LIBISCSI_API_VERSION
#define LIBISCSI_API_VERSION 20130701
#endif
static int iscsi_translate_sense(struct scsi_sense *sense) static int iscsi_translate_sense(struct scsi_sense *sense)
{ {
int ret; int ret;
@ -592,6 +596,20 @@ iscsi_co_writev_flags(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
iscsi_co_init_iscsitask(iscsilun, &iTask); iscsi_co_init_iscsitask(iscsilun, &iTask);
retry: retry:
if (iscsilun->use_16_for_rw) { if (iscsilun->use_16_for_rw) {
#if LIBISCSI_API_VERSION >= (20160603)
iTask.task = iscsi_write16_iov_task(iscsilun->iscsi, iscsilun->lun, lba,
NULL, num_sectors * iscsilun->block_size,
iscsilun->block_size, 0, 0, fua, 0, 0,
iscsi_co_generic_cb, &iTask,
(struct scsi_iovec *)iov->iov, iov->niov);
} else {
iTask.task = iscsi_write10_iov_task(iscsilun->iscsi, iscsilun->lun, lba,
NULL, num_sectors * iscsilun->block_size,
iscsilun->block_size, 0, 0, fua, 0, 0,
iscsi_co_generic_cb, &iTask,
(struct scsi_iovec *)iov->iov, iov->niov);
}
#else
iTask.task = iscsi_write16_task(iscsilun->iscsi, iscsilun->lun, lba, iTask.task = iscsi_write16_task(iscsilun->iscsi, iscsilun->lun, lba,
NULL, num_sectors * iscsilun->block_size, NULL, num_sectors * iscsilun->block_size,
iscsilun->block_size, 0, 0, fua, 0, 0, iscsilun->block_size, 0, 0, fua, 0, 0,
@ -602,11 +620,14 @@ retry:
iscsilun->block_size, 0, 0, fua, 0, 0, iscsilun->block_size, 0, 0, fua, 0, 0,
iscsi_co_generic_cb, &iTask); iscsi_co_generic_cb, &iTask);
} }
#endif
if (iTask.task == NULL) { if (iTask.task == NULL) {
return -ENOMEM; return -ENOMEM;
} }
#if LIBISCSI_API_VERSION < (20160603)
scsi_task_set_iov_out(iTask.task, (struct scsi_iovec *) iov->iov, scsi_task_set_iov_out(iTask.task, (struct scsi_iovec *) iov->iov,
iov->niov); iov->niov);
#endif
while (!iTask.complete) { while (!iTask.complete) {
iscsi_set_events(iscsilun); iscsi_set_events(iscsilun);
qemu_coroutine_yield(); qemu_coroutine_yield();
@ -789,6 +810,21 @@ static int coroutine_fn iscsi_co_readv(BlockDriverState *bs,
iscsi_co_init_iscsitask(iscsilun, &iTask); iscsi_co_init_iscsitask(iscsilun, &iTask);
retry: retry:
if (iscsilun->use_16_for_rw) { if (iscsilun->use_16_for_rw) {
#if LIBISCSI_API_VERSION >= (20160603)
iTask.task = iscsi_read16_iov_task(iscsilun->iscsi, iscsilun->lun, lba,
num_sectors * iscsilun->block_size,
iscsilun->block_size, 0, 0, 0, 0, 0,
iscsi_co_generic_cb, &iTask,
(struct scsi_iovec *)iov->iov, iov->niov);
} else {
iTask.task = iscsi_read10_iov_task(iscsilun->iscsi, iscsilun->lun, lba,
num_sectors * iscsilun->block_size,
iscsilun->block_size,
0, 0, 0, 0, 0,
iscsi_co_generic_cb, &iTask,
(struct scsi_iovec *)iov->iov, iov->niov);
}
#else
iTask.task = iscsi_read16_task(iscsilun->iscsi, iscsilun->lun, lba, iTask.task = iscsi_read16_task(iscsilun->iscsi, iscsilun->lun, lba,
num_sectors * iscsilun->block_size, num_sectors * iscsilun->block_size,
iscsilun->block_size, 0, 0, 0, 0, 0, iscsilun->block_size, 0, 0, 0, 0, 0,
@ -800,11 +836,13 @@ retry:
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
iscsi_co_generic_cb, &iTask); iscsi_co_generic_cb, &iTask);
} }
#endif
if (iTask.task == NULL) { if (iTask.task == NULL) {
return -ENOMEM; return -ENOMEM;
} }
#if LIBISCSI_API_VERSION < (20160603)
scsi_task_set_iov_in(iTask.task, (struct scsi_iovec *) iov->iov, iov->niov); scsi_task_set_iov_in(iTask.task, (struct scsi_iovec *) iov->iov, iov->niov);
#endif
while (!iTask.complete) { while (!iTask.complete) {
iscsi_set_events(iscsilun); iscsi_set_events(iscsilun);
qemu_coroutine_yield(); qemu_coroutine_yield();
@ -1606,7 +1644,13 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
ret = -ENOMEM; ret = -ENOMEM;
goto out; goto out;
} }
#if LIBISCSI_API_VERSION >= (20160603)
if (iscsi_init_transport(iscsi, iscsi_url->transport)) {
error_setg(errp, ("Error initializing transport."));
ret = -EINVAL;
goto out;
}
#endif
if (iscsi_set_targetname(iscsi, iscsi_url->target)) { if (iscsi_set_targetname(iscsi, iscsi_url->target)) {
error_setg(errp, "iSCSI: Failed to set target name."); error_setg(errp, "iSCSI: Failed to set target name.");
ret = -EINVAL; ret = -EINVAL;
@ -1649,7 +1693,7 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
/* timeout handling is broken in libiscsi before 1.15.0 */ /* timeout handling is broken in libiscsi before 1.15.0 */
timeout = parse_timeout(iscsi_url->target); timeout = parse_timeout(iscsi_url->target);
#if defined(LIBISCSI_API_VERSION) && LIBISCSI_API_VERSION >= 20150621 #if LIBISCSI_API_VERSION >= 20150621
iscsi_set_timeout(iscsi, timeout); iscsi_set_timeout(iscsi, timeout);
#else #else
if (timeout) { if (timeout) {
@ -2010,9 +2054,48 @@ static BlockDriver bdrv_iscsi = {
.bdrv_attach_aio_context = iscsi_attach_aio_context, .bdrv_attach_aio_context = iscsi_attach_aio_context,
}; };
#if LIBISCSI_API_VERSION >= (20160603)
static BlockDriver bdrv_iser = {
.format_name = "iser",
.protocol_name = "iser",
.instance_size = sizeof(IscsiLun),
.bdrv_needs_filename = true,
.bdrv_file_open = iscsi_open,
.bdrv_close = iscsi_close,
.bdrv_create = iscsi_create,
.create_opts = &iscsi_create_opts,
.bdrv_reopen_prepare = iscsi_reopen_prepare,
.bdrv_reopen_commit = iscsi_reopen_commit,
.bdrv_invalidate_cache = iscsi_invalidate_cache,
.bdrv_getlength = iscsi_getlength,
.bdrv_get_info = iscsi_get_info,
.bdrv_truncate = iscsi_truncate,
.bdrv_refresh_limits = iscsi_refresh_limits,
.bdrv_co_get_block_status = iscsi_co_get_block_status,
.bdrv_co_pdiscard = iscsi_co_pdiscard,
.bdrv_co_pwrite_zeroes = iscsi_co_pwrite_zeroes,
.bdrv_co_readv = iscsi_co_readv,
.bdrv_co_writev_flags = iscsi_co_writev_flags,
.bdrv_co_flush_to_disk = iscsi_co_flush,
#ifdef __linux__
.bdrv_aio_ioctl = iscsi_aio_ioctl,
#endif
.bdrv_detach_aio_context = iscsi_detach_aio_context,
.bdrv_attach_aio_context = iscsi_attach_aio_context,
};
#endif
static void iscsi_block_init(void) static void iscsi_block_init(void)
{ {
bdrv_register(&bdrv_iscsi); bdrv_register(&bdrv_iscsi);
#if LIBISCSI_API_VERSION >= (20160603)
bdrv_register(&bdrv_iser);
#endif
} }
block_init(iscsi_block_init); block_init(iscsi_block_init);

View File

@ -733,7 +733,7 @@ static BlockAIOCB *qemu_rbd_aio_readv(BlockDriverState *bs,
void *opaque) void *opaque)
{ {
return rbd_start_aio(bs, sector_num << BDRV_SECTOR_BITS, qiov, return rbd_start_aio(bs, sector_num << BDRV_SECTOR_BITS, qiov,
nb_sectors << BDRV_SECTOR_BITS, cb, opaque, (int64_t) nb_sectors << BDRV_SECTOR_BITS, cb, opaque,
RBD_AIO_READ); RBD_AIO_READ);
} }
@ -745,7 +745,7 @@ static BlockAIOCB *qemu_rbd_aio_writev(BlockDriverState *bs,
void *opaque) void *opaque)
{ {
return rbd_start_aio(bs, sector_num << BDRV_SECTOR_BITS, qiov, return rbd_start_aio(bs, sector_num << BDRV_SECTOR_BITS, qiov,
nb_sectors << BDRV_SECTOR_BITS, cb, opaque, (int64_t) nb_sectors << BDRV_SECTOR_BITS, cb, opaque,
RBD_AIO_WRITE); RBD_AIO_WRITE);
} }

View File

@ -651,7 +651,7 @@ void cpu_loop(CPUSPARCState *env)
static void usage(void) static void usage(void)
{ {
printf("qemu-" TARGET_NAME " version " QEMU_VERSION QEMU_PKGVERSION printf("qemu-" TARGET_NAME " version " QEMU_VERSION QEMU_PKGVERSION
", " QEMU_COPYRIGHT "\n" "\n" QEMU_COPYRIGHT "\n"
"usage: qemu-" TARGET_NAME " [options] program [arguments...]\n" "usage: qemu-" TARGET_NAME " [options] program [arguments...]\n"
"BSD CPU emulator (compiled for %s emulation)\n" "BSD CPU emulator (compiled for %s emulation)\n"
"\n" "\n"

View File

@ -15,7 +15,8 @@ Macros defined by qemu/atomic.h fall in three camps:
- compiler barriers: barrier(); - compiler barriers: barrier();
- weak atomic access and manual memory barriers: atomic_read(), - weak atomic access and manual memory barriers: atomic_read(),
atomic_set(), smp_rmb(), smp_wmb(), smp_mb(), smp_read_barrier_depends(); atomic_set(), smp_rmb(), smp_wmb(), smp_mb(), smp_mb_acquire(),
smp_mb_release(), smp_read_barrier_depends();
- sequentially consistent atomic access: everything else. - sequentially consistent atomic access: everything else.
@ -111,8 +112,8 @@ consistent primitives.
When using this model, variables are accessed with atomic_read() and When using this model, variables are accessed with atomic_read() and
atomic_set(), and restrictions to the ordering of accesses is enforced atomic_set(), and restrictions to the ordering of accesses is enforced
using the smp_rmb(), smp_wmb(), smp_mb() and smp_read_barrier_depends() using the memory barrier macros: smp_rmb(), smp_wmb(), smp_mb(),
memory barriers. smp_mb_acquire(), smp_mb_release(), smp_read_barrier_depends().
atomic_read() and atomic_set() prevents the compiler from using atomic_read() and atomic_set() prevents the compiler from using
optimizations that might otherwise optimize accesses out of existence optimizations that might otherwise optimize accesses out of existence
@ -124,7 +125,7 @@ other threads, and which are local to the current thread or protected
by other, more mundane means. by other, more mundane means.
Memory barriers control the order of references to shared memory. Memory barriers control the order of references to shared memory.
They come in four kinds: They come in six kinds:
- smp_rmb() guarantees that all the LOAD operations specified before - smp_rmb() guarantees that all the LOAD operations specified before
the barrier will appear to happen before all the LOAD operations the barrier will appear to happen before all the LOAD operations
@ -142,6 +143,16 @@ They come in four kinds:
In other words, smp_wmb() puts a partial ordering on stores, but is not In other words, smp_wmb() puts a partial ordering on stores, but is not
required to have any effect on loads. required to have any effect on loads.
- smp_mb_acquire() guarantees that all the LOAD operations specified before
the barrier will appear to happen before all the LOAD or STORE operations
specified after the barrier with respect to the other components of
the system.
- smp_mb_release() guarantees that all the STORE operations specified *after*
the barrier will appear to happen after all the LOAD or STORE operations
specified *before* the barrier with respect to the other components of
the system.
- smp_mb() guarantees that all the LOAD and STORE operations specified - smp_mb() guarantees that all the LOAD and STORE operations specified
before the barrier will appear to happen before all the LOAD and before the barrier will appear to happen before all the LOAD and
STORE operations specified after the barrier with respect to the other STORE operations specified after the barrier with respect to the other
@ -149,8 +160,9 @@ They come in four kinds:
smp_mb() puts a partial ordering on both loads and stores. It is smp_mb() puts a partial ordering on both loads and stores. It is
stronger than both a read and a write memory barrier; it implies both stronger than both a read and a write memory barrier; it implies both
smp_rmb() and smp_wmb(), but it also prevents STOREs coming before the smp_mb_acquire() and smp_mb_release(), but it also prevents STOREs
barrier from overtaking LOADs coming after the barrier and vice versa. coming before the barrier from overtaking LOADs coming after the
barrier and vice versa.
- smp_read_barrier_depends() is a weaker kind of read barrier. On - smp_read_barrier_depends() is a weaker kind of read barrier. On
most processors, whenever two loads are performed such that the most processors, whenever two loads are performed such that the
@ -173,24 +185,21 @@ They come in four kinds:
This is the set of barriers that is required *between* two atomic_read() This is the set of barriers that is required *between* two atomic_read()
and atomic_set() operations to achieve sequential consistency: and atomic_set() operations to achieve sequential consistency:
| 2nd operation | | 2nd operation |
|-----------------------------------------| |-----------------------------------------------|
1st operation | (after last) | atomic_read | atomic_set | 1st operation | (after last) | atomic_read | atomic_set |
---------------+--------------+-------------+------------| ---------------+----------------+-------------+----------------|
(before first) | | none | smp_wmb() | (before first) | | none | smp_mb_release |
---------------+--------------+-------------+------------| ---------------+----------------+-------------+----------------|
atomic_read | smp_rmb() | smp_rmb()* | ** | atomic_read | smp_mb_acquire | smp_rmb | ** |
---------------+--------------+-------------+------------| ---------------+----------------+-------------+----------------|
atomic_set | none | smp_mb()*** | smp_wmb() | atomic_set | none | smp_mb()*** | smp_wmb() |
---------------+--------------+-------------+------------| ---------------+----------------+-------------+----------------|
* Or smp_read_barrier_depends(). * Or smp_read_barrier_depends().
** This requires a load-store barrier. How to achieve this varies ** This requires a load-store barrier. This is achieved by
depending on the machine, but in practice smp_rmb()+smp_wmb() either smp_mb_acquire() or smp_mb_release().
should have the desired effect. For example, on PowerPC the
lwsync instruction is a combined load-load, load-store and
store-store barrier.
*** This requires a store-load barrier. On most machines, the only *** This requires a store-load barrier. On most machines, the only
way to achieve this is a full barrier. way to achieve this is a full barrier.
@ -199,11 +208,11 @@ and atomic_set() operations to achieve sequential consistency:
You can see that the two possible definitions of atomic_mb_read() You can see that the two possible definitions of atomic_mb_read()
and atomic_mb_set() are the following: and atomic_mb_set() are the following:
1) atomic_mb_read(p) = atomic_read(p); smp_rmb() 1) atomic_mb_read(p) = atomic_read(p); smp_mb_acquire()
atomic_mb_set(p, v) = smp_wmb(); atomic_set(p, v); smp_mb() atomic_mb_set(p, v) = smp_mb_release(); atomic_set(p, v); smp_mb()
2) atomic_mb_read(p) = smp_mb() atomic_read(p); smp_rmb() 2) atomic_mb_read(p) = smp_mb() atomic_read(p); smp_mb_acquire()
atomic_mb_set(p, v) = smp_wmb(); atomic_set(p, v); atomic_mb_set(p, v) = smp_mb_release(); atomic_set(p, v);
Usually the former is used, because smp_mb() is expensive and a program Usually the former is used, because smp_mb() is expensive and a program
normally has more reads than writes. Therefore it makes more sense to normally has more reads than writes. Therefore it makes more sense to
@ -222,7 +231,7 @@ place barriers instead:
thread 1 thread 1 thread 1 thread 1
------------------------- ------------------------ ------------------------- ------------------------
(other writes) (other writes)
smp_wmb() smp_mb_release()
atomic_mb_set(&a, x) atomic_set(&a, x) atomic_mb_set(&a, x) atomic_set(&a, x)
smp_wmb() smp_wmb()
atomic_mb_set(&b, y) atomic_set(&b, y) atomic_mb_set(&b, y) atomic_set(&b, y)
@ -233,7 +242,13 @@ place barriers instead:
y = atomic_mb_read(&b) y = atomic_read(&b) y = atomic_mb_read(&b) y = atomic_read(&b)
smp_rmb() smp_rmb()
x = atomic_mb_read(&a) x = atomic_read(&a) x = atomic_mb_read(&a) x = atomic_read(&a)
smp_rmb() smp_mb_acquire()
Note that the barrier between the stores in thread 1, and between
the loads in thread 2, has been optimized here to a write or a
read memory barrier respectively. On some architectures, notably
ARMv7, smp_mb_acquire and smp_mb_release are just as expensive as
smp_mb, but smp_rmb and/or smp_wmb are more efficient.
- sometimes, a thread is accessing many variables that are otherwise - sometimes, a thread is accessing many variables that are otherwise
unrelated to each other (for example because, apart from the current unrelated to each other (for example because, apart from the current
@ -246,12 +261,12 @@ place barriers instead:
n = 0; n = 0; n = 0; n = 0;
for (i = 0; i < 10; i++) => for (i = 0; i < 10; i++) for (i = 0; i < 10; i++) => for (i = 0; i < 10; i++)
n += atomic_mb_read(&a[i]); n += atomic_read(&a[i]); n += atomic_mb_read(&a[i]); n += atomic_read(&a[i]);
smp_rmb(); smp_mb_acquire();
Similarly, atomic_mb_set() can be transformed as follows: Similarly, atomic_mb_set() can be transformed as follows:
smp_mb(): smp_mb():
smp_wmb(); smp_mb_release();
for (i = 0; i < 10; i++) => for (i = 0; i < 10; i++) for (i = 0; i < 10; i++) => for (i = 0; i < 10; i++)
atomic_mb_set(&a[i], false); atomic_set(&a[i], false); atomic_mb_set(&a[i], false); atomic_set(&a[i], false);
smp_mb(); smp_mb();
@ -261,7 +276,7 @@ The two tricks can be combined. In this case, splitting a loop in
two lets you hoist the barriers out of the loops _and_ eliminate the two lets you hoist the barriers out of the loops _and_ eliminate the
expensive smp_mb(): expensive smp_mb():
smp_wmb(); smp_mb_release();
for (i = 0; i < 10; i++) { => for (i = 0; i < 10; i++) for (i = 0; i < 10; i++) { => for (i = 0; i < 10; i++)
atomic_mb_set(&a[i], false); atomic_set(&a[i], false); atomic_mb_set(&a[i], false); atomic_set(&a[i], false);
atomic_mb_set(&b[i], false); smb_wmb(); atomic_mb_set(&b[i], false); smb_wmb();
@ -312,8 +327,8 @@ access and for data dependency barriers:
smp_read_barrier_depends(); smp_read_barrier_depends();
z = b[y]; z = b[y];
smp_wmb() also pairs with atomic_mb_read(), and smp_rmb() also pairs smp_wmb() also pairs with atomic_mb_read() and smp_mb_acquire().
with atomic_mb_set(). and smp_rmb() also pairs with atomic_mb_set() and smp_mb_release().
COMPARISON WITH LINUX KERNEL MEMORY BARRIERS COMPARISON WITH LINUX KERNEL MEMORY BARRIERS
@ -359,8 +374,9 @@ and memory barriers, and the equivalents in QEMU:
note that smp_store_mb() is a little weaker than atomic_mb_set(). note that smp_store_mb() is a little weaker than atomic_mb_set().
atomic_mb_read() compiles to the same instructions as Linux's atomic_mb_read() compiles to the same instructions as Linux's
smp_load_acquire(), but this should be treated as an implementation smp_load_acquire(), but this should be treated as an implementation
detail. If required, QEMU might later add atomic_load_acquire() and detail. QEMU does have atomic_load_acquire() and atomic_store_release()
atomic_store_release() macros. macros, but for now they are only used within atomic.h. This may
change in the future.
SOURCES SOURCES

7
exec.c
View File

@ -1254,7 +1254,12 @@ static void *file_ram_alloc(RAMBlock *block,
} }
block->page_size = qemu_fd_getpagesize(fd); block->page_size = qemu_fd_getpagesize(fd);
block->mr->align = MAX(block->page_size, QEMU_VMALLOC_ALIGN); block->mr->align = block->page_size;
#if defined(__s390x__)
if (kvm_enabled()) {
block->mr->align = MAX(block->mr->align, QEMU_VMALLOC_ALIGN);
}
#endif
if (memory < block->page_size) { if (memory < block->page_size) {
error_setg(errp, "memory size 0x" RAM_ADDR_FMT " must be equal to " error_setg(errp, "memory size 0x" RAM_ADDR_FMT " must be equal to "

View File

@ -303,7 +303,7 @@ typedef struct GDBState {
int fd; int fd;
int running_state; int running_state;
#else #else
CharDriverState *chr; CharBackend chr;
CharDriverState *mon_chr; CharDriverState *mon_chr;
#endif #endif
char syscall_buf[256]; char syscall_buf[256];
@ -404,7 +404,7 @@ static void put_buffer(GDBState *s, const uint8_t *buf, int len)
#else #else
/* XXX this blocks entire thread. Rewrite to use /* XXX this blocks entire thread. Rewrite to use
* qemu_chr_fe_write and background I/O callbacks */ * qemu_chr_fe_write and background I/O callbacks */
qemu_chr_fe_write_all(s->chr, buf, len); qemu_chr_fe_write_all(&s->chr, buf, len);
#endif #endif
} }
@ -1471,6 +1471,9 @@ void gdb_exit(CPUArchState *env, int code)
{ {
GDBState *s; GDBState *s;
char buf[4]; char buf[4];
#ifndef CONFIG_USER_ONLY
CharDriverState *chr;
#endif
s = gdbserver_state; s = gdbserver_state;
if (!s) { if (!s) {
@ -1481,7 +1484,8 @@ void gdb_exit(CPUArchState *env, int code)
return; return;
} }
#else #else
if (!s->chr) { chr = qemu_chr_fe_get_driver(&s->chr);
if (!chr) {
return; return;
} }
#endif #endif
@ -1490,7 +1494,8 @@ void gdb_exit(CPUArchState *env, int code)
put_packet(s, buf); put_packet(s, buf);
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
qemu_chr_delete(s->chr); qemu_chr_fe_deinit(&s->chr);
qemu_chr_delete(chr);
#endif #endif
} }
@ -1745,13 +1750,9 @@ int gdbserver_start(const char *device)
sigaction(SIGINT, &act, NULL); sigaction(SIGINT, &act, NULL);
} }
#endif #endif
chr = qemu_chr_new_noreplay("gdb", device, NULL); chr = qemu_chr_new_noreplay("gdb", device);
if (!chr) if (!chr)
return -1; return -1;
qemu_chr_fe_claim_no_fail(chr);
qemu_chr_add_handlers(chr, gdb_chr_can_receive, gdb_chr_receive,
gdb_chr_event, NULL);
} }
s = gdbserver_state; s = gdbserver_state;
@ -1766,14 +1767,20 @@ int gdbserver_start(const char *device)
mon_chr->chr_write = gdb_monitor_write; mon_chr->chr_write = gdb_monitor_write;
monitor_init(mon_chr, 0); monitor_init(mon_chr, 0);
} else { } else {
if (s->chr) if (qemu_chr_fe_get_driver(&s->chr)) {
qemu_chr_delete(s->chr); qemu_chr_delete(qemu_chr_fe_get_driver(&s->chr));
}
mon_chr = s->mon_chr; mon_chr = s->mon_chr;
memset(s, 0, sizeof(GDBState)); memset(s, 0, sizeof(GDBState));
s->mon_chr = mon_chr;
} }
s->c_cpu = first_cpu; s->c_cpu = first_cpu;
s->g_cpu = first_cpu; s->g_cpu = first_cpu;
s->chr = chr; 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);
}
s->state = chr ? RS_IDLE : RS_INACTIVE; s->state = chr ? RS_IDLE : RS_INACTIVE;
s->mon_chr = mon_chr; s->mon_chr = mon_chr;
s->current_syscall_cb = NULL; s->current_syscall_cb = NULL;

2
hmp.c
View File

@ -2002,7 +2002,7 @@ void hmp_chardev_add(Monitor *mon, const QDict *qdict)
if (opts == NULL) { if (opts == NULL) {
error_setg(&err, "Parsing chardev args failed"); error_setg(&err, "Parsing chardev args failed");
} else { } else {
qemu_chr_new_from_opts(opts, NULL, &err); qemu_chr_new_from_opts(opts, &err);
qemu_opts_del(opts); qemu_opts_del(opts);
} }
hmp_handle_error(mon, &err); hmp_handle_error(mon, &err);

View File

@ -88,7 +88,7 @@ static void clipper_init(MachineState *machine)
pci_vga_init(pci_bus); pci_vga_init(pci_bus);
/* Serial code setup. */ /* Serial code setup. */
serial_hds_isa_init(isa_bus, MAX_SERIAL_PORTS); serial_hds_isa_init(isa_bus, 0, MAX_SERIAL_PORTS);
/* Network setup. e1000 is good enough, failing Tulip support. */ /* Network setup. e1000 is good enough, failing Tulip support. */
for (i = 0; i < nb_nics; i++) { for (i = 0; i < nb_nics; i++) {

View File

@ -125,7 +125,7 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp)
if (!chr) { if (!chr) {
char label[20]; char label[20];
snprintf(label, sizeof(label), "imx31.uart%d", i); snprintf(label, sizeof(label), "imx31.uart%d", i);
chr = qemu_chr_new(label, "null", NULL); chr = qemu_chr_new(label, "null");
} }
qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", chr); qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", chr);

View File

@ -114,7 +114,7 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp)
if (!chr) { if (!chr) {
char label[20]; char label[20];
snprintf(label, sizeof(label), "imx31.uart%d", i); snprintf(label, sizeof(label), "imx31.uart%d", i);
chr = qemu_chr_new(label, "null", NULL); chr = qemu_chr_new(label, "null");
} }
qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", chr); qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", chr);

View File

@ -193,7 +193,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp)
if (!chr) { if (!chr) {
char *label = g_strdup_printf("imx6.uart%d", i + 1); char *label = g_strdup_printf("imx6.uart%d", i + 1);
chr = qemu_chr_new(label, "null", NULL); chr = qemu_chr_new(label, "null");
g_free(label); g_free(label);
serial_hds[i] = chr; serial_hds[i] = chr;
} }

View File

@ -621,7 +621,7 @@ struct omap_sti_s {
qemu_irq irq; qemu_irq irq;
MemoryRegion iomem; MemoryRegion iomem;
MemoryRegion iomem_fifo; MemoryRegion iomem_fifo;
CharDriverState *chr; CharBackend chr;
uint32_t sysconfig; uint32_t sysconfig;
uint32_t systest; uint32_t systest;
@ -771,14 +771,15 @@ static void omap_sti_fifo_write(void *opaque, hwaddr addr,
/* Flush channel <i>value</i>. */ /* Flush channel <i>value</i>. */
/* XXX this blocks entire thread. Rewrite to use /* XXX this blocks entire thread. Rewrite to use
* qemu_chr_fe_write and background I/O callbacks */ * qemu_chr_fe_write and background I/O callbacks */
qemu_chr_fe_write_all(s->chr, (const uint8_t *) "\r", 1); qemu_chr_fe_write_all(&s->chr, (const uint8_t *) "\r", 1);
} else if (ch == STI_TRACE_CONSOLE_CHANNEL || 1) { } else if (ch == STI_TRACE_CONSOLE_CHANNEL || 1) {
if (value == 0xc0 || value == 0xc3) { if (value == 0xc0 || value == 0xc3) {
/* Open channel <i>ch</i>. */ /* Open channel <i>ch</i>. */
} else if (value == 0x00) } else if (value == 0x00) {
qemu_chr_fe_write_all(s->chr, (const uint8_t *) "\n", 1); qemu_chr_fe_write_all(&s->chr, (const uint8_t *) "\n", 1);
else } else {
qemu_chr_fe_write_all(s->chr, &byte, 1); qemu_chr_fe_write_all(&s->chr, &byte, 1);
}
} }
} }
@ -798,7 +799,8 @@ static struct omap_sti_s *omap_sti_init(struct omap_target_agent_s *ta,
s->irq = irq; s->irq = irq;
omap_sti_reset(s); omap_sti_reset(s);
s->chr = chr ?: qemu_chr_new("null", "null", NULL); qemu_chr_fe_init(&s->chr, chr ?: qemu_chr_new("null", "null"),
&error_abort);
memory_region_init_io(&s->iomem, NULL, &omap_sti_ops, s, "omap.sti", memory_region_init_io(&s->iomem, NULL, &omap_sti_ops, s, "omap.sti",
omap_l4_region_size(ta, 0)); omap_l4_region_size(ta, 0));

View File

@ -1764,7 +1764,7 @@ struct PXA2xxFIrState {
qemu_irq rx_dma; qemu_irq rx_dma;
qemu_irq tx_dma; qemu_irq tx_dma;
uint32_t enable; uint32_t enable;
CharDriverState *chr; CharBackend chr;
uint8_t control[3]; uint8_t control[3];
uint8_t status[2]; uint8_t status[2];
@ -1898,14 +1898,16 @@ static void pxa2xx_fir_write(void *opaque, hwaddr addr,
pxa2xx_fir_update(s); pxa2xx_fir_update(s);
break; break;
case ICDR: case ICDR:
if (s->control[2] & (1 << 2)) /* TXP */ if (s->control[2] & (1 << 2)) { /* TXP */
ch = value; ch = value;
else } else {
ch = ~value; ch = ~value;
if (s->chr && s->enable && (s->control[0] & (1 << 3))) /* TXE */ }
if (s->enable && (s->control[0] & (1 << 3))) { /* TXE */
/* XXX this blocks entire thread. Rewrite to use /* XXX this blocks entire thread. Rewrite to use
* qemu_chr_fe_write and background I/O callbacks */ * qemu_chr_fe_write and background I/O callbacks */
qemu_chr_fe_write_all(s->chr, &ch, 1); qemu_chr_fe_write_all(&s->chr, &ch, 1);
}
break; break;
case ICSR0: case ICSR0:
s->status[0] &= ~(value & 0x66); s->status[0] &= ~(value & 0x66);
@ -1973,11 +1975,8 @@ static void pxa2xx_fir_realize(DeviceState *dev, Error **errp)
{ {
PXA2xxFIrState *s = PXA2XX_FIR(dev); PXA2xxFIrState *s = PXA2XX_FIR(dev);
if (s->chr) { qemu_chr_fe_set_handlers(&s->chr, pxa2xx_fir_is_empty,
qemu_chr_fe_claim_no_fail(s->chr); pxa2xx_fir_rx, pxa2xx_fir_event, s, NULL, true);
qemu_chr_add_handlers(s->chr, pxa2xx_fir_is_empty,
pxa2xx_fir_rx, pxa2xx_fir_event, s);
}
} }
static bool pxa2xx_fir_vmstate_validate(void *opaque, int version_id) static bool pxa2xx_fir_vmstate_validate(void *opaque, int version_id)

View File

@ -912,7 +912,7 @@ typedef struct StrongARMUARTState {
SysBusDevice parent_obj; SysBusDevice parent_obj;
MemoryRegion iomem; MemoryRegion iomem;
CharDriverState *chr; CharBackend chr;
qemu_irq irq; qemu_irq irq;
uint8_t utcr0; uint8_t utcr0;
@ -1020,9 +1020,7 @@ static void strongarm_uart_update_parameters(StrongARMUARTState *s)
ssp.data_bits = data_bits; ssp.data_bits = data_bits;
ssp.stop_bits = stop_bits; ssp.stop_bits = stop_bits;
s->char_transmit_time = (NANOSECONDS_PER_SECOND / speed) * frame_size; s->char_transmit_time = (NANOSECONDS_PER_SECOND / speed) * frame_size;
if (s->chr) { qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
}
DPRINTF(stderr, "%s speed=%d parity=%c data=%d stop=%d\n", s->chr->label, DPRINTF(stderr, "%s speed=%d parity=%c data=%d stop=%d\n", s->chr->label,
speed, parity, data_bits, stop_bits); speed, parity, data_bits, stop_bits);
@ -1107,10 +1105,10 @@ static void strongarm_uart_tx(void *opaque)
if (s->utcr3 & UTCR3_LBM) /* loopback */ { if (s->utcr3 & UTCR3_LBM) /* loopback */ {
strongarm_uart_receive(s, &s->tx_fifo[s->tx_start], 1); strongarm_uart_receive(s, &s->tx_fifo[s->tx_start], 1);
} else if (s->chr) { } else if (qemu_chr_fe_get_driver(&s->chr)) {
/* XXX this blocks entire thread. Rewrite to use /* XXX this blocks entire thread. Rewrite to use
* qemu_chr_fe_write and background I/O callbacks */ * qemu_chr_fe_write and background I/O callbacks */
qemu_chr_fe_write_all(s->chr, &s->tx_fifo[s->tx_start], 1); qemu_chr_fe_write_all(&s->chr, &s->tx_fifo[s->tx_start], 1);
} }
s->tx_start = (s->tx_start + 1) % 8; s->tx_start = (s->tx_start + 1) % 8;
@ -1239,13 +1237,11 @@ static void strongarm_uart_init(Object *obj)
s->rx_timeout_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, strongarm_uart_rx_to, s); s->rx_timeout_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, strongarm_uart_rx_to, s);
s->tx_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, strongarm_uart_tx, s); s->tx_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, strongarm_uart_tx, s);
if (s->chr) { qemu_chr_fe_set_handlers(&s->chr,
qemu_chr_add_handlers(s->chr, strongarm_uart_can_receive,
strongarm_uart_can_receive, strongarm_uart_receive,
strongarm_uart_receive, strongarm_uart_event,
strongarm_uart_event, s, NULL, true);
s);
}
} }
static void strongarm_uart_reset(DeviceState *dev) static void strongarm_uart_reset(DeviceState *dev)

View File

@ -78,15 +78,17 @@ enum {
static inline void csrhci_fifo_wake(struct csrhci_s *s) static inline void csrhci_fifo_wake(struct csrhci_s *s)
{ {
CharBackend *be = s->chr.be;
if (!s->enable || !s->out_len) if (!s->enable || !s->out_len)
return; return;
/* XXX: Should wait for s->modem_state & CHR_TIOCM_RTS? */ /* XXX: Should wait for s->modem_state & CHR_TIOCM_RTS? */
if (s->chr.chr_can_read && s->chr.chr_can_read(s->chr.handler_opaque) && if (be && be->chr_can_read && be->chr_can_read(be->opaque) &&
s->chr.chr_read) { be->chr_read) {
s->chr.chr_read(s->chr.handler_opaque, be->chr_read(be->opaque,
s->outfifo + s->out_start ++, 1); s->outfifo + s->out_start++, 1);
s->out_len --; s->out_len--;
if (s->out_start >= s->out_size) { if (s->out_start >= s->out_size) {
s->out_start = 0; s->out_start = 0;
s->out_size = FIFO_LEN; s->out_size = FIFO_LEN;
@ -466,7 +468,6 @@ CharDriverState *uart_hci_init(void)
s->chr.opaque = s; s->chr.opaque = s;
s->chr.chr_write = csrhci_write; s->chr.chr_write = csrhci_write;
s->chr.chr_ioctl = csrhci_ioctl; s->chr.chr_ioctl = csrhci_ioctl;
s->chr.avail_connections = 1;
s->hci = qemu_next_hci(); s->hci = qemu_next_hci();
s->hci->opaque = s; s->hci->opaque = s;

View File

@ -79,9 +79,7 @@ static uint64_t bcm2835_aux_read(void *opaque, hwaddr offset, unsigned size)
s->read_pos = 0; s->read_pos = 0;
} }
} }
if (s->chr) { qemu_chr_fe_accept_input(&s->chr);
qemu_chr_accept_input(s->chr);
}
bcm2835_aux_update(s); bcm2835_aux_update(s);
return c; return c;
@ -168,11 +166,9 @@ static void bcm2835_aux_write(void *opaque, hwaddr offset, uint64_t value,
case AUX_MU_IO_REG: case AUX_MU_IO_REG:
/* "DLAB bit set means access baudrate register" is NYI */ /* "DLAB bit set means access baudrate register" is NYI */
ch = value; ch = value;
if (s->chr) { /* XXX this blocks entire thread. Rewrite to use
/* XXX this blocks entire thread. Rewrite to use * qemu_chr_fe_write and background I/O callbacks */
* qemu_chr_fe_write and background I/O callbacks */ qemu_chr_fe_write_all(&s->chr, &ch, 1);
qemu_chr_fe_write_all(s->chr, &ch, 1);
}
break; break;
case AUX_MU_IER_REG: case AUX_MU_IER_REG:
@ -282,10 +278,8 @@ static void bcm2835_aux_realize(DeviceState *dev, Error **errp)
{ {
BCM2835AuxState *s = BCM2835_AUX(dev); BCM2835AuxState *s = BCM2835_AUX(dev);
if (s->chr) { qemu_chr_fe_set_handlers(&s->chr, bcm2835_aux_can_receive,
qemu_chr_add_handlers(s->chr, bcm2835_aux_can_receive, bcm2835_aux_receive, NULL, s, NULL, true);
bcm2835_aux_receive, NULL, s);
}
} }
static Property bcm2835_aux_props[] = { static Property bcm2835_aux_props[] = {

View File

@ -142,9 +142,7 @@ static void uart_rx_reset(CadenceUARTState *s)
{ {
s->rx_wpos = 0; s->rx_wpos = 0;
s->rx_count = 0; s->rx_count = 0;
if (s->chr) { qemu_chr_fe_accept_input(&s->chr);
qemu_chr_accept_input(s->chr);
}
} }
static void uart_tx_reset(CadenceUARTState *s) static void uart_tx_reset(CadenceUARTState *s)
@ -156,10 +154,8 @@ static void uart_send_breaks(CadenceUARTState *s)
{ {
int break_enabled = 1; int break_enabled = 1;
if (s->chr) { qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_BREAK,
qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_BREAK, &break_enabled);
&break_enabled);
}
} }
static void uart_parameters_setup(CadenceUARTState *s) static void uart_parameters_setup(CadenceUARTState *s)
@ -210,9 +206,7 @@ static void uart_parameters_setup(CadenceUARTState *s)
packet_size += ssp.data_bits + ssp.stop_bits; packet_size += ssp.data_bits + ssp.stop_bits;
s->char_tx_time = (NANOSECONDS_PER_SECOND / ssp.speed) * packet_size; s->char_tx_time = (NANOSECONDS_PER_SECOND / ssp.speed) * packet_size;
if (s->chr) { qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
}
} }
static int uart_can_receive(void *opaque) static int uart_can_receive(void *opaque)
@ -278,7 +272,7 @@ static gboolean cadence_uart_xmit(GIOChannel *chan, GIOCondition cond,
int ret; int ret;
/* instant drain the fifo when there's no back-end */ /* instant drain the fifo when there's no back-end */
if (!s->chr) { if (!qemu_chr_fe_get_driver(&s->chr)) {
s->tx_count = 0; s->tx_count = 0;
return FALSE; return FALSE;
} }
@ -287,7 +281,7 @@ static gboolean cadence_uart_xmit(GIOChannel *chan, GIOCondition cond,
return FALSE; return FALSE;
} }
ret = qemu_chr_fe_write(s->chr, s->tx_fifo, s->tx_count); ret = qemu_chr_fe_write(&s->chr, s->tx_fifo, s->tx_count);
if (ret >= 0) { if (ret >= 0) {
s->tx_count -= ret; s->tx_count -= ret;
@ -295,7 +289,7 @@ static gboolean cadence_uart_xmit(GIOChannel *chan, GIOCondition cond,
} }
if (s->tx_count) { if (s->tx_count) {
guint r = qemu_chr_fe_add_watch(s->chr, G_IO_OUT|G_IO_HUP, guint r = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
cadence_uart_xmit, s); cadence_uart_xmit, s);
if (!r) { if (!r) {
s->tx_count = 0; s->tx_count = 0;
@ -368,9 +362,7 @@ static void uart_read_rx_fifo(CadenceUARTState *s, uint32_t *c)
*c = s->rx_fifo[rx_rpos]; *c = s->rx_fifo[rx_rpos];
s->rx_count--; s->rx_count--;
if (s->chr) { qemu_chr_fe_accept_input(&s->chr);
qemu_chr_accept_input(s->chr);
}
} else { } else {
*c = 0; *c = 0;
} }
@ -474,10 +466,8 @@ static void cadence_uart_realize(DeviceState *dev, Error **errp)
s->fifo_trigger_handle = timer_new_ns(QEMU_CLOCK_VIRTUAL, s->fifo_trigger_handle = timer_new_ns(QEMU_CLOCK_VIRTUAL,
fifo_trigger_update, s); fifo_trigger_update, s);
if (s->chr) { qemu_chr_fe_set_handlers(&s->chr, uart_can_receive, uart_receive,
qemu_chr_add_handlers(s->chr, uart_can_receive, uart_receive, uart_event, s, NULL, true);
uart_event, s);
}
} }
static void cadence_uart_init(Object *obj) static void cadence_uart_init(Object *obj)

View File

@ -39,7 +39,7 @@
typedef struct DebugconState { typedef struct DebugconState {
MemoryRegion io; MemoryRegion io;
CharDriverState *chr; CharBackend chr;
uint32_t readback; uint32_t readback;
} DebugconState; } DebugconState;
@ -62,7 +62,7 @@ static void debugcon_ioport_write(void *opaque, hwaddr addr, uint64_t val,
/* XXX this blocks entire thread. Rewrite to use /* XXX this blocks entire thread. Rewrite to use
* qemu_chr_fe_write and background I/O callbacks */ * qemu_chr_fe_write and background I/O callbacks */
qemu_chr_fe_write_all(s->chr, &ch, 1); qemu_chr_fe_write_all(&s->chr, &ch, 1);
} }
@ -87,12 +87,12 @@ static const MemoryRegionOps debugcon_ops = {
static void debugcon_realize_core(DebugconState *s, Error **errp) static void debugcon_realize_core(DebugconState *s, Error **errp)
{ {
if (!s->chr) { if (!qemu_chr_fe_get_driver(&s->chr)) {
error_setg(errp, "Can't create debugcon device, empty char device"); error_setg(errp, "Can't create debugcon device, empty char device");
return; return;
} }
qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, s); qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, NULL, s, NULL, true);
} }
static void debugcon_isa_realizefn(DeviceState *dev, Error **errp) static void debugcon_isa_realizefn(DeviceState *dev, Error **errp)

View File

@ -76,11 +76,9 @@ static void digic_uart_write(void *opaque, hwaddr addr, uint64_t value,
switch (addr) { switch (addr) {
case R_TX: case R_TX:
if (s->chr) { /* XXX this blocks entire thread. Rewrite to use
/* XXX this blocks entire thread. Rewrite to use * qemu_chr_fe_write and background I/O callbacks */
* qemu_chr_fe_write and background I/O callbacks */ qemu_chr_fe_write_all(&s->chr, &ch, 1);
qemu_chr_fe_write_all(s->chr, &ch, 1);
}
break; break;
case R_ST: case R_ST:
@ -147,9 +145,8 @@ static void digic_uart_realize(DeviceState *dev, Error **errp)
{ {
DigicUartState *s = DIGIC_UART(dev); DigicUartState *s = DIGIC_UART(dev);
if (s->chr) { qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx,
qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s); uart_event, s, NULL, true);
}
} }
static void digic_uart_init(Object *obj) static void digic_uart_init(Object *obj)

View File

@ -88,7 +88,7 @@ typedef struct ChannelState {
uint32_t reg; uint32_t reg;
uint8_t wregs[SERIAL_REGS], rregs[SERIAL_REGS]; uint8_t wregs[SERIAL_REGS], rregs[SERIAL_REGS];
SERIOQueue queue; SERIOQueue queue;
CharDriverState *chr; CharBackend chr;
int e0_mode, led_mode, caps_lock_mode, num_lock_mode; int e0_mode, led_mode, caps_lock_mode, num_lock_mode;
int disabled; int disabled;
int clock; int clock;
@ -416,7 +416,7 @@ static void escc_update_parameters(ChannelState *s)
int speed, parity, data_bits, stop_bits; int speed, parity, data_bits, stop_bits;
QEMUSerialSetParams ssp; QEMUSerialSetParams ssp;
if (!s->chr || s->type != ser) if (!qemu_chr_fe_get_driver(&s->chr) || s->type != ser)
return; return;
if (s->wregs[W_TXCTRL1] & TXCTRL1_PAREN) { if (s->wregs[W_TXCTRL1] & TXCTRL1_PAREN) {
@ -466,7 +466,7 @@ static void escc_update_parameters(ChannelState *s)
ssp.data_bits = data_bits; ssp.data_bits = data_bits;
ssp.stop_bits = stop_bits; ssp.stop_bits = stop_bits;
trace_escc_update_parameters(CHN_C(s), speed, parity, data_bits, stop_bits); trace_escc_update_parameters(CHN_C(s), speed, parity, data_bits, stop_bits);
qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp); qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
} }
static void escc_mem_write(void *opaque, hwaddr addr, static void escc_mem_write(void *opaque, hwaddr addr,
@ -556,11 +556,11 @@ static void escc_mem_write(void *opaque, hwaddr addr,
trace_escc_mem_writeb_data(CHN_C(s), val); trace_escc_mem_writeb_data(CHN_C(s), val);
s->tx = val; s->tx = val;
if (s->wregs[W_TXCTRL2] & TXCTRL2_TXEN) { // tx enabled if (s->wregs[W_TXCTRL2] & TXCTRL2_TXEN) { // tx enabled
if (s->chr) if (qemu_chr_fe_get_driver(&s->chr)) {
/* XXX this blocks entire thread. Rewrite to use /* XXX this blocks entire thread. Rewrite to use
* qemu_chr_fe_write and background I/O callbacks */ * qemu_chr_fe_write and background I/O callbacks */
qemu_chr_fe_write_all(s->chr, &s->tx, 1); qemu_chr_fe_write_all(&s->chr, &s->tx, 1);
else if (s->type == kbd && !s->disabled) { } else if (s->type == kbd && !s->disabled) {
handle_kbd_command(s, val); handle_kbd_command(s, val);
} }
} }
@ -599,8 +599,7 @@ static uint64_t escc_mem_read(void *opaque, hwaddr addr,
else else
ret = s->rx; ret = s->rx;
trace_escc_mem_readb_data(CHN_C(s), ret); trace_escc_mem_readb_data(CHN_C(s), ret);
if (s->chr) qemu_chr_fe_accept_input(&s->chr);
qemu_chr_accept_input(s->chr);
return ret; return ret;
default: default:
break; break;
@ -1013,10 +1012,11 @@ static void escc_realize(DeviceState *dev, Error **errp)
ESCC_SIZE << s->it_shift); ESCC_SIZE << s->it_shift);
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
if (s->chn[i].chr) { if (qemu_chr_fe_get_driver(&s->chn[i].chr)) {
s->chn[i].clock = s->frequency / 2; s->chn[i].clock = s->frequency / 2;
qemu_chr_add_handlers(s->chn[i].chr, serial_can_receive, qemu_chr_fe_set_handlers(&s->chn[i].chr, serial_can_receive,
serial_receive1, serial_event, &s->chn[i]); serial_receive1, serial_event,
&s->chn[i], NULL, true);
} }
} }

View File

@ -53,7 +53,7 @@ typedef struct ETRAXSerial {
SysBusDevice parent_obj; SysBusDevice parent_obj;
MemoryRegion mmio; MemoryRegion mmio;
CharDriverState *chr; CharBackend chr;
qemu_irq irq; qemu_irq irq;
int pending_tx; int pending_tx;
@ -128,7 +128,7 @@ ser_write(void *opaque, hwaddr addr,
case RW_DOUT: case RW_DOUT:
/* XXX this blocks entire thread. Rewrite to use /* XXX this blocks entire thread. Rewrite to use
* qemu_chr_fe_write and background I/O callbacks */ * qemu_chr_fe_write and background I/O callbacks */
qemu_chr_fe_write_all(s->chr, &ch, 1); qemu_chr_fe_write_all(&s->chr, &ch, 1);
s->regs[R_INTR] |= 3; s->regs[R_INTR] |= 3;
s->pending_tx = 1; s->pending_tx = 1;
s->regs[addr] = value; s->regs[addr] = value;
@ -231,11 +231,9 @@ static void etraxfs_ser_realize(DeviceState *dev, Error **errp)
{ {
ETRAXSerial *s = ETRAX_SERIAL(dev); ETRAXSerial *s = ETRAX_SERIAL(dev);
if (s->chr) { qemu_chr_fe_set_handlers(&s->chr,
qemu_chr_add_handlers(s->chr, serial_can_receive, serial_receive,
serial_can_receive, serial_receive, serial_event, s, NULL, true);
serial_event, s);
}
} }
static void etraxfs_ser_class_init(ObjectClass *klass, void *data) static void etraxfs_ser_class_init(ObjectClass *klass, void *data)

View File

@ -181,7 +181,7 @@ typedef struct Exynos4210UartState {
Exynos4210UartFIFO rx; Exynos4210UartFIFO rx;
Exynos4210UartFIFO tx; Exynos4210UartFIFO tx;
CharDriverState *chr; CharBackend chr;
qemu_irq irq; qemu_irq irq;
uint32_t channel; uint32_t channel;
@ -346,7 +346,7 @@ static void exynos4210_uart_update_parameters(Exynos4210UartState *s)
ssp.data_bits = data_bits; ssp.data_bits = data_bits;
ssp.stop_bits = stop_bits; ssp.stop_bits = stop_bits;
qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp); qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
PRINT_DEBUG("UART%d: speed: %d, parity: %c, data: %d, stop: %d\n", PRINT_DEBUG("UART%d: speed: %d, parity: %c, data: %d, stop: %d\n",
s->channel, speed, parity, data_bits, stop_bits); s->channel, speed, parity, data_bits, stop_bits);
@ -383,13 +383,13 @@ static void exynos4210_uart_write(void *opaque, hwaddr offset,
break; break;
case UTXH: case UTXH:
if (s->chr) { if (qemu_chr_fe_get_driver(&s->chr)) {
s->reg[I_(UTRSTAT)] &= ~(UTRSTAT_TRANSMITTER_EMPTY | s->reg[I_(UTRSTAT)] &= ~(UTRSTAT_TRANSMITTER_EMPTY |
UTRSTAT_Tx_BUFFER_EMPTY); UTRSTAT_Tx_BUFFER_EMPTY);
ch = (uint8_t)val; ch = (uint8_t)val;
/* XXX this blocks entire thread. Rewrite to use /* XXX this blocks entire thread. Rewrite to use
* qemu_chr_fe_write and background I/O callbacks */ * qemu_chr_fe_write and background I/O callbacks */
qemu_chr_fe_write_all(s->chr, &ch, 1); qemu_chr_fe_write_all(&s->chr, &ch, 1);
#if DEBUG_Tx_DATA #if DEBUG_Tx_DATA
fprintf(stderr, "%c", ch); fprintf(stderr, "%c", ch);
#endif #endif
@ -606,7 +606,7 @@ DeviceState *exynos4210_uart_create(hwaddr addr,
chr = serial_hds[channel]; chr = serial_hds[channel];
if (!chr) { if (!chr) {
snprintf(label, ARRAY_SIZE(label), "%s%d", chr_name, channel); snprintf(label, ARRAY_SIZE(label), "%s%d", chr_name, channel);
chr = qemu_chr_new(label, "null", NULL); chr = qemu_chr_new(label, "null");
if (!(chr)) { if (!(chr)) {
error_report("Can't assign serial port to UART%d", channel); error_report("Can't assign serial port to UART%d", channel);
exit(1); exit(1);
@ -640,8 +640,9 @@ static int exynos4210_uart_init(SysBusDevice *dev)
sysbus_init_irq(dev, &s->irq); sysbus_init_irq(dev, &s->irq);
qemu_chr_add_handlers(s->chr, exynos4210_uart_can_receive, qemu_chr_fe_set_handlers(&s->chr, exynos4210_uart_can_receive,
exynos4210_uart_receive, exynos4210_uart_event, s); exynos4210_uart_receive, exynos4210_uart_event,
s, NULL, true);
return 0; return 0;
} }

View File

@ -78,7 +78,7 @@ typedef struct UART {
MemoryRegion iomem; MemoryRegion iomem;
qemu_irq irq; qemu_irq irq;
CharDriverState *chr; CharBackend chr;
/* registers */ /* registers */
uint32_t status; uint32_t status;
@ -201,11 +201,12 @@ static void grlib_apbuart_write(void *opaque, hwaddr addr,
case DATA_OFFSET: case DATA_OFFSET:
case DATA_OFFSET + 3: /* When only one byte write */ case DATA_OFFSET + 3: /* When only one byte write */
/* Transmit when character device available and transmitter enabled */ /* Transmit when character device available and transmitter enabled */
if ((uart->chr) && (uart->control & UART_TRANSMIT_ENABLE)) { if (qemu_chr_fe_get_driver(&uart->chr) &&
(uart->control & UART_TRANSMIT_ENABLE)) {
c = value & 0xFF; c = value & 0xFF;
/* XXX this blocks entire thread. Rewrite to use /* XXX this blocks entire thread. Rewrite to use
* qemu_chr_fe_write and background I/O callbacks */ * qemu_chr_fe_write and background I/O callbacks */
qemu_chr_fe_write_all(uart->chr, &c, 1); qemu_chr_fe_write_all(&uart->chr, &c, 1);
/* Generate interrupt */ /* Generate interrupt */
if (uart->control & UART_TRANSMIT_INTERRUPT) { if (uart->control & UART_TRANSMIT_INTERRUPT) {
qemu_irq_pulse(uart->irq); qemu_irq_pulse(uart->irq);
@ -242,11 +243,11 @@ static int grlib_apbuart_init(SysBusDevice *dev)
{ {
UART *uart = GRLIB_APB_UART(dev); UART *uart = GRLIB_APB_UART(dev);
qemu_chr_add_handlers(uart->chr, qemu_chr_fe_set_handlers(&uart->chr,
grlib_apbuart_can_receive, grlib_apbuart_can_receive,
grlib_apbuart_receive, grlib_apbuart_receive,
grlib_apbuart_event, grlib_apbuart_event,
uart); uart, NULL, true);
sysbus_init_irq(dev, &uart->irq); sysbus_init_irq(dev, &uart->irq);

View File

@ -121,9 +121,7 @@ static uint64_t imx_serial_read(void *opaque, hwaddr offset,
s->usr2 &= ~USR2_RDR; s->usr2 &= ~USR2_RDR;
s->uts1 |= UTS1_RXEMPTY; s->uts1 |= UTS1_RXEMPTY;
imx_update(s); imx_update(s);
if (s->chr) { qemu_chr_fe_accept_input(&s->chr);
qemu_chr_accept_input(s->chr);
}
} }
return c; return c;
@ -172,20 +170,19 @@ static void imx_serial_write(void *opaque, hwaddr offset,
uint64_t value, unsigned size) uint64_t value, unsigned size)
{ {
IMXSerialState *s = (IMXSerialState *)opaque; IMXSerialState *s = (IMXSerialState *)opaque;
CharDriverState *chr = qemu_chr_fe_get_driver(&s->chr);
unsigned char ch; unsigned char ch;
DPRINTF("write(offset=0x%" HWADDR_PRIx ", value = 0x%x) to %s\n", DPRINTF("write(offset=0x%" HWADDR_PRIx ", value = 0x%x) to %s\n",
offset, (unsigned int)value, s->chr ? s->chr->label : "NODEV"); offset, (unsigned int)value, chr ? chr->label : "NODEV");
switch (offset >> 2) { switch (offset >> 2) {
case 0x10: /* UTXD */ case 0x10: /* UTXD */
ch = value; ch = value;
if (s->ucr2 & UCR2_TXEN) { if (s->ucr2 & UCR2_TXEN) {
if (s->chr) { /* XXX this blocks entire thread. Rewrite to use
/* XXX this blocks entire thread. Rewrite to use * qemu_chr_fe_write and background I/O callbacks */
* qemu_chr_fe_write and background I/O callbacks */ qemu_chr_fe_write_all(&s->chr, &ch, 1);
qemu_chr_fe_write_all(s->chr, &ch, 1);
}
s->usr1 &= ~USR1_TRDY; s->usr1 &= ~USR1_TRDY;
imx_update(s); imx_update(s);
s->usr1 |= USR1_TRDY; s->usr1 |= USR1_TRDY;
@ -214,9 +211,7 @@ static void imx_serial_write(void *opaque, hwaddr offset,
} }
if (value & UCR2_RXEN) { if (value & UCR2_RXEN) {
if (!(s->ucr2 & UCR2_RXEN)) { if (!(s->ucr2 & UCR2_RXEN)) {
if (s->chr) { qemu_chr_fe_accept_input(&s->chr);
qemu_chr_accept_input(s->chr);
}
} }
} }
s->ucr2 = value & 0xffff; s->ucr2 = value & 0xffff;
@ -318,12 +313,10 @@ static void imx_serial_realize(DeviceState *dev, Error **errp)
{ {
IMXSerialState *s = IMX_SERIAL(dev); IMXSerialState *s = IMX_SERIAL(dev);
if (s->chr) { DPRINTF("char dev for uart: %p\n", qemu_chr_fe_get_driver(&s->chr));
qemu_chr_add_handlers(s->chr, imx_can_receive, imx_receive,
imx_event, s); qemu_chr_fe_set_handlers(&s->chr, imx_can_receive, imx_receive,
} else { imx_event, s, NULL, true);
DPRINTF("No char dev for uart\n");
}
} }
static void imx_serial_init(Object *obj) static void imx_serial_init(Object *obj)

View File

@ -93,7 +93,7 @@ typedef struct SCC2698Block SCC2698Block;
struct SCC2698Channel { struct SCC2698Channel {
IPOctalState *ipoctal; IPOctalState *ipoctal;
CharDriverState *dev; CharBackend dev;
bool rx_enabled; bool rx_enabled;
uint8_t mr[2]; uint8_t mr[2];
uint8_t mr_idx; uint8_t mr_idx;
@ -288,9 +288,7 @@ static uint16_t io_read(IPackDevice *ip, uint8_t addr)
if (ch->rx_pending == 0) { if (ch->rx_pending == 0) {
ch->sr &= ~SR_RXRDY; ch->sr &= ~SR_RXRDY;
blk->isr &= ~ISR_RXRDY(channel); blk->isr &= ~ISR_RXRDY(channel);
if (ch->dev) { qemu_chr_fe_accept_input(&ch->dev);
qemu_chr_accept_input(ch->dev);
}
} else { } else {
ch->rhr_idx = (ch->rhr_idx + 1) % RX_FIFO_SIZE; ch->rhr_idx = (ch->rhr_idx + 1) % RX_FIFO_SIZE;
} }
@ -357,13 +355,11 @@ static void io_write(IPackDevice *ip, uint8_t addr, uint16_t val)
case REG_THRa: case REG_THRa:
case REG_THRb: case REG_THRb:
if (ch->sr & SR_TXRDY) { if (ch->sr & SR_TXRDY) {
uint8_t thr = reg;
DPRINTF("Write THR%c (0x%x)\n", channel + 'a', reg); DPRINTF("Write THR%c (0x%x)\n", channel + 'a', reg);
if (ch->dev) { /* XXX this blocks entire thread. Rewrite to use
uint8_t thr = reg; * qemu_chr_fe_write and background I/O callbacks */
/* XXX this blocks entire thread. Rewrite to use qemu_chr_fe_write_all(&ch->dev, &thr, 1);
* qemu_chr_fe_write and background I/O callbacks */
qemu_chr_fe_write_all(ch->dev, &thr, 1);
}
} else { } else {
DPRINTF("Write THR%c (0x%x), Tx disabled\n", channel + 'a', reg); DPRINTF("Write THR%c (0x%x), Tx disabled\n", channel + 'a', reg);
} }
@ -546,9 +542,10 @@ static void ipoctal_realize(DeviceState *dev, Error **errp)
ch->ipoctal = s; ch->ipoctal = s;
/* Redirect IP-Octal channels to host character devices */ /* Redirect IP-Octal channels to host character devices */
if (ch->dev) { if (qemu_chr_fe_get_driver(&ch->dev)) {
qemu_chr_add_handlers(ch->dev, hostdev_can_receive, qemu_chr_fe_set_handlers(&ch->dev, hostdev_can_receive,
hostdev_receive, hostdev_event, ch); hostdev_receive, hostdev_event,
ch, NULL, true);
DPRINTF("Redirecting channel %u to %s\n", i, ch->dev->label); DPRINTF("Redirecting channel %u to %s\n", i, ch->dev->label);
} else { } else {
DPRINTF("Could not redirect channel %u, no chardev set\n", i); DPRINTF("Could not redirect channel %u, no chardev set\n", i);

View File

@ -44,7 +44,7 @@ enum {
struct LM32JuartState { struct LM32JuartState {
SysBusDevice parent_obj; SysBusDevice parent_obj;
CharDriverState *chr; CharBackend chr;
uint32_t jtx; uint32_t jtx;
uint32_t jrx; uint32_t jrx;
@ -75,11 +75,9 @@ void lm32_juart_set_jtx(DeviceState *d, uint32_t jtx)
trace_lm32_juart_set_jtx(s->jtx); trace_lm32_juart_set_jtx(s->jtx);
s->jtx = jtx; s->jtx = jtx;
if (s->chr) { /* XXX this blocks entire thread. Rewrite to use
/* XXX this blocks entire thread. Rewrite to use * qemu_chr_fe_write and background I/O callbacks */
* qemu_chr_fe_write and background I/O callbacks */ qemu_chr_fe_write_all(&s->chr, &ch, 1);
qemu_chr_fe_write_all(s->chr, &ch, 1);
}
} }
void lm32_juart_set_jrx(DeviceState *d, uint32_t jtx) void lm32_juart_set_jrx(DeviceState *d, uint32_t jtx)
@ -120,9 +118,8 @@ static void lm32_juart_realize(DeviceState *dev, Error **errp)
{ {
LM32JuartState *s = LM32_JUART(dev); LM32JuartState *s = LM32_JUART(dev);
if (s->chr) { qemu_chr_fe_set_handlers(&s->chr, juart_can_rx, juart_rx,
qemu_chr_add_handlers(s->chr, juart_can_rx, juart_rx, juart_event, s); juart_event, s, NULL, true);
}
} }
static const VMStateDescription vmstate_lm32_juart = { static const VMStateDescription vmstate_lm32_juart = {

View File

@ -97,7 +97,7 @@ struct LM32UartState {
SysBusDevice parent_obj; SysBusDevice parent_obj;
MemoryRegion iomem; MemoryRegion iomem;
CharDriverState *chr; CharBackend chr;
qemu_irq irq; qemu_irq irq;
uint32_t regs[R_MAX]; uint32_t regs[R_MAX];
@ -142,7 +142,7 @@ static uint64_t uart_read(void *opaque, hwaddr addr,
r = s->regs[R_RXTX]; r = s->regs[R_RXTX];
s->regs[R_LSR] &= ~LSR_DR; s->regs[R_LSR] &= ~LSR_DR;
uart_update_irq(s); uart_update_irq(s);
qemu_chr_accept_input(s->chr); qemu_chr_fe_accept_input(&s->chr);
break; break;
case R_IIR: case R_IIR:
case R_LSR: case R_LSR:
@ -177,11 +177,9 @@ static void uart_write(void *opaque, hwaddr addr,
addr >>= 2; addr >>= 2;
switch (addr) { switch (addr) {
case R_RXTX: case R_RXTX:
if (s->chr) { /* XXX this blocks entire thread. Rewrite to use
/* XXX this blocks entire thread. Rewrite to use * qemu_chr_fe_write and background I/O callbacks */
* qemu_chr_fe_write and background I/O callbacks */ qemu_chr_fe_write_all(&s->chr, &ch, 1);
qemu_chr_fe_write_all(s->chr, &ch, 1);
}
break; break;
case R_IER: case R_IER:
case R_LCR: case R_LCR:
@ -267,9 +265,8 @@ static void lm32_uart_realize(DeviceState *dev, Error **errp)
{ {
LM32UartState *s = LM32_UART(dev); LM32UartState *s = LM32_UART(dev);
if (s->chr) { qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx,
qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s); uart_event, s, NULL, true);
}
} }
static const VMStateDescription vmstate_lm32_uart = { static const VMStateDescription vmstate_lm32_uart = {

View File

@ -10,6 +10,7 @@
#include "hw/m68k/mcf.h" #include "hw/m68k/mcf.h"
#include "sysemu/char.h" #include "sysemu/char.h"
#include "exec/address-spaces.h" #include "exec/address-spaces.h"
#include "qapi/error.h"
typedef struct { typedef struct {
MemoryRegion iomem; MemoryRegion iomem;
@ -26,7 +27,7 @@ typedef struct {
int tx_enabled; int tx_enabled;
int rx_enabled; int rx_enabled;
qemu_irq irq; qemu_irq irq;
CharDriverState *chr; CharBackend chr;
} mcf_uart_state; } mcf_uart_state;
/* UART Status Register bits. */ /* UART Status Register bits. */
@ -92,7 +93,7 @@ uint64_t mcf_uart_read(void *opaque, hwaddr addr,
if (s->fifo_len == 0) if (s->fifo_len == 0)
s->sr &= ~MCF_UART_RxRDY; s->sr &= ~MCF_UART_RxRDY;
mcf_uart_update(s); mcf_uart_update(s);
qemu_chr_accept_input(s->chr); qemu_chr_fe_accept_input(&s->chr);
return val; return val;
} }
case 0x10: case 0x10:
@ -113,10 +114,9 @@ uint64_t mcf_uart_read(void *opaque, hwaddr addr,
static void mcf_uart_do_tx(mcf_uart_state *s) static void mcf_uart_do_tx(mcf_uart_state *s)
{ {
if (s->tx_enabled && (s->sr & MCF_UART_TxEMP) == 0) { if (s->tx_enabled && (s->sr & MCF_UART_TxEMP) == 0) {
if (s->chr) /* XXX this blocks entire thread. Rewrite to use
/* XXX this blocks entire thread. Rewrite to use * qemu_chr_fe_write and background I/O callbacks */
* qemu_chr_fe_write and background I/O callbacks */ qemu_chr_fe_write_all(&s->chr, (unsigned char *)&s->tb, 1);
qemu_chr_fe_write_all(s->chr, (unsigned char *)&s->tb, 1);
s->sr |= MCF_UART_TxEMP; s->sr |= MCF_UART_TxEMP;
} }
if (s->tx_enabled) { if (s->tx_enabled) {
@ -280,12 +280,12 @@ void *mcf_uart_init(qemu_irq irq, CharDriverState *chr)
mcf_uart_state *s; mcf_uart_state *s;
s = g_malloc0(sizeof(mcf_uart_state)); s = g_malloc0(sizeof(mcf_uart_state));
s->chr = chr;
s->irq = irq; s->irq = irq;
if (chr) { if (chr) {
qemu_chr_fe_claim_no_fail(chr); qemu_chr_fe_init(&s->chr, chr, &error_abort);
qemu_chr_add_handlers(chr, mcf_uart_can_receive, mcf_uart_receive, qemu_chr_fe_set_handlers(&s->chr, mcf_uart_can_receive,
mcf_uart_event, s); mcf_uart_receive, mcf_uart_event,
s, NULL, true);
} }
mcf_uart_reset(s); mcf_uart_reset(s);
return s; return s;

View File

@ -61,7 +61,7 @@ struct MilkymistUartState {
SysBusDevice parent_obj; SysBusDevice parent_obj;
MemoryRegion regs_region; MemoryRegion regs_region;
CharDriverState *chr; CharBackend chr;
qemu_irq irq; qemu_irq irq;
uint32_t regs[R_MAX]; uint32_t regs[R_MAX];
@ -124,9 +124,7 @@ static void uart_write(void *opaque, hwaddr addr, uint64_t value,
addr >>= 2; addr >>= 2;
switch (addr) { switch (addr) {
case R_RXTX: case R_RXTX:
if (s->chr) { qemu_chr_fe_write_all(&s->chr, &ch, 1);
qemu_chr_fe_write_all(s->chr, &ch, 1);
}
s->regs[R_STAT] |= STAT_TX_EVT; s->regs[R_STAT] |= STAT_TX_EVT;
break; break;
case R_DIV: case R_DIV:
@ -138,7 +136,7 @@ static void uart_write(void *opaque, hwaddr addr, uint64_t value,
case R_STAT: case R_STAT:
/* write one to clear bits */ /* write one to clear bits */
s->regs[addr] &= ~(value & (STAT_RX_EVT | STAT_TX_EVT)); s->regs[addr] &= ~(value & (STAT_RX_EVT | STAT_TX_EVT));
qemu_chr_accept_input(s->chr); qemu_chr_fe_accept_input(&s->chr);
break; break;
default: default:
@ -200,9 +198,8 @@ static void milkymist_uart_realize(DeviceState *dev, Error **errp)
{ {
MilkymistUartState *s = MILKYMIST_UART(dev); MilkymistUartState *s = MILKYMIST_UART(dev);
if (s->chr) { qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx,
qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s); uart_event, s, NULL, true);
}
} }
static void milkymist_uart_init(Object *obj) static void milkymist_uart_init(Object *obj)

View File

@ -63,7 +63,7 @@ struct omap_uart_s *omap_uart_init(hwaddr base,
s->irq = irq; s->irq = irq;
s->serial = serial_mm_init(get_system_memory(), base, 2, irq, s->serial = serial_mm_init(get_system_memory(), base, 2, irq,
omap_clk_getrate(fclk)/16, omap_clk_getrate(fclk)/16,
chr ?: qemu_chr_new(label, "null", NULL), chr ?: qemu_chr_new(label, "null"),
DEVICE_NATIVE_ENDIAN); DEVICE_NATIVE_ENDIAN);
return s; return s;
} }
@ -183,6 +183,6 @@ void omap_uart_attach(struct omap_uart_s *s, CharDriverState *chr)
/* TODO: Should reuse or destroy current s->serial */ /* TODO: Should reuse or destroy current s->serial */
s->serial = serial_mm_init(get_system_memory(), s->base, 2, s->irq, s->serial = serial_mm_init(get_system_memory(), s->base, 2, s->irq,
omap_clk_getrate(s->fclk) / 16, omap_clk_getrate(s->fclk) / 16,
chr ?: qemu_chr_new("null", "null", NULL), chr ?: qemu_chr_new("null", "null"),
DEVICE_NATIVE_ENDIAN); DEVICE_NATIVE_ENDIAN);
} }

View File

@ -74,7 +74,7 @@ typedef struct ParallelState {
uint8_t control; uint8_t control;
qemu_irq irq; qemu_irq irq;
int irq_pending; int irq_pending;
CharDriverState *chr; CharBackend chr;
int hw_driver; int hw_driver;
int epp_timeout; int epp_timeout;
uint32_t last_read_offset; /* For debugging */ uint32_t last_read_offset; /* For debugging */
@ -131,7 +131,7 @@ parallel_ioport_write_sw(void *opaque, uint32_t addr, uint32_t val)
if ((s->control & PARA_CTR_STROBE) == 0) if ((s->control & PARA_CTR_STROBE) == 0)
/* XXX this blocks entire thread. Rewrite to use /* XXX this blocks entire thread. Rewrite to use
* qemu_chr_fe_write and background I/O callbacks */ * qemu_chr_fe_write and background I/O callbacks */
qemu_chr_fe_write_all(s->chr, &s->dataw, 1); qemu_chr_fe_write_all(&s->chr, &s->dataw, 1);
} else { } else {
if (s->control & PARA_CTR_INTEN) { if (s->control & PARA_CTR_INTEN) {
s->irq_pending = 1; s->irq_pending = 1;
@ -161,7 +161,7 @@ static void parallel_ioport_write_hw(void *opaque, uint32_t addr, uint32_t val)
if (s->dataw == val) if (s->dataw == val)
return; return;
pdebug("wd%02x\n", val); pdebug("wd%02x\n", val);
qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_WRITE_DATA, &parm); qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_PP_WRITE_DATA, &parm);
s->dataw = val; s->dataw = val;
break; break;
case PARA_REG_STS: case PARA_REG_STS:
@ -181,11 +181,11 @@ static void parallel_ioport_write_hw(void *opaque, uint32_t addr, uint32_t val)
} else { } else {
dir = 0; dir = 0;
} }
qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_DATA_DIR, &dir); qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_PP_DATA_DIR, &dir);
parm &= ~PARA_CTR_DIR; parm &= ~PARA_CTR_DIR;
} }
qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_WRITE_CONTROL, &parm); qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_PP_WRITE_CONTROL, &parm);
s->control = val; s->control = val;
break; break;
case PARA_REG_EPP_ADDR: case PARA_REG_EPP_ADDR:
@ -194,7 +194,8 @@ static void parallel_ioport_write_hw(void *opaque, uint32_t addr, uint32_t val)
pdebug("wa%02x s\n", val); pdebug("wa%02x s\n", val);
else { else {
struct ParallelIOArg ioarg = { .buffer = &parm, .count = 1 }; struct ParallelIOArg ioarg = { .buffer = &parm, .count = 1 };
if (qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE_ADDR, &ioarg)) { if (qemu_chr_fe_ioctl(&s->chr,
CHR_IOCTL_PP_EPP_WRITE_ADDR, &ioarg)) {
s->epp_timeout = 1; s->epp_timeout = 1;
pdebug("wa%02x t\n", val); pdebug("wa%02x t\n", val);
} }
@ -208,7 +209,7 @@ static void parallel_ioport_write_hw(void *opaque, uint32_t addr, uint32_t val)
pdebug("we%02x s\n", val); pdebug("we%02x s\n", val);
else { else {
struct ParallelIOArg ioarg = { .buffer = &parm, .count = 1 }; struct ParallelIOArg ioarg = { .buffer = &parm, .count = 1 };
if (qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg)) { if (qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg)) {
s->epp_timeout = 1; s->epp_timeout = 1;
pdebug("we%02x t\n", val); pdebug("we%02x t\n", val);
} }
@ -233,7 +234,7 @@ parallel_ioport_eppdata_write_hw2(void *opaque, uint32_t addr, uint32_t val)
pdebug("we%04x s\n", val); pdebug("we%04x s\n", val);
return; return;
} }
err = qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg); err = qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg);
if (err) { if (err) {
s->epp_timeout = 1; s->epp_timeout = 1;
pdebug("we%04x t\n", val); pdebug("we%04x t\n", val);
@ -256,7 +257,7 @@ parallel_ioport_eppdata_write_hw4(void *opaque, uint32_t addr, uint32_t val)
pdebug("we%08x s\n", val); pdebug("we%08x s\n", val);
return; return;
} }
err = qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg); err = qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg);
if (err) { if (err) {
s->epp_timeout = 1; s->epp_timeout = 1;
pdebug("we%08x t\n", val); pdebug("we%08x t\n", val);
@ -308,13 +309,13 @@ static uint32_t parallel_ioport_read_hw(void *opaque, uint32_t addr)
addr &= 7; addr &= 7;
switch(addr) { switch(addr) {
case PARA_REG_DATA: case PARA_REG_DATA:
qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_READ_DATA, &ret); qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_PP_READ_DATA, &ret);
if (s->last_read_offset != addr || s->datar != ret) if (s->last_read_offset != addr || s->datar != ret)
pdebug("rd%02x\n", ret); pdebug("rd%02x\n", ret);
s->datar = ret; s->datar = ret;
break; break;
case PARA_REG_STS: case PARA_REG_STS:
qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_READ_STATUS, &ret); qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_PP_READ_STATUS, &ret);
ret &= ~PARA_STS_TMOUT; ret &= ~PARA_STS_TMOUT;
if (s->epp_timeout) if (s->epp_timeout)
ret |= PARA_STS_TMOUT; ret |= PARA_STS_TMOUT;
@ -326,7 +327,7 @@ static uint32_t parallel_ioport_read_hw(void *opaque, uint32_t addr)
/* s->control has some bits fixed to 1. It is zero only when /* s->control has some bits fixed to 1. It is zero only when
it has not been yet written to. */ it has not been yet written to. */
if (s->control == 0) { if (s->control == 0) {
qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_READ_CONTROL, &ret); qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_PP_READ_CONTROL, &ret);
if (s->last_read_offset != addr) if (s->last_read_offset != addr)
pdebug("rc%02x\n", ret); pdebug("rc%02x\n", ret);
s->control = ret; s->control = ret;
@ -338,12 +339,14 @@ static uint32_t parallel_ioport_read_hw(void *opaque, uint32_t addr)
} }
break; break;
case PARA_REG_EPP_ADDR: case PARA_REG_EPP_ADDR:
if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT)) if ((s->control & (PARA_CTR_DIR | PARA_CTR_SIGNAL)) !=
(PARA_CTR_DIR | PARA_CTR_INIT))
/* Controls not correct for EPP addr cycle, so do nothing */ /* Controls not correct for EPP addr cycle, so do nothing */
pdebug("ra%02x s\n", ret); pdebug("ra%02x s\n", ret);
else { else {
struct ParallelIOArg ioarg = { .buffer = &ret, .count = 1 }; struct ParallelIOArg ioarg = { .buffer = &ret, .count = 1 };
if (qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ_ADDR, &ioarg)) { if (qemu_chr_fe_ioctl(&s->chr,
CHR_IOCTL_PP_EPP_READ_ADDR, &ioarg)) {
s->epp_timeout = 1; s->epp_timeout = 1;
pdebug("ra%02x t\n", ret); pdebug("ra%02x t\n", ret);
} }
@ -352,12 +355,13 @@ static uint32_t parallel_ioport_read_hw(void *opaque, uint32_t addr)
} }
break; break;
case PARA_REG_EPP_DATA: case PARA_REG_EPP_DATA:
if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT)) if ((s->control & (PARA_CTR_DIR | PARA_CTR_SIGNAL)) !=
(PARA_CTR_DIR | PARA_CTR_INIT))
/* Controls not correct for EPP data cycle, so do nothing */ /* Controls not correct for EPP data cycle, so do nothing */
pdebug("re%02x s\n", ret); pdebug("re%02x s\n", ret);
else { else {
struct ParallelIOArg ioarg = { .buffer = &ret, .count = 1 }; struct ParallelIOArg ioarg = { .buffer = &ret, .count = 1 };
if (qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg)) { if (qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg)) {
s->epp_timeout = 1; s->epp_timeout = 1;
pdebug("re%02x t\n", ret); pdebug("re%02x t\n", ret);
} }
@ -385,7 +389,7 @@ parallel_ioport_eppdata_read_hw2(void *opaque, uint32_t addr)
pdebug("re%04x s\n", eppdata); pdebug("re%04x s\n", eppdata);
return eppdata; return eppdata;
} }
err = qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg); err = qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg);
ret = le16_to_cpu(eppdata); ret = le16_to_cpu(eppdata);
if (err) { if (err) {
@ -412,7 +416,7 @@ parallel_ioport_eppdata_read_hw4(void *opaque, uint32_t addr)
pdebug("re%08x s\n", eppdata); pdebug("re%08x s\n", eppdata);
return eppdata; return eppdata;
} }
err = qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg); err = qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg);
ret = le32_to_cpu(eppdata); ret = le32_to_cpu(eppdata);
if (err) { if (err) {
@ -508,7 +512,7 @@ static void parallel_isa_realizefn(DeviceState *dev, Error **errp)
int base; int base;
uint8_t dummy; uint8_t dummy;
if (!s->chr) { if (!qemu_chr_fe_get_driver(&s->chr)) {
error_setg(errp, "Can't create parallel device, empty char device"); error_setg(errp, "Can't create parallel device, empty char device");
return; return;
} }
@ -530,7 +534,7 @@ static void parallel_isa_realizefn(DeviceState *dev, Error **errp)
isa_init_irq(isadev, &s->irq, isa->isairq); isa_init_irq(isadev, &s->irq, isa->isairq);
qemu_register_reset(parallel_reset, s); qemu_register_reset(parallel_reset, s);
if (qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_READ_STATUS, &dummy) == 0) { if (qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_PP_READ_STATUS, &dummy) == 0) {
s->hw_driver = 1; s->hw_driver = 1;
s->status = dummy; s->status = dummy;
} }
@ -605,7 +609,7 @@ bool parallel_mm_init(MemoryRegion *address_space,
s = g_malloc0(sizeof(ParallelState)); s = g_malloc0(sizeof(ParallelState));
s->irq = irq; s->irq = irq;
s->chr = chr; qemu_chr_fe_init(&s->chr, chr, &error_abort);
s->it_shift = it_shift; s->it_shift = it_shift;
qemu_register_reset(parallel_reset, s); qemu_register_reset(parallel_reset, s);

View File

@ -36,7 +36,7 @@ typedef struct PL011State {
int read_pos; int read_pos;
int read_count; int read_count;
int read_trigger; int read_trigger;
CharDriverState *chr; CharBackend chr;
qemu_irq irq; qemu_irq irq;
const unsigned char *id; const unsigned char *id;
} PL011State; } PL011State;
@ -87,9 +87,7 @@ static uint64_t pl011_read(void *opaque, hwaddr offset,
trace_pl011_read_fifo(s->read_count); trace_pl011_read_fifo(s->read_count);
s->rsr = c >> 8; s->rsr = c >> 8;
pl011_update(s); pl011_update(s);
if (s->chr) { qemu_chr_fe_accept_input(&s->chr);
qemu_chr_accept_input(s->chr);
}
r = c; r = c;
break; break;
case 1: /* UARTRSR */ case 1: /* UARTRSR */
@ -168,10 +166,9 @@ static void pl011_write(void *opaque, hwaddr offset,
case 0: /* UARTDR */ case 0: /* UARTDR */
/* ??? Check if transmitter is enabled. */ /* ??? Check if transmitter is enabled. */
ch = value; ch = value;
if (s->chr) /* XXX this blocks entire thread. Rewrite to use
/* XXX this blocks entire thread. Rewrite to use * qemu_chr_fe_write and background I/O callbacks */
* qemu_chr_fe_write and background I/O callbacks */ qemu_chr_fe_write_all(&s->chr, &ch, 1);
qemu_chr_fe_write_all(s->chr, &ch, 1);
s->int_level |= PL011_INT_TX; s->int_level |= PL011_INT_TX;
pl011_update(s); pl011_update(s);
break; break;
@ -331,10 +328,8 @@ static void pl011_realize(DeviceState *dev, Error **errp)
{ {
PL011State *s = PL011(dev); PL011State *s = PL011(dev);
if (s->chr) { qemu_chr_fe_set_handlers(&s->chr, pl011_can_receive, pl011_receive,
qemu_chr_add_handlers(s->chr, pl011_can_receive, pl011_receive, pl011_event, s, NULL, true);
pl011_event, s);
}
} }
static void pl011_class_init(ObjectClass *oc, void *data) static void pl011_class_init(ObjectClass *oc, void *data)

View File

@ -37,7 +37,7 @@ typedef struct OprtnsCommand {
typedef struct SCLPConsoleLM { typedef struct SCLPConsoleLM {
SCLPEvent event; SCLPEvent event;
CharDriverState *chr; CharBackend chr;
bool echo; /* immediate echo of input if true */ bool echo; /* immediate echo of input if true */
uint32_t write_errors; /* errors writing to char layer */ uint32_t write_errors; /* errors writing to char layer */
uint32_t length; /* length of byte stream in buffer */ uint32_t length; /* length of byte stream in buffer */
@ -91,7 +91,7 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
if (scon->echo) { if (scon->echo) {
/* XXX this blocks entire thread. Rewrite to use /* XXX this blocks entire thread. Rewrite to use
* qemu_chr_fe_write and background I/O callbacks */ * qemu_chr_fe_write and background I/O callbacks */
qemu_chr_fe_write_all(scon->chr, buf, size); qemu_chr_fe_write_all(&scon->chr, buf, size);
} }
} }
@ -195,14 +195,14 @@ static int write_console_data(SCLPEvent *event, const uint8_t *buf, int len)
{ {
SCLPConsoleLM *scon = SCLPLM_CONSOLE(event); SCLPConsoleLM *scon = SCLPLM_CONSOLE(event);
if (!scon->chr) { if (!qemu_chr_fe_get_driver(&scon->chr)) {
/* If there's no backend, we can just say we consumed all data. */ /* If there's no backend, we can just say we consumed all data. */
return len; return len;
} }
/* XXX this blocks entire thread. Rewrite to use /* XXX this blocks entire thread. Rewrite to use
* qemu_chr_fe_write and background I/O callbacks */ * qemu_chr_fe_write and background I/O callbacks */
return qemu_chr_fe_write_all(scon->chr, buf, len); return qemu_chr_fe_write_all(&scon->chr, buf, len);
} }
static int process_mdb(SCLPEvent *event, MDBO *mdbo) static int process_mdb(SCLPEvent *event, MDBO *mdbo)
@ -312,9 +312,8 @@ static int console_init(SCLPEvent *event)
} }
console_available = true; console_available = true;
if (scon->chr) { qemu_chr_fe_set_handlers(&scon->chr, chr_can_read,
qemu_chr_add_handlers(scon->chr, chr_can_read, chr_read, NULL, scon); chr_read, NULL, scon, NULL, true);
}
return 0; return 0;
} }

View File

@ -31,7 +31,7 @@ typedef struct ASCIIConsoleData {
typedef struct SCLPConsole { typedef struct SCLPConsole {
SCLPEvent event; SCLPEvent event;
CharDriverState *chr; CharBackend chr;
uint8_t iov[SIZE_BUFFER_VT220]; uint8_t iov[SIZE_BUFFER_VT220];
uint32_t iov_sclp; /* offset in buf for SCLP read operation */ uint32_t iov_sclp; /* offset in buf for SCLP read operation */
uint32_t iov_bs; /* offset in buf for char layer read operation */ uint32_t iov_bs; /* offset in buf for char layer read operation */
@ -163,14 +163,14 @@ static ssize_t write_console_data(SCLPEvent *event, const uint8_t *buf,
{ {
SCLPConsole *scon = SCLP_CONSOLE(event); SCLPConsole *scon = SCLP_CONSOLE(event);
if (!scon->chr) { if (!qemu_chr_fe_get_driver(&scon->chr)) {
/* If there's no backend, we can just say we consumed all data. */ /* If there's no backend, we can just say we consumed all data. */
return len; return len;
} }
/* XXX this blocks entire thread. Rewrite to use /* XXX this blocks entire thread. Rewrite to use
* qemu_chr_fe_write and background I/O callbacks */ * qemu_chr_fe_write and background I/O callbacks */
return qemu_chr_fe_write_all(scon->chr, buf, len); return qemu_chr_fe_write_all(&scon->chr, buf, len);
} }
static int write_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr) static int write_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr)
@ -227,10 +227,8 @@ static int console_init(SCLPEvent *event)
return -1; return -1;
} }
console_available = true; console_available = true;
if (scon->chr) { qemu_chr_fe_set_handlers(&scon->chr, chr_can_read,
qemu_chr_add_handlers(scon->chr, chr_can_read, chr_read, NULL, scon, NULL, true);
chr_read, NULL, scon);
}
return 0; return 0;
} }

View File

@ -133,13 +133,14 @@ static void serial_isa_init(ISABus *bus, int index, CharDriverState *chr)
qdev_init_nofail(dev); qdev_init_nofail(dev);
} }
void serial_hds_isa_init(ISABus *bus, int n) void serial_hds_isa_init(ISABus *bus, int from, int to)
{ {
int i; int i;
assert(n <= MAX_SERIAL_PORTS); assert(from >= 0);
assert(to <= MAX_SERIAL_PORTS);
for (i = 0; i < n; ++i) { for (i = from; i < to; ++i) {
if (serial_hds[i]) { if (serial_hds[i]) {
serial_isa_init(bus, i, serial_hds[i]); serial_isa_init(bus, i, serial_hds[i]);
} }

View File

@ -153,8 +153,9 @@ static void serial_update_parameters(SerialState *s)
int speed, parity, data_bits, stop_bits, frame_size; int speed, parity, data_bits, stop_bits, frame_size;
QEMUSerialSetParams ssp; QEMUSerialSetParams ssp;
if (s->divider == 0) if (s->divider == 0 || s->divider > s->baudbase) {
return; return;
}
/* Start bit. */ /* Start bit. */
frame_size = 1; frame_size = 1;
@ -181,7 +182,7 @@ static void serial_update_parameters(SerialState *s)
ssp.data_bits = data_bits; ssp.data_bits = data_bits;
ssp.stop_bits = stop_bits; ssp.stop_bits = stop_bits;
s->char_transmit_time = (NANOSECONDS_PER_SECOND / speed) * frame_size; s->char_transmit_time = (NANOSECONDS_PER_SECOND / speed) * frame_size;
qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp); qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
DPRINTF("speed=%d parity=%c data=%d stop=%d\n", DPRINTF("speed=%d parity=%c data=%d stop=%d\n",
speed, parity, data_bits, stop_bits); speed, parity, data_bits, stop_bits);
@ -194,7 +195,8 @@ static void serial_update_msl(SerialState *s)
timer_del(s->modem_status_poll); timer_del(s->modem_status_poll);
if (qemu_chr_fe_ioctl(s->chr,CHR_IOCTL_SERIAL_GET_TIOCM, &flags) == -ENOTSUP) { if (qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_GET_TIOCM,
&flags) == -ENOTSUP) {
s->poll_msl = -1; s->poll_msl = -1;
return; return;
} }
@ -259,11 +261,12 @@ static void serial_xmit(SerialState *s)
if (s->mcr & UART_MCR_LOOP) { if (s->mcr & UART_MCR_LOOP) {
/* in loopback mode, say that we just received a char */ /* in loopback mode, say that we just received a char */
serial_receive1(s, &s->tsr, 1); serial_receive1(s, &s->tsr, 1);
} else if (qemu_chr_fe_write(s->chr, &s->tsr, 1) != 1 && } else if (qemu_chr_fe_write(&s->chr, &s->tsr, 1) != 1 &&
s->tsr_retry < MAX_XMIT_RETRY) { s->tsr_retry < MAX_XMIT_RETRY) {
assert(s->watch_tag == 0); assert(s->watch_tag == 0);
s->watch_tag = qemu_chr_fe_add_watch(s->chr, G_IO_OUT|G_IO_HUP, s->watch_tag =
serial_watch_cb, s); qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
serial_watch_cb, s);
if (s->watch_tag > 0) { if (s->watch_tag > 0) {
s->tsr_retry++; s->tsr_retry++;
return; return;
@ -416,8 +419,8 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
break_enable = (val >> 6) & 1; break_enable = (val >> 6) & 1;
if (break_enable != s->last_break_enable) { if (break_enable != s->last_break_enable) {
s->last_break_enable = break_enable; s->last_break_enable = break_enable;
qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_BREAK, qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_BREAK,
&break_enable); &break_enable);
} }
} }
break; break;
@ -431,7 +434,7 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
if (s->poll_msl >= 0 && old_mcr != s->mcr) { if (s->poll_msl >= 0 && old_mcr != s->mcr) {
qemu_chr_fe_ioctl(s->chr,CHR_IOCTL_SERIAL_GET_TIOCM, &flags); qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_GET_TIOCM, &flags);
flags &= ~(CHR_TIOCM_RTS | CHR_TIOCM_DTR); flags &= ~(CHR_TIOCM_RTS | CHR_TIOCM_DTR);
@ -440,7 +443,7 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
if (val & UART_MCR_DTR) if (val & UART_MCR_DTR)
flags |= CHR_TIOCM_DTR; flags |= CHR_TIOCM_DTR;
qemu_chr_fe_ioctl(s->chr,CHR_IOCTL_SERIAL_SET_TIOCM, &flags); qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_TIOCM, &flags);
/* Update the modem status after a one-character-send wait-time, since there may be a response /* Update the modem status after a one-character-send wait-time, since there may be a response
from the device/computer at the other end of the serial line */ from the device/computer at the other end of the serial line */
timer_mod(s->modem_status_poll, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->char_transmit_time); timer_mod(s->modem_status_poll, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->char_transmit_time);
@ -485,7 +488,7 @@ static uint64_t serial_ioport_read(void *opaque, hwaddr addr, unsigned size)
serial_update_irq(s); serial_update_irq(s);
if (!(s->mcr & UART_MCR_LOOP)) { if (!(s->mcr & UART_MCR_LOOP)) {
/* in loopback mode, don't receive any data */ /* in loopback mode, don't receive any data */
qemu_chr_accept_input(s->chr); qemu_chr_fe_accept_input(&s->chr);
} }
} }
break; break;
@ -658,7 +661,7 @@ static int serial_post_load(void *opaque, int version_id)
} }
assert(s->watch_tag == 0); assert(s->watch_tag == 0);
s->watch_tag = qemu_chr_fe_add_watch(s->chr, G_IO_OUT|G_IO_HUP, s->watch_tag = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
serial_watch_cb, s); serial_watch_cb, s);
} else { } else {
/* tsr_retry == 0 implies LSR.TEMT = 1 (transmitter empty). */ /* tsr_retry == 0 implies LSR.TEMT = 1 (transmitter empty). */
@ -883,7 +886,7 @@ static void serial_reset(void *opaque)
void serial_realize_core(SerialState *s, Error **errp) void serial_realize_core(SerialState *s, Error **errp)
{ {
if (!s->chr) { if (!qemu_chr_fe_get_driver(&s->chr)) {
error_setg(errp, "Can't create serial device, empty char device"); error_setg(errp, "Can't create serial device, empty char device");
return; return;
} }
@ -893,8 +896,8 @@ void serial_realize_core(SerialState *s, Error **errp)
s->fifo_timeout_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, (QEMUTimerCB *) fifo_timeout_int, s); s->fifo_timeout_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, (QEMUTimerCB *) fifo_timeout_int, s);
qemu_register_reset(serial_reset, s); qemu_register_reset(serial_reset, s);
qemu_chr_add_handlers(s->chr, serial_can_receive1, serial_receive1, qemu_chr_fe_set_handlers(&s->chr, serial_can_receive1, serial_receive1,
serial_event, s); serial_event, s, NULL, true);
fifo8_create(&s->recv_fifo, UART_FIFO_LENGTH); fifo8_create(&s->recv_fifo, UART_FIFO_LENGTH);
fifo8_create(&s->xmit_fifo, UART_FIFO_LENGTH); fifo8_create(&s->xmit_fifo, UART_FIFO_LENGTH);
serial_reset(s); serial_reset(s);
@ -902,7 +905,7 @@ void serial_realize_core(SerialState *s, Error **errp)
void serial_exit_core(SerialState *s) void serial_exit_core(SerialState *s)
{ {
qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, NULL); qemu_chr_fe_deinit(&s->chr);
qemu_unregister_reset(serial_reset, s); qemu_unregister_reset(serial_reset, s);
} }
@ -932,7 +935,7 @@ SerialState *serial_init(int base, qemu_irq irq, int baudbase,
s->irq = irq; s->irq = irq;
s->baudbase = baudbase; s->baudbase = baudbase;
s->chr = chr; qemu_chr_fe_init(&s->chr, chr, &error_abort);
serial_realize_core(s, &error_fatal); serial_realize_core(s, &error_fatal);
vmstate_register(NULL, base, &vmstate_serial, s); vmstate_register(NULL, base, &vmstate_serial, s);
@ -989,7 +992,7 @@ SerialState *serial_mm_init(MemoryRegion *address_space,
s->it_shift = it_shift; s->it_shift = it_shift;
s->irq = irq; s->irq = irq;
s->baudbase = baudbase; s->baudbase = baudbase;
s->chr = chr; qemu_chr_fe_init(&s->chr, chr, &error_abort);
serial_realize_core(s, &error_fatal); serial_realize_core(s, &error_fatal);
vmstate_register(NULL, base, &vmstate_serial, s); vmstate_register(NULL, base, &vmstate_serial, s);

View File

@ -29,6 +29,7 @@
#include "hw/sh4/sh.h" #include "hw/sh4/sh.h"
#include "sysemu/char.h" #include "sysemu/char.h"
#include "exec/address-spaces.h" #include "exec/address-spaces.h"
#include "qapi/error.h"
//#define DEBUG_SERIAL //#define DEBUG_SERIAL
@ -62,7 +63,7 @@ typedef struct {
int flags; int flags;
int rtrg; int rtrg;
CharDriverState *chr; CharBackend chr;
qemu_irq eri; qemu_irq eri;
qemu_irq rxi; qemu_irq rxi;
@ -109,11 +110,11 @@ static void sh_serial_write(void *opaque, hwaddr offs,
} }
return; return;
case 0x0c: /* FTDR / TDR */ case 0x0c: /* FTDR / TDR */
if (s->chr) { if (qemu_chr_fe_get_driver(&s->chr)) {
ch = val; ch = val;
/* XXX this blocks entire thread. Rewrite to use /* XXX this blocks entire thread. Rewrite to use
* qemu_chr_fe_write and background I/O callbacks */ * qemu_chr_fe_write and background I/O callbacks */
qemu_chr_fe_write_all(s->chr, &ch, 1); qemu_chr_fe_write_all(&s->chr, &ch, 1);
} }
s->dr = val; s->dr = val;
s->flags &= ~SH_SERIAL_FLAG_TDE; s->flags &= ~SH_SERIAL_FLAG_TDE;
@ -395,12 +396,11 @@ void sh_serial_init(MemoryRegion *sysmem,
0, 0x28); 0, 0x28);
memory_region_add_subregion(sysmem, A7ADDR(base), &s->iomem_a7); memory_region_add_subregion(sysmem, A7ADDR(base), &s->iomem_a7);
s->chr = chr;
if (chr) { if (chr) {
qemu_chr_fe_claim_no_fail(chr); qemu_chr_fe_init(&s->chr, chr, &error_abort);
qemu_chr_add_handlers(chr, sh_serial_can_receive1, sh_serial_receive1, qemu_chr_fe_set_handlers(&s->chr, sh_serial_can_receive1,
sh_serial_event, s); sh_serial_receive1,
sh_serial_event, s, NULL, true);
} }
s->eri = eri_source; s->eri = eri_source;

View File

@ -11,7 +11,7 @@
typedef struct VIOsPAPRVTYDevice { typedef struct VIOsPAPRVTYDevice {
VIOsPAPRDevice sdev; VIOsPAPRDevice sdev;
CharDriverState *chardev; CharBackend chardev;
uint32_t in, out; uint32_t in, out;
uint8_t buf[VTERM_BUFSIZE]; uint8_t buf[VTERM_BUFSIZE];
} VIOsPAPRVTYDevice; } VIOsPAPRVTYDevice;
@ -51,7 +51,7 @@ static int vty_getchars(VIOsPAPRDevice *sdev, uint8_t *buf, int max)
buf[n++] = dev->buf[dev->out++ % VTERM_BUFSIZE]; buf[n++] = dev->buf[dev->out++ % VTERM_BUFSIZE];
} }
qemu_chr_accept_input(dev->chardev); qemu_chr_fe_accept_input(&dev->chardev);
return n; return n;
} }
@ -62,20 +62,20 @@ void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len)
/* XXX this blocks entire thread. Rewrite to use /* XXX this blocks entire thread. Rewrite to use
* qemu_chr_fe_write and background I/O callbacks */ * qemu_chr_fe_write and background I/O callbacks */
qemu_chr_fe_write_all(dev->chardev, buf, len); qemu_chr_fe_write_all(&dev->chardev, buf, len);
} }
static void spapr_vty_realize(VIOsPAPRDevice *sdev, Error **errp) static void spapr_vty_realize(VIOsPAPRDevice *sdev, Error **errp)
{ {
VIOsPAPRVTYDevice *dev = VIO_SPAPR_VTY_DEVICE(sdev); VIOsPAPRVTYDevice *dev = VIO_SPAPR_VTY_DEVICE(sdev);
if (!dev->chardev) { if (!qemu_chr_fe_get_driver(&dev->chardev)) {
error_setg(errp, "chardev property not set"); error_setg(errp, "chardev property not set");
return; return;
} }
qemu_chr_add_handlers(dev->chardev, vty_can_receive, qemu_chr_fe_set_handlers(&dev->chardev, vty_can_receive,
vty_receive, NULL, dev); vty_receive, NULL, dev, NULL, true);
} }
/* Forward declaration */ /* Forward declaration */

View File

@ -97,17 +97,13 @@ static uint64_t stm32f2xx_usart_read(void *opaque, hwaddr addr,
case USART_SR: case USART_SR:
retvalue = s->usart_sr; retvalue = s->usart_sr;
s->usart_sr &= ~USART_SR_TC; s->usart_sr &= ~USART_SR_TC;
if (s->chr) { qemu_chr_fe_accept_input(&s->chr);
qemu_chr_accept_input(s->chr);
}
return retvalue; return retvalue;
case USART_DR: case USART_DR:
DB_PRINT("Value: 0x%" PRIx32 ", %c\n", s->usart_dr, (char) s->usart_dr); DB_PRINT("Value: 0x%" PRIx32 ", %c\n", s->usart_dr, (char) s->usart_dr);
s->usart_sr |= USART_SR_TXE; s->usart_sr |= USART_SR_TXE;
s->usart_sr &= ~USART_SR_RXNE; s->usart_sr &= ~USART_SR_RXNE;
if (s->chr) { qemu_chr_fe_accept_input(&s->chr);
qemu_chr_accept_input(s->chr);
}
qemu_set_irq(s->irq, 0); qemu_set_irq(s->irq, 0);
return s->usart_dr & 0x3FF; return s->usart_dr & 0x3FF;
case USART_BRR: case USART_BRR:
@ -152,11 +148,9 @@ static void stm32f2xx_usart_write(void *opaque, hwaddr addr,
case USART_DR: case USART_DR:
if (value < 0xF000) { if (value < 0xF000) {
ch = value; ch = value;
if (s->chr) { /* XXX this blocks entire thread. Rewrite to use
/* XXX this blocks entire thread. Rewrite to use * qemu_chr_fe_write and background I/O callbacks */
* qemu_chr_fe_write and background I/O callbacks */ qemu_chr_fe_write_all(&s->chr, &ch, 1);
qemu_chr_fe_write_all(s->chr, &ch, 1);
}
s->usart_sr |= USART_SR_TC; s->usart_sr |= USART_SR_TC;
s->usart_sr &= ~USART_SR_TXE; s->usart_sr &= ~USART_SR_TXE;
} }
@ -212,10 +206,8 @@ static void stm32f2xx_usart_realize(DeviceState *dev, Error **errp)
{ {
STM32F2XXUsartState *s = STM32F2XX_USART(dev); STM32F2XXUsartState *s = STM32F2XX_USART(dev);
if (s->chr) { qemu_chr_fe_set_handlers(&s->chr, stm32f2xx_usart_can_receive,
qemu_chr_add_handlers(s->chr, stm32f2xx_usart_can_receive, stm32f2xx_usart_receive, NULL, s, NULL, true);
stm32f2xx_usart_receive, NULL, s);
}
} }
static void stm32f2xx_usart_class_init(ObjectClass *klass, void *data) static void stm32f2xx_usart_class_init(ObjectClass *klass, void *data)

View File

@ -24,7 +24,7 @@
typedef struct VirtConsole { typedef struct VirtConsole {
VirtIOSerialPort parent_obj; VirtIOSerialPort parent_obj;
CharDriverState *chr; CharBackend chr;
guint watch; guint watch;
} VirtConsole; } VirtConsole;
@ -49,12 +49,12 @@ static ssize_t flush_buf(VirtIOSerialPort *port,
VirtConsole *vcon = VIRTIO_CONSOLE(port); VirtConsole *vcon = VIRTIO_CONSOLE(port);
ssize_t ret; ssize_t ret;
if (!vcon->chr) { if (!qemu_chr_fe_get_driver(&vcon->chr)) {
/* If there's no backend, we can just say we consumed all data. */ /* If there's no backend, we can just say we consumed all data. */
return len; return len;
} }
ret = qemu_chr_fe_write(vcon->chr, buf, len); ret = qemu_chr_fe_write(&vcon->chr, buf, len);
trace_virtio_console_flush_buf(port->id, len, ret); trace_virtio_console_flush_buf(port->id, len, ret);
if (ret < len) { if (ret < len) {
@ -92,7 +92,7 @@ static ssize_t flush_buf(VirtIOSerialPort *port,
if (!k->is_console) { if (!k->is_console) {
virtio_serial_throttle_port(port, true); virtio_serial_throttle_port(port, true);
if (!vcon->watch) { if (!vcon->watch) {
vcon->watch = qemu_chr_fe_add_watch(vcon->chr, vcon->watch = qemu_chr_fe_add_watch(&vcon->chr,
G_IO_OUT|G_IO_HUP, G_IO_OUT|G_IO_HUP,
chr_write_unblocked, vcon); chr_write_unblocked, vcon);
} }
@ -108,8 +108,8 @@ static void set_guest_connected(VirtIOSerialPort *port, int guest_connected)
DeviceState *dev = DEVICE(port); DeviceState *dev = DEVICE(port);
VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port); VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port);
if (vcon->chr && !k->is_console) { if (!k->is_console) {
qemu_chr_fe_set_open(vcon->chr, guest_connected); qemu_chr_fe_set_open(&vcon->chr, guest_connected);
} }
if (dev->id) { if (dev->id) {
@ -122,9 +122,7 @@ static void guest_writable(VirtIOSerialPort *port)
{ {
VirtConsole *vcon = VIRTIO_CONSOLE(port); VirtConsole *vcon = VIRTIO_CONSOLE(port);
if (vcon->chr) { qemu_chr_fe_accept_input(&vcon->chr);
qemu_chr_accept_input(vcon->chr);
}
} }
/* Readiness of the guest to accept data on a port */ /* Readiness of the guest to accept data on a port */
@ -170,6 +168,7 @@ static void virtconsole_realize(DeviceState *dev, Error **errp)
VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(dev); VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(dev);
VirtConsole *vcon = VIRTIO_CONSOLE(dev); VirtConsole *vcon = VIRTIO_CONSOLE(dev);
VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(dev); VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(dev);
CharDriverState *chr = qemu_chr_fe_get_driver(&vcon->chr);
if (port->id == 0 && !k->is_console) { if (port->id == 0 && !k->is_console) {
error_setg(errp, "Port number 0 on virtio-serial devices reserved " error_setg(errp, "Port number 0 on virtio-serial devices reserved "
@ -177,7 +176,7 @@ static void virtconsole_realize(DeviceState *dev, Error **errp)
return; return;
} }
if (vcon->chr) { if (chr) {
/* /*
* For consoles we don't block guest data transfer just * For consoles we don't block guest data transfer just
* because nothing is connected - we'll just let it go * because nothing is connected - we'll just let it go
@ -188,14 +187,12 @@ static void virtconsole_realize(DeviceState *dev, Error **errp)
* trigger open/close of the device * trigger open/close of the device
*/ */
if (k->is_console) { if (k->is_console) {
vcon->chr->explicit_fe_open = 0; qemu_chr_fe_set_handlers(&vcon->chr, chr_can_read, chr_read,
qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read, NULL, vcon, NULL, true);
NULL, vcon);
virtio_serial_open(port); virtio_serial_open(port);
} else { } else {
vcon->chr->explicit_fe_open = 1; qemu_chr_fe_set_handlers(&vcon->chr, chr_can_read, chr_read,
qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read, chr_event, vcon, NULL, false);
chr_event, vcon);
} }
} }
} }

View File

@ -23,9 +23,11 @@
#include <sys/select.h> #include <sys/select.h>
#include <termios.h> #include <termios.h>
#include "qapi/error.h"
#include "hw/hw.h" #include "hw/hw.h"
#include "sysemu/char.h" #include "sysemu/char.h"
#include "hw/xen/xen_backend.h" #include "hw/xen/xen_backend.h"
#include "qapi/error.h"
#include <xen/io/console.h> #include <xen/io/console.h>
@ -43,7 +45,7 @@ struct XenConsole {
char console[XEN_BUFSIZE]; char console[XEN_BUFSIZE];
int ring_ref; int ring_ref;
void *sring; void *sring;
CharDriverState *chr; CharBackend chr;
int backlog; int backlog;
}; };
@ -148,11 +150,13 @@ static void xencons_send(struct XenConsole *con)
ssize_t len, size; ssize_t len, size;
size = con->buffer.size - con->buffer.consumed; size = con->buffer.size - con->buffer.consumed;
if (con->chr) if (qemu_chr_fe_get_driver(&con->chr)) {
len = qemu_chr_fe_write(con->chr, con->buffer.data + con->buffer.consumed, len = qemu_chr_fe_write(&con->chr,
size); con->buffer.data + con->buffer.consumed,
else size);
} else {
len = size; len = size;
}
if (len < 1) { if (len < 1) {
if (!con->backlog) { if (!con->backlog) {
con->backlog = 1; con->backlog = 1;
@ -196,13 +200,18 @@ static int con_init(struct XenDevice *xendev)
/* no Xen override, use qemu output device */ /* no Xen override, use qemu output device */
if (output == NULL) { if (output == NULL) {
con->chr = serial_hds[con->xendev.dev]; if (con->xendev.dev) {
qemu_chr_fe_init(&con->chr, serial_hds[con->xendev.dev],
&error_abort);
}
} else { } else {
snprintf(label, sizeof(label), "xencons%d", con->xendev.dev); snprintf(label, sizeof(label), "xencons%d", con->xendev.dev);
con->chr = qemu_chr_new(label, output, NULL); qemu_chr_fe_init(&con->chr,
qemu_chr_new(label, output), &error_abort);
} }
xenstore_store_pv_console_info(con->xendev.dev, con->chr); xenstore_store_pv_console_info(con->xendev.dev,
qemu_chr_fe_get_driver(&con->chr));
out: out:
g_free(type); g_free(type);
@ -235,17 +244,8 @@ static int con_initialise(struct XenDevice *xendev)
return -1; return -1;
xen_be_bind_evtchn(&con->xendev); xen_be_bind_evtchn(&con->xendev);
if (con->chr) { qemu_chr_fe_set_handlers(&con->chr, xencons_can_receive,
if (qemu_chr_fe_claim(con->chr) == 0) { xencons_receive, NULL, con, NULL, true);
qemu_chr_add_handlers(con->chr, xencons_can_receive,
xencons_receive, NULL, con);
} else {
xen_be_printf(xendev, 0,
"xen_console_init error chardev %s already used\n",
con->chr->label);
con->chr = NULL;
}
}
xen_be_printf(xendev, 1, "ring mfn %d, remote port %d, local port %d, limit %zd\n", xen_be_printf(xendev, 1, "ring mfn %d, remote port %d, local port %d, limit %zd\n",
con->ring_ref, con->ring_ref,
@ -259,10 +259,7 @@ static void con_disconnect(struct XenDevice *xendev)
{ {
struct XenConsole *con = container_of(xendev, struct XenConsole, xendev); struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
if (con->chr) { qemu_chr_fe_deinit(&con->chr);
qemu_chr_add_handlers(con->chr, NULL, NULL, NULL, NULL);
qemu_chr_fe_release(con->chr);
}
xen_be_unbind_evtchn(&con->xendev); xen_be_unbind_evtchn(&con->xendev);
if (con->sring) { if (con->sring) {

View File

@ -55,7 +55,7 @@ typedef struct XilinxUARTLite {
SysBusDevice parent_obj; SysBusDevice parent_obj;
MemoryRegion mmio; MemoryRegion mmio;
CharDriverState *chr; CharBackend chr;
qemu_irq irq; qemu_irq irq;
uint8_t rx_fifo[8]; uint8_t rx_fifo[8];
@ -107,7 +107,7 @@ uart_read(void *opaque, hwaddr addr, unsigned int size)
s->rx_fifo_len--; s->rx_fifo_len--;
uart_update_status(s); uart_update_status(s);
uart_update_irq(s); uart_update_irq(s);
qemu_chr_accept_input(s->chr); qemu_chr_fe_accept_input(&s->chr);
break; break;
default: default:
@ -143,11 +143,9 @@ uart_write(void *opaque, hwaddr addr,
break; break;
case R_TX: case R_TX:
if (s->chr) /* XXX this blocks entire thread. Rewrite to use
/* XXX this blocks entire thread. Rewrite to use * qemu_chr_fe_write and background I/O callbacks */
* qemu_chr_fe_write and background I/O callbacks */ qemu_chr_fe_write_all(&s->chr, &ch, 1);
qemu_chr_fe_write_all(s->chr, &ch, 1);
s->regs[addr] = value; s->regs[addr] = value;
/* hax. */ /* hax. */
@ -213,8 +211,8 @@ static void xilinx_uartlite_realize(DeviceState *dev, Error **errp)
{ {
XilinxUARTLite *s = XILINX_UARTLITE(dev); XilinxUARTLite *s = XILINX_UARTLITE(dev);
if (s->chr) qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx,
qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s); uart_event, s, NULL, true);
} }
static void xilinx_uartlite_init(Object *obj) static void xilinx_uartlite_init(Object *obj)

View File

@ -160,55 +160,67 @@ PropertyInfo qdev_prop_drive = {
/* --- character device --- */ /* --- character device --- */
static void parse_chr(DeviceState *dev, const char *str, void **ptr, static void get_chr(Object *obj, Visitor *v, const char *name, void *opaque,
const char *propname, Error **errp) Error **errp)
{ {
CharDriverState *chr = qemu_chr_find(str); DeviceState *dev = DEVICE(obj);
if (chr == NULL) { CharBackend *be = qdev_get_prop_ptr(dev, opaque);
char *p;
p = g_strdup(be->chr && be->chr->label ? be->chr->label : "");
visit_type_str(v, name, &p, errp);
g_free(p);
}
static void set_chr(Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp)
{
DeviceState *dev = DEVICE(obj);
Error *local_err = NULL;
Property *prop = opaque;
CharBackend *be = qdev_get_prop_ptr(dev, prop);
CharDriverState *s;
char *str;
if (dev->realized) {
qdev_prop_set_after_realize(dev, name, errp);
return;
}
visit_type_str(v, name, &str, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
if (!*str) {
g_free(str);
be->chr = NULL;
return;
}
s = qemu_chr_find(str);
g_free(str);
if (s == NULL) {
error_setg(errp, "Property '%s.%s' can't find value '%s'", error_setg(errp, "Property '%s.%s' can't find value '%s'",
object_get_typename(OBJECT(dev)), propname, str); object_get_typename(obj), prop->name, str);
return; return;
} }
if (qemu_chr_fe_claim(chr) != 0) {
error_setg(errp, "Property '%s.%s' can't take value '%s', it's in use", if (!qemu_chr_fe_init(be, s, errp)) {
object_get_typename(OBJECT(dev)), propname, str); error_prepend(errp, "Property '%s.%s' can't take value '%s': ",
object_get_typename(obj), prop->name, str);
return; return;
} }
*ptr = chr;
} }
static void release_chr(Object *obj, const char *name, void *opaque) static void release_chr(Object *obj, const char *name, void *opaque)
{ {
DeviceState *dev = DEVICE(obj); DeviceState *dev = DEVICE(obj);
Property *prop = opaque; Property *prop = opaque;
CharDriverState **ptr = qdev_get_prop_ptr(dev, prop); CharBackend *be = qdev_get_prop_ptr(dev, prop);
CharDriverState *chr = *ptr;
if (chr) { qemu_chr_fe_deinit(be);
qemu_chr_add_handlers(chr, NULL, NULL, NULL, NULL);
qemu_chr_fe_release(chr);
}
}
static char *print_chr(void *ptr)
{
CharDriverState *chr = ptr;
const char *val = chr->label ? chr->label : "";
return g_strdup(val);
}
static void get_chr(Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp)
{
get_pointer(obj, v, opaque, print_chr, name, errp);
}
static void set_chr(Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp)
{
set_pointer(obj, v, opaque, parse_chr, name, errp);
} }
PropertyInfo qdev_prop_chr = { PropertyInfo qdev_prop_chr = {

View File

@ -1589,7 +1589,7 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
pcspk_init(isa_bus, pit); pcspk_init(isa_bus, pit);
} }
serial_hds_isa_init(isa_bus, MAX_SERIAL_PORTS); serial_hds_isa_init(isa_bus, 0, MAX_SERIAL_PORTS);
parallel_hds_isa_init(isa_bus, MAX_PARALLEL_PORTS); parallel_hds_isa_init(isa_bus, MAX_PARALLEL_PORTS);
a20_line = qemu_allocate_irqs(handle_a20_line_change, first_cpu, 2); a20_line = qemu_allocate_irqs(handle_a20_line_change, first_cpu, 2);

View File

@ -62,7 +62,7 @@
typedef struct IPMIBmcExtern { typedef struct IPMIBmcExtern {
IPMIBmc parent; IPMIBmc parent;
CharDriverState *chr; CharBackend chr;
bool connected; bool connected;
@ -105,7 +105,7 @@ static void continue_send(IPMIBmcExtern *ibe)
goto check_reset; goto check_reset;
} }
send: send:
ret = qemu_chr_fe_write(ibe->chr, ibe->outbuf + ibe->outpos, ret = qemu_chr_fe_write(&ibe->chr, ibe->outbuf + ibe->outpos,
ibe->outlen - ibe->outpos); ibe->outlen - ibe->outpos);
if (ret > 0) { if (ret > 0) {
ibe->outpos += ret; ibe->outpos += ret;
@ -442,12 +442,13 @@ static void ipmi_bmc_extern_realize(DeviceState *dev, Error **errp)
{ {
IPMIBmcExtern *ibe = IPMI_BMC_EXTERN(dev); IPMIBmcExtern *ibe = IPMI_BMC_EXTERN(dev);
if (!ibe->chr) { if (!qemu_chr_fe_get_driver(&ibe->chr)) {
error_setg(errp, "IPMI external bmc requires chardev attribute"); error_setg(errp, "IPMI external bmc requires chardev attribute");
return; return;
} }
qemu_chr_add_handlers(ibe->chr, can_receive, receive, chr_event, ibe); qemu_chr_fe_set_handlers(&ibe->chr, can_receive, receive,
chr_event, ibe, NULL, true);
} }
static int ipmi_bmc_extern_post_migrate(void *opaque, int version_id) static int ipmi_bmc_extern_post_migrate(void *opaque, int version_id)

View File

@ -283,7 +283,7 @@ static void pc87312_realize(DeviceState *dev, Error **errp)
/* FIXME use a qdev chardev prop instead of parallel_hds[] */ /* FIXME use a qdev chardev prop instead of parallel_hds[] */
chr = parallel_hds[0]; chr = parallel_hds[0];
if (chr == NULL) { if (chr == NULL) {
chr = qemu_chr_new("par0", "null", NULL); chr = qemu_chr_new("par0", "null");
} }
isa = isa_create(bus, "isa-parallel"); isa = isa_create(bus, "isa-parallel");
d = DEVICE(isa); d = DEVICE(isa);
@ -303,7 +303,7 @@ static void pc87312_realize(DeviceState *dev, Error **errp)
chr = serial_hds[i]; chr = serial_hds[i];
if (chr == NULL) { if (chr == NULL) {
snprintf(name, sizeof(name), "ser%d", i); snprintf(name, sizeof(name), "ser%d", i);
chr = qemu_chr_new(name, "null", NULL); chr = qemu_chr_new(name, "null");
} }
isa = isa_create(bus, "isa-serial"); isa = isa_create(bus, "isa-serial");
d = DEVICE(isa); d = DEVICE(isa);

View File

@ -374,7 +374,7 @@ static void mips_fulong2e_init(MachineState *machine)
rtc_init(isa_bus, 2000, NULL); rtc_init(isa_bus, 2000, NULL);
serial_hds_isa_init(isa_bus, MAX_SERIAL_PORTS); serial_hds_isa_init(isa_bus, 0, MAX_SERIAL_PORTS);
parallel_hds_isa_init(isa_bus, 1); parallel_hds_isa_init(isa_bus, 1);
/* Sound card */ /* Sound card */

View File

@ -85,9 +85,10 @@ typedef struct {
uint32_t i2coe; uint32_t i2coe;
uint32_t i2cout; uint32_t i2cout;
uint32_t i2csel; uint32_t i2csel;
CharDriverState *display; CharBackend display;
char display_text[9]; char display_text[9];
SerialState *uart; SerialState *uart;
bool display_inited;
} MaltaFPGAState; } MaltaFPGAState;
#define TYPE_MIPS_MALTA "mips-malta" #define TYPE_MIPS_MALTA "mips-malta"
@ -124,8 +125,10 @@ static void malta_fpga_update_display(void *opaque)
} }
leds_text[8] = '\0'; leds_text[8] = '\0';
qemu_chr_fe_printf(s->display, "\e[H\n\n|\e[32m%-8.8s\e[00m|\r\n", leds_text); qemu_chr_fe_printf(&s->display, "\e[H\n\n|\e[32m%-8.8s\e[00m|\r\n",
qemu_chr_fe_printf(s->display, "\n\n\n\n|\e[31m%-8.8s\e[00m|", s->display_text); leds_text);
qemu_chr_fe_printf(&s->display, "\n\n\n\n|\e[31m%-8.8s\e[00m|",
s->display_text);
} }
/* /*
@ -530,23 +533,29 @@ static void malta_fpga_reset(void *opaque)
snprintf(s->display_text, 9, " "); snprintf(s->display_text, 9, " ");
} }
static void malta_fpga_led_init(CharDriverState *chr) static void malta_fgpa_display_event(void *opaque, int event)
{ {
qemu_chr_fe_printf(chr, "\e[HMalta LEDBAR\r\n"); MaltaFPGAState *s = opaque;
qemu_chr_fe_printf(chr, "+--------+\r\n");
qemu_chr_fe_printf(chr, "+ +\r\n"); if (event == CHR_EVENT_OPENED && !s->display_inited) {
qemu_chr_fe_printf(chr, "+--------+\r\n"); qemu_chr_fe_printf(&s->display, "\e[HMalta LEDBAR\r\n");
qemu_chr_fe_printf(chr, "\n"); qemu_chr_fe_printf(&s->display, "+--------+\r\n");
qemu_chr_fe_printf(chr, "Malta ASCII\r\n"); qemu_chr_fe_printf(&s->display, "+ +\r\n");
qemu_chr_fe_printf(chr, "+--------+\r\n"); qemu_chr_fe_printf(&s->display, "+--------+\r\n");
qemu_chr_fe_printf(chr, "+ +\r\n"); qemu_chr_fe_printf(&s->display, "\n");
qemu_chr_fe_printf(chr, "+--------+\r\n"); qemu_chr_fe_printf(&s->display, "Malta ASCII\r\n");
qemu_chr_fe_printf(&s->display, "+--------+\r\n");
qemu_chr_fe_printf(&s->display, "+ +\r\n");
qemu_chr_fe_printf(&s->display, "+--------+\r\n");
s->display_inited = true;
}
} }
static MaltaFPGAState *malta_fpga_init(MemoryRegion *address_space, static MaltaFPGAState *malta_fpga_init(MemoryRegion *address_space,
hwaddr base, qemu_irq uart_irq, CharDriverState *uart_chr) hwaddr base, qemu_irq uart_irq, CharDriverState *uart_chr)
{ {
MaltaFPGAState *s; MaltaFPGAState *s;
CharDriverState *chr;
s = (MaltaFPGAState *)g_malloc0(sizeof(MaltaFPGAState)); s = (MaltaFPGAState *)g_malloc0(sizeof(MaltaFPGAState));
@ -560,7 +569,10 @@ static MaltaFPGAState *malta_fpga_init(MemoryRegion *address_space,
memory_region_add_subregion(address_space, base, &s->iomem_lo); memory_region_add_subregion(address_space, base, &s->iomem_lo);
memory_region_add_subregion(address_space, base + 0xa00, &s->iomem_hi); memory_region_add_subregion(address_space, base + 0xa00, &s->iomem_hi);
s->display = qemu_chr_new("fpga", "vc:320x200", malta_fpga_led_init); 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);
s->uart = serial_mm_init(address_space, base + 0x900, 3, uart_irq, s->uart = serial_mm_init(address_space, base + 0x900, 3, uart_irq,
230400, uart_chr, DEVICE_NATIVE_ENDIAN); 230400, uart_chr, DEVICE_NATIVE_ENDIAN);
@ -1025,7 +1037,7 @@ void mips_malta_init(MachineState *machine)
if (!serial_hds[i]) { if (!serial_hds[i]) {
char label[32]; char label[32];
snprintf(label, sizeof(label), "serial%d", i); snprintf(label, sizeof(label), "serial%d", i);
serial_hds[i] = qemu_chr_new(label, "null", NULL); serial_hds[i] = qemu_chr_new(label, "null");
} }
} }
@ -1215,7 +1227,7 @@ void mips_malta_init(MachineState *machine)
isa_create_simple(isa_bus, "i8042"); isa_create_simple(isa_bus, "i8042");
rtc_init(isa_bus, 2000, NULL); rtc_init(isa_bus, 2000, NULL);
serial_hds_isa_init(isa_bus, 2); serial_hds_isa_init(isa_bus, 0, 2);
parallel_hds_isa_init(isa_bus, 1); parallel_hds_isa_init(isa_bus, 1);
for(i = 0; i < MAX_FD; i++) { for(i = 0; i < MAX_FD; i++) {

View File

@ -286,7 +286,7 @@ void mips_r4k_init(MachineState *machine)
pit = pit_init(isa_bus, 0x40, 0, NULL); pit = pit_init(isa_bus, 0x40, 0, NULL);
serial_hds_isa_init(isa_bus, MAX_SERIAL_PORTS); serial_hds_isa_init(isa_bus, 0, MAX_SERIAL_PORTS);
isa_vga_init(isa_bus); isa_vga_init(isa_bus);

View File

@ -88,7 +88,7 @@ typedef struct IVShmemState {
/* exactly one of these two may be set */ /* exactly one of these two may be set */
HostMemoryBackend *hostmem; /* with interrupts */ HostMemoryBackend *hostmem; /* with interrupts */
CharDriverState *server_chr; /* without interrupts */ CharBackend server_chr; /* without interrupts */
/* registers */ /* registers */
uint32_t intrmask; uint32_t intrmask;
@ -627,7 +627,7 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
msg = le64_to_cpu(s->msg_buf); msg = le64_to_cpu(s->msg_buf);
s->msg_buffered_bytes = 0; s->msg_buffered_bytes = 0;
fd = qemu_chr_fe_get_msgfd(s->server_chr); fd = qemu_chr_fe_get_msgfd(&s->server_chr);
process_msg(s, msg, fd, &err); process_msg(s, msg, fd, &err);
if (err) { if (err) {
@ -642,8 +642,8 @@ static int64_t ivshmem_recv_msg(IVShmemState *s, int *pfd, Error **errp)
n = 0; n = 0;
do { do {
ret = qemu_chr_fe_read_all(s->server_chr, (uint8_t *)&msg + n, ret = qemu_chr_fe_read_all(&s->server_chr, (uint8_t *)&msg + n,
sizeof(msg) - n); sizeof(msg) - n);
if (ret < 0 && ret != -EINTR) { if (ret < 0 && ret != -EINTR) {
error_setg_errno(errp, -ret, "read from server failed"); error_setg_errno(errp, -ret, "read from server failed");
return INT64_MIN; return INT64_MIN;
@ -651,7 +651,7 @@ static int64_t ivshmem_recv_msg(IVShmemState *s, int *pfd, Error **errp)
n += ret; n += ret;
} while (n < sizeof(msg)); } while (n < sizeof(msg));
*pfd = qemu_chr_fe_get_msgfd(s->server_chr); *pfd = qemu_chr_fe_get_msgfd(&s->server_chr);
return msg; return msg;
} }
@ -868,10 +868,11 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp)
s->ivshmem_bar2 = host_memory_backend_get_memory(s->hostmem, s->ivshmem_bar2 = host_memory_backend_get_memory(s->hostmem,
&error_abort); &error_abort);
} else { } else {
assert(s->server_chr); CharDriverState *chr = qemu_chr_fe_get_driver(&s->server_chr);
assert(chr);
IVSHMEM_DPRINTF("using shared memory server (socket = %s)\n", IVSHMEM_DPRINTF("using shared memory server (socket = %s)\n",
s->server_chr->filename); chr->filename);
/* we allocate enough space for 16 peers and grow as needed */ /* we allocate enough space for 16 peers and grow as needed */
resize_peers(s, 16); resize_peers(s, 16);
@ -893,8 +894,8 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp)
return; return;
} }
qemu_chr_add_handlers(s->server_chr, ivshmem_can_receive, qemu_chr_fe_set_handlers(&s->server_chr, ivshmem_can_receive,
ivshmem_read, NULL, s); ivshmem_read, NULL, s, NULL, true);
if (ivshmem_setup_interrupts(s) < 0) { if (ivshmem_setup_interrupts(s) < 0) {
error_setg(errp, "failed to initialize interrupts"); error_setg(errp, "failed to initialize interrupts");
@ -1121,7 +1122,7 @@ static void ivshmem_doorbell_realize(PCIDevice *dev, Error **errp)
{ {
IVShmemState *s = IVSHMEM_COMMON(dev); IVShmemState *s = IVSHMEM_COMMON(dev);
if (!s->server_chr) { if (!qemu_chr_fe_get_driver(&s->server_chr)) {
error_setg(errp, "You must specify a 'chardev'"); error_setg(errp, "You must specify a 'chardev'");
return; return;
} }
@ -1250,7 +1251,7 @@ static void ivshmem_realize(PCIDevice *dev, Error **errp)
" or ivshmem-doorbell instead"); " or ivshmem-doorbell instead");
} }
if (!!s->server_chr + !!s->shmobj != 1) { if (!!qemu_chr_fe_get_driver(&s->server_chr) + !!s->shmobj != 1) {
error_setg(errp, "You must specify either 'shm' or 'chardev'"); error_setg(errp, "You must specify either 'shm' or 'chardev'");
return; return;
} }

View File

@ -824,7 +824,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
i++; i++;
} }
serial_hds_isa_init(isa_bus, MAX_SERIAL_PORTS); serial_hds_isa_init(isa_bus, i, MAX_SERIAL_PORTS);
parallel_hds_isa_init(isa_bus, MAX_PARALLEL_PORTS); parallel_hds_isa_init(isa_bus, MAX_PARALLEL_PORTS);
for(i = 0; i < nb_nics; i++) for(i = 0; i < nb_nics; i++)

View File

@ -607,6 +607,7 @@ static void xilinx_spips_realize(DeviceState *dev, Error **errp)
XilinxSPIPS *s = XILINX_SPIPS(dev); XilinxSPIPS *s = XILINX_SPIPS(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev); SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
XilinxSPIPSClass *xsc = XILINX_SPIPS_GET_CLASS(s); XilinxSPIPSClass *xsc = XILINX_SPIPS_GET_CLASS(s);
qemu_irq *cs;
int i; int i;
DB_PRINT_L(0, "realized spips\n"); DB_PRINT_L(0, "realized spips\n");
@ -619,8 +620,10 @@ static void xilinx_spips_realize(DeviceState *dev, Error **errp)
} }
s->cs_lines = g_new0(qemu_irq, s->num_cs * s->num_busses); s->cs_lines = g_new0(qemu_irq, s->num_cs * s->num_busses);
ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi[0]); for (i = 0, cs = s->cs_lines; i < s->num_busses; ++i, cs += s->num_cs) {
ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi[1]); ssi_auto_connect_slaves(DEVICE(s), cs, s->spi[i]);
}
sysbus_init_irq(sbd, &s->irq); sysbus_init_irq(sbd, &s->irq);
for (i = 0; i < s->num_cs * s->num_busses; ++i) { for (i = 0; i < s->num_cs * s->num_busses; ++i) {
sysbus_init_irq(sbd, &s->cs_lines[i]); sysbus_init_irq(sbd, &s->cs_lines[i]);

View File

@ -48,7 +48,7 @@ typedef struct PassthruState PassthruState;
struct PassthruState { struct PassthruState {
CCIDCardState base; CCIDCardState base;
CharDriverState *cs; CharBackend cs;
uint8_t vscard_in_data[VSCARD_IN_SIZE]; uint8_t vscard_in_data[VSCARD_IN_SIZE];
uint32_t vscard_in_pos; uint32_t vscard_in_pos;
uint32_t vscard_in_hdr; uint32_t vscard_in_hdr;
@ -77,9 +77,9 @@ static void ccid_card_vscard_send_msg(PassthruState *s,
scr_msg_header.length = htonl(length); scr_msg_header.length = htonl(length);
/* XXX this blocks entire thread. Rewrite to use /* XXX this blocks entire thread. Rewrite to use
* qemu_chr_fe_write and background I/O callbacks */ * qemu_chr_fe_write and background I/O callbacks */
qemu_chr_fe_write_all(s->cs, (uint8_t *)&scr_msg_header, qemu_chr_fe_write_all(&s->cs, (uint8_t *)&scr_msg_header,
sizeof(VSCMsgHeader)); sizeof(VSCMsgHeader));
qemu_chr_fe_write_all(s->cs, payload, length); qemu_chr_fe_write_all(&s->cs, payload, length);
} }
static void ccid_card_vscard_send_apdu(PassthruState *s, static void ccid_card_vscard_send_apdu(PassthruState *s,
@ -264,7 +264,10 @@ static void ccid_card_vscard_handle_message(PassthruState *card,
static void ccid_card_vscard_drop_connection(PassthruState *card) static void ccid_card_vscard_drop_connection(PassthruState *card)
{ {
qemu_chr_delete(card->cs); CharDriverState *chr = qemu_chr_fe_get_driver(&card->cs);
qemu_chr_fe_deinit(&card->cs);
qemu_chr_delete(chr);
card->vscard_in_pos = card->vscard_in_hdr = 0; card->vscard_in_pos = card->vscard_in_hdr = 0;
} }
@ -309,8 +312,6 @@ static void ccid_card_vscard_event(void *opaque, int event)
case CHR_EVENT_BREAK: case CHR_EVENT_BREAK:
card->vscard_in_pos = card->vscard_in_hdr = 0; card->vscard_in_pos = card->vscard_in_hdr = 0;
break; break;
case CHR_EVENT_FOCUS:
break;
case CHR_EVENT_OPENED: case CHR_EVENT_OPENED:
DPRINTF(card, D_INFO, "%s: CHR_EVENT_OPENED\n", __func__); DPRINTF(card, D_INFO, "%s: CHR_EVENT_OPENED\n", __func__);
break; break;
@ -324,7 +325,7 @@ static void passthru_apdu_from_guest(
{ {
PassthruState *card = PASSTHRU_CCID_CARD(base); PassthruState *card = PASSTHRU_CCID_CARD(base);
if (!card->cs) { if (!qemu_chr_fe_get_driver(&card->cs)) {
printf("ccid-passthru: no chardev, discarding apdu length %d\n", len); printf("ccid-passthru: no chardev, discarding apdu length %d\n", len);
return; return;
} }
@ -345,12 +346,12 @@ static int passthru_initfn(CCIDCardState *base)
card->vscard_in_pos = 0; card->vscard_in_pos = 0;
card->vscard_in_hdr = 0; card->vscard_in_hdr = 0;
if (card->cs) { if (qemu_chr_fe_get_driver(&card->cs)) {
DPRINTF(card, D_INFO, "initing chardev\n"); DPRINTF(card, D_INFO, "initing chardev\n");
qemu_chr_add_handlers(card->cs, qemu_chr_fe_set_handlers(&card->cs,
ccid_card_vscard_can_read, ccid_card_vscard_can_read,
ccid_card_vscard_read, ccid_card_vscard_read,
ccid_card_vscard_event, card); ccid_card_vscard_event, card, NULL, true);
ccid_card_vscard_send_init(card); ccid_card_vscard_send_init(card);
} else { } else {
error_report("missing chardev"); error_report("missing chardev");

View File

@ -103,7 +103,7 @@ typedef struct {
uint8_t event_trigger; uint8_t event_trigger;
QEMUSerialSetParams params; QEMUSerialSetParams params;
int latency; /* ms */ int latency; /* ms */
CharDriverState *cs; CharBackend cs;
} USBSerialState; } USBSerialState;
#define TYPE_USB_SERIAL "usb-serial-dev" #define TYPE_USB_SERIAL "usb-serial-dev"
@ -209,8 +209,10 @@ static uint8_t usb_get_modem_lines(USBSerialState *s)
int flags; int flags;
uint8_t ret; uint8_t ret;
if (qemu_chr_fe_ioctl(s->cs, CHR_IOCTL_SERIAL_GET_TIOCM, &flags) == -ENOTSUP) if (qemu_chr_fe_ioctl(&s->cs,
CHR_IOCTL_SERIAL_GET_TIOCM, &flags) == -ENOTSUP) {
return FTDI_CTS|FTDI_DSR|FTDI_RLSD; return FTDI_CTS|FTDI_DSR|FTDI_RLSD;
}
ret = 0; ret = 0;
if (flags & CHR_TIOCM_CTS) if (flags & CHR_TIOCM_CTS)
@ -260,7 +262,7 @@ static void usb_serial_handle_control(USBDevice *dev, USBPacket *p,
case DeviceOutVendor | FTDI_SET_MDM_CTRL: case DeviceOutVendor | FTDI_SET_MDM_CTRL:
{ {
static int flags; static int flags;
qemu_chr_fe_ioctl(s->cs,CHR_IOCTL_SERIAL_GET_TIOCM, &flags); qemu_chr_fe_ioctl(&s->cs, CHR_IOCTL_SERIAL_GET_TIOCM, &flags);
if (value & FTDI_SET_RTS) { if (value & FTDI_SET_RTS) {
if (value & FTDI_RTS) if (value & FTDI_RTS)
flags |= CHR_TIOCM_RTS; flags |= CHR_TIOCM_RTS;
@ -273,7 +275,7 @@ static void usb_serial_handle_control(USBDevice *dev, USBPacket *p,
else else
flags &= ~CHR_TIOCM_DTR; flags &= ~CHR_TIOCM_DTR;
} }
qemu_chr_fe_ioctl(s->cs,CHR_IOCTL_SERIAL_SET_TIOCM, &flags); qemu_chr_fe_ioctl(&s->cs, CHR_IOCTL_SERIAL_SET_TIOCM, &flags);
break; break;
} }
case DeviceOutVendor | FTDI_SET_FLOW_CTRL: case DeviceOutVendor | FTDI_SET_FLOW_CTRL:
@ -292,7 +294,7 @@ static void usb_serial_handle_control(USBDevice *dev, USBPacket *p,
divisor = 1; divisor = 1;
s->params.speed = (48000000 / 2) / (8 * divisor + subdivisor8); s->params.speed = (48000000 / 2) / (8 * divisor + subdivisor8);
qemu_chr_fe_ioctl(s->cs, CHR_IOCTL_SERIAL_SET_PARAMS, &s->params); qemu_chr_fe_ioctl(&s->cs, CHR_IOCTL_SERIAL_SET_PARAMS, &s->params);
break; break;
} }
case DeviceOutVendor | FTDI_SET_DATA: case DeviceOutVendor | FTDI_SET_DATA:
@ -321,7 +323,7 @@ static void usb_serial_handle_control(USBDevice *dev, USBPacket *p,
DPRINTF("unsupported stop bits %d\n", value & FTDI_STOP); DPRINTF("unsupported stop bits %d\n", value & FTDI_STOP);
goto fail; goto fail;
} }
qemu_chr_fe_ioctl(s->cs, CHR_IOCTL_SERIAL_SET_PARAMS, &s->params); qemu_chr_fe_ioctl(&s->cs, CHR_IOCTL_SERIAL_SET_PARAMS, &s->params);
/* TODO: TX ON/OFF */ /* TODO: TX ON/OFF */
break; break;
case DeviceInVendor | FTDI_GET_MDM_ST: case DeviceInVendor | FTDI_GET_MDM_ST:
@ -368,7 +370,7 @@ static void usb_serial_handle_data(USBDevice *dev, USBPacket *p)
iov = p->iov.iov + i; iov = p->iov.iov + i;
/* XXX this blocks entire thread. Rewrite to use /* XXX this blocks entire thread. Rewrite to use
* qemu_chr_fe_write and background I/O callbacks */ * qemu_chr_fe_write and background I/O callbacks */
qemu_chr_fe_write_all(s->cs, iov->iov_base, iov->iov_len); qemu_chr_fe_write_all(&s->cs, iov->iov_base, iov->iov_len);
} }
p->actual_length = p->iov.size; p->actual_length = p->iov.size;
break; break;
@ -464,8 +466,6 @@ static void usb_serial_event(void *opaque, int event)
case CHR_EVENT_BREAK: case CHR_EVENT_BREAK:
s->event_trigger |= FTDI_BI; s->event_trigger |= FTDI_BI;
break; break;
case CHR_EVENT_FOCUS:
break;
case CHR_EVENT_OPENED: case CHR_EVENT_OPENED:
if (!s->dev.attached) { if (!s->dev.attached) {
usb_device_attach(&s->dev, &error_abort); usb_device_attach(&s->dev, &error_abort);
@ -483,12 +483,13 @@ static void usb_serial_realize(USBDevice *dev, Error **errp)
{ {
USBSerialState *s = USB_SERIAL_DEV(dev); USBSerialState *s = USB_SERIAL_DEV(dev);
Error *local_err = NULL; Error *local_err = NULL;
CharDriverState *chr = qemu_chr_fe_get_driver(&s->cs);
usb_desc_create_serial(dev); usb_desc_create_serial(dev);
usb_desc_init(dev); usb_desc_init(dev);
dev->auto_attach = 0; dev->auto_attach = 0;
if (!s->cs) { if (!chr) {
error_setg(errp, "Property chardev is required"); error_setg(errp, "Property chardev is required");
return; return;
} }
@ -499,11 +500,11 @@ static void usb_serial_realize(USBDevice *dev, Error **errp)
return; return;
} }
qemu_chr_add_handlers(s->cs, usb_serial_can_read, usb_serial_read, qemu_chr_fe_set_handlers(&s->cs, usb_serial_can_read, usb_serial_read,
usb_serial_event, s); usb_serial_event, s, NULL, true);
usb_serial_handle_reset(dev); usb_serial_handle_reset(dev);
if (s->cs->be_open && !dev->attached) { if (chr->be_open && !dev->attached) {
usb_device_attach(dev, &error_abort); usb_device_attach(dev, &error_abort);
} }
} }
@ -547,7 +548,7 @@ static USBDevice *usb_serial_init(USBBus *bus, const char *filename)
filename++; filename++;
snprintf(label, sizeof(label), "usbserial%d", index++); snprintf(label, sizeof(label), "usbserial%d", index++);
cdrv = qemu_chr_new(label, filename, NULL); cdrv = qemu_chr_new(label, filename);
if (!cdrv) if (!cdrv)
return NULL; return NULL;
@ -565,7 +566,7 @@ static USBDevice *usb_braille_init(USBBus *bus, const char *unused)
USBDevice *dev; USBDevice *dev;
CharDriverState *cdrv; CharDriverState *cdrv;
cdrv = qemu_chr_new("braille", "braille", NULL); cdrv = qemu_chr_new("braille", "braille");
if (!cdrv) if (!cdrv)
return NULL; return NULL;

View File

@ -105,7 +105,7 @@ struct PacketIdQueue {
struct USBRedirDevice { struct USBRedirDevice {
USBDevice dev; USBDevice dev;
/* Properties */ /* Properties */
CharDriverState *cs; CharBackend cs;
uint8_t debug; uint8_t debug;
char *filter_str; char *filter_str;
int32_t bootindex; int32_t bootindex;
@ -283,9 +283,10 @@ static gboolean usbredir_write_unblocked(GIOChannel *chan, GIOCondition cond,
static int usbredir_write(void *priv, uint8_t *data, int count) static int usbredir_write(void *priv, uint8_t *data, int count)
{ {
USBRedirDevice *dev = priv; USBRedirDevice *dev = priv;
CharDriverState *chr = qemu_chr_fe_get_driver(&dev->cs);
int r; int r;
if (!dev->cs->be_open) { if (!chr->be_open) {
return 0; return 0;
} }
@ -294,10 +295,10 @@ static int usbredir_write(void *priv, uint8_t *data, int count)
return 0; return 0;
} }
r = qemu_chr_fe_write(dev->cs, data, count); r = qemu_chr_fe_write(&dev->cs, data, count);
if (r < count) { if (r < count) {
if (!dev->watch) { if (!dev->watch) {
dev->watch = qemu_chr_fe_add_watch(dev->cs, G_IO_OUT|G_IO_HUP, dev->watch = qemu_chr_fe_add_watch(&dev->cs, G_IO_OUT | G_IO_HUP,
usbredir_write_unblocked, dev); usbredir_write_unblocked, dev);
} }
if (r < 0) { if (r < 0) {
@ -1375,7 +1376,7 @@ static void usbredir_realize(USBDevice *udev, Error **errp)
USBRedirDevice *dev = USB_REDIRECT(udev); USBRedirDevice *dev = USB_REDIRECT(udev);
int i; int i;
if (dev->cs == NULL) { if (!qemu_chr_fe_get_driver(&dev->cs)) {
error_setg(errp, QERR_MISSING_PARAMETER, "chardev"); error_setg(errp, QERR_MISSING_PARAMETER, "chardev");
return; return;
} }
@ -1406,8 +1407,9 @@ static void usbredir_realize(USBDevice *udev, Error **errp)
dev->compatible_speedmask = USB_SPEED_MASK_FULL | USB_SPEED_MASK_HIGH; dev->compatible_speedmask = USB_SPEED_MASK_FULL | USB_SPEED_MASK_HIGH;
/* Let the backend know we are ready */ /* Let the backend know we are ready */
qemu_chr_add_handlers(dev->cs, usbredir_chardev_can_read, qemu_chr_fe_set_handlers(&dev->cs, usbredir_chardev_can_read,
usbredir_chardev_read, usbredir_chardev_event, dev); usbredir_chardev_read, usbredir_chardev_event,
dev, NULL, true);
qemu_add_vm_change_state_handler(usbredir_vm_state_change, dev); qemu_add_vm_change_state_handler(usbredir_vm_state_change, dev);
} }
@ -1426,9 +1428,11 @@ static void usbredir_cleanup_device_queues(USBRedirDevice *dev)
static void usbredir_handle_destroy(USBDevice *udev) static void usbredir_handle_destroy(USBDevice *udev)
{ {
USBRedirDevice *dev = USB_REDIRECT(udev); USBRedirDevice *dev = USB_REDIRECT(udev);
CharDriverState *chr = qemu_chr_fe_get_driver(&dev->cs);
qemu_chr_fe_deinit(&dev->cs);
qemu_chr_delete(chr);
qemu_chr_delete(dev->cs);
dev->cs = NULL;
/* Note must be done after qemu_chr_close, as that causes a close event */ /* Note must be done after qemu_chr_close, as that causes a close event */
qemu_bh_delete(dev->chardev_close_bh); qemu_bh_delete(dev->chardev_close_bh);
qemu_bh_delete(dev->device_reject_bh); qemu_bh_delete(dev->device_reject_bh);

View File

@ -116,7 +116,7 @@ static bool ioeventfd_enabled(void)
static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg) static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg)
{ {
CharDriverState *chr = dev->opaque; CharBackend *chr = dev->opaque;
uint8_t *p = (uint8_t *) msg; uint8_t *p = (uint8_t *) msg;
int r, size = VHOST_USER_HDR_SIZE; int r, size = VHOST_USER_HDR_SIZE;
@ -196,7 +196,7 @@ static bool vhost_user_one_time_request(VhostUserRequest request)
static int vhost_user_write(struct vhost_dev *dev, VhostUserMsg *msg, static int vhost_user_write(struct vhost_dev *dev, VhostUserMsg *msg,
int *fds, int fd_num) int *fds, int fd_num)
{ {
CharDriverState *chr = dev->opaque; CharBackend *chr = dev->opaque;
int ret, size = VHOST_USER_HDR_SIZE + msg->size; int ret, size = VHOST_USER_HDR_SIZE + msg->size;
/* /*

View File

@ -265,7 +265,7 @@ static void lx_init(const LxBoardDesc *board, MachineState *machine)
} }
if (!serial_hds[0]) { if (!serial_hds[0]) {
serial_hds[0] = qemu_chr_new("serial0", "null", NULL); serial_hds[0] = qemu_chr_new("serial0", "null");
} }
serial_mm_init(system_io, 0x0d050020, 2, xtensa_get_extint(env, 0), serial_mm_init(system_io, 0x0d050020, 2, xtensa_get_extint(env, 0),

View File

@ -255,8 +255,9 @@ struct MemoryListener {
hwaddr addr, hwaddr len); hwaddr addr, hwaddr len);
/* Lower = earlier (during add), later (during del) */ /* Lower = earlier (during add), later (during del) */
unsigned priority; unsigned priority;
AddressSpace *address_space_filter; AddressSpace *address_space;
QTAILQ_ENTRY(MemoryListener) link; QTAILQ_ENTRY(MemoryListener) link;
QTAILQ_ENTRY(MemoryListener) link_as;
}; };
/** /**
@ -278,7 +279,7 @@ struct AddressSpace {
struct AddressSpaceDispatch *dispatch; struct AddressSpaceDispatch *dispatch;
struct AddressSpaceDispatch *next_dispatch; struct AddressSpaceDispatch *next_dispatch;
MemoryListener dispatch_listener; MemoryListener dispatch_listener;
QTAILQ_HEAD(memory_listeners_as, MemoryListener) listeners;
QTAILQ_ENTRY(AddressSpace) address_spaces_link; QTAILQ_ENTRY(AddressSpace) address_spaces_link;
}; };

View File

@ -22,7 +22,7 @@ typedef struct {
/*< public >*/ /*< public >*/
MemoryRegion iomem; MemoryRegion iomem;
CharDriverState *chr; CharBackend chr;
qemu_irq irq; qemu_irq irq;
uint8_t read_fifo[BCM2835_AUX_RX_FIFO_LEN]; uint8_t read_fifo[BCM2835_AUX_RX_FIFO_LEN];

View File

@ -44,7 +44,7 @@ typedef struct {
uint32_t rx_count; uint32_t rx_count;
uint32_t tx_count; uint32_t tx_count;
uint64_t char_tx_time; uint64_t char_tx_time;
CharDriverState *chr; CharBackend chr;
qemu_irq irq; qemu_irq irq;
QEMUTimer *fifo_trigger_handle; QEMUTimer *fifo_trigger_handle;
} CadenceUARTState; } CadenceUARTState;

View File

@ -19,6 +19,7 @@
#define HW_CHAR_DIGIC_UART_H #define HW_CHAR_DIGIC_UART_H
#include "hw/sysbus.h" #include "hw/sysbus.h"
#include "sysemu/char.h"
#define TYPE_DIGIC_UART "digic-uart" #define TYPE_DIGIC_UART "digic-uart"
#define DIGIC_UART(obj) \ #define DIGIC_UART(obj) \
@ -37,7 +38,7 @@ typedef struct DigicUartState {
/*< public >*/ /*< public >*/
MemoryRegion regs_region; MemoryRegion regs_region;
CharDriverState *chr; CharBackend chr;
uint32_t reg_rx; uint32_t reg_rx;
uint32_t reg_st; uint32_t reg_st;

View File

@ -19,6 +19,7 @@
#define IMX_SERIAL_H #define IMX_SERIAL_H
#include "hw/sysbus.h" #include "hw/sysbus.h"
#include "sysemu/char.h"
#define TYPE_IMX_SERIAL "imx.serial" #define TYPE_IMX_SERIAL "imx.serial"
#define IMX_SERIAL(obj) OBJECT_CHECK(IMXSerialState, (obj), TYPE_IMX_SERIAL) #define IMX_SERIAL(obj) OBJECT_CHECK(IMXSerialState, (obj), TYPE_IMX_SERIAL)
@ -96,7 +97,7 @@ typedef struct IMXSerialState {
uint32_t ucr3; uint32_t ucr3;
qemu_irq irq; qemu_irq irq;
CharDriverState *chr; CharBackend chr;
} IMXSerialState; } IMXSerialState;
#endif #endif

View File

@ -28,8 +28,10 @@
#include "hw/hw.h" #include "hw/hw.h"
#include "sysemu/sysemu.h" #include "sysemu/sysemu.h"
#include "sysemu/char.h"
#include "exec/memory.h" #include "exec/memory.h"
#include "qemu/fifo8.h" #include "qemu/fifo8.h"
#include "sysemu/char.h"
#define UART_FIFO_LENGTH 16 /* 16550A Fifo Length */ #define UART_FIFO_LENGTH 16 /* 16550A Fifo Length */
@ -52,7 +54,7 @@ struct SerialState {
it can be reset while reading iir */ it can be reset while reading iir */
int thr_ipending; int thr_ipending;
qemu_irq irq; qemu_irq irq;
CharDriverState *chr; CharBackend chr;
int last_break_enable; int last_break_enable;
int it_shift; int it_shift;
int baudbase; int baudbase;
@ -94,6 +96,6 @@ SerialState *serial_mm_init(MemoryRegion *address_space,
/* serial-isa.c */ /* serial-isa.c */
#define TYPE_ISA_SERIAL "isa-serial" #define TYPE_ISA_SERIAL "isa-serial"
void serial_hds_isa_init(ISABus *bus, int n); void serial_hds_isa_init(ISABus *bus, int from, int to);
#endif #endif

View File

@ -67,7 +67,7 @@ typedef struct {
uint32_t usart_cr3; uint32_t usart_cr3;
uint32_t usart_gtpr; uint32_t usart_gtpr;
CharDriverState *chr; CharBackend chr;
qemu_irq irq; qemu_irq irq;
} STM32F2XXUsartState; } STM32F2XXUsartState;
#endif /* HW_STM32F2XX_USART_H */ #endif /* HW_STM32F2XX_USART_H */

View File

@ -146,7 +146,7 @@ extern PropertyInfo qdev_prop_arraylen;
DEFINE_PROP(_n, _s, _f, qdev_prop_ptr, void*) DEFINE_PROP(_n, _s, _f, qdev_prop_ptr, void*)
#define DEFINE_PROP_CHR(_n, _s, _f) \ #define DEFINE_PROP_CHR(_n, _s, _f) \
DEFINE_PROP(_n, _s, _f, qdev_prop_chr, CharDriverState*) DEFINE_PROP(_n, _s, _f, qdev_prop_chr, CharBackend)
#define DEFINE_PROP_STRING(_n, _s, _f) \ #define DEFINE_PROP_STRING(_n, _s, _f) \
DEFINE_PROP(_n, _s, _f, qdev_prop_string, char*) DEFINE_PROP(_n, _s, _f, qdev_prop_string, char*)
#define DEFINE_PROP_NETDEV(_n, _s, _f) \ #define DEFINE_PROP_NETDEV(_n, _s, _f) \

View File

@ -72,16 +72,16 @@
* Add one here, and similarly in smp_rmb() and smp_read_barrier_depends(). * Add one here, and similarly in smp_rmb() and smp_read_barrier_depends().
*/ */
#define smp_mb() ({ barrier(); __atomic_thread_fence(__ATOMIC_SEQ_CST); }) #define smp_mb() ({ barrier(); __atomic_thread_fence(__ATOMIC_SEQ_CST); })
#define smp_wmb() ({ barrier(); __atomic_thread_fence(__ATOMIC_RELEASE); }) #define smp_mb_release() ({ barrier(); __atomic_thread_fence(__ATOMIC_RELEASE); })
#define smp_rmb() ({ barrier(); __atomic_thread_fence(__ATOMIC_ACQUIRE); }) #define smp_mb_acquire() ({ barrier(); __atomic_thread_fence(__ATOMIC_ACQUIRE); })
/* Most compilers currently treat consume and acquire the same, but really /* Most compilers currently treat consume and acquire the same, but really
* no processors except Alpha need a barrier here. Leave it in if * no processors except Alpha need a barrier here. Leave it in if
* using Thread Sanitizer to avoid warnings, otherwise optimize it away. * using Thread Sanitizer to avoid warnings, otherwise optimize it away.
*/ */
#if defined(__SANITIZE_THREAD__) #if defined(__SANITIZE_THREAD__)
#define smp_read_barrier_depends() ({ barrier(); __atomic_thread_fence(__ATOMIC_CONSUME); }) #define smp_read_barrier_depends() ({ barrier(); __atomic_thread_fence(__ATOMIC_CONSUME); })
#elif defined(__alpha__) #elif defined(__alpha__)
#define smp_read_barrier_depends() asm volatile("mb":::"memory") #define smp_read_barrier_depends() asm volatile("mb":::"memory")
#else #else
@ -135,44 +135,18 @@
__atomic_store_n(ptr, i, __ATOMIC_RELEASE); \ __atomic_store_n(ptr, i, __ATOMIC_RELEASE); \
} while(0) } while(0)
/* atomic_mb_read/set semantics map Java volatile variables. They are #define atomic_load_acquire(ptr) \
* less expensive on some platforms (notably POWER & ARMv7) than fully
* sequentially consistent operations.
*
* As long as they are used as paired operations they are safe to
* use. See docs/atomic.txt for more discussion.
*/
#if defined(_ARCH_PPC)
#define atomic_mb_read(ptr) \
({ \ ({ \
QEMU_BUILD_BUG_ON(sizeof(*ptr) > sizeof(void *)); \ QEMU_BUILD_BUG_ON(sizeof(*ptr) > sizeof(void *)); \
typeof_strip_qual(*ptr) _val; \ typeof_strip_qual(*ptr) _val; \
__atomic_load(ptr, &_val, __ATOMIC_RELAXED); \ __atomic_load(ptr, &_val, __ATOMIC_ACQUIRE); \
smp_rmb(); \
_val; \ _val; \
}) })
#define atomic_mb_set(ptr, i) do { \ #define atomic_store_release(ptr, i) do { \
QEMU_BUILD_BUG_ON(sizeof(*ptr) > sizeof(void *)); \ QEMU_BUILD_BUG_ON(sizeof(*ptr) > sizeof(void *)); \
smp_wmb(); \ __atomic_store_n(ptr, i, __ATOMIC_RELEASE); \
__atomic_store_n(ptr, i, __ATOMIC_RELAXED); \
smp_mb(); \
} while(0) } while(0)
#else
#define atomic_mb_read(ptr) \
({ \
QEMU_BUILD_BUG_ON(sizeof(*ptr) > sizeof(void *)); \
typeof_strip_qual(*ptr) _val; \
__atomic_load(ptr, &_val, __ATOMIC_SEQ_CST); \
_val; \
})
#define atomic_mb_set(ptr, i) do { \
QEMU_BUILD_BUG_ON(sizeof(*ptr) > sizeof(void *)); \
__atomic_store_n(ptr, i, __ATOMIC_SEQ_CST); \
} while(0)
#endif
/* All the remaining operations are fully sequentially consistent */ /* All the remaining operations are fully sequentially consistent */
@ -238,8 +212,8 @@
* here (a compiler barrier only). QEMU doesn't do accesses to write-combining * here (a compiler barrier only). QEMU doesn't do accesses to write-combining
* qemu memory or non-temporal load/stores from C code. * qemu memory or non-temporal load/stores from C code.
*/ */
#define smp_wmb() barrier() #define smp_mb_release() barrier()
#define smp_rmb() barrier() #define smp_mb_acquire() barrier()
/* /*
* __sync_lock_test_and_set() is documented to be an acquire barrier only, * __sync_lock_test_and_set() is documented to be an acquire barrier only,
@ -248,11 +222,6 @@
*/ */
#define atomic_xchg(ptr, i) (barrier(), __sync_lock_test_and_set(ptr, i)) #define atomic_xchg(ptr, i) (barrier(), __sync_lock_test_and_set(ptr, i))
/*
* Load/store with Java volatile semantics.
*/
#define atomic_mb_set(ptr, i) ((void)atomic_xchg(ptr, i))
#elif defined(_ARCH_PPC) #elif defined(_ARCH_PPC)
/* /*
@ -263,13 +232,15 @@
* smp_mb has the same problem as on x86 for not-very-new GCC * smp_mb has the same problem as on x86 for not-very-new GCC
* (http://patchwork.ozlabs.org/patch/126184/, Nov 2011). * (http://patchwork.ozlabs.org/patch/126184/, Nov 2011).
*/ */
#define smp_wmb() ({ asm volatile("eieio" ::: "memory"); (void)0; }) #define smp_wmb() ({ asm volatile("eieio" ::: "memory"); (void)0; })
#if defined(__powerpc64__) #if defined(__powerpc64__)
#define smp_rmb() ({ asm volatile("lwsync" ::: "memory"); (void)0; }) #define smp_mb_release() ({ asm volatile("lwsync" ::: "memory"); (void)0; })
#define smp_mb_acquire() ({ asm volatile("lwsync" ::: "memory"); (void)0; })
#else #else
#define smp_rmb() ({ asm volatile("sync" ::: "memory"); (void)0; }) #define smp_mb_release() ({ asm volatile("sync" ::: "memory"); (void)0; })
#define smp_mb_acquire() ({ asm volatile("sync" ::: "memory"); (void)0; })
#endif #endif
#define smp_mb() ({ asm volatile("sync" ::: "memory"); (void)0; }) #define smp_mb() ({ asm volatile("sync" ::: "memory"); (void)0; })
#endif /* _ARCH_PPC */ #endif /* _ARCH_PPC */
@ -277,18 +248,18 @@
* For (host) platforms we don't have explicit barrier definitions * For (host) platforms we don't have explicit barrier definitions
* for, we use the gcc __sync_synchronize() primitive to generate a * for, we use the gcc __sync_synchronize() primitive to generate a
* full barrier. This should be safe on all platforms, though it may * full barrier. This should be safe on all platforms, though it may
* be overkill for smp_wmb() and smp_rmb(). * be overkill for smp_mb_acquire() and smp_mb_release().
*/ */
#ifndef smp_mb #ifndef smp_mb
#define smp_mb() __sync_synchronize() #define smp_mb() __sync_synchronize()
#endif #endif
#ifndef smp_wmb #ifndef smp_mb_acquire
#define smp_wmb() __sync_synchronize() #define smp_mb_acquire() __sync_synchronize()
#endif #endif
#ifndef smp_rmb #ifndef smp_mb_release
#define smp_rmb() __sync_synchronize() #define smp_mb_release() __sync_synchronize()
#endif #endif
#ifndef smp_read_barrier_depends #ifndef smp_read_barrier_depends
@ -341,41 +312,16 @@
atomic_set(ptr, i); \ atomic_set(ptr, i); \
} while (0) } while (0)
/* These have the same semantics as Java volatile variables. #define atomic_load_acquire(ptr) ({ \
* See http://gee.cs.oswego.edu/dl/jmm/cookbook.html:
* "1. Issue a StoreStore barrier (wmb) before each volatile store."
* 2. Issue a StoreLoad barrier after each volatile store.
* Note that you could instead issue one before each volatile load, but
* this would be slower for typical programs using volatiles in which
* reads greatly outnumber writes. Alternatively, if available, you
* can implement volatile store as an atomic instruction (for example
* XCHG on x86) and omit the barrier. This may be more efficient if
* atomic instructions are cheaper than StoreLoad barriers.
* 3. Issue LoadLoad and LoadStore barriers after each volatile load."
*
* If you prefer to think in terms of "pairing" of memory barriers,
* an atomic_mb_read pairs with an atomic_mb_set.
*
* And for the few ia64 lovers that exist, an atomic_mb_read is a ld.acq,
* while an atomic_mb_set is a st.rel followed by a memory barrier.
*
* These are a bit weaker than __atomic_load/store with __ATOMIC_SEQ_CST
* (see docs/atomics.txt), and I'm not sure that __ATOMIC_ACQ_REL is enough.
* Just always use the barriers manually by the rules above.
*/
#define atomic_mb_read(ptr) ({ \
typeof(*ptr) _val = atomic_read(ptr); \ typeof(*ptr) _val = atomic_read(ptr); \
smp_rmb(); \ smp_mb_acquire(); \
_val; \ _val; \
}) })
#ifndef atomic_mb_set #define atomic_store_release(ptr, i) do { \
#define atomic_mb_set(ptr, i) do { \ smp_mb_release(); \
smp_wmb(); \
atomic_set(ptr, i); \ atomic_set(ptr, i); \
smp_mb(); \
} while (0) } while (0)
#endif
#ifndef atomic_xchg #ifndef atomic_xchg
#if defined(__clang__) #if defined(__clang__)
@ -404,4 +350,39 @@
#define atomic_or(ptr, n) ((void) __sync_fetch_and_or(ptr, n)) #define atomic_or(ptr, n) ((void) __sync_fetch_and_or(ptr, n))
#endif /* __ATOMIC_RELAXED */ #endif /* __ATOMIC_RELAXED */
#ifndef smp_wmb
#define smp_wmb() smp_mb_release()
#endif
#ifndef smp_rmb
#define smp_rmb() smp_mb_acquire()
#endif
/* This is more efficient than a store plus a fence. */
#if !defined(__SANITIZE_THREAD__)
#if defined(__i386__) || defined(__x86_64__) || defined(__s390x__)
#define atomic_mb_set(ptr, i) ((void)atomic_xchg(ptr, i))
#endif
#endif
/* atomic_mb_read/set semantics map Java volatile variables. They are
* less expensive on some platforms (notably POWER) than fully
* sequentially consistent operations.
*
* As long as they are used as paired operations they are safe to
* use. See docs/atomic.txt for more discussion.
*/
#ifndef atomic_mb_read
#define atomic_mb_read(ptr) \
atomic_load_acquire(ptr)
#endif
#ifndef atomic_mb_set
#define atomic_mb_set(ptr, i) do { \
atomic_store_release(ptr, i); \
smp_mb(); \
} while(0)
#endif
#endif /* QEMU_ATOMIC_H */ #endif /* QEMU_ATOMIC_H */

View File

@ -13,12 +13,13 @@
/* character device */ /* character device */
#define CHR_EVENT_BREAK 0 /* serial break char */ typedef enum {
#define CHR_EVENT_FOCUS 1 /* focus to this terminal (modal input needed) */ CHR_EVENT_BREAK, /* serial break char */
#define CHR_EVENT_OPENED 2 /* new connection established */ CHR_EVENT_OPENED, /* new connection established */
#define CHR_EVENT_MUX_IN 3 /* mux-focus was set to this terminal */ CHR_EVENT_MUX_IN, /* mux-focus was set to this terminal */
#define CHR_EVENT_MUX_OUT 4 /* mux-focus will move on */ CHR_EVENT_MUX_OUT, /* mux-focus will move on */
#define CHR_EVENT_CLOSED 5 /* connection closed */ CHR_EVENT_CLOSED /* connection closed */
} QEMUChrEvent;
#define CHR_IOCTL_SERIAL_SET_PARAMS 1 #define CHR_IOCTL_SERIAL_SET_PARAMS 1
@ -72,10 +73,20 @@ typedef enum {
QEMU_CHAR_FEATURE_LAST, QEMU_CHAR_FEATURE_LAST,
} CharDriverFeature; } CharDriverFeature;
/* This is the backend as seen by frontend, the actual backend is
* CharDriverState */
typedef struct CharBackend {
CharDriverState *chr;
IOEventHandler *chr_event;
IOCanReadHandler *chr_can_read;
IOReadHandler *chr_read;
void *opaque;
int tag;
int fe_open;
} CharBackend;
struct CharDriverState { struct CharDriverState {
QemuMutex chr_write_lock; QemuMutex chr_write_lock;
void (*init)(struct CharDriverState *s);
int (*chr_write)(struct CharDriverState *s, const uint8_t *buf, int len); int (*chr_write)(struct CharDriverState *s, const uint8_t *buf, int len);
int (*chr_sync_read)(struct CharDriverState *s, int (*chr_sync_read)(struct CharDriverState *s,
const uint8_t *buf, int len); const uint8_t *buf, int len);
@ -87,25 +98,17 @@ struct CharDriverState {
int (*set_msgfds)(struct CharDriverState *s, int *fds, int num); int (*set_msgfds)(struct CharDriverState *s, int *fds, int num);
int (*chr_add_client)(struct CharDriverState *chr, int fd); int (*chr_add_client)(struct CharDriverState *chr, int fd);
int (*chr_wait_connected)(struct CharDriverState *chr, Error **errp); int (*chr_wait_connected)(struct CharDriverState *chr, Error **errp);
IOEventHandler *chr_event; void (*chr_free)(struct CharDriverState *chr);
IOCanReadHandler *chr_can_read;
IOReadHandler *chr_read;
void *handler_opaque;
void (*chr_close)(struct CharDriverState *chr);
void (*chr_disconnect)(struct CharDriverState *chr); void (*chr_disconnect)(struct CharDriverState *chr);
void (*chr_accept_input)(struct CharDriverState *chr); void (*chr_accept_input)(struct CharDriverState *chr);
void (*chr_set_echo)(struct CharDriverState *chr, bool echo); void (*chr_set_echo)(struct CharDriverState *chr, bool echo);
void (*chr_set_fe_open)(struct CharDriverState *chr, int fe_open); void (*chr_set_fe_open)(struct CharDriverState *chr, int fe_open);
void (*chr_fe_event)(struct CharDriverState *chr, int event); CharBackend *be;
void *opaque; void *opaque;
char *label; char *label;
char *filename; char *filename;
int logfd; int logfd;
int be_open; int be_open;
int fe_open;
int explicit_fe_open;
int explicit_be_open;
int avail_connections;
int is_mux; int is_mux;
guint fd_in_tag; guint fd_in_tag;
bool replay; bool replay;
@ -130,13 +133,11 @@ CharDriverState *qemu_chr_alloc(ChardevCommon *backend, Error **errp);
* Create a new character backend from a QemuOpts list. * Create a new character backend from a QemuOpts list.
* *
* @opts see qemu-config.c for a list of valid options * @opts see qemu-config.c for a list of valid options
* @init not sure..
* *
* Returns: a new character backend * Returns: a new character backend
*/ */
CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts, CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
void (*init)(struct CharDriverState *s), Error **errp);
Error **errp);
/** /**
* @qemu_chr_parse_common: * @qemu_chr_parse_common:
@ -155,18 +156,19 @@ void qemu_chr_parse_common(QemuOpts *opts, ChardevCommon *backend);
* *
* @label the name of the backend * @label the name of the backend
* @filename the URI * @filename the URI
* @init not sure..
* *
* Returns: a new character backend * Returns: a new character backend
*/ */
CharDriverState *qemu_chr_new(const char *label, const char *filename, CharDriverState *qemu_chr_new(const char *label, const char *filename);
void (*init)(struct CharDriverState *s));
/** /**
* @qemu_chr_disconnect: * @qemu_chr_fe_disconnect:
* *
* Close a fd accpeted by character backend. * Close a fd accpeted by character backend.
* Without associated CharDriver, do nothing.
*/ */
void qemu_chr_disconnect(CharDriverState *chr); void qemu_chr_fe_disconnect(CharBackend *be);
/** /**
* @qemu_chr_cleanup: * @qemu_chr_cleanup:
@ -176,11 +178,12 @@ void qemu_chr_disconnect(CharDriverState *chr);
void qemu_chr_cleanup(void); void qemu_chr_cleanup(void);
/** /**
* @qemu_chr_wait_connected: * @qemu_chr_fe_wait_connected:
* *
* Wait for characted backend to be connected. * Wait for characted backend to be connected, return < 0 on error or
* if no assicated CharDriver.
*/ */
int qemu_chr_wait_connected(CharDriverState *chr, Error **errp); int qemu_chr_fe_wait_connected(CharBackend *be, Error **errp);
/** /**
* @qemu_chr_new_noreplay: * @qemu_chr_new_noreplay:
@ -191,12 +194,10 @@ int qemu_chr_wait_connected(CharDriverState *chr, Error **errp);
* *
* @label the name of the backend * @label the name of the backend
* @filename the URI * @filename the URI
* @init not sure..
* *
* Returns: a new character backend * Returns: a new character backend
*/ */
CharDriverState *qemu_chr_new_noreplay(const char *label, const char *filename, CharDriverState *qemu_chr_new_noreplay(const char *label, const char *filename);
void (*init)(struct CharDriverState *s));
/** /**
* @qemu_chr_delete: * @qemu_chr_delete:
@ -219,37 +220,31 @@ void qemu_chr_free(CharDriverState *chr);
* Ask the backend to override its normal echo setting. This only really * Ask the backend to override its normal echo setting. This only really
* applies to the stdio backend and is used by the QMP server such that you * applies to the stdio backend and is used by the QMP server such that you
* can see what you type if you try to type QMP commands. * can see what you type if you try to type QMP commands.
* Without associated CharDriver, do nothing.
* *
* @echo true to enable echo, false to disable echo * @echo true to enable echo, false to disable echo
*/ */
void qemu_chr_fe_set_echo(struct CharDriverState *chr, bool echo); void qemu_chr_fe_set_echo(CharBackend *be, bool echo);
/** /**
* @qemu_chr_fe_set_open: * @qemu_chr_fe_set_open:
* *
* Set character frontend open status. This is an indication that the * Set character frontend open status. This is an indication that the
* front end is ready (or not) to begin doing I/O. * front end is ready (or not) to begin doing I/O.
* Without associated CharDriver, do nothing.
*/ */
void qemu_chr_fe_set_open(struct CharDriverState *chr, int fe_open); void qemu_chr_fe_set_open(CharBackend *be, int fe_open);
/**
* @qemu_chr_fe_event:
*
* Send an event from the front end to the back end.
*
* @event the event to send
*/
void qemu_chr_fe_event(CharDriverState *s, int event);
/** /**
* @qemu_chr_fe_printf: * @qemu_chr_fe_printf:
* *
* Write to a character backend using a printf style interface. * Write to a character backend using a printf style interface. This
* This function is thread-safe. * function is thread-safe. It does nothing without associated
* CharDriver.
* *
* @fmt see #printf * @fmt see #printf
*/ */
void qemu_chr_fe_printf(CharDriverState *s, const char *fmt, ...) void qemu_chr_fe_printf(CharBackend *be, const char *fmt, ...)
GCC_FMT_ATTR(2, 3); GCC_FMT_ATTR(2, 3);
/** /**
@ -258,13 +253,13 @@ void qemu_chr_fe_printf(CharDriverState *s, const char *fmt, ...)
* If the backend is connected, create and add a #GSource that fires * If the backend is connected, create and add a #GSource that fires
* when the given condition (typically G_IO_OUT|G_IO_HUP or G_IO_HUP) * when the given condition (typically G_IO_OUT|G_IO_HUP or G_IO_HUP)
* is active; return the #GSource's tag. If it is disconnected, * is active; return the #GSource's tag. If it is disconnected,
* return 0. * or without associated CharDriver, return 0.
* *
* @cond the condition to poll for * @cond the condition to poll for
* @func the function to call when the condition happens * @func the function to call when the condition happens
* @user_data the opaque pointer to pass to @func * @user_data the opaque pointer to pass to @func
*/ */
guint qemu_chr_fe_add_watch(CharDriverState *s, GIOCondition cond, guint qemu_chr_fe_add_watch(CharBackend *be, GIOCondition cond,
GIOFunc func, void *user_data); GIOFunc func, void *user_data);
/** /**
@ -277,9 +272,9 @@ guint qemu_chr_fe_add_watch(CharDriverState *s, GIOCondition cond,
* @buf the data * @buf the data
* @len the number of bytes to send * @len the number of bytes to send
* *
* Returns: the number of bytes consumed * Returns: the number of bytes consumed (0 if no assicated CharDriver)
*/ */
int qemu_chr_fe_write(CharDriverState *s, const uint8_t *buf, int len); int qemu_chr_fe_write(CharBackend *be, const uint8_t *buf, int len);
/** /**
* @qemu_chr_fe_write_all: * @qemu_chr_fe_write_all:
@ -292,9 +287,9 @@ int qemu_chr_fe_write(CharDriverState *s, const uint8_t *buf, int len);
* @buf the data * @buf the data
* @len the number of bytes to send * @len the number of bytes to send
* *
* Returns: the number of bytes consumed * Returns: the number of bytes consumed (0 if no assicated CharDriver)
*/ */
int qemu_chr_fe_write_all(CharDriverState *s, const uint8_t *buf, int len); int qemu_chr_fe_write_all(CharBackend *be, const uint8_t *buf, int len);
/** /**
* @qemu_chr_fe_read_all: * @qemu_chr_fe_read_all:
@ -304,9 +299,9 @@ int qemu_chr_fe_write_all(CharDriverState *s, const uint8_t *buf, int len);
* @buf the data buffer * @buf the data buffer
* @len the number of bytes to read * @len the number of bytes to read
* *
* Returns: the number of bytes read * Returns: the number of bytes read (0 if no assicated CharDriver)
*/ */
int qemu_chr_fe_read_all(CharDriverState *s, uint8_t *buf, int len); int qemu_chr_fe_read_all(CharBackend *be, uint8_t *buf, int len);
/** /**
* @qemu_chr_fe_ioctl: * @qemu_chr_fe_ioctl:
@ -316,10 +311,11 @@ int qemu_chr_fe_read_all(CharDriverState *s, uint8_t *buf, int len);
* @cmd see CHR_IOCTL_* * @cmd see CHR_IOCTL_*
* @arg the data associated with @cmd * @arg the data associated with @cmd
* *
* Returns: if @cmd is not supported by the backend, -ENOTSUP, otherwise the * Returns: if @cmd is not supported by the backend or there is no
* return value depends on the semantics of @cmd * associated CharDriver, -ENOTSUP, otherwise the return
* value depends on the semantics of @cmd
*/ */
int qemu_chr_fe_ioctl(CharDriverState *s, int cmd, void *arg); int qemu_chr_fe_ioctl(CharBackend *be, int cmd, void *arg);
/** /**
* @qemu_chr_fe_get_msgfd: * @qemu_chr_fe_get_msgfd:
@ -332,7 +328,7 @@ int qemu_chr_fe_ioctl(CharDriverState *s, int cmd, void *arg);
* this function will return -1 until a client sends a new file * this function will return -1 until a client sends a new file
* descriptor. * descriptor.
*/ */
int qemu_chr_fe_get_msgfd(CharDriverState *s); int qemu_chr_fe_get_msgfd(CharBackend *be);
/** /**
* @qemu_chr_fe_get_msgfds: * @qemu_chr_fe_get_msgfds:
@ -345,7 +341,7 @@ int qemu_chr_fe_get_msgfd(CharDriverState *s);
* this function will return -1 until a client sends a new set of file * this function will return -1 until a client sends a new set of file
* descriptors. * descriptors.
*/ */
int qemu_chr_fe_get_msgfds(CharDriverState *s, int *fds, int num); int qemu_chr_fe_get_msgfds(CharBackend *be, int *fds, int num);
/** /**
* @qemu_chr_fe_set_msgfds: * @qemu_chr_fe_set_msgfds:
@ -356,38 +352,9 @@ int qemu_chr_fe_get_msgfds(CharDriverState *s, int *fds, int num);
* result in overwriting the fd array with the new value without being send. * result in overwriting the fd array with the new value without being send.
* Upon writing the message the fd array is freed. * Upon writing the message the fd array is freed.
* *
* Returns: -1 if fd passing isn't supported. * Returns: -1 if fd passing isn't supported or no associated CharDriver.
*/ */
int qemu_chr_fe_set_msgfds(CharDriverState *s, int *fds, int num); int qemu_chr_fe_set_msgfds(CharBackend *be, int *fds, int num);
/**
* @qemu_chr_fe_claim:
*
* Claim a backend before using it, should be called before calling
* qemu_chr_add_handlers().
*
* Returns: -1 if the backend is already in use by another frontend, 0 on
* success.
*/
int qemu_chr_fe_claim(CharDriverState *s);
/**
* @qemu_chr_fe_claim_no_fail:
*
* Like qemu_chr_fe_claim, but will exit qemu with an error when the
* backend is already in use.
*/
void qemu_chr_fe_claim_no_fail(CharDriverState *s);
/**
* @qemu_chr_fe_claim:
*
* Release a backend for use by another frontend.
*
* Returns: -1 if the backend is already in use by another frontend, 0 on
* success.
*/
void qemu_chr_fe_release(CharDriverState *s);
/** /**
* @qemu_chr_be_can_write: * @qemu_chr_be_can_write:
@ -432,22 +399,70 @@ void qemu_chr_be_write_impl(CharDriverState *s, uint8_t *buf, int len);
*/ */
void qemu_chr_be_event(CharDriverState *s, int event); void qemu_chr_be_event(CharDriverState *s, int event);
void qemu_chr_add_handlers(CharDriverState *s, /**
IOCanReadHandler *fd_can_read, * @qemu_chr_fe_init:
IOReadHandler *fd_read, *
IOEventHandler *fd_event, * Initializes a front end for the given CharBackend and
void *opaque); * CharDriver. Call qemu_chr_fe_deinit() to remove the association and
* release the driver.
*
* Returns: false on error.
*/
bool qemu_chr_fe_init(CharBackend *b, CharDriverState *s, Error **errp);
/* This API can make handler run in the context what you pass to. */ /**
void qemu_chr_add_handlers_full(CharDriverState *s, * @qemu_chr_fe_get_driver:
IOCanReadHandler *fd_can_read, *
IOReadHandler *fd_read, * Returns the driver associated with a CharBackend or NULL if no
IOEventHandler *fd_event, * associated CharDriver.
void *opaque, */
GMainContext *context); CharDriverState *qemu_chr_fe_get_driver(CharBackend *be);
/**
* @qemu_chr_fe_deinit:
*
* Dissociate the CharBackend from the CharDriver.
*
* Safe to call without associated CharDriver.
*/
void qemu_chr_fe_deinit(CharBackend *b);
/**
* @qemu_chr_fe_set_handlers:
* @b: a CharBackend
* @fd_can_read: callback to get the amount of data the frontend may
* receive
* @fd_read: callback to receive data from char
* @fd_event: event callback
* @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
* any of the handler is non-NULL
*
* Set the front end char handlers. The front end takes the focus if
* any of the handler is non-NULL.
*
* Without associated CharDriver, nothing is changed.
*/
void qemu_chr_fe_set_handlers(CharBackend *b,
IOCanReadHandler *fd_can_read,
IOReadHandler *fd_read,
IOEventHandler *fd_event,
void *opaque,
GMainContext *context,
bool set_open);
/**
* @qemu_chr_fe_take_focus:
*
* Take the focus (if the front end is muxed).
*
* Without associated CharDriver, nothing is changed.
*/
void qemu_chr_fe_take_focus(CharBackend *b);
void qemu_chr_be_generic_open(CharDriverState *s); void qemu_chr_be_generic_open(CharDriverState *s);
void qemu_chr_accept_input(CharDriverState *s); void qemu_chr_fe_accept_input(CharBackend *be);
int qemu_chr_add_client(CharDriverState *s, int fd); int qemu_chr_add_client(CharDriverState *s, int fd);
CharDriverState *qemu_chr_find(const char *name); CharDriverState *qemu_chr_find(const char *name);
bool chr_is_ringbuf(const CharDriverState *chr); bool chr_is_ringbuf(const CharDriverState *chr);
@ -458,10 +473,15 @@ void qemu_chr_set_feature(CharDriverState *chr,
CharDriverFeature feature); CharDriverFeature feature);
QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename); QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename);
typedef void CharDriverParse(QemuOpts *opts, ChardevBackend *backend,
Error **errp);
typedef CharDriverState *CharDriverCreate(const char *id,
ChardevBackend *backend,
ChardevReturn *ret, bool *be_opened,
Error **errp);
void register_char_driver(const char *name, ChardevBackendKind kind, void register_char_driver(const char *name, ChardevBackendKind kind,
void (*parse)(QemuOpts *opts, ChardevBackend *backend, Error **errp), CharDriverParse *parse, CharDriverCreate *create);
CharDriverState *(*create)(const char *id, ChardevBackend *backend,
ChardevReturn *ret, Error **errp));
extern int term_escape_char; extern int term_escape_char;

View File

@ -2215,15 +2215,14 @@ int kvm_sw_breakpoints_active(CPUState *cpu)
struct kvm_set_guest_debug_data { struct kvm_set_guest_debug_data {
struct kvm_guest_debug dbg; struct kvm_guest_debug dbg;
CPUState *cpu;
int err; int err;
}; };
static void kvm_invoke_set_guest_debug(CPUState *unused_cpu, void *data) static void kvm_invoke_set_guest_debug(CPUState *cpu, void *data)
{ {
struct kvm_set_guest_debug_data *dbg_data = data; struct kvm_set_guest_debug_data *dbg_data = data;
dbg_data->err = kvm_vcpu_ioctl(dbg_data->cpu, KVM_SET_GUEST_DEBUG, dbg_data->err = kvm_vcpu_ioctl(cpu, KVM_SET_GUEST_DEBUG,
&dbg_data->dbg); &dbg_data->dbg);
} }

View File

@ -3956,7 +3956,7 @@ static void handle_arg_strace(const char *arg)
static void handle_arg_version(const char *arg) static void handle_arg_version(const char *arg)
{ {
printf("qemu-" TARGET_NAME " version " QEMU_VERSION QEMU_PKGVERSION printf("qemu-" TARGET_NAME " version " QEMU_VERSION QEMU_PKGVERSION
", " QEMU_COPYRIGHT "\n"); "\n" QEMU_COPYRIGHT "\n");
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }

View File

@ -97,13 +97,6 @@ static AddrRange addrrange_intersection(AddrRange r1, AddrRange r2)
enum ListenerDirection { Forward, Reverse }; enum ListenerDirection { Forward, Reverse };
static bool memory_listener_match(MemoryListener *listener,
MemoryRegionSection *section)
{
return !listener->address_space_filter
|| listener->address_space_filter == section->address_space;
}
#define MEMORY_LISTENER_CALL_GLOBAL(_callback, _direction, _args...) \ #define MEMORY_LISTENER_CALL_GLOBAL(_callback, _direction, _args...) \
do { \ do { \
MemoryListener *_listener; \ MemoryListener *_listener; \
@ -129,24 +122,23 @@ static bool memory_listener_match(MemoryListener *listener,
} \ } \
} while (0) } while (0)
#define MEMORY_LISTENER_CALL(_callback, _direction, _section, _args...) \ #define MEMORY_LISTENER_CALL(_as, _callback, _direction, _section, _args...) \
do { \ do { \
MemoryListener *_listener; \ MemoryListener *_listener; \
struct memory_listeners_as *list = &(_as)->listeners; \
\ \
switch (_direction) { \ switch (_direction) { \
case Forward: \ case Forward: \
QTAILQ_FOREACH(_listener, &memory_listeners, link) { \ QTAILQ_FOREACH(_listener, list, link_as) { \
if (_listener->_callback \ if (_listener->_callback) { \
&& memory_listener_match(_listener, _section)) { \
_listener->_callback(_listener, _section, ##_args); \ _listener->_callback(_listener, _section, ##_args); \
} \ } \
} \ } \
break; \ break; \
case Reverse: \ case Reverse: \
QTAILQ_FOREACH_REVERSE(_listener, &memory_listeners, \ QTAILQ_FOREACH_REVERSE(_listener, list, memory_listeners_as, \
memory_listeners, link) { \ link_as) { \
if (_listener->_callback \ if (_listener->_callback) { \
&& memory_listener_match(_listener, _section)) { \
_listener->_callback(_listener, _section, ##_args); \ _listener->_callback(_listener, _section, ##_args); \
} \ } \
} \ } \
@ -160,7 +152,7 @@ static bool memory_listener_match(MemoryListener *listener,
#define MEMORY_LISTENER_UPDATE_REGION(fr, as, dir, callback, _args...) \ #define MEMORY_LISTENER_UPDATE_REGION(fr, as, dir, callback, _args...) \
do { \ do { \
MemoryRegionSection mrs = section_from_flat_range(fr, as); \ MemoryRegionSection mrs = section_from_flat_range(fr, as); \
MEMORY_LISTENER_CALL(callback, dir, &mrs, ##_args); \ MEMORY_LISTENER_CALL(as, callback, dir, &mrs, ##_args); \
} while(0) } while(0)
struct CoalescedMemoryRange { struct CoalescedMemoryRange {
@ -749,7 +741,7 @@ static void address_space_add_del_ioeventfds(AddressSpace *as,
.offset_within_address_space = int128_get64(fd->addr.start), .offset_within_address_space = int128_get64(fd->addr.start),
.size = fd->addr.size, .size = fd->addr.size,
}; };
MEMORY_LISTENER_CALL(eventfd_del, Forward, &section, MEMORY_LISTENER_CALL(as, eventfd_del, Forward, &section,
fd->match_data, fd->data, fd->e); fd->match_data, fd->data, fd->e);
++iold; ++iold;
} else if (inew < fds_new_nb } else if (inew < fds_new_nb
@ -762,7 +754,7 @@ static void address_space_add_del_ioeventfds(AddressSpace *as,
.offset_within_address_space = int128_get64(fd->addr.start), .offset_within_address_space = int128_get64(fd->addr.start),
.size = fd->addr.size, .size = fd->addr.size,
}; };
MEMORY_LISTENER_CALL(eventfd_add, Reverse, &section, MEMORY_LISTENER_CALL(as, eventfd_add, Reverse, &section,
fd->match_data, fd->data, fd->e); fd->match_data, fd->data, fd->e);
++inew; ++inew;
} else { } else {
@ -1507,7 +1499,7 @@ bool memory_region_is_skip_dump(MemoryRegion *mr)
uint8_t memory_region_get_dirty_log_mask(MemoryRegion *mr) uint8_t memory_region_get_dirty_log_mask(MemoryRegion *mr)
{ {
uint8_t mask = mr->dirty_log_mask; uint8_t mask = mr->dirty_log_mask;
if (global_dirty_log) { if (global_dirty_log && mr->ram_block) {
mask |= (1 << DIRTY_MEMORY_MIGRATION); mask |= (1 << DIRTY_MEMORY_MIGRATION);
} }
return mask; return mask;
@ -1650,14 +1642,26 @@ bool memory_region_test_and_clear_dirty(MemoryRegion *mr, hwaddr addr,
void memory_region_sync_dirty_bitmap(MemoryRegion *mr) void memory_region_sync_dirty_bitmap(MemoryRegion *mr)
{ {
MemoryListener *listener;
AddressSpace *as; AddressSpace *as;
FlatView *view;
FlatRange *fr; FlatRange *fr;
QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) { /* If the same address space has multiple log_sync listeners, we
FlatView *view = address_space_get_flatview(as); * visit that address space's FlatView multiple times. But because
* log_sync listeners are rare, it's still cheaper than walking each
* address space once.
*/
QTAILQ_FOREACH(listener, &memory_listeners, link) {
if (!listener->log_sync) {
continue;
}
as = listener->address_space;
view = address_space_get_flatview(as);
FOR_EACH_FLAT_RANGE(fr, view) { FOR_EACH_FLAT_RANGE(fr, view) {
if (fr->mr == mr) { if (fr->mr == mr) {
MEMORY_LISTENER_UPDATE_REGION(fr, as, Forward, log_sync); MemoryRegionSection mrs = section_from_flat_range(fr, as);
listener->log_sync(listener, &mrs);
} }
} }
flatview_unref(view); flatview_unref(view);
@ -1774,7 +1778,7 @@ static void memory_region_update_coalesced_range_as(MemoryRegion *mr, AddressSpa
.size = fr->addr.size, .size = fr->addr.size,
}; };
MEMORY_LISTENER_CALL(coalesced_mmio_del, Reverse, &section, MEMORY_LISTENER_CALL(as, coalesced_mmio_del, Reverse, &section,
int128_get64(fr->addr.start), int128_get64(fr->addr.start),
int128_get64(fr->addr.size)); int128_get64(fr->addr.size));
QTAILQ_FOREACH(cmr, &mr->coalesced, link) { QTAILQ_FOREACH(cmr, &mr->coalesced, link) {
@ -1785,7 +1789,7 @@ static void memory_region_update_coalesced_range_as(MemoryRegion *mr, AddressSpa
continue; continue;
} }
tmp = addrrange_intersection(tmp, fr->addr); tmp = addrrange_intersection(tmp, fr->addr);
MEMORY_LISTENER_CALL(coalesced_mmio_add, Forward, &section, MEMORY_LISTENER_CALL(as, coalesced_mmio_add, Forward, &section,
int128_get64(tmp.start), int128_get64(tmp.start),
int128_get64(tmp.size)); int128_get64(tmp.size));
} }
@ -2176,13 +2180,13 @@ void memory_global_dirty_log_sync(void)
if (!listener->log_sync) { if (!listener->log_sync) {
continue; continue;
} }
/* Global listeners are being phased out. */ as = listener->address_space;
assert(listener->address_space_filter);
as = listener->address_space_filter;
view = address_space_get_flatview(as); view = address_space_get_flatview(as);
FOR_EACH_FLAT_RANGE(fr, view) { FOR_EACH_FLAT_RANGE(fr, view) {
MemoryRegionSection mrs = section_from_flat_range(fr, as); if (fr->dirty_log_mask) {
listener->log_sync(listener, &mrs); MemoryRegionSection mrs = section_from_flat_range(fr, as);
listener->log_sync(listener, &mrs);
}
} }
flatview_unref(view); flatview_unref(view);
} }
@ -2218,11 +2222,6 @@ static void listener_add_address_space(MemoryListener *listener,
FlatView *view; FlatView *view;
FlatRange *fr; FlatRange *fr;
if (listener->address_space_filter
&& listener->address_space_filter != as) {
return;
}
if (listener->begin) { if (listener->begin) {
listener->begin(listener); listener->begin(listener);
} }
@ -2255,12 +2254,11 @@ static void listener_add_address_space(MemoryListener *listener,
flatview_unref(view); flatview_unref(view);
} }
void memory_listener_register(MemoryListener *listener, AddressSpace *filter) void memory_listener_register(MemoryListener *listener, AddressSpace *as)
{ {
MemoryListener *other = NULL; MemoryListener *other = NULL;
AddressSpace *as;
listener->address_space_filter = filter; listener->address_space = as;
if (QTAILQ_EMPTY(&memory_listeners) if (QTAILQ_EMPTY(&memory_listeners)
|| listener->priority >= QTAILQ_LAST(&memory_listeners, || listener->priority >= QTAILQ_LAST(&memory_listeners,
memory_listeners)->priority) { memory_listeners)->priority) {
@ -2274,14 +2272,26 @@ void memory_listener_register(MemoryListener *listener, AddressSpace *filter)
QTAILQ_INSERT_BEFORE(other, listener, link); QTAILQ_INSERT_BEFORE(other, listener, link);
} }
QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) { if (QTAILQ_EMPTY(&as->listeners)
listener_add_address_space(listener, as); || listener->priority >= QTAILQ_LAST(&as->listeners,
memory_listeners)->priority) {
QTAILQ_INSERT_TAIL(&as->listeners, listener, link_as);
} else {
QTAILQ_FOREACH(other, &as->listeners, link_as) {
if (listener->priority < other->priority) {
break;
}
}
QTAILQ_INSERT_BEFORE(other, listener, link_as);
} }
listener_add_address_space(listener, as);
} }
void memory_listener_unregister(MemoryListener *listener) void memory_listener_unregister(MemoryListener *listener)
{ {
QTAILQ_REMOVE(&memory_listeners, listener, link); QTAILQ_REMOVE(&memory_listeners, listener, link);
QTAILQ_REMOVE(&listener->address_space->listeners, listener, link_as);
} }
void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name) void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name)
@ -2295,6 +2305,7 @@ void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name)
flatview_init(as->current_map); flatview_init(as->current_map);
as->ioeventfd_nb = 0; as->ioeventfd_nb = 0;
as->ioeventfds = NULL; as->ioeventfds = NULL;
QTAILQ_INIT(&as->listeners);
QTAILQ_INSERT_TAIL(&address_spaces, as, address_spaces_link); QTAILQ_INSERT_TAIL(&address_spaces, as, address_spaces_link);
as->name = g_strdup(name ? name : "anonymous"); as->name = g_strdup(name ? name : "anonymous");
address_space_init_dispatch(as); address_space_init_dispatch(as);
@ -2304,14 +2315,10 @@ void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name)
static void do_address_space_destroy(AddressSpace *as) static void do_address_space_destroy(AddressSpace *as)
{ {
MemoryListener *listener;
bool do_free = as->malloced; bool do_free = as->malloced;
address_space_destroy_dispatch(as); address_space_destroy_dispatch(as);
assert(QTAILQ_EMPTY(&as->listeners));
QTAILQ_FOREACH(listener, &memory_listeners, link) {
assert(listener->address_space_filter != as);
}
flatview_unref(as->current_map); flatview_unref(as->current_map);
g_free(as->name); g_free(as->name);

View File

@ -186,7 +186,7 @@ typedef struct {
} MonitorQAPIEventConf; } MonitorQAPIEventConf;
struct Monitor { struct Monitor {
CharDriverState *chr; CharBackend chr;
int reset_seen; int reset_seen;
int flags; int flags;
int suspend_cnt; int suspend_cnt;
@ -297,7 +297,7 @@ static void monitor_flush_locked(Monitor *mon)
len = qstring_get_length(mon->outbuf); len = qstring_get_length(mon->outbuf);
if (len && !mon->mux_out) { if (len && !mon->mux_out) {
rc = qemu_chr_fe_write(mon->chr, (const uint8_t *) buf, len); rc = qemu_chr_fe_write(&mon->chr, (const uint8_t *) buf, len);
if ((rc < 0 && errno != EAGAIN) || (rc == len)) { if ((rc < 0 && errno != EAGAIN) || (rc == len)) {
/* all flushed or error */ /* all flushed or error */
QDECREF(mon->outbuf); QDECREF(mon->outbuf);
@ -311,8 +311,9 @@ static void monitor_flush_locked(Monitor *mon)
mon->outbuf = tmp; mon->outbuf = tmp;
} }
if (mon->out_watch == 0) { if (mon->out_watch == 0) {
mon->out_watch = qemu_chr_fe_add_watch(mon->chr, G_IO_OUT|G_IO_HUP, mon->out_watch =
monitor_unblocked, mon); qemu_chr_fe_add_watch(&mon->chr, G_IO_OUT | G_IO_HUP,
monitor_unblocked, mon);
} }
} }
} }
@ -581,9 +582,7 @@ static void monitor_data_init(Monitor *mon)
static void monitor_data_destroy(Monitor *mon) static void monitor_data_destroy(Monitor *mon)
{ {
if (mon->chr) { qemu_chr_fe_deinit(&mon->chr);
qemu_chr_add_handlers(mon->chr, NULL, NULL, NULL, NULL);
}
if (monitor_is_qmp(mon)) { if (monitor_is_qmp(mon)) {
json_message_parser_destroy(&mon->qmp.parser); json_message_parser_destroy(&mon->qmp.parser);
} }
@ -1745,7 +1744,7 @@ void qmp_getfd(const char *fdname, Error **errp)
mon_fd_t *monfd; mon_fd_t *monfd;
int fd; int fd;
fd = qemu_chr_fe_get_msgfd(cur_mon->chr); fd = qemu_chr_fe_get_msgfd(&cur_mon->chr);
if (fd == -1) { if (fd == -1) {
error_setg(errp, QERR_FD_NOT_SUPPLIED); error_setg(errp, QERR_FD_NOT_SUPPLIED);
return; return;
@ -1870,7 +1869,7 @@ AddfdInfo *qmp_add_fd(bool has_fdset_id, int64_t fdset_id, bool has_opaque,
Monitor *mon = cur_mon; Monitor *mon = cur_mon;
AddfdInfo *fdinfo; AddfdInfo *fdinfo;
fd = qemu_chr_fe_get_msgfd(mon->chr); fd = qemu_chr_fe_get_msgfd(&mon->chr);
if (fd == -1) { if (fd == -1) {
error_setg(errp, QERR_FD_NOT_SUPPLIED); error_setg(errp, QERR_FD_NOT_SUPPLIED);
goto error; goto error;
@ -3977,7 +3976,7 @@ void monitor_init(CharDriverState *chr, int flags)
mon = g_malloc(sizeof(*mon)); mon = g_malloc(sizeof(*mon));
monitor_data_init(mon); monitor_data_init(mon);
mon->chr = chr; qemu_chr_fe_init(&mon->chr, chr, &error_abort);
mon->flags = flags; mon->flags = flags;
if (flags & MONITOR_USE_READLINE) { if (flags & MONITOR_USE_READLINE) {
mon->rs = readline_init(monitor_readline_printf, mon->rs = readline_init(monitor_readline_printf,
@ -3988,13 +3987,13 @@ void monitor_init(CharDriverState *chr, int flags)
} }
if (monitor_is_qmp(mon)) { if (monitor_is_qmp(mon)) {
qemu_chr_add_handlers(chr, monitor_can_read, monitor_qmp_read, qemu_chr_fe_set_handlers(&mon->chr, monitor_can_read, monitor_qmp_read,
monitor_qmp_event, mon); monitor_qmp_event, mon, NULL, true);
qemu_chr_fe_set_echo(chr, true); qemu_chr_fe_set_echo(&mon->chr, true);
json_message_parser_init(&mon->qmp.parser, handle_qmp_command); json_message_parser_init(&mon->qmp.parser, handle_qmp_command);
} else { } else {
qemu_chr_add_handlers(chr, monitor_can_read, monitor_read, qemu_chr_fe_set_handlers(&mon->chr, monitor_can_read, monitor_read,
monitor_event, mon); monitor_event, mon, NULL, true);
} }
qemu_mutex_lock(&monitor_lock); qemu_mutex_lock(&monitor_lock);

View File

@ -68,9 +68,9 @@ typedef struct CompareState {
char *pri_indev; char *pri_indev;
char *sec_indev; char *sec_indev;
char *outdev; char *outdev;
CharDriverState *chr_pri_in; CharBackend chr_pri_in;
CharDriverState *chr_sec_in; CharBackend chr_sec_in;
CharDriverState *chr_out; CharBackend chr_out;
SocketReadState pri_rs; SocketReadState pri_rs;
SocketReadState sec_rs; SocketReadState sec_rs;
@ -101,7 +101,7 @@ enum {
SECONDARY_IN, SECONDARY_IN,
}; };
static int compare_chr_send(CharDriverState *out, static int compare_chr_send(CharBackend *out,
const uint8_t *buf, const uint8_t *buf,
uint32_t size); uint32_t size);
@ -385,7 +385,7 @@ static void colo_compare_connection(void *opaque, void *user_data)
} }
if (result) { if (result) {
ret = compare_chr_send(s->chr_out, pkt->data, pkt->size); ret = compare_chr_send(&s->chr_out, pkt->data, pkt->size);
if (ret < 0) { if (ret < 0) {
error_report("colo_send_primary_packet failed"); error_report("colo_send_primary_packet failed");
} }
@ -408,7 +408,7 @@ static void colo_compare_connection(void *opaque, void *user_data)
} }
} }
static int compare_chr_send(CharDriverState *out, static int compare_chr_send(CharBackend *out,
const uint8_t *buf, const uint8_t *buf,
uint32_t size) uint32_t size)
{ {
@ -451,7 +451,8 @@ static void compare_pri_chr_in(void *opaque, const uint8_t *buf, int size)
ret = net_fill_rstate(&s->pri_rs, buf, size); ret = net_fill_rstate(&s->pri_rs, buf, size);
if (ret == -1) { if (ret == -1) {
qemu_chr_add_handlers(s->chr_pri_in, NULL, NULL, NULL, NULL); qemu_chr_fe_set_handlers(&s->chr_pri_in, NULL, NULL, NULL,
NULL, NULL, true);
error_report("colo-compare primary_in error"); error_report("colo-compare primary_in error");
} }
} }
@ -467,7 +468,8 @@ static void compare_sec_chr_in(void *opaque, const uint8_t *buf, int size)
ret = net_fill_rstate(&s->sec_rs, buf, size); ret = net_fill_rstate(&s->sec_rs, buf, size);
if (ret == -1) { if (ret == -1) {
qemu_chr_add_handlers(s->chr_sec_in, NULL, NULL, NULL, NULL); qemu_chr_fe_set_handlers(&s->chr_sec_in, NULL, NULL, NULL,
NULL, NULL, true);
error_report("colo-compare secondary_in error"); error_report("colo-compare secondary_in error");
} }
} }
@ -480,10 +482,10 @@ static void *colo_compare_thread(void *opaque)
worker_context = g_main_context_new(); worker_context = g_main_context_new();
qemu_chr_add_handlers_full(s->chr_pri_in, compare_chr_can_read, qemu_chr_fe_set_handlers(&s->chr_pri_in, compare_chr_can_read,
compare_pri_chr_in, NULL, s, worker_context); compare_pri_chr_in, NULL, s, worker_context, true);
qemu_chr_add_handlers_full(s->chr_sec_in, compare_chr_can_read, qemu_chr_fe_set_handlers(&s->chr_sec_in, compare_chr_can_read,
compare_sec_chr_in, NULL, s, worker_context); compare_sec_chr_in, NULL, s, worker_context, true);
compare_loop = g_main_loop_new(worker_context, FALSE); compare_loop = g_main_loop_new(worker_context, FALSE);
@ -545,7 +547,7 @@ static void compare_pri_rs_finalize(SocketReadState *pri_rs)
if (packet_enqueue(s, PRIMARY_IN)) { if (packet_enqueue(s, PRIMARY_IN)) {
trace_colo_compare_main("primary: unsupported packet in"); trace_colo_compare_main("primary: unsupported packet in");
compare_chr_send(s->chr_out, pri_rs->buf, pri_rs->packet_len); compare_chr_send(&s->chr_out, pri_rs->buf, pri_rs->packet_len);
} else { } else {
/* compare connection */ /* compare connection */
g_queue_foreach(&s->conn_list, colo_compare_connection, s); g_queue_foreach(&s->conn_list, colo_compare_connection, s);
@ -589,6 +591,7 @@ static int find_and_check_chardev(CharDriverState **chr,
chr_name); chr_name);
return 1; return 1;
} }
return 0; return 0;
} }
@ -619,6 +622,7 @@ static void check_old_packet_regular(void *opaque)
static void colo_compare_complete(UserCreatable *uc, Error **errp) static void colo_compare_complete(UserCreatable *uc, Error **errp)
{ {
CompareState *s = COLO_COMPARE(uc); CompareState *s = COLO_COMPARE(uc);
CharDriverState *chr;
char thread_name[64]; char thread_name[64];
static int compare_id; static int compare_id;
@ -634,24 +638,21 @@ static void colo_compare_complete(UserCreatable *uc, Error **errp)
return; return;
} }
if (find_and_check_chardev(&s->chr_pri_in, s->pri_indev, errp)) { if (find_and_check_chardev(&chr, s->pri_indev, errp) ||
!qemu_chr_fe_init(&s->chr_pri_in, chr, errp)) {
return; return;
} }
if (find_and_check_chardev(&s->chr_sec_in, s->sec_indev, errp)) { if (find_and_check_chardev(&chr, s->sec_indev, errp) ||
!qemu_chr_fe_init(&s->chr_sec_in, chr, errp)) {
return; return;
} }
if (find_and_check_chardev(&s->chr_out, s->outdev, errp)) { if (find_and_check_chardev(&chr, s->outdev, errp) ||
!qemu_chr_fe_init(&s->chr_out, chr, errp)) {
return; return;
} }
qemu_chr_fe_claim_no_fail(s->chr_pri_in);
qemu_chr_fe_claim_no_fail(s->chr_sec_in);
qemu_chr_fe_claim_no_fail(s->chr_out);
net_socket_rs_init(&s->pri_rs, compare_pri_rs_finalize); net_socket_rs_init(&s->pri_rs, compare_pri_rs_finalize);
net_socket_rs_init(&s->sec_rs, compare_sec_rs_finalize); net_socket_rs_init(&s->sec_rs, compare_sec_rs_finalize);
@ -702,17 +703,9 @@ static void colo_compare_finalize(Object *obj)
{ {
CompareState *s = COLO_COMPARE(obj); CompareState *s = COLO_COMPARE(obj);
if (s->chr_pri_in) { qemu_chr_fe_deinit(&s->chr_pri_in);
qemu_chr_add_handlers(s->chr_pri_in, NULL, NULL, NULL, NULL); qemu_chr_fe_deinit(&s->chr_sec_in);
qemu_chr_fe_release(s->chr_pri_in); qemu_chr_fe_deinit(&s->chr_out);
}
if (s->chr_sec_in) {
qemu_chr_add_handlers(s->chr_sec_in, NULL, NULL, NULL, NULL);
qemu_chr_fe_release(s->chr_sec_in);
}
if (s->chr_out) {
qemu_chr_fe_release(s->chr_out);
}
g_queue_free(&s->conn_list); g_queue_free(&s->conn_list);

View File

@ -38,12 +38,12 @@ typedef struct MirrorState {
NetFilterState parent_obj; NetFilterState parent_obj;
char *indev; char *indev;
char *outdev; char *outdev;
CharDriverState *chr_in; CharBackend chr_in;
CharDriverState *chr_out; CharBackend chr_out;
SocketReadState rs; SocketReadState rs;
} MirrorState; } MirrorState;
static int filter_mirror_send(CharDriverState *chr_out, static int filter_mirror_send(CharBackend *chr_out,
const struct iovec *iov, const struct iovec *iov,
int iovcnt) int iovcnt)
{ {
@ -110,7 +110,8 @@ static void redirector_chr_read(void *opaque, const uint8_t *buf, int size)
ret = net_fill_rstate(&s->rs, buf, size); ret = net_fill_rstate(&s->rs, buf, size);
if (ret == -1) { if (ret == -1) {
qemu_chr_add_handlers(s->chr_in, NULL, NULL, NULL, NULL); qemu_chr_fe_set_handlers(&s->chr_in, NULL, NULL, NULL,
NULL, NULL, true);
} }
} }
@ -121,7 +122,8 @@ static void redirector_chr_event(void *opaque, int event)
switch (event) { switch (event) {
case CHR_EVENT_CLOSED: case CHR_EVENT_CLOSED:
qemu_chr_add_handlers(s->chr_in, NULL, NULL, NULL, NULL); qemu_chr_fe_set_handlers(&s->chr_in, NULL, NULL, NULL,
NULL, NULL, true);
break; break;
default: default:
break; break;
@ -138,7 +140,7 @@ static ssize_t filter_mirror_receive_iov(NetFilterState *nf,
MirrorState *s = FILTER_MIRROR(nf); MirrorState *s = FILTER_MIRROR(nf);
int ret; int ret;
ret = filter_mirror_send(s->chr_out, iov, iovcnt); ret = filter_mirror_send(&s->chr_out, iov, iovcnt);
if (ret) { if (ret) {
error_report("filter_mirror_send failed(%s)", strerror(-ret)); error_report("filter_mirror_send failed(%s)", strerror(-ret));
} }
@ -160,8 +162,8 @@ static ssize_t filter_redirector_receive_iov(NetFilterState *nf,
MirrorState *s = FILTER_REDIRECTOR(nf); MirrorState *s = FILTER_REDIRECTOR(nf);
int ret; int ret;
if (s->chr_out) { if (qemu_chr_fe_get_driver(&s->chr_out)) {
ret = filter_mirror_send(s->chr_out, iov, iovcnt); ret = filter_mirror_send(&s->chr_out, iov, iovcnt);
if (ret) { if (ret) {
error_report("filter_mirror_send failed(%s)", strerror(-ret)); error_report("filter_mirror_send failed(%s)", strerror(-ret));
} }
@ -175,27 +177,21 @@ static void filter_mirror_cleanup(NetFilterState *nf)
{ {
MirrorState *s = FILTER_MIRROR(nf); MirrorState *s = FILTER_MIRROR(nf);
if (s->chr_out) { qemu_chr_fe_deinit(&s->chr_out);
qemu_chr_fe_release(s->chr_out);
}
} }
static void filter_redirector_cleanup(NetFilterState *nf) static void filter_redirector_cleanup(NetFilterState *nf)
{ {
MirrorState *s = FILTER_REDIRECTOR(nf); MirrorState *s = FILTER_REDIRECTOR(nf);
if (s->chr_in) { qemu_chr_fe_deinit(&s->chr_in);
qemu_chr_add_handlers(s->chr_in, NULL, NULL, NULL, NULL); qemu_chr_fe_deinit(&s->chr_out);
qemu_chr_fe_release(s->chr_in);
}
if (s->chr_out) {
qemu_chr_fe_release(s->chr_out);
}
} }
static void filter_mirror_setup(NetFilterState *nf, Error **errp) static void filter_mirror_setup(NetFilterState *nf, Error **errp)
{ {
MirrorState *s = FILTER_MIRROR(nf); MirrorState *s = FILTER_MIRROR(nf);
CharDriverState *chr;
if (!s->outdev) { if (!s->outdev) {
error_setg(errp, "filter mirror needs 'outdev' " error_setg(errp, "filter mirror needs 'outdev' "
@ -203,17 +199,14 @@ static void filter_mirror_setup(NetFilterState *nf, Error **errp)
return; return;
} }
s->chr_out = qemu_chr_find(s->outdev); chr = qemu_chr_find(s->outdev);
if (s->chr_out == NULL) { if (chr == NULL) {
error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
"Device '%s' not found", s->outdev); "Device '%s' not found", s->outdev);
return; return;
} }
if (qemu_chr_fe_claim(s->chr_out) != 0) { qemu_chr_fe_init(&s->chr_out, chr, errp);
error_setg(errp, QERR_DEVICE_IN_USE, s->outdev);
return;
}
} }
static void redirector_rs_finalize(SocketReadState *rs) static void redirector_rs_finalize(SocketReadState *rs)
@ -227,6 +220,7 @@ static void redirector_rs_finalize(SocketReadState *rs)
static void filter_redirector_setup(NetFilterState *nf, Error **errp) static void filter_redirector_setup(NetFilterState *nf, Error **errp)
{ {
MirrorState *s = FILTER_REDIRECTOR(nf); MirrorState *s = FILTER_REDIRECTOR(nf);
CharDriverState *chr;
if (!s->indev && !s->outdev) { if (!s->indev && !s->outdev) {
error_setg(errp, "filter redirector needs 'indev' or " error_setg(errp, "filter redirector needs 'indev' or "
@ -243,26 +237,32 @@ static void filter_redirector_setup(NetFilterState *nf, Error **errp)
net_socket_rs_init(&s->rs, redirector_rs_finalize); net_socket_rs_init(&s->rs, redirector_rs_finalize);
if (s->indev) { if (s->indev) {
s->chr_in = qemu_chr_find(s->indev); chr = qemu_chr_find(s->indev);
if (s->chr_in == NULL) { if (chr == NULL) {
error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
"IN Device '%s' not found", s->indev); "IN Device '%s' not found", s->indev);
return; return;
} }
qemu_chr_fe_claim_no_fail(s->chr_in); if (!qemu_chr_fe_init(&s->chr_in, chr, errp)) {
qemu_chr_add_handlers(s->chr_in, redirector_chr_can_read, return;
redirector_chr_read, redirector_chr_event, nf); }
qemu_chr_fe_set_handlers(&s->chr_in, redirector_chr_can_read,
redirector_chr_read, redirector_chr_event,
nf, NULL, true);
} }
if (s->outdev) { if (s->outdev) {
s->chr_out = qemu_chr_find(s->outdev); chr = qemu_chr_find(s->outdev);
if (s->chr_out == NULL) { if (chr == NULL) {
error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
"OUT Device '%s' not found", s->outdev); "OUT Device '%s' not found", s->outdev);
return; return;
} }
qemu_chr_fe_claim_no_fail(s->chr_out); if (!qemu_chr_fe_init(&s->chr_out, chr, errp)) {
return;
}
} }
} }

View File

@ -40,6 +40,7 @@
#include "sysemu/char.h" #include "sysemu/char.h"
#include "sysemu/sysemu.h" #include "sysemu/sysemu.h"
#include "qemu/cutils.h" #include "qemu/cutils.h"
#include "qapi/error.h"
static int get_str_sep(char *buf, int buf_size, const char **pp, int sep) static int get_str_sep(char *buf, int buf_size, const char **pp, int sep)
{ {
@ -682,7 +683,7 @@ int net_slirp_smb(const char *exported_dir)
#endif /* !defined(_WIN32) */ #endif /* !defined(_WIN32) */
struct GuestFwd { struct GuestFwd {
CharDriverState *hd; CharBackend hd;
struct in_addr server; struct in_addr server;
int port; int port;
Slirp *slirp; Slirp *slirp;
@ -746,15 +747,24 @@ static int slirp_guestfwd(SlirpState *s, const char *config_str,
return -1; return -1;
} }
} else { } else {
fwd = g_new(struct GuestFwd, 1); Error *err = NULL;
fwd->hd = qemu_chr_new(buf, p, NULL); CharDriverState *chr = qemu_chr_new(buf, p);
if (!fwd->hd) {
if (!chr) {
error_report("could not open guest forwarding device '%s'", buf); error_report("could not open guest forwarding device '%s'", buf);
return -1;
}
fwd = g_new(struct GuestFwd, 1);
qemu_chr_fe_init(&fwd->hd, chr, &err);
if (err) {
error_report_err(err);
g_free(fwd); g_free(fwd);
return -1; return -1;
} }
if (slirp_add_exec(s->slirp, 3, fwd->hd, &server, port) < 0) { if (slirp_add_exec(s->slirp, 3, qemu_chr_fe_get_driver(&fwd->hd),
&server, port) < 0) {
error_report("conflicting/invalid host:port in guest forwarding " error_report("conflicting/invalid host:port in guest forwarding "
"rule '%s'", config_str); "rule '%s'", config_str);
g_free(fwd); g_free(fwd);
@ -764,9 +774,8 @@ static int slirp_guestfwd(SlirpState *s, const char *config_str,
fwd->port = port; fwd->port = port;
fwd->slirp = s->slirp; fwd->slirp = s->slirp;
qemu_chr_fe_claim_no_fail(fwd->hd); qemu_chr_fe_set_handlers(&fwd->hd, guestfwd_can_read, guestfwd_read,
qemu_chr_add_handlers(fwd->hd, guestfwd_can_read, guestfwd_read, NULL, fwd, NULL, true);
NULL, fwd);
} }
return 0; return 0;

View File

@ -20,7 +20,7 @@
typedef struct VhostUserState { typedef struct VhostUserState {
NetClientState nc; NetClientState nc;
CharDriverState *chr; CharBackend chr; /* only queue index 0 */
VHostNetState *vhost_net; VHostNetState *vhost_net;
guint watch; guint watch;
uint64_t acked_features; uint64_t acked_features;
@ -62,7 +62,7 @@ static void vhost_user_stop(int queues, NetClientState *ncs[])
} }
} }
static int vhost_user_start(int queues, NetClientState *ncs[]) static int vhost_user_start(int queues, NetClientState *ncs[], CharBackend *be)
{ {
VhostNetOptions options; VhostNetOptions options;
struct vhost_net *net = NULL; struct vhost_net *net = NULL;
@ -78,7 +78,7 @@ static int vhost_user_start(int queues, NetClientState *ncs[])
s = DO_UPCAST(VhostUserState, nc, ncs[i]); s = DO_UPCAST(VhostUserState, nc, ncs[i]);
options.net_backend = ncs[i]; options.net_backend = ncs[i];
options.opaque = s->chr; options.opaque = be;
options.busyloop_timeout = 0; options.busyloop_timeout = 0;
net = vhost_net_init(&options); net = vhost_net_init(&options);
if (!net) { if (!net) {
@ -150,10 +150,8 @@ static void vhost_user_cleanup(NetClientState *nc)
g_free(s->vhost_net); g_free(s->vhost_net);
s->vhost_net = NULL; s->vhost_net = NULL;
} }
if (s->chr) { if (nc->queue_index == 0) {
qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, NULL); qemu_chr_fe_deinit(&s->chr);
qemu_chr_fe_release(s->chr);
s->chr = NULL;
} }
qemu_purge_queued_packets(nc); qemu_purge_queued_packets(nc);
@ -187,7 +185,7 @@ static gboolean net_vhost_user_watch(GIOChannel *chan, GIOCondition cond,
{ {
VhostUserState *s = opaque; VhostUserState *s = opaque;
qemu_chr_disconnect(s->chr); qemu_chr_fe_disconnect(&s->chr);
return FALSE; return FALSE;
} }
@ -197,6 +195,7 @@ static void net_vhost_user_event(void *opaque, int event)
const char *name = opaque; const char *name = opaque;
NetClientState *ncs[MAX_QUEUE_NUM]; NetClientState *ncs[MAX_QUEUE_NUM];
VhostUserState *s; VhostUserState *s;
CharDriverState *chr;
Error *err = NULL; Error *err = NULL;
int queues; int queues;
@ -206,13 +205,14 @@ static void net_vhost_user_event(void *opaque, int event)
assert(queues < MAX_QUEUE_NUM); assert(queues < MAX_QUEUE_NUM);
s = DO_UPCAST(VhostUserState, nc, ncs[0]); s = DO_UPCAST(VhostUserState, nc, ncs[0]);
trace_vhost_user_event(s->chr->label, event); chr = qemu_chr_fe_get_driver(&s->chr);
trace_vhost_user_event(chr->label, event);
switch (event) { switch (event) {
case CHR_EVENT_OPENED: case CHR_EVENT_OPENED:
s->watch = qemu_chr_fe_add_watch(s->chr, G_IO_HUP, s->watch = qemu_chr_fe_add_watch(&s->chr, G_IO_HUP,
net_vhost_user_watch, s); net_vhost_user_watch, s);
if (vhost_user_start(queues, ncs) < 0) { if (vhost_user_start(queues, ncs, &s->chr) < 0) {
qemu_chr_disconnect(s->chr); qemu_chr_fe_disconnect(&s->chr);
return; return;
} }
qmp_set_link(name, true, &err); qmp_set_link(name, true, &err);
@ -235,6 +235,7 @@ static int net_vhost_user_init(NetClientState *peer, const char *device,
const char *name, CharDriverState *chr, const char *name, CharDriverState *chr,
int queues) int queues)
{ {
Error *err = NULL;
NetClientState *nc, *nc0 = NULL; NetClientState *nc, *nc0 = NULL;
VhostUserState *s; VhostUserState *s;
int i; int i;
@ -244,28 +245,28 @@ static int net_vhost_user_init(NetClientState *peer, const char *device,
for (i = 0; i < queues; i++) { for (i = 0; i < queues; i++) {
nc = qemu_new_net_client(&net_vhost_user_info, peer, device, name); nc = qemu_new_net_client(&net_vhost_user_info, peer, device, name);
if (!nc0) {
nc0 = nc;
}
snprintf(nc->info_str, sizeof(nc->info_str), "vhost-user%d to %s", snprintf(nc->info_str, sizeof(nc->info_str), "vhost-user%d to %s",
i, chr->label); i, chr->label);
nc->queue_index = i; nc->queue_index = i;
if (!nc0) {
nc0 = nc;
s = DO_UPCAST(VhostUserState, nc, nc);
if (!qemu_chr_fe_init(&s->chr, chr, &err)) {
error_report_err(err);
return -1;
}
}
s = DO_UPCAST(VhostUserState, nc, nc);
s->chr = chr;
} }
s = DO_UPCAST(VhostUserState, nc, nc0); s = DO_UPCAST(VhostUserState, nc, nc0);
do { do {
Error *err = NULL; if (qemu_chr_fe_wait_connected(&s->chr, &err) < 0) {
if (qemu_chr_wait_connected(chr, &err) < 0) {
error_report_err(err); error_report_err(err);
return -1; return -1;
} }
qemu_chr_add_handlers(chr, NULL, NULL, qemu_chr_fe_set_handlers(&s->chr, NULL, NULL,
net_vhost_user_event, nc0->name); net_vhost_user_event, nc0->name, NULL, true);
} while (!s->started); } while (!s->started);
assert(s->vhost_net); assert(s->vhost_net);
@ -294,8 +295,6 @@ static CharDriverState *net_vhost_claim_chardev(
return NULL; return NULL;
} }
qemu_chr_fe_claim_no_fail(chr);
return chr; return chr;
} }

File diff suppressed because it is too large Load Diff

View File

@ -44,7 +44,7 @@
#include <getopt.h> #include <getopt.h>
#define QEMU_IMG_VERSION "qemu-img version " QEMU_VERSION QEMU_PKGVERSION \ #define QEMU_IMG_VERSION "qemu-img version " QEMU_VERSION QEMU_PKGVERSION \
", " QEMU_COPYRIGHT "\n" "\n" QEMU_COPYRIGHT "\n"
typedef struct img_cmd_t { typedef struct img_cmd_t {
const char *name; const char *name;

29
qtest.c
View File

@ -38,7 +38,7 @@ bool qtest_allowed;
static DeviceState *irq_intercept_dev; static DeviceState *irq_intercept_dev;
static FILE *qtest_log_fp; static FILE *qtest_log_fp;
static CharDriverState *qtest_chr; static CharBackend qtest_chr;
static GString *inbuf; static GString *inbuf;
static int irq_levels[MAX_IRQ]; static int irq_levels[MAX_IRQ];
static qemu_timeval start_time; static qemu_timeval start_time;
@ -190,7 +190,7 @@ static void qtest_get_time(qemu_timeval *tv)
} }
} }
static void qtest_send_prefix(CharDriverState *chr) static void qtest_send_prefix(CharBackend *chr)
{ {
qemu_timeval tv; qemu_timeval tv;
@ -218,7 +218,7 @@ static void GCC_FMT_ATTR(1, 2) qtest_log_send(const char *fmt, ...)
va_end(ap); va_end(ap);
} }
static void do_qtest_send(CharDriverState *chr, const char *str, size_t len) static void do_qtest_send(CharBackend *chr, const char *str, size_t len)
{ {
qemu_chr_fe_write_all(chr, (uint8_t *)str, len); qemu_chr_fe_write_all(chr, (uint8_t *)str, len);
if (qtest_log_fp && qtest_opened) { if (qtest_log_fp && qtest_opened) {
@ -226,12 +226,12 @@ static void do_qtest_send(CharDriverState *chr, const char *str, size_t len)
} }
} }
static void qtest_send(CharDriverState *chr, const char *str) static void qtest_send(CharBackend *chr, const char *str)
{ {
do_qtest_send(chr, str, strlen(str)); do_qtest_send(chr, str, strlen(str));
} }
static void GCC_FMT_ATTR(2, 3) qtest_sendf(CharDriverState *chr, static void GCC_FMT_ATTR(2, 3) qtest_sendf(CharBackend *chr,
const char *fmt, ...) const char *fmt, ...)
{ {
va_list ap; va_list ap;
@ -249,7 +249,7 @@ static void qtest_irq_handler(void *opaque, int n, int level)
qemu_set_irq(old_irq, level); qemu_set_irq(old_irq, level);
if (irq_levels[n] != level) { if (irq_levels[n] != level) {
CharDriverState *chr = qtest_chr; CharBackend *chr = &qtest_chr;
irq_levels[n] = level; irq_levels[n] = level;
qtest_send_prefix(chr); qtest_send_prefix(chr);
qtest_sendf(chr, "IRQ %s %d\n", qtest_sendf(chr, "IRQ %s %d\n",
@ -257,7 +257,7 @@ static void qtest_irq_handler(void *opaque, int n, int level)
} }
} }
static void qtest_process_command(CharDriverState *chr, gchar **words) static void qtest_process_command(CharBackend *chr, gchar **words)
{ {
const gchar *command; const gchar *command;
@ -585,7 +585,7 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
} }
} }
static void qtest_process_inbuf(CharDriverState *chr, GString *inbuf) static void qtest_process_inbuf(CharBackend *chr, GString *inbuf)
{ {
char *end; char *end;
@ -609,7 +609,7 @@ static void qtest_process_inbuf(CharDriverState *chr, GString *inbuf)
static void qtest_read(void *opaque, const uint8_t *buf, int size) static void qtest_read(void *opaque, const uint8_t *buf, int size)
{ {
CharDriverState *chr = opaque; CharBackend *chr = opaque;
g_string_append_len(inbuf, (const gchar *)buf, size); g_string_append_len(inbuf, (const gchar *)buf, size);
qtest_process_inbuf(chr, inbuf); qtest_process_inbuf(chr, inbuf);
@ -670,7 +670,7 @@ void qtest_init(const char *qtest_chrdev, const char *qtest_log, Error **errp)
{ {
CharDriverState *chr; CharDriverState *chr;
chr = qemu_chr_new("qtest", qtest_chrdev, NULL); chr = qemu_chr_new("qtest", qtest_chrdev);
if (chr == NULL) { if (chr == NULL) {
error_setg(errp, "Failed to initialize device for qtest: \"%s\"", error_setg(errp, "Failed to initialize device for qtest: \"%s\"",
@ -686,16 +686,17 @@ void qtest_init(const char *qtest_chrdev, const char *qtest_log, Error **errp)
qtest_log_fp = stderr; qtest_log_fp = stderr;
} }
qemu_chr_add_handlers(chr, qtest_can_read, qtest_read, qtest_event, chr); qemu_chr_fe_init(&qtest_chr, chr, errp);
qemu_chr_fe_set_echo(chr, true); qemu_chr_fe_set_handlers(&qtest_chr, qtest_can_read, qtest_read,
qtest_event, &qtest_chr, NULL, true);
qemu_chr_fe_set_echo(&qtest_chr, true);
inbuf = g_string_new(""); inbuf = g_string_new("");
qtest_chr = chr;
} }
bool qtest_driver(void) bool qtest_driver(void)
{ {
return qtest_chr; return qtest_chr.chr != NULL;
} }
static void qtest_accel_class_init(ObjectClass *oc, void *data) static void qtest_accel_class_init(ObjectClass *oc, void *data)

View File

@ -199,7 +199,7 @@ static int spice_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
return read_bytes; return read_bytes;
} }
static void spice_chr_close(struct CharDriverState *chr) static void spice_chr_free(struct CharDriverState *chr)
{ {
SpiceCharDriver *s = chr->opaque; SpiceCharDriver *s = chr->opaque;
@ -236,15 +236,6 @@ static void spice_port_set_fe_open(struct CharDriverState *chr, int fe_open)
#endif #endif
} }
static void spice_chr_fe_event(struct CharDriverState *chr, int event)
{
#if SPICE_SERVER_VERSION >= 0x000c02
SpiceCharDriver *s = chr->opaque;
spice_server_port_event(&s->sin, event);
#endif
}
static void print_allowed_subtypes(void) static void print_allowed_subtypes(void)
{ {
const char** psubtype; const char** psubtype;
@ -289,10 +280,8 @@ static CharDriverState *chr_open(const char *subtype,
chr->opaque = s; chr->opaque = s;
chr->chr_write = spice_chr_write; chr->chr_write = spice_chr_write;
chr->chr_add_watch = spice_chr_add_watch; chr->chr_add_watch = spice_chr_add_watch;
chr->chr_close = spice_chr_close; chr->chr_free = spice_chr_free;
chr->chr_set_fe_open = set_fe_open; chr->chr_set_fe_open = set_fe_open;
chr->explicit_be_open = true;
chr->chr_fe_event = spice_chr_fe_event;
chr->chr_accept_input = spice_chr_accept_input; chr->chr_accept_input = spice_chr_accept_input;
QLIST_INSERT_HEAD(&spice_chars, s, next); QLIST_INSERT_HEAD(&spice_chars, s, next);
@ -303,6 +292,7 @@ static CharDriverState *chr_open(const char *subtype,
static CharDriverState *qemu_chr_open_spice_vmc(const char *id, static CharDriverState *qemu_chr_open_spice_vmc(const char *id,
ChardevBackend *backend, ChardevBackend *backend,
ChardevReturn *ret, ChardevReturn *ret,
bool *be_opened,
Error **errp) Error **errp)
{ {
ChardevSpiceChannel *spicevmc = backend->u.spicevmc.data; ChardevSpiceChannel *spicevmc = backend->u.spicevmc.data;
@ -321,6 +311,7 @@ static CharDriverState *qemu_chr_open_spice_vmc(const char *id,
return NULL; return NULL;
} }
*be_opened = false;
return chr_open(type, spice_vmc_set_fe_open, common, errp); return chr_open(type, spice_vmc_set_fe_open, common, errp);
} }
@ -328,6 +319,7 @@ static CharDriverState *qemu_chr_open_spice_vmc(const char *id,
static CharDriverState *qemu_chr_open_spice_port(const char *id, static CharDriverState *qemu_chr_open_spice_port(const char *id,
ChardevBackend *backend, ChardevBackend *backend,
ChardevReturn *ret, ChardevReturn *ret,
bool *be_opened,
Error **errp) Error **errp)
{ {
ChardevSpicePort *spiceport = backend->u.spiceport.data; ChardevSpicePort *spiceport = backend->u.spiceport.data;
@ -345,6 +337,7 @@ static CharDriverState *qemu_chr_open_spice_port(const char *id,
if (!chr) { if (!chr) {
return NULL; return NULL;
} }
*be_opened = false;
s = chr->opaque; s = chr->opaque;
s->sin.portname = g_strdup(name); s->sin.portname = g_strdup(name);

View File

@ -457,13 +457,12 @@ static void gen_lea_v_seg(DisasContext *s, TCGMemOp aflag, TCGv a0,
#endif #endif
case MO_32: case MO_32:
/* 32 bit address */ /* 32 bit address */
if (ovr_seg < 0 && s->addseg) {
ovr_seg = def_seg;
}
if (ovr_seg < 0) { if (ovr_seg < 0) {
if (s->addseg) { tcg_gen_ext32u_tl(cpu_A0, a0);
ovr_seg = def_seg; return;
} else {
tcg_gen_ext32u_tl(cpu_A0, a0);
return;
}
} }
break; break;
case MO_16: case MO_16:
@ -5372,7 +5371,8 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
{ {
AddressParts a = gen_lea_modrm_0(env, s, modrm); AddressParts a = gen_lea_modrm_0(env, s, modrm);
TCGv ea = gen_lea_modrm_1(a); TCGv ea = gen_lea_modrm_1(a);
gen_op_mov_reg_v(dflag, reg, ea); gen_lea_v_seg(s, s->aflag, ea, -1, -1);
gen_op_mov_reg_v(dflag, reg, cpu_A0);
} }
break; break;

View File

@ -2097,15 +2097,9 @@ static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
save_globals(s, allocated_regs); save_globals(s, allocated_regs);
} }
static void tcg_reg_alloc_movi(TCGContext *s, const TCGArg *args, static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots,
TCGLifeData arg_life) tcg_target_ulong val, TCGLifeData arg_life)
{ {
TCGTemp *ots;
tcg_target_ulong val;
ots = &s->temps[args[0]];
val = args[1];
if (ots->fixed_reg) { if (ots->fixed_reg) {
/* For fixed registers, we do not do any constant propagation. */ /* For fixed registers, we do not do any constant propagation. */
tcg_out_movi(s, ots->type, ots->reg, val); tcg_out_movi(s, ots->type, ots->reg, val);
@ -2126,6 +2120,15 @@ static void tcg_reg_alloc_movi(TCGContext *s, const TCGArg *args,
} }
} }
static void tcg_reg_alloc_movi(TCGContext *s, const TCGArg *args,
TCGLifeData arg_life)
{
TCGTemp *ots = &s->temps[args[0]];
tcg_target_ulong val = args[1];
tcg_reg_alloc_do_movi(s, ots, val, arg_life);
}
static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def, static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def,
const TCGArg *args, TCGLifeData arg_life) const TCGArg *args, TCGLifeData arg_life)
{ {
@ -2141,21 +2144,29 @@ static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def,
otype = ots->type; otype = ots->type;
itype = ts->type; itype = ts->type;
/* If the source value is not in a register, and we're going to be if (ts->val_type == TEMP_VAL_CONST) {
forced to have it in a register in order to perform the copy, /* propagate constant or generate sti */
then copy the SOURCE value into its own register first. That way tcg_target_ulong val = ts->val;
we don't have to reload SOURCE the next time it is used. */ if (IS_DEAD_ARG(1)) {
if (((NEED_SYNC_ARG(0) || ots->fixed_reg) && ts->val_type != TEMP_VAL_REG) temp_dead(s, ts);
|| ts->val_type == TEMP_VAL_MEM) { }
tcg_reg_alloc_do_movi(s, ots, val, arg_life);
return;
}
/* If the source value is in memory we're going to be forced
to have it in a register in order to perform the copy. Copy
the SOURCE value into its own register first, that way we
don't have to reload SOURCE the next time it is used. */
if (ts->val_type == TEMP_VAL_MEM) {
temp_load(s, ts, tcg_target_available_regs[itype], allocated_regs); temp_load(s, ts, tcg_target_available_regs[itype], allocated_regs);
} }
tcg_debug_assert(ts->val_type == TEMP_VAL_REG);
if (IS_DEAD_ARG(0) && !ots->fixed_reg) { if (IS_DEAD_ARG(0) && !ots->fixed_reg) {
/* mov to a non-saved dead register makes no sense (even with /* mov to a non-saved dead register makes no sense (even with
liveness analysis disabled). */ liveness analysis disabled). */
tcg_debug_assert(NEED_SYNC_ARG(0)); tcg_debug_assert(NEED_SYNC_ARG(0));
/* The code above should have moved the temp to a register. */
tcg_debug_assert(ts->val_type == TEMP_VAL_REG);
if (!ots->mem_allocated) { if (!ots->mem_allocated) {
temp_allocate_frame(s, args[0]); temp_allocate_frame(s, args[0]);
} }
@ -2164,20 +2175,7 @@ static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def,
temp_dead(s, ts); temp_dead(s, ts);
} }
temp_dead(s, ots); temp_dead(s, ots);
} else if (ts->val_type == TEMP_VAL_CONST) {
/* propagate constant */
if (ots->val_type == TEMP_VAL_REG) {
s->reg_to_temp[ots->reg] = NULL;
}
ots->val_type = TEMP_VAL_CONST;
ots->val = ts->val;
if (IS_DEAD_ARG(1)) {
temp_dead(s, ts);
}
} else { } else {
/* The code in the first if block should have moved the
temp to a register. */
tcg_debug_assert(ts->val_type == TEMP_VAL_REG);
if (IS_DEAD_ARG(1) && !ts->fixed_reg && !ots->fixed_reg) { if (IS_DEAD_ARG(1) && !ts->fixed_reg && !ots->fixed_reg) {
/* the mov can be suppressed */ /* the mov can be suppressed */
if (ots->val_type == TEMP_VAL_REG) { if (ots->val_type == TEMP_VAL_REG) {

View File

@ -8,6 +8,8 @@ SYSEMU_TARGET_LIST := $(subst -softmmu.mak,,$(notdir \
check-unit-y = tests/check-qdict$(EXESUF) check-unit-y = tests/check-qdict$(EXESUF)
gcov-files-check-qdict-y = qobject/qdict.c gcov-files-check-qdict-y = qobject/qdict.c
check-unit-y = tests/test-char$(EXESUF)
gcov-files-check-qdict-y = qemu-char.c
check-unit-y += tests/check-qfloat$(EXESUF) check-unit-y += tests/check-qfloat$(EXESUF)
gcov-files-check-qfloat-y = qobject/qfloat.c gcov-files-check-qfloat-y = qobject/qfloat.c
check-unit-y += tests/check-qint$(EXESUF) check-unit-y += tests/check-qint$(EXESUF)
@ -481,6 +483,8 @@ tests/check-qnull$(EXESUF): tests/check-qnull.o $(test-util-obj-y)
tests/check-qjson$(EXESUF): tests/check-qjson.o $(test-util-obj-y) tests/check-qjson$(EXESUF): tests/check-qjson.o $(test-util-obj-y)
tests/check-qom-interface$(EXESUF): tests/check-qom-interface.o $(test-qom-obj-y) tests/check-qom-interface$(EXESUF): tests/check-qom-interface.o $(test-qom-obj-y)
tests/check-qom-proplist$(EXESUF): tests/check-qom-proplist.o $(test-qom-obj-y) tests/check-qom-proplist$(EXESUF): tests/check-qom-proplist.o $(test-qom-obj-y)
tests/test-char$(EXESUF): tests/test-char.o qemu-char.o qemu-timer.o $(test-util-obj-y) $(qtest-obj-y) $(test-io-obj-y)
tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(test-block-obj-y) tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(test-block-obj-y)
tests/test-aio$(EXESUF): tests/test-aio.o $(test-block-obj-y) tests/test-aio$(EXESUF): tests/test-aio.o $(test-block-obj-y)
tests/test-rfifolock$(EXESUF): tests/test-rfifolock.o $(test-util-obj-y) tests/test-rfifolock$(EXESUF): tests/test-rfifolock.o $(test-util-obj-y)

View File

@ -193,7 +193,7 @@ static void *thread_func(void *p)
rcu_register_thread(); rcu_register_thread();
atomic_inc(&n_ready_threads); atomic_inc(&n_ready_threads);
while (!atomic_mb_read(&test_start)) { while (!atomic_read(&test_start)) {
cpu_relax(); cpu_relax();
} }
@ -393,11 +393,11 @@ static void run_test(void)
while (atomic_read(&n_ready_threads) != n_rw_threads + n_rz_threads) { while (atomic_read(&n_ready_threads) != n_rw_threads + n_rz_threads) {
cpu_relax(); cpu_relax();
} }
atomic_mb_set(&test_start, true); atomic_set(&test_start, true);
do { do {
remaining = sleep(duration); remaining = sleep(duration);
} while (remaining); } while (remaining);
atomic_mb_set(&test_stop, true); atomic_set(&test_stop, true);
for (i = 0; i < n_rw_threads; i++) { for (i = 0; i < n_rw_threads; i++) {
qemu_thread_join(&rw_threads[i]); qemu_thread_join(&rw_threads[i]);

View File

@ -2250,14 +2250,14 @@ SSE_OP(a ## sd);
#define SSE_COMI(op, field)\ #define SSE_COMI(op, field)\
{\ {\
unsigned int eflags;\ unsigned long eflags;\
XMMReg a, b;\ XMMReg a, b;\
a.field[0] = a1;\ a.field[0] = a1;\
b.field[0] = b1;\ b.field[0] = b1;\
asm volatile (#op " %2, %1\n"\ asm volatile (#op " %2, %1\n"\
"pushf\n"\ "pushf\n"\
"pop %0\n"\ "pop %0\n"\
: "=m" (eflags)\ : "=rm" (eflags)\
: "x" (a.dq), "x" (b.dq));\ : "x" (a.dq), "x" (b.dq));\
printf("%-9s: a=%f b=%f cc=%04x\n",\ printf("%-9s: a=%f b=%f cc=%04x\n",\
#op, a1, b1,\ #op, a1, b1,\

253
tests/test-char.c Normal file
View File

@ -0,0 +1,253 @@
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "qemu/config-file.h"
#include "sysemu/char.h"
#include "sysemu/sysemu.h"
#include "qapi/error.h"
#include "qmp-commands.h"
typedef struct FeHandler {
int read_count;
int last_event;
char read_buf[128];
} FeHandler;
static int fe_can_read(void *opaque)
{
FeHandler *h = opaque;
return sizeof(h->read_buf) - h->read_count;
}
static void fe_read(void *opaque, const uint8_t *buf, int size)
{
FeHandler *h = opaque;
g_assert_cmpint(size, <=, fe_can_read(opaque));
memcpy(h->read_buf + h->read_count, buf, size);
h->read_count += size;
}
static void fe_event(void *opaque, int event)
{
FeHandler *h = opaque;
h->last_event = event;
}
#ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS
static void char_stdio_test_subprocess(void)
{
CharDriverState *chr;
CharBackend be;
int ret;
chr = qemu_chr_new("label", "stdio");
g_assert_nonnull(chr);
qemu_chr_fe_init(&be, chr, &error_abort);
qemu_chr_fe_set_open(&be, true);
ret = qemu_chr_fe_write(&be, (void *)"buf", 4);
g_assert_cmpint(ret, ==, 4);
qemu_chr_fe_deinit(&be);
qemu_chr_delete(chr);
}
static void char_stdio_test(void)
{
g_test_trap_subprocess("/char/stdio/subprocess", 0, 0);
g_test_trap_assert_passed();
g_test_trap_assert_stdout("buf");
}
#endif
static void char_ringbuf_test(void)
{
QemuOpts *opts;
CharDriverState *chr;
CharBackend be;
char *data;
int ret;
opts = qemu_opts_create(qemu_find_opts("chardev"), "ringbuf-label",
1, &error_abort);
qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
qemu_opt_set(opts, "size", "5", &error_abort);
chr = qemu_chr_new_from_opts(opts, NULL);
g_assert_null(chr);
qemu_opts_del(opts);
opts = qemu_opts_create(qemu_find_opts("chardev"), "ringbuf-label",
1, &error_abort);
qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
qemu_opt_set(opts, "size", "2", &error_abort);
chr = qemu_chr_new_from_opts(opts, &error_abort);
g_assert_nonnull(chr);
qemu_opts_del(opts);
qemu_chr_fe_init(&be, chr, &error_abort);
ret = qemu_chr_fe_write(&be, (void *)"buff", 4);
g_assert_cmpint(ret, ==, 4);
data = qmp_ringbuf_read("ringbuf-label", 4, false, 0, &error_abort);
g_assert_cmpstr(data, ==, "ff");
g_free(data);
data = qmp_ringbuf_read("ringbuf-label", 4, false, 0, &error_abort);
g_assert_cmpstr(data, ==, "");
g_free(data);
qemu_chr_fe_deinit(&be);
qemu_chr_delete(chr);
}
static void char_mux_test(void)
{
QemuOpts *opts;
CharDriverState *chr, *base;
char *data;
FeHandler h1 = { 0, }, h2 = { 0, };
CharBackend chr_be1, chr_be2;
opts = qemu_opts_create(qemu_find_opts("chardev"), "mux-label",
1, &error_abort);
qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
qemu_opt_set(opts, "size", "128", &error_abort);
qemu_opt_set(opts, "mux", "on", &error_abort);
chr = qemu_chr_new_from_opts(opts, &error_abort);
g_assert_nonnull(chr);
qemu_opts_del(opts);
qemu_chr_fe_init(&chr_be1, chr, &error_abort);
qemu_chr_fe_set_handlers(&chr_be1,
fe_can_read,
fe_read,
fe_event,
&h1,
NULL, true);
qemu_chr_fe_init(&chr_be2, chr, &error_abort);
qemu_chr_fe_set_handlers(&chr_be2,
fe_can_read,
fe_read,
fe_event,
&h2,
NULL, true);
qemu_chr_fe_take_focus(&chr_be2);
base = qemu_chr_find("mux-label-base");
g_assert_cmpint(qemu_chr_be_can_write(base), !=, 0);
qemu_chr_be_write(base, (void *)"hello", 6);
g_assert_cmpint(h1.read_count, ==, 0);
g_assert_cmpint(h2.read_count, ==, 6);
g_assert_cmpstr(h2.read_buf, ==, "hello");
h2.read_count = 0;
/* switch focus */
qemu_chr_be_write(base, (void *)"\1c", 2);
qemu_chr_be_write(base, (void *)"hello", 6);
g_assert_cmpint(h2.read_count, ==, 0);
g_assert_cmpint(h1.read_count, ==, 6);
g_assert_cmpstr(h1.read_buf, ==, "hello");
h1.read_count = 0;
/* remove first handler */
qemu_chr_fe_set_handlers(&chr_be1, NULL, NULL, NULL, NULL, NULL, true);
qemu_chr_be_write(base, (void *)"hello", 6);
g_assert_cmpint(h1.read_count, ==, 0);
g_assert_cmpint(h2.read_count, ==, 0);
qemu_chr_be_write(base, (void *)"\1c", 2);
qemu_chr_be_write(base, (void *)"hello", 6);
g_assert_cmpint(h1.read_count, ==, 0);
g_assert_cmpint(h2.read_count, ==, 6);
g_assert_cmpstr(h2.read_buf, ==, "hello");
h2.read_count = 0;
/* print help */
qemu_chr_be_write(base, (void *)"\1?", 2);
data = qmp_ringbuf_read("mux-label-base", 128, false, 0, &error_abort);
g_assert_cmpint(strlen(data), !=, 0);
g_free(data);
qemu_chr_fe_deinit(&chr_be1);
qemu_chr_fe_deinit(&chr_be2);
qemu_chr_delete(chr);
}
static void char_null_test(void)
{
Error *err = NULL;
CharDriverState *chr;
CharBackend be;
int ret;
chr = qemu_chr_find("label-null");
g_assert_null(chr);
chr = qemu_chr_new("label-null", "null");
chr = qemu_chr_find("label-null");
g_assert_nonnull(chr);
g_assert(qemu_chr_has_feature(chr,
QEMU_CHAR_FEATURE_FD_PASS) == false);
g_assert(qemu_chr_has_feature(chr,
QEMU_CHAR_FEATURE_RECONNECTABLE) == false);
/* check max avail */
qemu_chr_fe_init(&be, chr, &error_abort);
qemu_chr_fe_init(&be, chr, &err);
error_free_or_abort(&err);
/* deinit & reinit */
qemu_chr_fe_deinit(&be);
qemu_chr_fe_init(&be, chr, &error_abort);
qemu_chr_fe_set_open(&be, true);
qemu_chr_fe_set_handlers(&be,
fe_can_read,
fe_read,
fe_event,
NULL, NULL, true);
ret = qemu_chr_fe_write(&be, (void *)"buf", 4);
g_assert_cmpint(ret, ==, 4);
qemu_chr_fe_deinit(&be);
qemu_chr_delete(chr);
}
static void char_invalid_test(void)
{
CharDriverState *chr;
chr = qemu_chr_new("label-invalid", "invalid");
g_assert_null(chr);
}
int main(int argc, char **argv)
{
g_test_init(&argc, &argv, NULL);
module_call_init(MODULE_INIT_QOM);
qemu_add_opts(&qemu_chardev_opts);
g_test_add_func("/char/null", char_null_test);
g_test_add_func("/char/invalid", char_invalid_test);
g_test_add_func("/char/ringbuf", char_ringbuf_test);
g_test_add_func("/char/mux", char_mux_test);
#ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS
g_test_add_func("/char/stdio/subprocess", char_stdio_test_subprocess);
g_test_add_func("/char/stdio", char_stdio_test);
#endif
return g_test_run();
}

View File

@ -11,6 +11,7 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "libqtest.h" #include "libqtest.h"
#include "qapi/error.h"
#include "qemu/option.h" #include "qemu/option.h"
#include "qemu/range.h" #include "qemu/range.h"
#include "qemu/sockets.h" #include "qemu/sockets.h"
@ -19,6 +20,7 @@
#include "libqos/libqos.h" #include "libqos/libqos.h"
#include "libqos/pci-pc.h" #include "libqos/pci-pc.h"
#include "libqos/virtio-pci.h" #include "libqos/virtio-pci.h"
#include "qapi/error.h"
#include "libqos/pci-pc.h" #include "libqos/pci-pc.h"
#include "libqos/virtio-pci.h" #include "libqos/virtio-pci.h"
@ -141,7 +143,7 @@ typedef struct TestServer {
gchar *socket_path; gchar *socket_path;
gchar *mig_path; gchar *mig_path;
gchar *chr_name; gchar *chr_name;
CharDriverState *chr; CharBackend chr;
int fds_num; int fds_num;
int fds[VHOST_MEMORY_MAX_NREGIONS]; int fds[VHOST_MEMORY_MAX_NREGIONS];
VhostUserMemory memory; VhostUserMemory memory;
@ -261,13 +263,13 @@ static int chr_can_read(void *opaque)
static void chr_read(void *opaque, const uint8_t *buf, int size) static void chr_read(void *opaque, const uint8_t *buf, int size)
{ {
TestServer *s = opaque; TestServer *s = opaque;
CharDriverState *chr = s->chr; CharBackend *chr = &s->chr;
VhostUserMsg msg; VhostUserMsg msg;
uint8_t *p = (uint8_t *) &msg; uint8_t *p = (uint8_t *) &msg;
int fd; int fd;
if (s->test_fail) { if (s->test_fail) {
qemu_chr_disconnect(chr); qemu_chr_fe_disconnect(chr);
/* now switch to non-failure */ /* now switch to non-failure */
s->test_fail = false; s->test_fail = false;
} }
@ -312,7 +314,7 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
g_assert_cmpint(msg.payload.u64 & (0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES), g_assert_cmpint(msg.payload.u64 & (0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES),
!=, 0ULL); !=, 0ULL);
if (s->test_flags == TEST_FLAGS_DISCONNECT) { if (s->test_flags == TEST_FLAGS_DISCONNECT) {
qemu_chr_disconnect(chr); qemu_chr_fe_disconnect(chr);
s->test_flags = TEST_FLAGS_BAD; s->test_flags = TEST_FLAGS_BAD;
} }
break; break;
@ -344,7 +346,8 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
case VHOST_USER_SET_MEM_TABLE: case VHOST_USER_SET_MEM_TABLE:
/* received the mem table */ /* received the mem table */
memcpy(&s->memory, &msg.payload.memory, sizeof(msg.payload.memory)); memcpy(&s->memory, &msg.payload.memory, sizeof(msg.payload.memory));
s->fds_num = qemu_chr_fe_get_msgfds(chr, s->fds, G_N_ELEMENTS(s->fds)); s->fds_num = qemu_chr_fe_get_msgfds(chr, s->fds,
G_N_ELEMENTS(s->fds));
/* signal the test that it can continue */ /* signal the test that it can continue */
g_cond_signal(&s->data_cond); g_cond_signal(&s->data_cond);
@ -453,13 +456,15 @@ static void chr_event(void *opaque, int event)
static void test_server_create_chr(TestServer *server, const gchar *opt) static void test_server_create_chr(TestServer *server, const gchar *opt)
{ {
gchar *chr_path; gchar *chr_path;
CharDriverState *chr;
chr_path = g_strdup_printf("unix:%s%s", server->socket_path, opt); chr_path = g_strdup_printf("unix:%s%s", server->socket_path, opt);
server->chr = qemu_chr_new(server->chr_name, chr_path, NULL); chr = qemu_chr_new(server->chr_name, chr_path);
g_free(chr_path); g_free(chr_path);
qemu_chr_add_handlers(server->chr, chr_can_read, chr_read, qemu_chr_fe_init(&server->chr, chr, &error_abort);
chr_event, server); qemu_chr_fe_set_handlers(&server->chr, chr_can_read, chr_read,
chr_event, server, NULL, true);
} }
static void test_server_listen(TestServer *server) static void test_server_listen(TestServer *server)
@ -483,8 +488,10 @@ static inline void test_server_connect(TestServer *server)
static gboolean _test_server_free(TestServer *server) static gboolean _test_server_free(TestServer *server)
{ {
int i; int i;
CharDriverState *chr = qemu_chr_fe_get_driver(&server->chr);
qemu_chr_delete(server->chr); qemu_chr_fe_deinit(&server->chr);
qemu_chr_delete(chr);
for (i = 0; i < server->fds_num; i++) { for (i = 0; i < server->fds_num; i++) {
close(server->fds[i]); close(server->fds[i]);
@ -721,7 +728,7 @@ reconnect_cb(gpointer user_data)
{ {
TestServer *s = user_data; TestServer *s = user_data;
qemu_chr_disconnect(s->chr); qemu_chr_fe_disconnect(&s->chr);
return FALSE; return FALSE;
} }

View File

@ -1083,6 +1083,7 @@ static void kbd_send_chars(void *opaque)
void kbd_put_keysym_console(QemuConsole *s, int keysym) void kbd_put_keysym_console(QemuConsole *s, int keysym)
{ {
uint8_t buf[16], *q; uint8_t buf[16], *q;
CharBackend *be;
int c; int c;
if (!s || (s->console_type == GRAPHIC_CONSOLE)) if (!s || (s->console_type == GRAPHIC_CONSOLE))
@ -1125,7 +1126,8 @@ void kbd_put_keysym_console(QemuConsole *s, int keysym)
if (s->echo) { if (s->echo) {
console_puts(s->chr, buf, q - buf); console_puts(s->chr, buf, q - buf);
} }
if (s->chr->chr_read) { be = s->chr->be;
if (be && be->chr_read) {
qemu_fifo_write(&s->out_fifo, buf, q - buf); qemu_fifo_write(&s->out_fifo, buf, q - buf);
kbd_send_chars(s); kbd_send_chars(s);
} }
@ -2033,8 +2035,6 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
} }
qemu_chr_be_generic_open(chr); qemu_chr_be_generic_open(chr);
if (chr->init)
chr->init(chr);
} }
static CharDriverState *text_console_init(ChardevVC *vc, Error **errp) static CharDriverState *text_console_init(ChardevVC *vc, Error **errp)
@ -2079,10 +2079,6 @@ static CharDriverState *text_console_init(ChardevVC *vc, Error **errp)
s->chr = chr; s->chr = chr;
chr->opaque = s; chr->opaque = s;
chr->chr_set_echo = text_console_set_echo; chr->chr_set_echo = text_console_set_echo;
/* console/chardev init sometimes completes elsewhere in a 2nd
* stage, so defer OPENED events until they are fully initialized
*/
chr->explicit_be_open = true;
if (display_state) { if (display_state) {
text_console_do_init(chr, display_state); text_console_do_init(chr, display_state);
@ -2093,8 +2089,13 @@ static CharDriverState *text_console_init(ChardevVC *vc, Error **errp)
static VcHandler *vc_handler = text_console_init; static VcHandler *vc_handler = text_console_init;
static CharDriverState *vc_init(const char *id, ChardevBackend *backend, static CharDriverState *vc_init(const char *id, ChardevBackend *backend,
ChardevReturn *ret, Error **errp) ChardevReturn *ret, bool *be_opened,
Error **errp)
{ {
/* console/chardev init sometimes completes elsewhere in a 2nd
* stage, so defer OPENED events until they are fully initialized
*/
*be_opened = false;
return vc_handler(backend->u.vc.data, errp); return vc_handler(backend->u.vc.data, errp);
} }

View File

@ -1685,9 +1685,6 @@ static CharDriverState *gd_vc_handler(ChardevVC *vc, Error **errp)
/* Temporary, until gd_vc_vte_init runs. */ /* Temporary, until gd_vc_vte_init runs. */
chr->opaque = g_new0(VirtualConsole, 1); chr->opaque = g_new0(VirtualConsole, 1);
/* defer OPENED events until our vc is fully initialized */
chr->explicit_be_open = true;
vcs[nb_vcs++] = chr; vcs[nb_vcs++] = chr;
return chr; return chr;
@ -1789,9 +1786,6 @@ static GSList *gd_vc_vte_init(GtkDisplayState *s, VirtualConsole *vc,
gtk_label_new(vc->label)); gtk_label_new(vc->label));
qemu_chr_be_generic_open(vc->vte.chr); qemu_chr_be_generic_open(vc->vte.chr);
if (vc->vte.chr->init) {
vc->vte.chr->init(vc->vte.chr);
}
return group; return group;
} }

View File

@ -360,7 +360,11 @@ void qemu_event_destroy(QemuEvent *ev)
void qemu_event_set(QemuEvent *ev) void qemu_event_set(QemuEvent *ev)
{ {
if (atomic_mb_read(&ev->value) != EV_SET) { /* qemu_event_set has release semantics, but because it *loads*
* ev->value we need a full memory barrier here.
*/
smp_mb();
if (atomic_read(&ev->value) != EV_SET) {
if (atomic_xchg(&ev->value, EV_SET) == EV_BUSY) { if (atomic_xchg(&ev->value, EV_SET) == EV_BUSY) {
/* There were waiters, wake them up. */ /* There were waiters, wake them up. */
futex_wake(ev, INT_MAX); futex_wake(ev, INT_MAX);
@ -370,7 +374,11 @@ void qemu_event_set(QemuEvent *ev)
void qemu_event_reset(QemuEvent *ev) void qemu_event_reset(QemuEvent *ev)
{ {
if (atomic_mb_read(&ev->value) == EV_SET) { unsigned value;
value = atomic_read(&ev->value);
smp_mb_acquire();
if (value == EV_SET) {
/* /*
* If there was a concurrent reset (or even reset+wait), * If there was a concurrent reset (or even reset+wait),
* do nothing. Otherwise change EV_SET->EV_FREE. * do nothing. Otherwise change EV_SET->EV_FREE.
@ -383,7 +391,8 @@ void qemu_event_wait(QemuEvent *ev)
{ {
unsigned value; unsigned value;
value = atomic_mb_read(&ev->value); value = atomic_read(&ev->value);
smp_mb_acquire();
if (value != EV_SET) { if (value != EV_SET) {
if (value == EV_FREE) { if (value == EV_FREE) {
/* /*

View File

@ -274,7 +274,11 @@ void qemu_event_destroy(QemuEvent *ev)
void qemu_event_set(QemuEvent *ev) void qemu_event_set(QemuEvent *ev)
{ {
if (atomic_mb_read(&ev->value) != EV_SET) { /* qemu_event_set has release semantics, but because it *loads*
* ev->value we need a full memory barrier here.
*/
smp_mb();
if (atomic_read(&ev->value) != EV_SET) {
if (atomic_xchg(&ev->value, EV_SET) == EV_BUSY) { if (atomic_xchg(&ev->value, EV_SET) == EV_BUSY) {
/* There were waiters, wake them up. */ /* There were waiters, wake them up. */
SetEvent(ev->event); SetEvent(ev->event);
@ -284,7 +288,11 @@ void qemu_event_set(QemuEvent *ev)
void qemu_event_reset(QemuEvent *ev) void qemu_event_reset(QemuEvent *ev)
{ {
if (atomic_mb_read(&ev->value) == EV_SET) { unsigned value;
value = atomic_read(&ev->value);
smp_mb_acquire();
if (value == EV_SET) {
/* If there was a concurrent reset (or even reset+wait), /* If there was a concurrent reset (or even reset+wait),
* do nothing. Otherwise change EV_SET->EV_FREE. * do nothing. Otherwise change EV_SET->EV_FREE.
*/ */
@ -296,7 +304,8 @@ void qemu_event_wait(QemuEvent *ev)
{ {
unsigned value; unsigned value;
value = atomic_mb_read(&ev->value); value = atomic_read(&ev->value);
smp_mb_acquire();
if (value != EV_SET) { if (value != EV_SET) {
if (value == EV_FREE) { if (value == EV_FREE) {
/* qemu_event_set is not yet going to call SetEvent, but we are /* qemu_event_set is not yet going to call SetEvent, but we are

View File

@ -82,14 +82,16 @@ static void wait_for_readers(void)
/* Instead of using atomic_mb_set for index->waiting, and /* Instead of using atomic_mb_set for index->waiting, and
* atomic_mb_read for index->ctr, memory barriers are placed * atomic_mb_read for index->ctr, memory barriers are placed
* manually since writes to different threads are independent. * manually since writes to different threads are independent.
* atomic_mb_set has a smp_wmb before... * qemu_event_reset has acquire semantics, so no memory barrier
* is needed here.
*/ */
smp_wmb();
QLIST_FOREACH(index, &registry, node) { QLIST_FOREACH(index, &registry, node) {
atomic_set(&index->waiting, true); atomic_set(&index->waiting, true);
} }
/* ... and a smp_mb after. */ /* Here, order the stores to index->waiting before the
* loads of index->ctr.
*/
smp_mb(); smp_mb();
QLIST_FOREACH_SAFE(index, &registry, node, tmp) { QLIST_FOREACH_SAFE(index, &registry, node, tmp) {
@ -104,9 +106,6 @@ static void wait_for_readers(void)
} }
} }
/* atomic_mb_read has smp_rmb after. */
smp_rmb();
if (QLIST_EMPTY(&registry)) { if (QLIST_EMPTY(&registry)) {
break; break;
} }

15
vl.c
View File

@ -1958,7 +1958,7 @@ static void main_loop(void)
static void version(void) static void version(void)
{ {
printf("QEMU emulator version " QEMU_VERSION QEMU_PKGVERSION ", " printf("QEMU emulator version " QEMU_VERSION QEMU_PKGVERSION "\n"
QEMU_COPYRIGHT "\n"); QEMU_COPYRIGHT "\n");
} }
@ -2369,7 +2369,7 @@ static int chardev_init_func(void *opaque, QemuOpts *opts, Error **errp)
{ {
Error *local_err = NULL; Error *local_err = NULL;
qemu_chr_new_from_opts(opts, NULL, &local_err); qemu_chr_new_from_opts(opts, &local_err);
if (local_err) { if (local_err) {
error_report_err(local_err); error_report_err(local_err);
return -1; return -1;
@ -2417,7 +2417,6 @@ static int mon_init_func(void *opaque, QemuOpts *opts, Error **errp)
exit(1); exit(1);
} }
qemu_chr_fe_claim_no_fail(chr);
monitor_init(chr, flags); monitor_init(chr, flags);
return 0; return 0;
} }
@ -2514,7 +2513,7 @@ static int serial_parse(const char *devname)
exit(1); exit(1);
} }
snprintf(label, sizeof(label), "serial%d", index); snprintf(label, sizeof(label), "serial%d", index);
serial_hds[index] = qemu_chr_new(label, devname, NULL); serial_hds[index] = qemu_chr_new(label, devname);
if (!serial_hds[index]) { if (!serial_hds[index]) {
error_report("could not connect serial device" error_report("could not connect serial device"
" to character backend '%s'", devname); " to character backend '%s'", devname);
@ -2536,7 +2535,7 @@ static int parallel_parse(const char *devname)
exit(1); exit(1);
} }
snprintf(label, sizeof(label), "parallel%d", index); snprintf(label, sizeof(label), "parallel%d", index);
parallel_hds[index] = qemu_chr_new(label, devname, NULL); parallel_hds[index] = qemu_chr_new(label, devname);
if (!parallel_hds[index]) { if (!parallel_hds[index]) {
error_report("could not connect parallel device" error_report("could not connect parallel device"
" to character backend '%s'", devname); " to character backend '%s'", devname);
@ -2567,7 +2566,7 @@ static int virtcon_parse(const char *devname)
qemu_opt_set(dev_opts, "driver", "virtconsole", &error_abort); qemu_opt_set(dev_opts, "driver", "virtconsole", &error_abort);
snprintf(label, sizeof(label), "virtcon%d", index); snprintf(label, sizeof(label), "virtcon%d", index);
virtcon_hds[index] = qemu_chr_new(label, devname, NULL); virtcon_hds[index] = qemu_chr_new(label, devname);
if (!virtcon_hds[index]) { if (!virtcon_hds[index]) {
error_report("could not connect virtio console" error_report("could not connect virtio console"
" to character backend '%s'", devname); " to character backend '%s'", devname);
@ -2600,7 +2599,7 @@ static int sclp_parse(const char *devname)
qemu_opt_set(dev_opts, "driver", "sclpconsole", &error_abort); qemu_opt_set(dev_opts, "driver", "sclpconsole", &error_abort);
snprintf(label, sizeof(label), "sclpcon%d", index); snprintf(label, sizeof(label), "sclpcon%d", index);
sclp_hds[index] = qemu_chr_new(label, devname, NULL); sclp_hds[index] = qemu_chr_new(label, devname);
if (!sclp_hds[index]) { if (!sclp_hds[index]) {
error_report("could not connect sclp console" error_report("could not connect sclp console"
" to character backend '%s'", devname); " to character backend '%s'", devname);
@ -2616,7 +2615,7 @@ static int debugcon_parse(const char *devname)
{ {
QemuOpts *opts; QemuOpts *opts;
if (!qemu_chr_new("debugcon", devname, NULL)) { if (!qemu_chr_new("debugcon", devname)) {
exit(1); exit(1);
} }
opts = qemu_opts_create(qemu_find_opts("device"), "debugcon", 1, NULL); opts = qemu_opts_create(qemu_find_opts("device"), "debugcon", 1, NULL);