Re: [Qemu-devel] [qemu-s390x] [PATCH v2 1/2] target/s390x: Split out s390-tod.h
On 09.02.19 07:31, Richard Henderson wrote: > We will need these from CONFIG_USER_ONLY as well, > which cannot access include/hw/. > > Signed-off-by: Richard Henderson > --- > include/hw/s390x/tod.h | 16 +--- > target/s390x/s390-tod.h | 29 + > 2 files changed, 30 insertions(+), 15 deletions(-) > create mode 100644 target/s390x/s390-tod.h > > diff --git a/include/hw/s390x/tod.h b/include/hw/s390x/tod.h > index 47ef9de869..9c4a6000c3 100644 > --- a/include/hw/s390x/tod.h > +++ b/include/hw/s390x/tod.h > @@ -12,6 +12,7 @@ > #define HW_S390_TOD_H > > #include "hw/qdev.h" > +#include "s390-tod.h" > > typedef struct S390TOD { > uint8_t high; > @@ -50,21 +51,6 @@ typedef struct S390TODClass { > void (*set)(S390TODState *td, const S390TOD *tod, Error **errp); > } S390TODClass; > > -/* The value of the TOD clock for 1.1.1970. */ > -#define TOD_UNIX_EPOCH 0x7d91048bca00ULL > - > -/* Converts ns to s390's clock format */ > -static inline uint64_t time2tod(uint64_t ns) > -{ > -return (ns << 9) / 125 + (((ns & 0xff80ull) / 125) << 9); > -} > - > -/* Converts s390's clock format to ns */ > -static inline uint64_t tod2time(uint64_t t) > -{ > -return ((t >> 9) * 125) + (((t & 0x1ff) * 125) >> 9); > -} > - > void s390_init_tod(void); > S390TODState *s390_get_todstate(void); > > diff --git a/target/s390x/s390-tod.h b/target/s390x/s390-tod.h > new file mode 100644 > index 00..8b74d6a6d8 > --- /dev/null > +++ b/target/s390x/s390-tod.h > @@ -0,0 +1,29 @@ > +/* > + * TOD (Time Of Day) clock > + * > + * Copyright 2018 Red Hat, Inc. > + * Author(s): David Hildenbrand > + * > + * This work is licensed under the terms of the GNU GPL, version 2 or later. > + * See the COPYING file in the top-level directory. > + */ > + > +#ifndef TARGET_S390_TOD_H > +#define TARGET_S390_TOD_H > + > +/* The value of the TOD clock for 1.1.1970. */ > +#define TOD_UNIX_EPOCH 0x7d91048bca00ULL > + > +/* Converts ns to s390's clock format */ > +static inline uint64_t time2tod(uint64_t ns) > +{ > +return (ns << 9) / 125 + (((ns & 0xff80ull) / 125) << 9); > +} > + > +/* Converts s390's clock format to ns */ > +static inline uint64_t tod2time(uint64_t t) > +{ > +return ((t >> 9) * 125) + (((t & 0x1ff) * 125) >> 9); > +} > + > +#endif > Reviewed-by: David Hildenbrand -- Thanks, David / dhildenb
[Qemu-devel] [PATCH v1 0/9] Misc fixes to pvrdma device
Hi, Please review the following patch-set which consist of cosmetics fixes to device's user interface (traces, error_report and monitor) and some bug fixes. Thanks Markus, Eric, Marcel and David for reviewing v0. Appreciate your review to this v1. v0 -> v1: * Explain why device attributes are exposed only in HMP interface. * Squash the 3 patches related to HMP interface into one. * Make monitor dump function simple. * Make HMP interface available only if pvrdma is included (detected by build robot). * Remove patch 03/10 ("Warn when too many consecutive poll CQ triggered on an empty CQ) and add the two counters to patch 0/7 (monitor). * Add Marcel's R-Bs. * Add mutex protection to cqe_ctx list. * Add two new patches. Thanks, Yuval Yuval Shaia (9): hw/rdma: Switch to generic error reporting way hw/rdma: Introduce locked qlist hw/rdma: Protect against concurrent execution of poll_cq {monitor,hw/pvrdma}: Expose device internals via monitor interface hw/rdma: Free all MAD receive buffers when device is closed hw/rdma: Free all receive buffers when QP is destroyed hw/pvrdma: Delete unneeded function argument hw/pvrdma: Delete pvrdma_exit function hw/pvrdma: Unregister from shutdown notifier when device goes down hmp-commands-info.hx | 16 ++ hw/rdma/rdma_backend.c| 482 +- hw/rdma/rdma_backend.h| 3 +- hw/rdma/rdma_backend_defs.h | 10 +- hw/rdma/rdma_rm.c | 134 +- hw/rdma/rdma_rm_defs.h| 28 +- hw/rdma/rdma_utils.c | 77 +- hw/rdma/rdma_utils.h | 59 ++--- hw/rdma/trace-events | 32 ++- hw/rdma/vmw/pvrdma.h | 7 +- hw/rdma/vmw/pvrdma_cmd.c | 113 ++-- hw/rdma/vmw/pvrdma_dev_ring.c | 26 +- hw/rdma/vmw/pvrdma_hmp.h | 21 ++ hw/rdma/vmw/pvrdma_main.c | 217 --- hw/rdma/vmw/pvrdma_qp_ops.c | 52 +--- hw/rdma/vmw/trace-events | 16 +- monitor.c | 10 + 17 files changed, 704 insertions(+), 599 deletions(-) create mode 100644 hw/rdma/vmw/pvrdma_hmp.h -- 2.17.2
[Qemu-devel] [PATCH v1 5/9] hw/rdma: Free all MAD receive buffers when device is closed
When device is going down free all saved MAD buffers. Signed-off-by: Yuval Shaia Reviewed-by: Marcel Apfelbaum --- hw/rdma/rdma_backend.c| 33 - hw/rdma/vmw/pvrdma_main.c | 2 ++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/hw/rdma/rdma_backend.c b/hw/rdma/rdma_backend.c index b2730f6009..c51e7cac59 100644 --- a/hw/rdma/rdma_backend.c +++ b/hw/rdma/rdma_backend.c @@ -64,6 +64,32 @@ static inline void complete_work(enum ibv_wc_status status, uint32_t vendor_err, comp_handler(ctx, &wc); } +static void free_cqe_ctx(gpointer data, gpointer user_data) +{ +BackendCtx *bctx; +RdmaDeviceResources *rdma_dev_res = user_data; +unsigned long cqe_ctx_id = GPOINTER_TO_INT(data); + +bctx = rdma_rm_get_cqe_ctx(rdma_dev_res, cqe_ctx_id); +if (bctx) { +rdma_rm_dealloc_cqe_ctx(rdma_dev_res, cqe_ctx_id); +} +g_free(bctx); +} + +static void clean_recv_mads(RdmaBackendDev *backend_dev) +{ +unsigned long cqe_ctx_id; + +do { +cqe_ctx_id = rdma_locked_list_pop_int64(&backend_dev->recv_mads_list); +if (cqe_ctx_id != -ENOENT) { +free_cqe_ctx(GINT_TO_POINTER(cqe_ctx_id), + backend_dev->rdma_dev_res); +} +} while (cqe_ctx_id != -ENOENT); +} + static int rdma_poll_cq(RdmaDeviceResources *rdma_dev_res, struct ibv_cq *ibcq) { int i, ne, total_ne = 0; @@ -1037,6 +1063,11 @@ static int mad_init(RdmaBackendDev *backend_dev, CharBackend *mad_chr_be) return 0; } +static void mad_stop(RdmaBackendDev *backend_dev) +{ +clean_recv_mads(backend_dev); +} + static void mad_fini(RdmaBackendDev *backend_dev) { disable_rdmacm_mux_async(backend_dev); @@ -1224,12 +1255,12 @@ void rdma_backend_start(RdmaBackendDev *backend_dev) void rdma_backend_stop(RdmaBackendDev *backend_dev) { +mad_stop(backend_dev); stop_backend_thread(&backend_dev->comp_thread); } void rdma_backend_fini(RdmaBackendDev *backend_dev) { -rdma_backend_stop(backend_dev); mad_fini(backend_dev); g_hash_table_destroy(ah_hash); ibv_destroy_comp_channel(backend_dev->channel); diff --git a/hw/rdma/vmw/pvrdma_main.c b/hw/rdma/vmw/pvrdma_main.c index 8ffe79ceca..90dc9b191b 100644 --- a/hw/rdma/vmw/pvrdma_main.c +++ b/hw/rdma/vmw/pvrdma_main.c @@ -361,6 +361,8 @@ static void pvrdma_fini(PCIDevice *pdev) pvrdma_qp_ops_fini(); +rdma_backend_stop(&dev->backend_dev); + rdma_rm_fini(&dev->rdma_dev_res, &dev->backend_dev, dev->backend_eth_device_name); -- 2.17.2
[Qemu-devel] [PATCH v1 2/9] hw/rdma: Introduce locked qlist
To make code more readable move handling of locked list to a generic functions. Signed-off-by: Yuval Shaia --- hw/rdma/rdma_backend.c | 20 +-- hw/rdma/rdma_backend_defs.h | 8 ++-- hw/rdma/rdma_utils.c| 39 + hw/rdma/rdma_utils.h| 9 + 4 files changed, 55 insertions(+), 21 deletions(-) diff --git a/hw/rdma/rdma_backend.c b/hw/rdma/rdma_backend.c index 5f60856d19..2f6372f8f0 100644 --- a/hw/rdma/rdma_backend.c +++ b/hw/rdma/rdma_backend.c @@ -527,9 +527,7 @@ static unsigned int save_mad_recv_buffer(RdmaBackendDev *backend_dev, bctx->up_ctx = ctx; bctx->sge = *sge; -qemu_mutex_lock(&backend_dev->recv_mads_list.lock); -qlist_append_int(backend_dev->recv_mads_list.list, bctx_id); -qemu_mutex_unlock(&backend_dev->recv_mads_list.lock); +rdma_locked_list_append_int64(&backend_dev->recv_mads_list, bctx_id); return 0; } @@ -913,23 +911,19 @@ static inline void build_mad_hdr(struct ibv_grh *grh, union ibv_gid *sgid, static void process_incoming_mad_req(RdmaBackendDev *backend_dev, RdmaCmMuxMsg *msg) { -QObject *o_ctx_id; unsigned long cqe_ctx_id; BackendCtx *bctx; char *mad; trace_mad_message("recv", msg->umad.mad, msg->umad_len); -qemu_mutex_lock(&backend_dev->recv_mads_list.lock); -o_ctx_id = qlist_pop(backend_dev->recv_mads_list.list); -qemu_mutex_unlock(&backend_dev->recv_mads_list.lock); -if (!o_ctx_id) { +cqe_ctx_id = rdma_locked_list_pop_int64(&backend_dev->recv_mads_list); +if (cqe_ctx_id == -ENOENT) { rdma_warn_report("No more free MADs buffers, waiting for a while"); sleep(THR_POLL_TO); return; } -cqe_ctx_id = qnum_get_uint(qobject_to(QNum, o_ctx_id)); bctx = rdma_rm_get_cqe_ctx(backend_dev->rdma_dev_res, cqe_ctx_id); if (unlikely(!bctx)) { rdma_error_report("No matching ctx for req %ld", cqe_ctx_id); @@ -994,8 +988,7 @@ static int mad_init(RdmaBackendDev *backend_dev, CharBackend *mad_chr_be) return -EIO; } -qemu_mutex_init(&backend_dev->recv_mads_list.lock); -backend_dev->recv_mads_list.list = qlist_new(); +rdma_locked_list_init(&backend_dev->recv_mads_list); enable_rdmacm_mux_async(backend_dev); @@ -1010,10 +1003,7 @@ static void mad_fini(RdmaBackendDev *backend_dev) { disable_rdmacm_mux_async(backend_dev); qemu_chr_fe_disconnect(backend_dev->rdmacm_mux.chr_be); -if (backend_dev->recv_mads_list.list) { -qlist_destroy_obj(QOBJECT(backend_dev->recv_mads_list.list)); -qemu_mutex_destroy(&backend_dev->recv_mads_list.lock); -} +rdma_locked_list_destroy(&backend_dev->recv_mads_list); } int rdma_backend_get_gid_index(RdmaBackendDev *backend_dev, diff --git a/hw/rdma/rdma_backend_defs.h b/hw/rdma/rdma_backend_defs.h index 15ae8b970e..bec0457f25 100644 --- a/hw/rdma/rdma_backend_defs.h +++ b/hw/rdma/rdma_backend_defs.h @@ -20,6 +20,7 @@ #include "chardev/char-fe.h" #include #include "contrib/rdmacm-mux/rdmacm-mux.h" +#include "rdma_utils.h" typedef struct RdmaDeviceResources RdmaDeviceResources; @@ -30,11 +31,6 @@ typedef struct RdmaBackendThread { bool is_running; /* Set by the thread to report its status */ } RdmaBackendThread; -typedef struct RecvMadList { -QemuMutex lock; -QList *list; -} RecvMadList; - typedef struct RdmaCmMux { CharBackend *chr_be; int can_receive; @@ -48,7 +44,7 @@ typedef struct RdmaBackendDev { struct ibv_context *context; struct ibv_comp_channel *channel; uint8_t port_num; -RecvMadList recv_mads_list; +LockedList recv_mads_list; RdmaCmMux rdmacm_mux; } RdmaBackendDev; diff --git a/hw/rdma/rdma_utils.c b/hw/rdma/rdma_utils.c index f1c980c6be..a2a4ea2a15 100644 --- a/hw/rdma/rdma_utils.c +++ b/hw/rdma/rdma_utils.c @@ -14,6 +14,8 @@ */ #include "qemu/osdep.h" +#include "qapi/qmp/qlist.h" +#include "qapi/qmp/qnum.h" #include "trace.h" #include "rdma_utils.h" @@ -55,3 +57,40 @@ void rdma_pci_dma_unmap(PCIDevice *dev, void *buffer, dma_addr_t len) pci_dma_unmap(dev, buffer, len, DMA_DIRECTION_TO_DEVICE, 0); } } + +void rdma_locked_list_init(LockedList *list) +{ +qemu_mutex_init(&list->lock); +list->list = qlist_new(); +} + +void rdma_locked_list_destroy(LockedList *list) +{ +if (list->list) { +qlist_destroy_obj(QOBJECT(list->list)); +qemu_mutex_destroy(&list->lock); +list->list = NULL; +} +} + +void rdma_locked_list_append_int64(LockedList *list, int64_t value) +{ +qemu_mutex_lock(&list->lock); +qlist_append_int(list->list, value); +qemu_mutex_unlock(&list->lock); +} + +int64_t rdma_locked_list_pop_int64(LockedList *list) +{ +QObject *obj; + +qemu_mutex_lock(&list->lock); +obj = qlist_pop(list->list); +qemu_mutex_unlock(&list->lock); + +if (!obj) { +return -ENOENT; +
[Qemu-devel] [PATCH v1 6/9] hw/rdma: Free all receive buffers when QP is destroyed
When QP is destroyed the backend QP is destroyed as well. This ensures we clean all received buffer we posted to it. However, a contexts of these buffers are still remain in the device. Fix it by maintaining a list of buffer's context and free them when QP is destroyed. Signed-off-by: Yuval Shaia --- hw/rdma/rdma_backend.c | 26 -- hw/rdma/rdma_backend.h | 2 +- hw/rdma/rdma_backend_defs.h | 2 +- hw/rdma/rdma_rm.c | 2 +- hw/rdma/rdma_utils.c| 27 +++ hw/rdma/rdma_utils.h| 9 + 6 files changed, 59 insertions(+), 9 deletions(-) diff --git a/hw/rdma/rdma_backend.c b/hw/rdma/rdma_backend.c index c51e7cac59..11cc13596a 100644 --- a/hw/rdma/rdma_backend.c +++ b/hw/rdma/rdma_backend.c @@ -39,6 +39,7 @@ typedef struct BackendCtx { void *up_ctx; struct ibv_sge sge; /* Used to save MAD recv buffer */ +RdmaBackendQP *backend_qp; /* To maintain recv buffers */ } BackendCtx; struct backend_umad { @@ -73,6 +74,7 @@ static void free_cqe_ctx(gpointer data, gpointer user_data) bctx = rdma_rm_get_cqe_ctx(rdma_dev_res, cqe_ctx_id); if (bctx) { rdma_rm_dealloc_cqe_ctx(rdma_dev_res, cqe_ctx_id); +atomic_dec(&rdma_dev_res->stats.missing_cqe); } g_free(bctx); } @@ -84,13 +86,15 @@ static void clean_recv_mads(RdmaBackendDev *backend_dev) do { cqe_ctx_id = rdma_locked_list_pop_int64(&backend_dev->recv_mads_list); if (cqe_ctx_id != -ENOENT) { +atomic_inc(&backend_dev->rdma_dev_res->stats.missing_cqe); free_cqe_ctx(GINT_TO_POINTER(cqe_ctx_id), backend_dev->rdma_dev_res); } } while (cqe_ctx_id != -ENOENT); } -static int rdma_poll_cq(RdmaDeviceResources *rdma_dev_res, struct ibv_cq *ibcq) +static int rdma_poll_cq(RdmaBackendDev *backend_dev, +RdmaDeviceResources *rdma_dev_res, struct ibv_cq *ibcq) { int i, ne, total_ne = 0; BackendCtx *bctx; @@ -112,6 +116,8 @@ static int rdma_poll_cq(RdmaDeviceResources *rdma_dev_res, struct ibv_cq *ibcq) comp_handler(bctx->up_ctx, &wc[i]); +rdma_locked_glist_remove_int32(&bctx->backend_qp->cqe_ctx_list, + wc[i].wr_id); rdma_rm_dealloc_cqe_ctx(rdma_dev_res, wc[i].wr_id); g_free(bctx); } @@ -174,14 +180,12 @@ static void *comp_handler_thread(void *arg) } backend_dev->rdma_dev_res->stats.poll_cq_from_bk++; -rdma_poll_cq(backend_dev->rdma_dev_res, ev_cq); +rdma_poll_cq(backend_dev, backend_dev->rdma_dev_res, ev_cq); ibv_ack_cq_events(ev_cq, 1); } } -/* TODO: Post cqe for all remaining buffs that were posted */ - backend_dev->comp_thread.is_running = false; qemu_thread_exit(0); @@ -310,7 +314,7 @@ void rdma_backend_poll_cq(RdmaDeviceResources *rdma_dev_res, RdmaBackendCQ *cq) int polled; rdma_dev_res->stats.poll_cq_from_guest++; -polled = rdma_poll_cq(rdma_dev_res, cq->ibcq); +polled = rdma_poll_cq(cq->backend_dev, rdma_dev_res, cq->ibcq); if (!polled) { rdma_dev_res->stats.poll_cq_from_guest_empty++; } @@ -500,6 +504,7 @@ void rdma_backend_post_send(RdmaBackendDev *backend_dev, bctx = g_malloc0(sizeof(*bctx)); bctx->up_ctx = ctx; +bctx->backend_qp = qp; rc = rdma_rm_alloc_cqe_ctx(backend_dev->rdma_dev_res, &bctx_id, bctx); if (unlikely(rc)) { @@ -507,6 +512,8 @@ void rdma_backend_post_send(RdmaBackendDev *backend_dev, goto err_free_bctx; } +rdma_locked_glist_append_int32(&qp->cqe_ctx_list, bctx_id); + rc = build_host_sge_array(backend_dev->rdma_dev_res, new_sge, sge, num_sge, &backend_dev->rdma_dev_res->stats.tx_len); if (rc) { @@ -615,6 +622,7 @@ void rdma_backend_post_recv(RdmaBackendDev *backend_dev, bctx = g_malloc0(sizeof(*bctx)); bctx->up_ctx = ctx; +bctx->backend_qp = qp; rc = rdma_rm_alloc_cqe_ctx(rdma_dev_res, &bctx_id, bctx); if (unlikely(rc)) { @@ -622,6 +630,8 @@ void rdma_backend_post_recv(RdmaBackendDev *backend_dev, goto err_free_bctx; } +rdma_locked_glist_append_int32(&qp->cqe_ctx_list, bctx_id); + rc = build_host_sge_array(rdma_dev_res, new_sge, sge, num_sge, &backend_dev->rdma_dev_res->stats.rx_bufs_len); if (rc) { @@ -761,6 +771,8 @@ int rdma_backend_create_qp(RdmaBackendQP *qp, uint8_t qp_type, return -EIO; } +rdma_locked_glist_init(&qp->cqe_ctx_list); + qp->ibpd = pd->ibpd; /* TODO: Query QP to get max_inline_data and save it to be used in send */ @@ -918,11 +930,13 @@ int rdma_backend_query_qp(RdmaBackendQP *qp, struct ibv_qp_attr *attr, return ibv_query_qp(qp->ibqp, attr, attr_mask, init_attr); } -void rdma_backend_destroy_qp(RdmaBackendQP *qp)
[Qemu-devel] [PATCH v1 4/9] {monitor, hw/pvrdma}: Expose device internals via monitor interface
Allow interrogating device internals through HMP interface. The exposed indicators can be used for troubleshooting by developers or sysadmin. There is no need to expose these attributes to a management system (e.x. libvirt) because (1) most of them are not "device-management' related info and (2) there is no guarantee the interface is stable. Signed-off-by: Yuval Shaia --- hmp-commands-info.hx | 16 hw/rdma/rdma_backend.c| 70 ++- hw/rdma/rdma_rm.c | 7 hw/rdma/rdma_rm_defs.h| 27 +- hw/rdma/vmw/pvrdma.h | 5 +++ hw/rdma/vmw/pvrdma_hmp.h | 21 +++ hw/rdma/vmw/pvrdma_main.c | 77 +++ monitor.c | 10 + 8 files changed, 215 insertions(+), 18 deletions(-) create mode 100644 hw/rdma/vmw/pvrdma_hmp.h diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx index cbee8b944d..9153c33974 100644 --- a/hmp-commands-info.hx +++ b/hmp-commands-info.hx @@ -524,6 +524,22 @@ STEXI Show CPU statistics. ETEXI +#if defined(CONFIG_PVRDMA) +{ +.name = "pvrdmacounters", +.args_type = "", +.params = "", +.help = "show pvrdma device counters", +.cmd= hmp_info_pvrdmacounters, +}, + +STEXI +@item info pvrdmacounters +@findex info pvrdmacounters +Show pvrdma device counters. +ETEXI +#endif + #if defined(CONFIG_SLIRP) { .name = "usernet", diff --git a/hw/rdma/rdma_backend.c b/hw/rdma/rdma_backend.c index dc2a078b23..b2730f6009 100644 --- a/hw/rdma/rdma_backend.c +++ b/hw/rdma/rdma_backend.c @@ -64,9 +64,9 @@ static inline void complete_work(enum ibv_wc_status status, uint32_t vendor_err, comp_handler(ctx, &wc); } -static void rdma_poll_cq(RdmaDeviceResources *rdma_dev_res, struct ibv_cq *ibcq) +static int rdma_poll_cq(RdmaDeviceResources *rdma_dev_res, struct ibv_cq *ibcq) { -int i, ne; +int i, ne, total_ne = 0; BackendCtx *bctx; struct ibv_wc wc[2]; @@ -89,12 +89,18 @@ static void rdma_poll_cq(RdmaDeviceResources *rdma_dev_res, struct ibv_cq *ibcq) rdma_rm_dealloc_cqe_ctx(rdma_dev_res, wc[i].wr_id); g_free(bctx); } +total_ne += ne; } while (ne > 0); +atomic_sub(&rdma_dev_res->stats.missing_cqe, total_ne); qemu_mutex_unlock(&rdma_dev_res->lock); if (ne < 0) { rdma_error_report("ibv_poll_cq fail, rc=%d, errno=%d", ne, errno); } + +rdma_dev_res->stats.completions += total_ne; + +return total_ne; } static void *comp_handler_thread(void *arg) @@ -122,6 +128,9 @@ static void *comp_handler_thread(void *arg) while (backend_dev->comp_thread.run) { do { rc = qemu_poll_ns(pfds, 1, THR_POLL_TO * (int64_t)SCALE_MS); +if (!rc) { +backend_dev->rdma_dev_res->stats.poll_cq_ppoll_to++; +} } while (!rc && backend_dev->comp_thread.run); if (backend_dev->comp_thread.run) { @@ -138,6 +147,7 @@ static void *comp_handler_thread(void *arg) errno); } +backend_dev->rdma_dev_res->stats.poll_cq_from_bk++; rdma_poll_cq(backend_dev->rdma_dev_res, ev_cq); ibv_ack_cq_events(ev_cq, 1); @@ -271,7 +281,13 @@ int rdma_backend_query_port(RdmaBackendDev *backend_dev, void rdma_backend_poll_cq(RdmaDeviceResources *rdma_dev_res, RdmaBackendCQ *cq) { -rdma_poll_cq(rdma_dev_res, cq->ibcq); +int polled; + +rdma_dev_res->stats.poll_cq_from_guest++; +polled = rdma_poll_cq(rdma_dev_res, cq->ibcq); +if (!polled) { +rdma_dev_res->stats.poll_cq_from_guest_empty++; +} } static GHashTable *ah_hash; @@ -333,7 +349,7 @@ static void ah_cache_init(void) static int build_host_sge_array(RdmaDeviceResources *rdma_dev_res, struct ibv_sge *dsge, struct ibv_sge *ssge, -uint8_t num_sge) +uint8_t num_sge, uint64_t *total_length) { RdmaRmMR *mr; int ssge_idx; @@ -349,6 +365,8 @@ static int build_host_sge_array(RdmaDeviceResources *rdma_dev_res, dsge->length = ssge[ssge_idx].length; dsge->lkey = rdma_backend_mr_lkey(&mr->backend_mr); +*total_length += dsge->length; + dsge++; } @@ -445,8 +463,10 @@ void rdma_backend_post_send(RdmaBackendDev *backend_dev, rc = mad_send(backend_dev, sgid_idx, sgid, sge, num_sge); if (rc) { complete_work(IBV_WC_GENERAL_ERR, VENDOR_ERR_MAD_SEND, ctx); +backend_dev->rdma_dev_res->stats.mad_tx_err++; } else { complete_work(IBV_WC_SUCCESS, 0, ctx); +backend_dev->rdma_dev_res->stats.mad_tx++; } } return; @@ -458,20 +478,21 @@ void rdma_backend_post_send(RdmaBackendDev *backend_dev, rc = rdma_rm_alloc
[Qemu-devel] [PATCH v1 7/9] hw/pvrdma: Delete unneeded function argument
The function argument rdma_dev_res is not needed as it is stored in the backend_dev object at init. Signed-off-by: Yuval Shaia Reviewed-by: Marcel Apfelbaum --- hw/rdma/rdma_backend.c | 13 ++--- hw/rdma/rdma_backend.h | 1 - hw/rdma/vmw/pvrdma_qp_ops.c | 3 +-- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/hw/rdma/rdma_backend.c b/hw/rdma/rdma_backend.c index 11cc13596a..bb3c2d71a1 100644 --- a/hw/rdma/rdma_backend.c +++ b/hw/rdma/rdma_backend.c @@ -593,7 +593,6 @@ static unsigned int save_mad_recv_buffer(RdmaBackendDev *backend_dev, } void rdma_backend_post_recv(RdmaBackendDev *backend_dev, -RdmaDeviceResources *rdma_dev_res, RdmaBackendQP *qp, uint8_t qp_type, struct ibv_sge *sge, uint32_t num_sge, void *ctx) { @@ -612,9 +611,9 @@ void rdma_backend_post_recv(RdmaBackendDev *backend_dev, rc = save_mad_recv_buffer(backend_dev, sge, num_sge, ctx); if (rc) { complete_work(IBV_WC_GENERAL_ERR, rc, ctx); -rdma_dev_res->stats.mad_rx_bufs_err++; +backend_dev->rdma_dev_res->stats.mad_rx_bufs_err++; } else { -rdma_dev_res->stats.mad_rx_bufs++; +backend_dev->rdma_dev_res->stats.mad_rx_bufs++; } } return; @@ -624,7 +623,7 @@ void rdma_backend_post_recv(RdmaBackendDev *backend_dev, bctx->up_ctx = ctx; bctx->backend_qp = qp; -rc = rdma_rm_alloc_cqe_ctx(rdma_dev_res, &bctx_id, bctx); +rc = rdma_rm_alloc_cqe_ctx(backend_dev->rdma_dev_res, &bctx_id, bctx); if (unlikely(rc)) { complete_work(IBV_WC_GENERAL_ERR, VENDOR_ERR_NOMEM, ctx); goto err_free_bctx; @@ -632,7 +631,7 @@ void rdma_backend_post_recv(RdmaBackendDev *backend_dev, rdma_locked_glist_append_int32(&qp->cqe_ctx_list, bctx_id); -rc = build_host_sge_array(rdma_dev_res, new_sge, sge, num_sge, +rc = build_host_sge_array(backend_dev->rdma_dev_res, new_sge, sge, num_sge, &backend_dev->rdma_dev_res->stats.rx_bufs_len); if (rc) { complete_work(IBV_WC_GENERAL_ERR, rc, ctx); @@ -651,13 +650,13 @@ void rdma_backend_post_recv(RdmaBackendDev *backend_dev, } atomic_inc(&backend_dev->rdma_dev_res->stats.missing_cqe); -rdma_dev_res->stats.rx_bufs++; +backend_dev->rdma_dev_res->stats.rx_bufs++; return; err_dealloc_cqe_ctx: backend_dev->rdma_dev_res->stats.rx_bufs_err++; -rdma_rm_dealloc_cqe_ctx(rdma_dev_res, bctx_id); +rdma_rm_dealloc_cqe_ctx(backend_dev->rdma_dev_res, bctx_id); err_free_bctx: g_free(bctx); diff --git a/hw/rdma/rdma_backend.h b/hw/rdma/rdma_backend.h index cb5efa2a3a..5d507a1c41 100644 --- a/hw/rdma/rdma_backend.h +++ b/hw/rdma/rdma_backend.h @@ -111,7 +111,6 @@ void rdma_backend_post_send(RdmaBackendDev *backend_dev, union ibv_gid *dgid, uint32_t dqpn, uint32_t dqkey, void *ctx); void rdma_backend_post_recv(RdmaBackendDev *backend_dev, -RdmaDeviceResources *rdma_dev_res, RdmaBackendQP *qp, uint8_t qp_type, struct ibv_sge *sge, uint32_t num_sge, void *ctx); diff --git a/hw/rdma/vmw/pvrdma_qp_ops.c b/hw/rdma/vmw/pvrdma_qp_ops.c index 16db726dac..508d8fca3c 100644 --- a/hw/rdma/vmw/pvrdma_qp_ops.c +++ b/hw/rdma/vmw/pvrdma_qp_ops.c @@ -231,8 +231,7 @@ void pvrdma_qp_recv(PVRDMADev *dev, uint32_t qp_handle) continue; } -rdma_backend_post_recv(&dev->backend_dev, &dev->rdma_dev_res, - &qp->backend_qp, qp->qp_type, +rdma_backend_post_recv(&dev->backend_dev, &qp->backend_qp, qp->qp_type, (struct ibv_sge *)&wqe->sge[0], wqe->hdr.num_sge, comp_ctx); -- 2.17.2
[Qemu-devel] [PATCH v1 3/9] hw/rdma: Protect against concurrent execution of poll_cq
The function rdma_poll_cq is called from two contexts - completion handler thread which sense new completion on backend channel and explicitly as result of guest issuing poll_cq command. Add lock to protect against concurrent executions. Signed-off-by: Yuval Shaia Reviewed-by: Marcel Apfelbaum --- hw/rdma/rdma_backend.c | 2 ++ hw/rdma/rdma_rm.c | 4 hw/rdma/rdma_rm_defs.h | 1 + 3 files changed, 7 insertions(+) diff --git a/hw/rdma/rdma_backend.c b/hw/rdma/rdma_backend.c index 2f6372f8f0..dc2a078b23 100644 --- a/hw/rdma/rdma_backend.c +++ b/hw/rdma/rdma_backend.c @@ -70,6 +70,7 @@ static void rdma_poll_cq(RdmaDeviceResources *rdma_dev_res, struct ibv_cq *ibcq) BackendCtx *bctx; struct ibv_wc wc[2]; +qemu_mutex_lock(&rdma_dev_res->lock); do { ne = ibv_poll_cq(ibcq, ARRAY_SIZE(wc), wc); @@ -89,6 +90,7 @@ static void rdma_poll_cq(RdmaDeviceResources *rdma_dev_res, struct ibv_cq *ibcq) g_free(bctx); } } while (ne > 0); +qemu_mutex_unlock(&rdma_dev_res->lock); if (ne < 0) { rdma_error_report("ibv_poll_cq fail, rc=%d, errno=%d", ne, errno); diff --git a/hw/rdma/rdma_rm.c b/hw/rdma/rdma_rm.c index 64c6ea1a4e..7cc597cdc8 100644 --- a/hw/rdma/rdma_rm.c +++ b/hw/rdma/rdma_rm.c @@ -618,12 +618,16 @@ int rdma_rm_init(RdmaDeviceResources *dev_res, struct ibv_device_attr *dev_attr, init_ports(dev_res); +qemu_mutex_init(&dev_res->lock); + return 0; } void rdma_rm_fini(RdmaDeviceResources *dev_res, RdmaBackendDev *backend_dev, const char *ifname) { +qemu_mutex_destroy(&dev_res->lock); + fini_ports(dev_res, backend_dev, ifname); res_tbl_free(&dev_res->uc_tbl); diff --git a/hw/rdma/rdma_rm_defs.h b/hw/rdma/rdma_rm_defs.h index 0ba61d1838..f0ee1f3072 100644 --- a/hw/rdma/rdma_rm_defs.h +++ b/hw/rdma/rdma_rm_defs.h @@ -105,6 +105,7 @@ typedef struct RdmaDeviceResources { RdmaRmResTbl cq_tbl; RdmaRmResTbl cqe_ctx_tbl; GHashTable *qp_hash; /* Keeps mapping between real and emulated */ +QemuMutex lock; } RdmaDeviceResources; #endif -- 2.17.2
[Qemu-devel] [PATCH v1 1/9] hw/rdma: Switch to generic error reporting way
Utilize error_report for all pr_err calls and some pr_dbg that are considered as errors. For the remaining pr_dbg calls, the important ones were replaced by trace points while other deleted. Signed-off-by: Yuval Shaia --- hw/rdma/rdma_backend.c| 336 ++ hw/rdma/rdma_rm.c | 121 +--- hw/rdma/rdma_utils.c | 11 +- hw/rdma/rdma_utils.h | 45 + hw/rdma/trace-events | 32 +++- hw/rdma/vmw/pvrdma.h | 2 +- hw/rdma/vmw/pvrdma_cmd.c | 113 +++- hw/rdma/vmw/pvrdma_dev_ring.c | 26 +-- hw/rdma/vmw/pvrdma_main.c | 132 + hw/rdma/vmw/pvrdma_qp_ops.c | 49 ++--- hw/rdma/vmw/trace-events | 16 +- 11 files changed, 337 insertions(+), 546 deletions(-) diff --git a/hw/rdma/rdma_backend.c b/hw/rdma/rdma_backend.c index fd571f21e5..5f60856d19 100644 --- a/hw/rdma/rdma_backend.c +++ b/hw/rdma/rdma_backend.c @@ -14,7 +14,6 @@ */ #include "qemu/osdep.h" -#include "qemu/error-report.h" #include "sysemu/sysemu.h" #include "qapi/error.h" #include "qapi/qmp/qlist.h" @@ -39,7 +38,6 @@ typedef struct BackendCtx { void *up_ctx; -bool is_tx_req; struct ibv_sge sge; /* Used to save MAD recv buffer */ } BackendCtx; @@ -52,7 +50,7 @@ static void (*comp_handler)(void *ctx, struct ibv_wc *wc); static void dummy_comp_handler(void *ctx, struct ibv_wc *wc) { -pr_err("No completion handler is registered\n"); +rdma_error_report("No completion handler is registered"); } static inline void complete_work(enum ibv_wc_status status, uint32_t vendor_err, @@ -66,29 +64,24 @@ static inline void complete_work(enum ibv_wc_status status, uint32_t vendor_err, comp_handler(ctx, &wc); } -static void poll_cq(RdmaDeviceResources *rdma_dev_res, struct ibv_cq *ibcq) +static void rdma_poll_cq(RdmaDeviceResources *rdma_dev_res, struct ibv_cq *ibcq) { int i, ne; BackendCtx *bctx; struct ibv_wc wc[2]; -pr_dbg("Entering poll_cq loop on cq %p\n", ibcq); do { ne = ibv_poll_cq(ibcq, ARRAY_SIZE(wc), wc); -pr_dbg("Got %d completion(s) from cq %p\n", ne, ibcq); +trace_rdma_poll_cq(ne, ibcq); for (i = 0; i < ne; i++) { -pr_dbg("wr_id=0x%" PRIx64 "\n", wc[i].wr_id); -pr_dbg("status=%d\n", wc[i].status); - bctx = rdma_rm_get_cqe_ctx(rdma_dev_res, wc[i].wr_id); if (unlikely(!bctx)) { -pr_dbg("Error: Failed to find ctx for req %" PRId64 "\n", - wc[i].wr_id); +rdma_error_report("No matching ctx for req %"PRId64, + wc[i].wr_id); continue; } -pr_dbg("Processing %s CQE\n", bctx->is_tx_req ? "send" : "recv"); comp_handler(bctx->up_ctx, &wc[i]); @@ -98,7 +91,7 @@ static void poll_cq(RdmaDeviceResources *rdma_dev_res, struct ibv_cq *ibcq) } while (ne > 0); if (ne < 0) { -pr_dbg("Got error %d from ibv_poll_cq\n", ne); +rdma_error_report("ibv_poll_cq fail, rc=%d, errno=%d", ne, errno); } } @@ -115,12 +108,10 @@ static void *comp_handler_thread(void *arg) flags = fcntl(backend_dev->channel->fd, F_GETFL); rc = fcntl(backend_dev->channel->fd, F_SETFL, flags | O_NONBLOCK); if (rc < 0) { -pr_dbg("Fail to change to non-blocking mode\n"); +rdma_error_report("Failed to change backend channel FD to non-blocking"); return NULL; } -pr_dbg("Starting\n"); - pfds[0].fd = backend_dev->channel->fd; pfds[0].events = G_IO_IN | G_IO_HUP | G_IO_ERR; @@ -132,27 +123,25 @@ static void *comp_handler_thread(void *arg) } while (!rc && backend_dev->comp_thread.run); if (backend_dev->comp_thread.run) { -pr_dbg("Waiting for completion on channel %p\n", backend_dev->channel); rc = ibv_get_cq_event(backend_dev->channel, &ev_cq, &ev_ctx); -pr_dbg("ibv_get_cq_event=%d\n", rc); if (unlikely(rc)) { -pr_dbg("---> ibv_get_cq_event (%d)\n", rc); +rdma_error_report("ibv_get_cq_event fail, rc=%d, errno=%d", rc, + errno); continue; } rc = ibv_req_notify_cq(ev_cq, 0); if (unlikely(rc)) { -pr_dbg("Error %d from ibv_req_notify_cq\n", rc); +rdma_error_report("ibv_req_notify_cq fail, rc=%d, errno=%d", rc, + errno); } -poll_cq(backend_dev->rdma_dev_res, ev_cq); +rdma_poll_cq(backend_dev->rdma_dev_res, ev_cq); ibv_ack_cq_events(ev_cq, 1); } } -pr_dbg("Going down\n"); - /* TODO: Post cqe for all remaining buffs that were posted */ backend_dev->comp_thread.is_running = false; @@ -177,55 +166,54 @@ static inline int rdmacm_mux_can_process_asy
[Qemu-devel] [PATCH v1 9/9] hw/pvrdma: Unregister from shutdown notifier when device goes down
This hook was installed to close the device when VM is going down. After the device is closed there is no need to be informed on VM shutdown. Signed-off-by: Yuval Shaia --- hw/rdma/vmw/pvrdma_main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/rdma/vmw/pvrdma_main.c b/hw/rdma/vmw/pvrdma_main.c index 8b379c6435..1177c0822f 100644 --- a/hw/rdma/vmw/pvrdma_main.c +++ b/hw/rdma/vmw/pvrdma_main.c @@ -359,6 +359,8 @@ static void pvrdma_fini(PCIDevice *pdev) { PVRDMADev *dev = PVRDMA_DEV(pdev); +notifier_remove(&dev->shutdown_notifier); + pvrdma_qp_ops_fini(); rdma_backend_stop(&dev->backend_dev); -- 2.17.2
Re: [Qemu-devel] [qemu-s390x] [PATCH v2 2/2] This is a non-privileged instruction that was only implemented for system mode. However, the stck instruction is used by glibc, so this was causing SIGILL
On 09.02.19 07:31, Richard Henderson wrote: > Signed-off-by: Richard Henderson > --- > target/s390x/helper.h | 2 +- > target/s390x/misc_helper.c | 34 ++ > target/s390x/translate.c | 2 ++ > target/s390x/insn-data.def | 11 ++- > 4 files changed, 31 insertions(+), 18 deletions(-) > > diff --git a/target/s390x/helper.h b/target/s390x/helper.h > index 018e9dd414..6260b50496 100644 > --- a/target/s390x/helper.h > +++ b/target/s390x/helper.h > @@ -121,13 +121,13 @@ DEF_HELPER_4(cu41, i32, env, i32, i32, i32) > DEF_HELPER_4(cu42, i32, env, i32, i32, i32) > DEF_HELPER_5(msa, i32, env, i32, i32, i32, i32) > DEF_HELPER_FLAGS_1(stpt, TCG_CALL_NO_RWG, i64, env) > +DEF_HELPER_FLAGS_1(stck, TCG_CALL_NO_RWG_SE, i64, env) > > #ifndef CONFIG_USER_ONLY > DEF_HELPER_3(servc, i32, env, i64, i64) > DEF_HELPER_4(diag, void, env, i32, i32, i32) > DEF_HELPER_3(load_psw, noreturn, env, i64, i64) > DEF_HELPER_FLAGS_2(spx, TCG_CALL_NO_RWG, void, env, i64) > -DEF_HELPER_FLAGS_1(stck, TCG_CALL_NO_RWG_SE, i64, env) > DEF_HELPER_FLAGS_2(sck, TCG_CALL_NO_RWG, i32, env, i64) > DEF_HELPER_FLAGS_2(sckc, TCG_CALL_NO_RWG, void, env, i64) > DEF_HELPER_FLAGS_2(sckpf, TCG_CALL_NO_RWG, void, env, i64) > diff --git a/target/s390x/misc_helper.c b/target/s390x/misc_helper.c > index 52262f62df..ee67c1fa0c 100644 > --- a/target/s390x/misc_helper.c > +++ b/target/s390x/misc_helper.c > @@ -30,6 +30,7 @@ > #include "exec/cpu_ldst.h" > #include "qapi/error.h" > #include "tcg_s390x.h" > +#include "s390-tod.h" > > #if !defined(CONFIG_USER_ONLY) > #include "sysemu/cpus.h" > @@ -76,8 +77,28 @@ uint64_t HELPER(stpt)(CPUS390XState *env) > #endif > } > > -#ifndef CONFIG_USER_ONLY > +/* Store Clock */ > +uint64_t HELPER(stck)(CPUS390XState *env) > +{ > +#ifdef CONFIG_USER_ONLY > +struct timespec ts; > +uint64_t ns; > > +clock_gettime(CLOCK_REALTIME, &ts); > +ns = ts.tv_sec * NANOSECONDS_PER_SECOND + ts.tv_nsec; > + > +return TOD_UNIX_EPOCH + time2tod(ns); > +#else > +S390TODState *td = s390_get_todstate(); > +S390TODClass *tdc = S390_TOD_GET_CLASS(td); > +S390TOD tod; > + > +tdc->get(td, &tod, &error_abort); > +return tod.low; > +#endif > +} > + > +#ifndef CONFIG_USER_ONLY > /* SCLP service call */ > uint32_t HELPER(servc)(CPUS390XState *env, uint64_t r1, uint64_t r2) > { > @@ -138,17 +159,6 @@ void HELPER(spx)(CPUS390XState *env, uint64_t a1) > tlb_flush_page(cs, TARGET_PAGE_SIZE); > } > > -/* Store Clock */ > -uint64_t HELPER(stck)(CPUS390XState *env) > -{ > -S390TODState *td = s390_get_todstate(); > -S390TODClass *tdc = S390_TOD_GET_CLASS(td); > -S390TOD tod; > - > -tdc->get(td, &tod, &error_abort); > -return tod.low; > -} > - > static void update_ckc_timer(CPUS390XState *env) > { > S390TODState *td = s390_get_todstate(); > diff --git a/target/s390x/translate.c b/target/s390x/translate.c > index 639084af07..19072efec6 100644 > --- a/target/s390x/translate.c > +++ b/target/s390x/translate.c > @@ -4060,6 +4060,7 @@ static DisasJumpType op_stap(DisasContext *s, DisasOps > *o) > tcg_gen_ld32u_i64(o->out, cpu_env, offsetof(CPUS390XState, core_id)); > return DISAS_NEXT; > } > +#endif > > static DisasJumpType op_stck(DisasContext *s, DisasOps *o) > { > @@ -4096,6 +4097,7 @@ static DisasJumpType op_stcke(DisasContext *s, DisasOps > *o) > return DISAS_NEXT; > } > > +#ifndef CONFIG_USER_ONLY > static DisasJumpType op_sck(DisasContext *s, DisasOps *o) > { > tcg_gen_qemu_ld_i64(o->in1, o->addr1, get_mem_index(s), MO_TEQ | > MO_ALIGN); > diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def > index dab805fd90..61582372ab 100644 > --- a/target/s390x/insn-data.def > +++ b/target/s390x/insn-data.def > @@ -837,6 +837,12 @@ > C(0xe33e, STRV,RXY_a, Z, la2, r1_32u, new, m1_32, rev32, 0) > C(0xe32f, STRVG, RXY_a, Z, la2, r1_o, new, m1_64, rev64, 0) > > +/* STORE CLOCK */ > +C(0xb205, STCK,S, Z, la2, 0, new, m1_64, stck, 0) > +C(0xb27c, STCKF, S, SCF, la2, 0, new, m1_64, stck, 0) > +/* STORE CLOCK EXTENDED */ > +C(0xb278, STCKE, S, Z, 0, a2, 0, 0, stcke, 0) > + > /* STORE FACILITY LIST EXTENDED */ > C(0xb2b0, STFLE, S, SFLE, 0, a2, 0, 0, stfle, 0) > /* STORE FPC */ > @@ -1020,11 +1026,6 @@ > F(0x8000, SSM, S, Z, 0, m2_8u, 0, 0, ssm, 0, IF_PRIV) > /* SIGNAL PROCESSOR */ > F(0xae00, SIGP,RS_a, Z, 0, a2, 0, 0, sigp, 0, IF_PRIV) > -/* STORE CLOCK */ > -C(0xb205, STCK,S, Z, la2, 0, new, m1_64, stck, 0) > -C(0xb27c, STCKF, S, SCF, la2, 0, new, m1_64, stck, 0) > -/* STORE CLOCK EXTENDED */ > -C(0xb278, STCKE, S, Z, 0, a2, 0, 0, stcke, 0) > /* STORE CLOCK COMPARATOR */ > F(0xb207, STCKC, S, Z, la2, 0, new, m1_64a, stckc, 0, IF_PRIV) > /* STORE CONTROL */ > Apart from what Thomas already said Reviewed-by: David Hildenbrand -- Thanks,
[Qemu-devel] [PATCH v1 8/9] hw/pvrdma: Delete pvrdma_exit function
This hook is not called and was implemented by mistake. Signed-off-by: Yuval Shaia --- hw/rdma/vmw/pvrdma_main.c | 6 -- 1 file changed, 6 deletions(-) diff --git a/hw/rdma/vmw/pvrdma_main.c b/hw/rdma/vmw/pvrdma_main.c index 90dc9b191b..8b379c6435 100644 --- a/hw/rdma/vmw/pvrdma_main.c +++ b/hw/rdma/vmw/pvrdma_main.c @@ -701,18 +701,12 @@ out: } } -static void pvrdma_exit(PCIDevice *pdev) -{ -pvrdma_fini(pdev); -} - static void pvrdma_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); k->realize = pvrdma_realize; -k->exit = pvrdma_exit; k->vendor_id = PCI_VENDOR_ID_VMWARE; k->device_id = PCI_DEVICE_ID_VMWARE_PVRDMA; k->revision = 0x00; -- 2.17.2
[Qemu-devel] [Bug 1813398] Re: qemu user calls malloc after fork in multi-threaded process
note that the bug affects qemu-user on a glibc system too in case malloc is interposed: glibc can only take the internal locks of its own malloc implementation, any other malloc has the same issue as musl's after fork. -- You received this bug notification because you are a member of qemu- devel-ml, which is subscribed to QEMU. https://bugs.launchpad.net/bugs/1813398 Title: qemu user calls malloc after fork in multi-threaded process Status in QEMU: New Bug description: qemu user may hang in malloc on a musl based system because it calls malloc after fork (in a pthread_atfork handler) in the child process. this is undefined behaviour since the parent process is multi-threaded and only as-safe functions may be called in the child then. (if malloc/free is called concurrently with fork the malloc state will be corrupted in the child, it works on glibc because glibc takes the malloc locks before the fork syscall, but that breaks the as-safety of fork and thus non-conforming to posix) discussed at https://www.openwall.com/lists/musl/2019/01/26/1 the bug is hard to reproduce (requires the call_rcu thread to call free concurrently with do_fork in the main thread), this one is observed with qemu-arm 3.1.0 running on x86_64 executing an arm busybox sh: (gdb) bt #0 malloc (n=, n@entry=9) at src/malloc/malloc.c:306 #1 0x60184ad3 in g_malloc (n_bytes=n_bytes@entry=9) at gmem.c:99 #2 0x6018bcab in g_strdup (str=, str@entry=0x60200abf "call_rcu") at gstrfuncs.c:363 #3 0x6016e31d in qemu_thread_create (thread=thread@entry=0x7ffe367d1870, name=name@entry=0x60200abf "call_rcu", start_routine=start_routine@entry=0x60174c00 , arg=arg@entry=0x0, mode=mode@entry=1) at /home/pmos/build/src/qemu-3.1.0/util/qemu-thread-posix.c:526 #4 0x60174b99 in rcu_init_complete () at /home/pmos/build/src/qemu-3.1.0/util/rcu.c:327 #5 0x601c4fac in __fork_handler (who=1) at src/thread/pthread_atfork.c:26 #6 0x601be8db in fork () at src/process/fork.c:33 #7 0x6009d191 in do_fork (env=0x627aaed0, flags=flags@entry=17, newsp=newsp@entry=0, parent_tidptr=parent_tidptr@entry=0, newtls=newtls@entry=0, child_tidptr=child_tidptr@entry=0) at /home/pmos/build/src/qemu-3.1.0/linux-user/syscall.c:5528 #8 0x600af894 in do_syscall1 (cpu_env=cpu_env@entry=0x627aaed0, num=num@entry=2, arg1=arg1@entry=0, arg2=arg2@entry=-8700192, arg3=, arg4=8, arg5=1015744, arg6=-74144, arg7=0, arg8=0) at /home/pmos/build/src/qemu-3.1.0/linux-user/syscall.c:7042 #9 0x600a835c in do_syscall (cpu_env=cpu_env@entry=0x627aaed0, num=2, arg1=0, arg2=-8700192, arg3=, arg4=, arg5=1015744, arg6=-74144, arg7=0, arg8=0) at /home/pmos/build/src/qemu-3.1.0/linux-user/syscall.c:11533 #10 0x600c265f in cpu_loop (env=env@entry=0x627aaed0) at /home/pmos/build/src/qemu-3.1.0/linux-user/arm/cpu_loop.c:360 #11 0x600417a2 in main (argc=, argv=0x7ffe367d57b8, envp=) at /home/pmos/build/src/qemu-3.1.0/linux-user/main.c:819 To manage notifications about this bug go to: https://bugs.launchpad.net/qemu/+bug/1813398/+subscriptions
Re: [Qemu-devel] [PATCH v13 00/31] Fix some filename generation issues
On 01.02.19 20:29, Max Reitz wrote: > Once more, I’ll spare both me and you another iteration of the cover > letter, so I direct you to the previous version’s cover letter (which > will direct you further): > > http://lists.nongnu.org/archive/html/qemu-block/2018-10/msg00229.html > > There are mostly rebase fixes in this version. Provided no major > complaints arise, I intend to merge this series in the next week or so. Thanks for the reviews in all of the versions until now, applied to my block branch: https://git.xanclic.moe/XanClic/qemu/commits/branch/block Max signature.asc Description: OpenPGP digital signature
[Qemu-devel] [PATCH v3 00/10] iotests: Fix some issues
No fundamental changes from v2, so if you’re new to this series, the cover letter is here: http://lists.nongnu.org/archive/html/qemu-block/2019-01/msg01123.html Otherwise, these are the changes: v3: - Patch 10: Rebased onto 039be85c410bfb4b53cdee2083b4245e0d4e4181 git-backport-diff against v2: Key: [] : patches are identical [] : number of functional differences between upstream/downstream patch [down] : patch is downstream-only The flags [FC] indicate (F)unctional and (C)ontextual differences, respectively 001/10:[] [--] 'iotests: Re-add filename filters' 002/10:[] [--] 'iotests: Fix 237 for Python 2.x' 003/10:[] [--] 'iotests: Remove superfluous rm from 232' 004/10:[] [--] 'iotests: Fix 232 for LUKS' 005/10:[] [--] 'iotests: Fix 207 to use QMP filters for qmp_log' 006/10:[] [--] 'iotests.py: Add is_str()' 007/10:[] [--] 'iotests.py: Filter filename in any string value' 008/10:[] [--] 'iotests: Filter SSH paths' 009/10:[] [--] 'iotests: Let 045 be run concurrently' 010/10:[0012] [FC] 'iotests.py: s/_/-/g on keys in qmp_log()' Max Reitz (10): iotests: Re-add filename filters iotests: Fix 237 for Python 2.x iotests: Remove superfluous rm from 232 iotests: Fix 232 for LUKS iotests: Fix 207 to use QMP filters for qmp_log iotests.py: Add is_str() iotests.py: Filter filename in any string value iotests: Filter SSH paths iotests: Let 045 be run concurrently iotests.py: s/_/-/g on keys in qmp_log() scripts/qemu.py | 5 ++-- tests/qemu-iotests/045| 2 +- tests/qemu-iotests/206.out| 56 +-- tests/qemu-iotests/207| 10 +-- tests/qemu-iotests/207.out| 18 +-- tests/qemu-iotests/210| 5 ++-- tests/qemu-iotests/210.out| 28 +- tests/qemu-iotests/211| 5 ++-- tests/qemu-iotests/211.out| 26 tests/qemu-iotests/212| 5 ++-- tests/qemu-iotests/212.out| 44 +-- tests/qemu-iotests/213| 5 ++-- tests/qemu-iotests/213.out| 46 ++-- tests/qemu-iotests/232| 5 +++- tests/qemu-iotests/237| 7 +++-- tests/qemu-iotests/237.out| 54 - tests/qemu-iotests/common.rc | 1 + tests/qemu-iotests/iotests.py | 14 +++-- 18 files changed, 178 insertions(+), 158 deletions(-) -- 2.20.1
[Qemu-devel] [PATCH v3 05/10] iotests: Fix 207 to use QMP filters for qmp_log
Fixes: 08fcd6111e1949f456e1b232ebeeb0cc17019a92 Signed-off-by: Max Reitz Reviewed-by: John Snow --- tests/qemu-iotests/207 | 10 +++--- tests/qemu-iotests/207.out | 4 ++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/tests/qemu-iotests/207 b/tests/qemu-iotests/207 index c617ee7453..dfd3c51bd1 100755 --- a/tests/qemu-iotests/207 +++ b/tests/qemu-iotests/207 @@ -27,12 +27,16 @@ import re iotests.verify_image_format(supported_fmts=['raw']) iotests.verify_protocol(supported=['ssh']) -def filter_hash(msg): -return re.sub('"hash": "[0-9a-f]+"', '"hash": HASH', msg) +def filter_hash(qmsg): +def _filter(key, value): +if key == 'hash' and re.match('[0-9a-f]+', value): +return 'HASH' +return value +return iotests.filter_qmp(qmsg, _filter) def blockdev_create(vm, options): result = vm.qmp_log('blockdev-create', job_id='job0', options=options, -filters=[iotests.filter_testfiles, filter_hash]) +filters=[iotests.filter_qmp_testfiles, filter_hash]) if 'return' in result: assert result['return'] == {} diff --git a/tests/qemu-iotests/207.out b/tests/qemu-iotests/207.out index 45ac7c2a8f..88d2240f54 100644 --- a/tests/qemu-iotests/207.out +++ b/tests/qemu-iotests/207.out @@ -40,7 +40,7 @@ Job failed: remote host key does not match host_key_check 'wrong' {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": HASH, "mode": "hash", "type": "md5"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 8388608}}} +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": "HASH", "mode": "hash", "type": "md5"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 8388608}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -55,7 +55,7 @@ Job failed: remote host key does not match host_key_check 'wrong' {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": HASH, "mode": "hash", "type": "sha1"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}} +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": "HASH", "mode": "hash", "type": "sha1"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -- 2.20.1
[Qemu-devel] [PATCH v3 01/10] iotests: Re-add filename filters
A previous commit removed the default filters for qmp_log with the intention to make them explicit; but this happened only for test 206. There are more tests (for more exotic image formats than qcow2) which require the filename filter, though. Note that 237 is still broken for Python 2.x, which is fixed in the next commit. Fixes: f8ca8609d8549def45b28e82ecac64adaeee9f12 Signed-off-by: Max Reitz Reviewed-by: John Snow --- tests/qemu-iotests/210 | 5 +++-- tests/qemu-iotests/211 | 5 +++-- tests/qemu-iotests/212 | 5 +++-- tests/qemu-iotests/213 | 5 +++-- tests/qemu-iotests/237 | 5 +++-- 5 files changed, 15 insertions(+), 10 deletions(-) diff --git a/tests/qemu-iotests/210 b/tests/qemu-iotests/210 index d142841e2b..565e3b7b9b 100755 --- a/tests/qemu-iotests/210 +++ b/tests/qemu-iotests/210 @@ -27,7 +27,8 @@ iotests.verify_image_format(supported_fmts=['luks']) iotests.verify_protocol(supported=['file']) def blockdev_create(vm, options): -result = vm.qmp_log('blockdev-create', job_id='job0', options=options) +result = vm.qmp_log('blockdev-create', job_id='job0', options=options, +filters=[iotests.filter_qmp_testfiles]) if 'return' in result: assert result['return'] == {} @@ -53,7 +54,7 @@ with iotests.FilePath('t.luks') as disk_path, \ 'size': 0 }) vm.qmp_log('blockdev-add', driver='file', filename=disk_path, - node_name='imgfile') + node_name='imgfile', filters=[iotests.filter_qmp_testfiles]) blockdev_create(vm, { 'driver': imgfmt, 'file': 'imgfile', diff --git a/tests/qemu-iotests/211 b/tests/qemu-iotests/211 index 7b7985db6c..5d285450b5 100755 --- a/tests/qemu-iotests/211 +++ b/tests/qemu-iotests/211 @@ -27,7 +27,8 @@ iotests.verify_image_format(supported_fmts=['vdi']) iotests.verify_protocol(supported=['file']) def blockdev_create(vm, options): -result = vm.qmp_log('blockdev-create', job_id='job0', options=options) +result = vm.qmp_log('blockdev-create', job_id='job0', options=options, +filters=[iotests.filter_qmp_testfiles]) if 'return' in result: assert result['return'] == {} @@ -51,7 +52,7 @@ with iotests.FilePath('t.vdi') as disk_path, \ 'size': 0 }) vm.qmp_log('blockdev-add', driver='file', filename=disk_path, - node_name='imgfile') + node_name='imgfile', filters=[iotests.filter_qmp_testfiles]) blockdev_create(vm, { 'driver': imgfmt, 'file': 'imgfile', diff --git a/tests/qemu-iotests/212 b/tests/qemu-iotests/212 index 95c8810d83..42b74f208b 100755 --- a/tests/qemu-iotests/212 +++ b/tests/qemu-iotests/212 @@ -27,7 +27,8 @@ iotests.verify_image_format(supported_fmts=['parallels']) iotests.verify_protocol(supported=['file']) def blockdev_create(vm, options): -result = vm.qmp_log('blockdev-create', job_id='job0', options=options) +result = vm.qmp_log('blockdev-create', job_id='job0', options=options, +filters=[iotests.filter_qmp_testfiles]) if 'return' in result: assert result['return'] == {} @@ -51,7 +52,7 @@ with iotests.FilePath('t.parallels') as disk_path, \ 'size': 0 }) vm.qmp_log('blockdev-add', driver='file', filename=disk_path, - node_name='imgfile') + node_name='imgfile', filters=[iotests.filter_qmp_testfiles]) blockdev_create(vm, { 'driver': imgfmt, 'file': 'imgfile', diff --git a/tests/qemu-iotests/213 b/tests/qemu-iotests/213 index 4054439e3c..5604f3cebb 100755 --- a/tests/qemu-iotests/213 +++ b/tests/qemu-iotests/213 @@ -27,7 +27,8 @@ iotests.verify_image_format(supported_fmts=['vhdx']) iotests.verify_protocol(supported=['file']) def blockdev_create(vm, options): -result = vm.qmp_log('blockdev-create', job_id='job0', options=options) +result = vm.qmp_log('blockdev-create', job_id='job0', options=options, +filters=[iotests.filter_qmp_testfiles]) if 'return' in result: assert result['return'] == {} @@ -51,7 +52,7 @@ with iotests.FilePath('t.vhdx') as disk_path, \ 'size': 0 }) vm.qmp_log('blockdev-add', driver='file', filename=disk_path, - node_name='imgfile') + node_name='imgfile', filters=[iotests.filter_qmp_testfiles]) blockdev_create(vm, { 'driver': imgfmt, 'file': 'imgfile', diff --git a/tests/qemu-iotests/237 b/tests/qemu-iotests/237 index 251771d7fb..fe0dd0f461 100755 --- a/tests/qemu-iotests/237 +++ b/tests/qemu-iotests/237 @@ -27,7 +27,8 @@ from iotests import imgfmt iotests.verify_image_format(supported_fmts=['vmdk']) def blockdev_create(vm, options): -result = vm.qmp_log('blockdev-create', job_id='job0', options=options) +result = vm.qmp_log('blockdev-create', job_id='job0', options=o
[Qemu-devel] [PATCH v3 02/10] iotests: Fix 237 for Python 2.x
math.ceil() returns an integer on Python 3.x, but a float on Python 2.x. range() always needs integers, so we need an explicit conversion on 2.x (which does not hurt on 3.x). It is not quite clear whether we want to support Python 2.x for any prolonged time, but this may as well be fixed along with the other issues some iotests have right now. Signed-off-by: Max Reitz Reviewed-by: John Snow Reviewed-by: Philippe Mathieu-Daudé --- tests/qemu-iotests/237 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/qemu-iotests/237 b/tests/qemu-iotests/237 index fe0dd0f461..06897f8c87 100755 --- a/tests/qemu-iotests/237 +++ b/tests/qemu-iotests/237 @@ -224,7 +224,7 @@ with iotests.FilePath('t.vmdk') as disk_path, \ iotests.log("= %s %d =" % (subfmt, size)) iotests.log("") -num_extents = math.ceil(size / 2.0**31) +num_extents = int(math.ceil(size / 2.0**31)) extents = [ "ext%d" % (i) for i in range(1, num_extents + 1) ] vm.launch() -- 2.20.1
[Qemu-devel] [PATCH v3 04/10] iotests: Fix 232 for LUKS
With IMGOPTSSYNTAX, $TEST_IMG is useless for this test (it only tests the file-posix protocol driver). Therefore, if $TEST_IMG_FILE is set, use that instead. Because this test requires the file protocol, $TEST_IMG_FILE will always be set if $IMGOPTSSYNTAX is true. Signed-off-by: Max Reitz Reviewed-by: John Snow --- tests/qemu-iotests/232 | 4 1 file changed, 4 insertions(+) diff --git a/tests/qemu-iotests/232 b/tests/qemu-iotests/232 index 93e5d641a3..e48bc8f5db 100755 --- a/tests/qemu-iotests/232 +++ b/tests/qemu-iotests/232 @@ -69,6 +69,10 @@ size=128M _make_test_img $size +if [ -n "$TEST_IMG_FILE" ]; then +TEST_IMG=$TEST_IMG_FILE +fi + echo echo "=== -drive with read-write image: read-only/auto-read-only combinations ===" echo -- 2.20.1
[Qemu-devel] [PATCH v3 03/10] iotests: Remove superfluous rm from 232
This test creates no such file. Signed-off-by: Max Reitz Reviewed-by: Eric Blake Reviewed-by: John Snow --- tests/qemu-iotests/232 | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/qemu-iotests/232 b/tests/qemu-iotests/232 index 0708b8b155..93e5d641a3 100755 --- a/tests/qemu-iotests/232 +++ b/tests/qemu-iotests/232 @@ -29,7 +29,6 @@ status=1 # failure is the default! _cleanup() { _cleanup_test_img -rm -f $TEST_IMG.snap } trap "_cleanup; exit \$status" 0 1 2 3 15 -- 2.20.1
[Qemu-devel] [PATCH v3 09/10] iotests: Let 045 be run concurrently
Adding a telnet monitor for no real purpose on a fixed port is not so great. Just use a null monitor instead. Signed-off-by: Max Reitz Reviewed-by: John Snow --- scripts/qemu.py| 5 ++--- tests/qemu-iotests/045 | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/scripts/qemu.py b/scripts/qemu.py index 0a5e02eb56..e642a55816 100644 --- a/scripts/qemu.py +++ b/scripts/qemu.py @@ -136,10 +136,9 @@ class QEMUMachine(object): return False # This can be used to add an unused monitor instance. -def add_monitor_telnet(self, ip, port): -args = 'tcp:%s:%d,server,nowait,telnet' % (ip, port) +def add_monitor_null(self): self._args.append('-monitor') -self._args.append(args) +self._args.append('null') def add_fd(self, fd, fdset, opaque, opts=''): """ diff --git a/tests/qemu-iotests/045 b/tests/qemu-iotests/045 index 55a5d31ca8..d5484a0ee1 100755 --- a/tests/qemu-iotests/045 +++ b/tests/qemu-iotests/045 @@ -132,7 +132,7 @@ class TestSCMFd(iotests.QMPTestCase): qemu_img('create', '-f', iotests.imgfmt, image0, '128K') # Add an unused monitor, to verify it works fine when two monitor # instances present -self.vm.add_monitor_telnet("0",4445) +self.vm.add_monitor_null() self.vm.launch() def tearDown(self): -- 2.20.1
[Qemu-devel] [PATCH v3 06/10] iotests.py: Add is_str()
On Python 2.x, strings are not always unicode strings. This function checks whether a given value is a plain string, or a unicode string (if there is a difference). Signed-off-by: Max Reitz Reviewed-by: John Snow --- tests/qemu-iotests/iotests.py | 6 ++ 1 file changed, 6 insertions(+) diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 82dd096c6e..52fc77563c 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -236,6 +236,12 @@ def image_size(img): r = qemu_img_pipe('info', '--output=json', '-f', imgfmt, img) return json.loads(r)['virtual-size'] +def is_str(val): +if sys.version_info.major >= 3: +return isinstance(val, str) +else: +return isinstance(val, str) or isinstance(val, unicode) + test_dir_re = re.compile(r"%s" % test_dir) def filter_test_dir(msg): return test_dir_re.sub("TEST_DIR", msg) -- 2.20.1
[Qemu-devel] [PATCH v3 10/10] iotests.py: s/_/-/g on keys in qmp_log()
This follows what qmp() does, so the output will correspond to the actual QMP command. Signed-off-by: Max Reitz Reviewed-by: John Snow --- tests/qemu-iotests/206.out| 56 +-- tests/qemu-iotests/207.out| 18 +-- tests/qemu-iotests/210.out| 28 +- tests/qemu-iotests/211.out| 26 tests/qemu-iotests/212.out| 44 +-- tests/qemu-iotests/213.out| 46 ++-- tests/qemu-iotests/237.out| 54 - tests/qemu-iotests/iotests.py | 6 ++-- 8 files changed, 140 insertions(+), 138 deletions(-) diff --git a/tests/qemu-iotests/206.out b/tests/qemu-iotests/206.out index 91f4db55d3..0f1c23babb 100644 --- a/tests/qemu-iotests/206.out +++ b/tests/qemu-iotests/206.out @@ -1,13 +1,13 @@ === Successful image creation (defaults) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "node_name": "imgfile"}} +{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "node-name": "imgfile"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "imgfile", "size": 134217728}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "imgfile", "size": 134217728}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -24,12 +24,12 @@ Format specific information: === Successful image creation (inline blockdev-add, explicit defaults) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "nocow": false, "preallocation": "off", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "nocow": false, "preallocation": "off", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 65536, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2"}, "lazy-refcounts": false, "preallocation": "off", "refcount-bits": 16, "size": 67108864, "version": "v3"}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 65536, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2"}, "lazy-refcounts": false, "preallocation": "off", "refcount-bits": 16, "size": 67108864, "version": "v3"}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -46,12 +46,12 @@ Format specific information: === Successful image creation (v3 non-default options) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "nocow": true, "preallocation": "falloc", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "nocow": true, "preallocation": "falloc", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 2097152, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2"}, "lazy-refcounts": true, "preallocation": "metadata", "refcount-bits": 1, "size": 33554432, "version": "v3"}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 2097152, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2"}, "lazy-refcounts": true, "preallocation": "metadata", "refcount-bits": 1, "size": 33554432, "version": "v3"}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -68,12 +68,12 @@ Format specific information: === Successful image creation (v2 non-default options) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"b
Re: [Qemu-devel] [PATCH v3 10/10] iotests.py: s/_/-/g on keys in qmp_log()
On 10.02.19 15:57, Max Reitz wrote: > This follows what qmp() does, so the output will correspond to the > actual QMP command. > > Signed-off-by: Max Reitz > Reviewed-by: John Snow Dang it, sorry, I forgot to drop this R-b tag while rebasing. It shouldn't be here. :-/ Max > --- > tests/qemu-iotests/206.out| 56 +-- > tests/qemu-iotests/207.out| 18 +-- > tests/qemu-iotests/210.out| 28 +- > tests/qemu-iotests/211.out| 26 > tests/qemu-iotests/212.out| 44 +-- > tests/qemu-iotests/213.out| 46 ++-- > tests/qemu-iotests/237.out| 54 - > tests/qemu-iotests/iotests.py | 6 ++-- > 8 files changed, 140 insertions(+), 138 deletions(-) signature.asc Description: OpenPGP digital signature
[Qemu-devel] [PATCH v3 07/10] iotests.py: Filter filename in any string value
filter_qmp_testfiles() currently filters the filename only for specific keys. However, there are more keys that take filenames (such as block-commit's @top and @base, or ssh's @path), and it does not make sense to list them all here. "$TEST_DIR/$PID-" should have enough entropy not to appear anywhere randomly. Signed-off-by: Max Reitz Reviewed-by: John Snow --- tests/qemu-iotests/iotests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 52fc77563c..cba91a9927 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -289,7 +289,7 @@ def filter_testfiles(msg): def filter_qmp_testfiles(qmsg): def _filter(key, value): -if key == 'filename' or key == 'backing-file': +if is_str(value): return filter_testfiles(value) return value return filter_qmp(qmsg, _filter) -- 2.20.1
[Qemu-devel] [PATCH v3 08/10] iotests: Filter SSH paths
8908b253c4ad5f8874c8d13abec169c696a5cd32 has implemented filtering of remote paths for NFS, but forgot SSH. This patch takes care of that. Signed-off-by: Max Reitz Reviewed-by: John Snow --- tests/qemu-iotests/common.rc | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc index e15e7a7c8e..09a27f02d0 100644 --- a/tests/qemu-iotests/common.rc +++ b/tests/qemu-iotests/common.rc @@ -145,6 +145,7 @@ else TEST_IMG="nbd:127.0.0.1:10810" elif [ "$IMGPROTO" = "ssh" ]; then TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT +REMOTE_TEST_DIR="ssh://127.0.0.1$TEST_DIR" TEST_IMG="ssh://127.0.0.1$TEST_IMG_FILE" elif [ "$IMGPROTO" = "nfs" ]; then TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT -- 2.20.1
Re: [Qemu-devel] [v2 PATCH] hw/arm/bcm2835_peripherals: add bcm283x sp804-alike timer
Patchew URL: https://patchew.org/QEMU/20190209144918.GA14036@nyan/ Hi, This series failed the docker-mingw@fedora build test. Please find the testing commands and their output below. If you have Docker installed, you can probably reproduce it locally. === TEST SCRIPT BEGIN === #!/bin/bash time make docker-test-mingw@fedora SHOW_ENV=1 J=14 === TEST SCRIPT END === from /tmp/qemu-test/src/include/hw/qdev.h:4, from /tmp/qemu-test/src/include/hw/sysbus.h:6, from /tmp/qemu-test/src/hw/timer/bcm283x_timer.c:2: /tmp/qemu-test/src/include/qom/object.h:518:12: error: expected ')' before '*' token ((type *)object_dynamic_cast_assert(OBJECT(obj), (name), \ ^ /tmp/qemu-test/src/include/hw/timer/bcm283x_timer.h:24:5: note: in expansion of macro 'OBJECT_CHECK' OBJECT_CHECK(BCM283xSP804State, (obj), TYPE_BCM283xSP804) ^~~~ /tmp/qemu-test/src/include/qom/object.h:518:14: error: expected ')' before 'object_dynamic_cast_assert' ((type *)object_dynamic_cast_assert(OBJECT(obj), (name), \ ^~ /tmp/qemu-test/src/include/hw/timer/bcm283x_timer.h:24:5: note: in expansion of macro 'OBJECT_CHECK' OBJECT_CHECK(BCM283xSP804State, (obj), TYPE_BCM283xSP804) ^~~~ In file included from /tmp/qemu-test/src/hw/timer/bcm283x_timer.c:7: /tmp/qemu-test/src/include/hw/timer/bcm283x_timer.h:32:5: error: unknown type name 'bcm283x_timer_state' bcm283x_timer_state *timer; ^~~ /tmp/qemu-test/src/hw/timer/bcm283x_timer.c:33:34: error: unknown type name 'bcm283x_timer_state'; did you mean 'ptimer_state'? static void bcm283x_timer_update(bcm283x_timer_state *s) ^~~ ptimer_state /tmp/qemu-test/src/hw/timer/bcm283x_timer.c: In function 'bcm283x_timer_read': /tmp/qemu-test/src/hw/timer/bcm283x_timer.c:44:5: error: unknown type name 'bcm283x_timer_state'; use 'struct' keyword to refer to the type bcm283x_timer_state *s = (bcm283x_timer_state *) opaque; ^~~ struct /tmp/qemu-test/src/hw/timer/bcm283x_timer.c:44:31: error: 'bcm283x_timer_state' undeclared (first use in this function) bcm283x_timer_state *s = (bcm283x_timer_state *) opaque; ^~~ /tmp/qemu-test/src/hw/timer/bcm283x_timer.c:44:31: note: each undeclared identifier is reported only once for each function it appears in /tmp/qemu-test/src/hw/timer/bcm283x_timer.c:44:52: error: expected expression before ')' token bcm283x_timer_state *s = (bcm283x_timer_state *) opaque; ^ /tmp/qemu-test/src/hw/timer/bcm283x_timer.c:49:17: error: request for member 'limit' in something not a structure or union return s->limit; ^~ /tmp/qemu-test/src/hw/timer/bcm283x_timer.c:51:34: error: request for member 'timer' in something not a structure or union return ptimer_get_count(s->timer); ^~ /tmp/qemu-test/src/hw/timer/bcm283x_timer.c:53:17: error: request for member 'control' in something not a structure or union return s->control; ^~ /tmp/qemu-test/src/hw/timer/bcm283x_timer.c:61:17: error: request for member 'int_level' in something not a structure or union return s->int_level; ^~ /tmp/qemu-test/src/hw/timer/bcm283x_timer.c:63:15: error: request for member 'control' in something not a structure or union if ((s->control & TIMER_CTRL_IE) == 0) { ^~ /tmp/qemu-test/src/hw/timer/bcm283x_timer.c:66:17: error: request for member 'int_level' in something not a structure or union return s->int_level; ^~ /tmp/qemu-test/src/hw/timer/bcm283x_timer.c: At top level: /tmp/qemu-test/src/hw/timer/bcm283x_timer.c:74:39: error: unknown type name 'bcm283x_timer_state'; did you mean 'ptimer_state'? static void bcm283x_timer_recalibrate(bcm283x_timer_state *s, int reload) ^~~ ptimer_state /tmp/qemu-test/src/hw/timer/bcm283x_timer.c: In function 'bcm283x_timer_write': /tmp/qemu-test/src/hw/timer/bcm283x_timer.c:86:5: error: unknown type name 'bcm283x_timer_state'; use 'struct' keyword to refer to the type bcm283x_timer_state *s = (bcm283x_timer_state *) opaque; ^~~ struct /tmp/qemu-test/src/hw/timer/bcm283x_timer.c:86:31: error: 'bcm283x_timer_state' undeclared (first use in this function) bcm283x_timer_state *s = (bcm283x_timer_state *) opaque; ^~~ /tmp/qemu-test/src/hw/timer/bcm283x_timer.c:86:52: error: expected expression before ')' token bcm283x_timer_state *s = (bcm283x_timer_state *) opaque; ^ /tmp/qemu-test/src/hw/time
[Qemu-devel] [v3 PATCH] hw/arm/bcm2835_peripherals: add bcm283x sp804-alike timer
Signed-off-by: Mark --- hw/arm/bcm2835_peripherals.c | 20 ++ hw/timer/Makefile.objs | 2 + hw/timer/bcm283x_timer.c | 299 +++ include/hw/arm/bcm2835_peripherals.h | 2 + include/hw/timer/bcm283x_timer.h | 38 5 files changed, 361 insertions(+) create mode 100644 hw/timer/bcm283x_timer.c create mode 100644 include/hw/timer/bcm283x_timer.h diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c index 6be7660e8c..60fa359887 100644 --- a/hw/arm/bcm2835_peripherals.c +++ b/hw/arm/bcm2835_peripherals.c @@ -117,6 +117,13 @@ static void bcm2835_peripherals_init(Object *obj) OBJECT(&s->sdhci.sdbus), &error_abort); object_property_add_const_link(OBJECT(&s->gpio), "sdbus-sdhost", OBJECT(&s->sdhost.sdbus), &error_abort); + +/* SP804-alike ARM Timer */ +object_initialize(&s->bcm283xsp804, sizeof(s->bcm283xsp804), +TYPE_BCM283xSP804); +object_property_add_child(obj, "bcm283xsp804", OBJECT(&s->bcm283xsp804), +NULL); +qdev_set_parent_bus(DEVICE(&s->bcm283xsp804), sysbus_get_default()); } static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) @@ -334,6 +341,19 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } + +/* SP804-alike ARM Timer */ +object_property_set_bool(OBJECT(&s->bcm283xsp804), true, "realized", &err); +if (err) { +error_propagate(errp, err); +return; +} + +memory_region_add_subregion(&s->peri_mr, ARMCTRL_TIMER0_1_OFFSET, +sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->bcm283xsp804), 0)); +sysbus_connect_irq(SYS_BUS_DEVICE(&s->bcm283xsp804), 0, +qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_ARM_IRQ, + INTERRUPT_ARM_TIMER)); } static void bcm2835_peripherals_class_init(ObjectClass *oc, void *data) diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs index 0e9a4530f8..09a3706701 100644 --- a/hw/timer/Makefile.objs +++ b/hw/timer/Makefile.objs @@ -47,3 +47,5 @@ common-obj-$(CONFIG_SUN4V_RTC) += sun4v-rtc.o common-obj-$(CONFIG_CMSDK_APB_TIMER) += cmsdk-apb-timer.o common-obj-$(CONFIG_CMSDK_APB_DUALTIMER) += cmsdk-apb-dualtimer.o common-obj-$(CONFIG_MSF2) += mss-timer.o + +common-obj-$(CONFIG_RASPI) += bcm283x_timer.o diff --git a/hw/timer/bcm283x_timer.c b/hw/timer/bcm283x_timer.c new file mode 100644 index 00..55e8a68807 --- /dev/null +++ b/hw/timer/bcm283x_timer.c @@ -0,0 +1,299 @@ +#include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "qemu/timer.h" +#include "qemu-common.h" +#include "hw/qdev.h" +#include "hw/ptimer.h" +#include "hw/timer/bcm283x_timer.h" +#include "qemu/main-loop.h" +#include "qemu/log.h" + +/* TODO: implement free-running timer as per BCM283x peripheral specification */ + +#define TIMER_CTRL_32BIT(1 << 1) +#define TIMER_CTRL_DIV1 (0 << 2) +#define TIMER_CTRL_DIV16(1 << 2) +#define TIMER_CTRL_DIV256 (2 << 2) +#define TIMER_CTRL_IE (1 << 5) +#define TIMER_CTRL_ENABLE (1 << 7) + +struct bcm283x_timer_state { +ptimer_state *timer; +uint32_t control; +uint32_t limit; +int freq; +int int_level; +qemu_irq irq; +/* Not implemented */ +int prev_div; +/* Not implemented */ +int free_run_cnt; +}; + +static void bcm283x_timer_update(bcm283x_timer_state *s) +{ +if (s->int_level && (s->control & TIMER_CTRL_IE)) { +qemu_irq_raise(s->irq); +} else { +qemu_irq_lower(s->irq); +} +} + +static uint32_t bcm283x_timer_read(void *opaque, hwaddr offset) +{ +bcm283x_timer_state *s = (bcm283x_timer_state *) opaque; + +switch (offset >> 2) { +case 0: /* Load register */ +case 6: /* Reload register */ +return s->limit; +case 1: /* Value register */ +return ptimer_get_count(s->timer); +case 2: /* Control register */ +return s->control; +case 3: /* IRQ clear/ACK register */ +/* + * The register is write-only, + * but returns reverse "ARMT" string bytes + */ +return 0x544D5241; +case 4: /* RAW IRQ register */ +return s->int_level; +case 5: /* Masked IRQ register */ +if ((s->control & TIMER_CTRL_IE) == 0) { +return 0; +} +return s->int_level; +default: +qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad offset %x\n", __func__, (int) offset); +return 0; +} +} + +static void bcm283x_timer_recalibrate(bcm283x_timer_state *s, int reload) +{ +uint32_t limit; + +/* Consider timer periodic */ +limit = s->limit; + +ptimer_set_limit(s->timer, limit, reload); +} + +static void bcm283x_timer_write(void *opaque, hwaddr offset, uint32_t value) +{ +bcm283x_timer_state *s = (bcm283x_timer_state *) opaque; +int freq;
[Qemu-devel] [PATCH] cuda: decrease time delay before raising VIA SR interrupt
In order to handle a race condition in MacOS 9, a delay was introduced when raising the VIA SR interrupt inspired by similar code in MacOnLinux. During original testing of the MacOS 9 patches it was found that the 30us delay used in MacOnLinux did not work reliably within QEMU, and a value of 300us was required to function correctly. Recent experiments have shown that the previous reliability issues are no longer present, and this value can be reduced down to 20us with no apparent ill effects in my local tests. This has the benefit of considerably improving the responsiveness of the ADB keyboard and mouse with the guest. Signed-off-by: Mark Cave-Ayland --- hw/misc/macio/cuda.c | 11 +-- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index c4f7a2f39b..3febacdd1e 100644 --- a/hw/misc/macio/cuda.c +++ b/hw/misc/macio/cuda.c @@ -97,17 +97,8 @@ static void cuda_set_sr_int(void *opaque) static void cuda_delay_set_sr_int(CUDAState *s) { -MOS6522CUDAState *mcs = &s->mos6522_cuda; -MOS6522State *ms = MOS6522(mcs); -MOS6522DeviceClass *mdc = MOS6522_DEVICE_GET_CLASS(ms); int64_t expire; -if (ms->dirb == 0xff || s->sr_delay_ns == 0) { -/* Disabled or not in Mac OS, fire the IRQ directly */ -mdc->set_sr_int(ms); -return; -} - trace_cuda_delay_set_sr_int(); expire = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->sr_delay_ns; @@ -542,7 +533,7 @@ static void cuda_realize(DeviceState *dev, Error **errp) s->tick_offset = (uint32_t)mktimegm(&tm) + RTC_OFFSET; s->sr_delay_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, cuda_set_sr_int, s); -s->sr_delay_ns = 300 * SCALE_US; +s->sr_delay_ns = 20 * SCALE_US; s->adb_poll_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, cuda_adb_poll, s); s->adb_poll_mask = 0x; -- 2.11.0
[Qemu-devel] [Bug 1815371] [NEW] SPICE session's connection_id's are not unique
Public bug reported: From: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=920897 = When creating a virtual machine with qemu (e.g. via libvirt) including a SPICE server, the client_id of the SPICE session is not unique. For example, starting multiple virtual machines on the same libvirtd, the client_id is the same for all virtual machine's SPICE sessions. A description of the client_id can be found in https://www.spice-space.org/static/docs/spice_protocol.pdf under section 2.11. c) : "UINT32 connection_id - In case of a new session (i.e., channel type is RED_CHANNEL_MAIN) this field is set to zero, and in response the server will allocate session id and will send it via the RedLinkReply message. In case of all other channel types, this field will be equal to the allocated session id" The relevant code for generating client ids in libspice-server1 can be found here: https://gitlab.freedesktop.org/spice/spice/blob/v0.12.8/server/reds.c#L1614 This uses rand() to generate the random id, but qemu (at least in the case of qemu-system-x86) fails to initialize the RNG seed (with e.g. srand()). The result is, that every SPICE session started (by e.g. libvirtd) has the same client_id. Usually, this is not a problem, but running something like a SPICE proxy, relying on the client_id to correctly route connections, this creates problems. Adding something like 'srand(time(NULL));' to qemu (in vl.c) solves this issue. Related (as seen in some VNC patches, e.g. 'CVE-2017-15124/04-ui-avoid-pointless-VNC-updates-if-framebuffer-isn-t-.patch/ui/vnc.c' ): srand(time(NULL)+getpid()+getpid()*987654+rand()); Tested on Debian 9.7 with kernel 4.9.0-6-amd64 #1 SMP Debian 4.9.88-1+deb9u1 (2018-05-07) x86_64 GNU/Linux. = ** Affects: qemu Importance: Undecided Status: New ** Affects: qemu (Debian) Importance: Unknown Status: Unknown ** Bug watch added: Debian Bug tracker #920897 https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=920897 ** Also affects: qemu (Debian) via https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=920897 Importance: Unknown Status: Unknown -- You received this bug notification because you are a member of qemu- devel-ml, which is subscribed to QEMU. https://bugs.launchpad.net/bugs/1815371 Title: SPICE session's connection_id's are not unique Status in QEMU: New Status in qemu package in Debian: Unknown Bug description: From: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=920897 = When creating a virtual machine with qemu (e.g. via libvirt) including a SPICE server, the client_id of the SPICE session is not unique. For example, starting multiple virtual machines on the same libvirtd, the client_id is the same for all virtual machine's SPICE sessions. A description of the client_id can be found in https://www.spice-space.org/static/docs/spice_protocol.pdf under section 2.11. c) : "UINT32 connection_id - In case of a new session (i.e., channel type is RED_CHANNEL_MAIN) this field is set to zero, and in response the server will allocate session id and will send it via the RedLinkReply message. In case of all other channel types, this field will be equal to the allocated session id" The relevant code for generating client ids in libspice-server1 can be found here: https://gitlab.freedesktop.org/spice/spice/blob/v0.12.8/server/reds.c#L1614 This uses rand() to generate the random id, but qemu (at least in the case of qemu-system-x86) fails to initialize the RNG seed (with e.g. srand()). The result is, that every SPICE session started (by e.g. libvirtd) has the same client_id. Usually, this is not a problem, but running something like a SPICE proxy, relying on the client_id to correctly route connections, this creates problems. Adding something like 'srand(time(NULL));' to qemu (in vl.c) solves this issue. Related (as seen in some VNC patches, e.g. 'CVE-2017-15124/04-ui-avoid-pointless-VNC-updates-if-framebuffer-isn-t-.patch/ui/vnc.c' ): srand(time(NULL)+getpid()+getpid()*987654+rand()); Tested on Debian 9.7 with kernel 4.9.0-6-amd64 #1 SMP Debian 4.9.88-1+deb9u1 (2018-05-07) x86_64 GNU/Linux. = To manage notifications about this bug go to: https://bugs.launchpad.net/qemu/+bug/1815371/+subscriptions
Re: [Qemu-devel] [PATCH slirp 0/5] Make it a standalone project
On Fri, 8 Feb 2019 at 20:58, wrote: > As discussed earlier in "[PATCH for-3.2 00/41] RFC: slirp: make it > again a standalone project" and other threads, it would be useful to > make slirp a separate project (the submodule approach was discarded) > for various projects to share. > The following patches add meson build system (if necessary for older > distros, autotools could be added - however I believe python & ninja > are generally available on the QEMU supported platforms) Do you really need to make QEMU add an extra build dependency just to use a different build system? From my end that seems like just unnecessary pain for us (we're going to need to ship libslirp as a submodule for a while until it's been around long enough to be in stable distros, so its build dependencies will get added to QEMU's build deps). Is the standalone project going to provide a shared library or just a .a static library? (ie are you confident enough in the long-term stability of your API and ABI to do the shared library yet? the prudent approach might be to start with just the .a...) thanks -- PMM
Re: [Qemu-devel] [PATCH 1/1] RFC: net/slirp: link with libslirp
On Fri, 8 Feb 2019 at 20:44, Marc-André Lureau wrote: > > Once libslirp has received its first release, we can link with the > external libslirp library. > > The migration data should be compatible with current and older qemu > versions (same compatibility as today). See "slirp: add state > saving/loading" patch. However, the content should be treated as a > blob, as the format may change eventually in the future. Could you elaborate a bit on what you mean by "the format might change" ? It's not clear to me what libslirp's API/ABI guarantees are here to ensure that QEMU can retain cross-QEMU-version migration compatibility and that QEMU version X with libslirp version Y can migrate both to and from QEMU version X with libslirp version Z. thanks -- PMM
Re: [Qemu-devel] [PATCH slirp 0/5] Make it a standalone project
Hello, Peter Maydell, le dim. 10 févr. 2019 21:35:37 +, a ecrit: > On Fri, 8 Feb 2019 at 20:58, wrote: > > As discussed earlier in "[PATCH for-3.2 00/41] RFC: slirp: make it > > again a standalone project" and other threads, it would be useful to > > make slirp a separate project (the submodule approach was discarded) > > for various projects to share. > > > The following patches add meson build system (if necessary for older > > distros, autotools could be added - however I believe python & ninja > > are generally available on the QEMU supported platforms) > > Do you really need to make QEMU add an extra build dependency > just to use a different build system? AIUI, this patches series is meant for the slirp repository, not the QEMU repository. I.e. just to show how it'll look like, until a project it settled somewhere and the discussion can happen there. Samuel
Re: [Qemu-devel] [PATCH 03/17] target/arm: Add MTE system registers
On Sun, 10 Feb 2019 at 01:23, Richard Henderson wrote: > > On 2/5/19 11:27 AM, Peter Maydell wrote: > >> +++ b/target/arm/translate-a64.c > >> @@ -1668,6 +1668,17 @@ static void handle_msr_i(DisasContext *s, uint32_t > >> insn, > >> s->base.is_jmp = DISAS_UPDATE; > >> break; > >> > >> +case 0x1c: /* TCO */ > >> +if (!dc_isar_feature(aa64_mte_insn_reg, s)) { > >> +goto do_unallocated; > >> +} > >> +if (crm & 1) { > >> +set_pstate_bits(PSTATE_TCO); > >> +} else { > >> +clear_pstate_bits(PSTATE_TCO); > >> +} > >> +break; > > Don't we need to break the TB here or something to pick up > > the new value of TCO when we generate code for a following > > load or store ? (TCO is self-synchronizing so there is no > > requirement for an ISB before it takes effect.) > > Actually, we already break the TB here by default. Do we? I didn't see any code (apart from the handling in the DAIFSet/Clear codepaths, which aren't used for TCO). thanks -- PMM
Re: [Qemu-devel] [PATCH slirp 0/5] Make it a standalone project
On Sun, 10 Feb 2019 at 21:38, Samuel Thibault wrote: > > Hello, > > Peter Maydell, le dim. 10 févr. 2019 21:35:37 +, a ecrit: > > On Fri, 8 Feb 2019 at 20:58, wrote: > > > As discussed earlier in "[PATCH for-3.2 00/41] RFC: slirp: make it > > > again a standalone project" and other threads, it would be useful to > > > make slirp a separate project (the submodule approach was discarded) > > > for various projects to share. > > > > > The following patches add meson build system (if necessary for older > > > distros, autotools could be added - however I believe python & ninja > > > are generally available on the QEMU supported platforms) > > > > Do you really need to make QEMU add an extra build dependency > > just to use a different build system? > > AIUI, this patches series is meant for the slirp repository, not the > QEMU repository. I.e. just to show how it'll look like, until a project > it settled somewhere and the discussion can happen there. Yes, but we're going to be pulling it in as a submodule, so a split out libslirp in its own repository with extra build dependencies is harder to work with than one without. thanks -- PMM
Re: [Qemu-devel] [PATCH slirp 0/5] Make it a standalone project
Hi On Sun, Feb 10, 2019 at 10:42 PM Peter Maydell wrote: > > On Sun, 10 Feb 2019 at 21:38, Samuel Thibault wrote: > > > > Hello, > > > > Peter Maydell, le dim. 10 févr. 2019 21:35:37 +, a ecrit: > > > On Fri, 8 Feb 2019 at 20:58, wrote: > > > > As discussed earlier in "[PATCH for-3.2 00/41] RFC: slirp: make it > > > > again a standalone project" and other threads, it would be useful to > > > > make slirp a separate project (the submodule approach was discarded) > > > > for various projects to share. > > > > > > > The following patches add meson build system (if necessary for older > > > > distros, autotools could be added - however I believe python & ninja > > > > are generally available on the QEMU supported platforms) > > > > > > Do you really need to make QEMU add an extra build dependency > > > just to use a different build system? > > > > AIUI, this patches series is meant for the slirp repository, not the > > QEMU repository. I.e. just to show how it'll look like, until a project > > it settled somewhere and the discussion can happen there. > > Yes, but we're going to be pulling it in as a submodule, > so a split out libslirp in its own repository with extra > build dependencies is harder to work with than one without. > Why do you think it should be a submodule? That's the approach I proposed first, but Daniel suggested to make it immediately a shared library if possible. Regarding the build system, if meson/ninja is problematic for some distro, we can come up with autotools or plain Make for a while. -- Marc-André Lureau
Re: [Qemu-devel] [PATCH slirp 0/5] Make it a standalone project
On Sun, 10 Feb 2019 at 22:03, Marc-André Lureau wrote: > Why do you think it should be a submodule? That's the approach I > proposed first, but Daniel suggested to make it immediately a shared > library if possible. It needs to be a submodule because you don't have a time machine to arrange for it to be an available package in all the stable versions of the distros we support. As and when it is packaged in the oldest stable versions we care about, we can drop the submodule, but submodule is where we need to start. (This is the same as we did with third party bits of code like pixman.) I think immediately going for the shared library (as opposed to static) is a bit of a bold decision also because it is a hard commitment to API and ABI compatibility, which previously has been something the slirp code didn't need to care about at all. > Regarding the build system, if meson/ninja is problematic for some > distro, we can come up with autotools or plain Make for a while. I think plain make would be more convenient. Otherwise everybody building QEMU needs to install a random extra build tool. thanks -- PMM
[Qemu-devel] [PATCH] hw/riscv/virt: re-add machine-specific compatible string to /soc/ node
Re-add the previous compatible string "riscv-virtio-soc" to the soc device tree node to allow U-Boot and Linux to bind machine-specific drivers to it. The current compatible string "simple-bus" is retained. This is required by U-Boot to bind devices early, as part of the pre-relocation driver model. Fixes: 53f54508dae6("hw/riscv/virtio: Set the soc device tree node as a simple-bus") Signed-off-by: Lukas Auer --- hw/riscv/virt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 3e8b19c668..c53bb905ff 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -157,6 +157,7 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap, char *nodename; uint32_t plic_phandle, phandle = 1; int i; +const char soc_compat[] = "riscv-virtio-soc\0simple-bus"; fdt = s->fdt = create_device_tree(&s->fdt_size); if (!fdt) { @@ -171,7 +172,7 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap, qemu_fdt_add_subnode(fdt, "/soc"); qemu_fdt_setprop(fdt, "/soc", "ranges", NULL, 0); -qemu_fdt_setprop_string(fdt, "/soc", "compatible", "simple-bus"); +qemu_fdt_setprop(fdt, "/soc", "compatible", soc_compat, sizeof(soc_compat)); qemu_fdt_setprop_cell(fdt, "/soc", "#size-cells", 0x2); qemu_fdt_setprop_cell(fdt, "/soc", "#address-cells", 0x2); -- 2.20.1
[Qemu-devel] Bug: Lost slirp functionality on qemu-system-ppc build for windows.
Hi, I just cross compiled Qemu-system-ppc for Windows on Fedora 29 and discovered slirp does not work anymore. Tap networking works fine. Bisecting got me here: a9d8b3ec4385793815d7121785730422fa3dfb68 is the first bad commit commit a9d8b3ec4385793815d7121785730422fa3dfb68 Author: Marc-André Lureau Date: Thu Jan 17 15:43:52 2019 +0400 slirp: replace remaining qemu headers dependency Except for the migration code which is gated by WITH_QEMU, only include our own headers, so libslirp can be built standalone. Signed-off-by: Marc-André Lureau Signed-off-by: Samuel Thibault :04 04 cd06df21ed96497cd12f2a20adb3d66cb0da8010 ab5afd3f50910e39b2b700722cd47de8f0cf9e2c Mslirp Best, Howard
Re: [Qemu-devel] [PATCH 03/17] target/arm: Add MTE system registers
On 2/10/19 1:40 PM, Peter Maydell wrote: >> Actually, we already break the TB here by default. > > Do we? I didn't see any code (apart from the handling > in the DAIFSet/Clear codepaths, which aren't used for TCO). At the start of the function: /* End the TB by default, chaining is ok. */ s->base.is_jmp = DISAS_TOO_MANY; Since the change to TCO is from an immediate, the change to MTE_ACTIVE is also constant, and so chaining will work. r~
[Qemu-devel] [Bug 1815371] Re: SPICE session's connection_id's are not unique
** Changed in: qemu (Debian) Status: Unknown => Confirmed -- You received this bug notification because you are a member of qemu- devel-ml, which is subscribed to QEMU. https://bugs.launchpad.net/bugs/1815371 Title: SPICE session's connection_id's are not unique Status in QEMU: New Status in qemu package in Debian: Confirmed Bug description: From: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=920897 = When creating a virtual machine with qemu (e.g. via libvirt) including a SPICE server, the client_id of the SPICE session is not unique. For example, starting multiple virtual machines on the same libvirtd, the client_id is the same for all virtual machine's SPICE sessions. A description of the client_id can be found in https://www.spice-space.org/static/docs/spice_protocol.pdf under section 2.11. c) : "UINT32 connection_id - In case of a new session (i.e., channel type is RED_CHANNEL_MAIN) this field is set to zero, and in response the server will allocate session id and will send it via the RedLinkReply message. In case of all other channel types, this field will be equal to the allocated session id" The relevant code for generating client ids in libspice-server1 can be found here: https://gitlab.freedesktop.org/spice/spice/blob/v0.12.8/server/reds.c#L1614 This uses rand() to generate the random id, but qemu (at least in the case of qemu-system-x86) fails to initialize the RNG seed (with e.g. srand()). The result is, that every SPICE session started (by e.g. libvirtd) has the same client_id. Usually, this is not a problem, but running something like a SPICE proxy, relying on the client_id to correctly route connections, this creates problems. Adding something like 'srand(time(NULL));' to qemu (in vl.c) solves this issue. Related (as seen in some VNC patches, e.g. 'CVE-2017-15124/04-ui-avoid-pointless-VNC-updates-if-framebuffer-isn-t-.patch/ui/vnc.c' ): srand(time(NULL)+getpid()+getpid()*987654+rand()); Tested on Debian 9.7 with kernel 4.9.0-6-amd64 #1 SMP Debian 4.9.88-1+deb9u1 (2018-05-07) x86_64 GNU/Linux. = To manage notifications about this bug go to: https://bugs.launchpad.net/qemu/+bug/1815371/+subscriptions
Re: [Qemu-devel] [PATCH] cuda: decrease time delay before raising VIA SR interrupt
On Sun, Feb 10, 2019 at 05:44:21PM +, Mark Cave-Ayland wrote: > In order to handle a race condition in MacOS 9, a delay was introduced when > raising the VIA SR interrupt inspired by similar code in MacOnLinux. > > During original testing of the MacOS 9 patches it was found that the 30us > delay used in MacOnLinux did not work reliably within QEMU, and a value of > 300us was required to function correctly. > > Recent experiments have shown that the previous reliability issues are no > longer present, and this value can be reduced down to 20us with no apparent > ill effects in my local tests. This has the benefit of considerably improving > the responsiveness of the ADB keyboard and mouse with the guest. > > Signed-off-by: Mark Cave-Ayland Applied to ppc-for-4.0, thanks. > --- > hw/misc/macio/cuda.c | 11 +-- > 1 file changed, 1 insertion(+), 10 deletions(-) > > diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c > index c4f7a2f39b..3febacdd1e 100644 > --- a/hw/misc/macio/cuda.c > +++ b/hw/misc/macio/cuda.c > @@ -97,17 +97,8 @@ static void cuda_set_sr_int(void *opaque) > > static void cuda_delay_set_sr_int(CUDAState *s) > { > -MOS6522CUDAState *mcs = &s->mos6522_cuda; > -MOS6522State *ms = MOS6522(mcs); > -MOS6522DeviceClass *mdc = MOS6522_DEVICE_GET_CLASS(ms); > int64_t expire; > > -if (ms->dirb == 0xff || s->sr_delay_ns == 0) { > -/* Disabled or not in Mac OS, fire the IRQ directly */ > -mdc->set_sr_int(ms); > -return; > -} > - > trace_cuda_delay_set_sr_int(); > > expire = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->sr_delay_ns; > @@ -542,7 +533,7 @@ static void cuda_realize(DeviceState *dev, Error **errp) > s->tick_offset = (uint32_t)mktimegm(&tm) + RTC_OFFSET; > > s->sr_delay_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, cuda_set_sr_int, s); > -s->sr_delay_ns = 300 * SCALE_US; > +s->sr_delay_ns = 20 * SCALE_US; > > s->adb_poll_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, cuda_adb_poll, s); > s->adb_poll_mask = 0x; -- David Gibson| I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson signature.asc Description: PGP signature
Re: [Qemu-devel] [PATCH] mac_newworld: change default NIC to sungem for mac99 machine
On Fri, Feb 08, 2019 at 05:22:01PM +, Mark Cave-Ayland wrote: > This model brings out-of-the-box networking for all of Linux, MacOS 9 and OS X > without requiring the installation of additional drivers. > > Signed-off-by: Mark Cave-Ayland Applied, thanks. > --- > hw/ppc/mac_newworld.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c > index 10be728c37..98461052ac 100644 > --- a/hw/ppc/mac_newworld.c > +++ b/hw/ppc/mac_newworld.c > @@ -432,7 +432,7 @@ static void ppc_core99_init(MachineState *machine) > } > > for (i = 0; i < nb_nics; i++) { > -pci_nic_init_nofail(&nd_table[i], pci_bus, "ne2k_pci", NULL); > +pci_nic_init_nofail(&nd_table[i], pci_bus, "sungem", NULL); > } > > /* The NewWorld NVRAM is not located in the MacIO device */ -- David Gibson| I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson signature.asc Description: PGP signature
Re: [Qemu-devel] [PATCH] spapr: Disallow unsupported kernel-irqchip settings
On Fri, Feb 08, 2019 at 07:17:47PM +0100, Greg Kurz wrote: > Split mode doesn't make sense on pseries, neither with XICS nor XIVE. But > passing kernel-irqchip=split silently behaves like kernel-irqchip=on. > Other architectures that support kernel-irqchip do terminate QEMU when > split mode is requested but not available though. Do the same with pseries > for consistency. > > Similarly, passing kernel-irqchip=on,accel=tcg starts the machine with the > emulated interrupt controller, ie, behaves like kernel-irqchip=off. However, > when passing kernel-irqchip=on,accel=kvm, if we can't initialize the KVM > XICS for some reason, ie, xics_kvm_init() fails, then QEMU is terminated. > This is inconsistent. Terminate QEMU all the same when requesting the > in-kernel interrupt controller without KVM. > > Signed-off-by: Greg Kurz > --- > > The odds for someone to have an existing pseries setup with split mode are > very low since this is really an x86 thingy. And I guess we don't really > care to break the silly kernel-irqchip=on,accel=tcg case. But if we really > need to stay bug compatible, the errors can be turned into warnings. Applied, thanks. > --- > hw/ppc/spapr_irq.c | 13 + > 1 file changed, 13 insertions(+) > > diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c > index 2d7a7c163876..80b0083b8e38 100644 > --- a/hw/ppc/spapr_irq.c > +++ b/hw/ppc/spapr_irq.c > @@ -600,6 +600,19 @@ sPAPRIrq spapr_irq_dual = { > */ > void spapr_irq_init(sPAPRMachineState *spapr, Error **errp) > { > +MachineState *machine = MACHINE(spapr); > + > +if (machine_kernel_irqchip_split(machine)) { > +error_setg(errp, "kernel_irqchip split mode not supported on > pseries"); > +return; > +} > + > +if (!kvm_enabled() && machine_kernel_irqchip_required(machine)) { > +error_setg(errp, > + "kernel_irqchip requested but only available with KVM"); > +return; > +} > + > /* Initialize the MSI IRQ allocator. */ > if (!SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) { > spapr_irq_msi_init(spapr, spapr->irq->nr_msis); > -- David Gibson| I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson signature.asc Description: PGP signature
[Qemu-devel] [PATCH] target/xtensa: don't specify windowed registers manually
Use libisa to extract whether opcode uses windowed registers and construct mask based on that. This only leaves special case for the 'entry' opcode, as it needs to probe a register dynamically. Signed-off-by: Max Filippov --- target/xtensa/cpu.h | 2 +- target/xtensa/helper.c| 1 + target/xtensa/translate.c | 493 +- 3 files changed, 12 insertions(+), 484 deletions(-) diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h index b665bfc0068a..f1861244720e 100644 --- a/target/xtensa/cpu.h +++ b/target/xtensa/cpu.h @@ -380,7 +380,6 @@ typedef struct XtensaOpcodeOps { XtensaOpcodeUintTest test_overflow; const uint32_t *par; uint32_t op_flags; -uint32_t windowed_register_op; uint32_t coprocessor; } XtensaOpcodeOps; @@ -438,6 +437,7 @@ struct XtensaConfig { xtensa_isa isa; XtensaOpcodeOps **opcode_ops; const XtensaOpcodeTranslators **opcode_translators; +xtensa_regfile a_regfile; uint32_t clock_freq_khz; diff --git a/target/xtensa/helper.c b/target/xtensa/helper.c index bcf2f20d4858..6cf1dbb8a69b 100644 --- a/target/xtensa/helper.c +++ b/target/xtensa/helper.c @@ -88,6 +88,7 @@ static void init_libisa(XtensaConfig *config) #endif config->opcode_ops[i] = ops; } +config->a_regfile = xtensa_regfile_lookup(config->isa, "AR"); } void xtensa_finalize_config(XtensaConfig *config) diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index d1e9f59b31bd..6e4f0ad44c80 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -916,6 +916,16 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) opnds = xtensa_opcode_num_operands(isa, opc); for (opnd = vopnd = 0; opnd < opnds; ++opnd) { +if (xtensa_operand_is_register(isa, opc, opnd) && +xtensa_operand_regfile(isa, opc, opnd) == +dc->config->a_regfile) { +uint32_t v; + +xtensa_operand_get_field(isa, opc, opnd, fmt, slot, + dc->slotbuf, &v); +xtensa_operand_decode(isa, opc, opnd, &v); +windowed_register |= 1u << v; +} if (xtensa_operand_is_visible(isa, opc, opnd)) { uint32_t v; @@ -952,16 +962,6 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) if (ops->test_overflow) { windowed_register |= ops->test_overflow(dc, arg, ops->par); } -if (ops->windowed_register_op) { -uint32_t reg_opnd = ops->windowed_register_op; - -while (reg_opnd) { -unsigned i = ctz32(reg_opnd); - -windowed_register |= 1 << arg[i]; -reg_opnd ^= 1 << i; -} -} coprocessor |= ops->coprocessor; } @@ -1474,12 +1474,6 @@ static void translate_call0(DisasContext *dc, const uint32_t arg[], gen_jumpi(dc, arg[0], 0); } -static uint32_t test_overflow_callw(DisasContext *dc, const uint32_t arg[], -const uint32_t par[]) -{ -return 1 << (par[0] * 4); -} - static void translate_callw(DisasContext *dc, const uint32_t arg[], const uint32_t par[]) { @@ -2435,42 +2429,33 @@ static const XtensaOpcodeOps core_ops[] = { { .name = "abs", .translate = translate_abs, -.windowed_register_op = 0x3, }, { .name = "add", .translate = translate_add, -.windowed_register_op = 0x7, }, { .name = "add.n", .translate = translate_add, -.windowed_register_op = 0x7, }, { .name = "addi", .translate = translate_addi, -.windowed_register_op = 0x3, }, { .name = "addi.n", .translate = translate_addi, -.windowed_register_op = 0x3, }, { .name = "addmi", .translate = translate_addi, -.windowed_register_op = 0x3, }, { .name = "addx2", .translate = translate_addx, .par = (const uint32_t[]){1}, -.windowed_register_op = 0x7, }, { .name = "addx4", .translate = translate_addx, .par = (const uint32_t[]){2}, -.windowed_register_op = 0x7, }, { .name = "addx8", .translate = translate_addx, .par = (const uint32_t[]){3}, -.windowed_register_op = 0x7, }, { .name = "all4", .translate = translate_all, @@ -2482,7 +2467,6 @@ static const XtensaOpcodeOps core_ops[] = { }, { .name = "and", .translate = translate_and, -.windowed_register_op = 0x7, }, { .name = "andb", .translate = translate_boolean, @@ -2503,52 +2487,42 @@ static const XtensaOpcodeOps core_ops[] = { .name = "ball", .translate = translate_ball, .par = (const uint32_t[])
[Qemu-devel] [PATCH v2 00/26] target/arm: Implement ARMv8.5-MemTag
Based-on: <20190204131228.25949-1-richard.hender...@linaro.org> aka "[PATCH v3 0/4] target/arm: Implement ARMv8.5-BTI". The full tree is available at https://github.org/rth7680/qemu.git tgt-arm-mte Changes since v1: * Updates to a newer revision of the spec. I know there is still work to do here: another argument to STG, ST2G, and a new STZGM insn. * User emulation adds an x-tagged-pages property. Without that, all pages are MemAttr != Tagged and so all accesses unchecked. I am not turning off SCTLR_EL1.ATA0, so even without x-tagged-pages the program has access to tag generation (e.g. the IRG insn). * System emulation is new, though effectively untested. I need to fiddle around with the kernel to see what I can put together there. What I can see is: address-space: cpu-tag-memory-0 -07fe (prio 0, i/o): tag-memory 0200-09ff (prio 0, ram): mach-virt.tag address-space: cpu-memory-0 - (prio 0, i/o): system 4000-00013fff (prio 0, ram): mach-virt.ram * New checks for alignment and page permissions before allowing access to the tag memory. r~ Richard Henderson (26): target/arm: Split out arm_sctlr target/arm: Split helper_msr_i_pstate into 3 target/arm: Add clear_pstate_bits, share gen_ss_advance target/arm: Add MTE_ACTIVE to tb_flags target/arm: Extract TCMA with ARMVAParameters target/arm: Add MTE system registers target/arm: Assert no manual change to CACHED_PSTATE_BITS target/arm: Fill in helper_mte_check target/arm: Suppress tag check for sp+offset target/arm: Implement the IRG instruction target/arm: Implement ADDG, SUBG instructions target/arm: Implement the GMI instruction target/arm: Implement the SUBP instruction target/arm: Define arm_cpu_do_unaligned_access for CONFIG_USER_ONLY target/arm: Implement LDG, STG, ST2G instructions target/arm: Implement the STGP instruction target/arm: Implement the access tag cache flushes target/arm: Implement data cache set allocation tags target/arm: Set PSTATE.TCO on exception entry tcg: Introduce target-specific page data for user-only target/arm: Cache the Tagged bit for a page in MemTxAttrs target/arm: Create tagged ram when MTE is enabled target/arm: Add allocation tag storage for user mode target/arm: Add allocation tag storage for system mode target/arm: Enable MTE tests/tcg/aarch64: Add mte smoke tests include/exec/cpu-all.h| 10 +- target/arm/cpu.h | 52 ++- target/arm/helper-a64.h | 15 + target/arm/helper.h | 3 - target/arm/internals.h| 37 +++ target/arm/translate.h| 36 ++ accel/tcg/translate-all.c | 28 ++ hw/arm/virt.c | 33 ++ linux-user/mmap.c | 10 +- linux-user/syscall.c | 4 +- target/arm/cpu.c | 31 +- target/arm/cpu64.c| 19 ++ target/arm/helper-a64.c | 30 ++ target/arm/helper.c | 208 ++-- target/arm/mte_helper.c | 529 ++ target/arm/op_helper.c| 80 + target/arm/translate-a64.c| 352 target/arm/translate.c| 11 - tests/tcg/aarch64/mte-1.c | 27 ++ tests/tcg/aarch64/mte-2.c | 39 +++ target/arm/Makefile.objs | 2 +- tests/tcg/aarch64/Makefile.target | 4 + 22 files changed, 1360 insertions(+), 200 deletions(-) create mode 100644 target/arm/mte_helper.c create mode 100644 tests/tcg/aarch64/mte-1.c create mode 100644 tests/tcg/aarch64/mte-2.c -- 2.17.2
[Qemu-devel] [PATCH v2 02/26] target/arm: Split helper_msr_i_pstate into 3
The EL0+UMA check is unique to DAIF. While SPSel had avoided the check by nature of already checking EL >= 1, the other post v8.0 extensions to MSR (imm) allow EL0 and do not require UMA. Avoid the unconditional write to pc and use raise_exception_ra to unwind. Signed-off-by: Richard Henderson --- target/arm/helper-a64.h| 3 +++ target/arm/helper.h| 1 - target/arm/internals.h | 15 ++ target/arm/helper-a64.c| 30 +++ target/arm/op_helper.c | 42 -- target/arm/translate-a64.c | 41 ++--- 6 files changed, 73 insertions(+), 59 deletions(-) diff --git a/target/arm/helper-a64.h b/target/arm/helper-a64.h index aff8d6c9f3..a915c1247f 100644 --- a/target/arm/helper-a64.h +++ b/target/arm/helper-a64.h @@ -19,6 +19,9 @@ DEF_HELPER_FLAGS_2(udiv64, TCG_CALL_NO_RWG_SE, i64, i64, i64) DEF_HELPER_FLAGS_2(sdiv64, TCG_CALL_NO_RWG_SE, s64, s64, s64) DEF_HELPER_FLAGS_1(rbit64, TCG_CALL_NO_RWG_SE, i64, i64) +DEF_HELPER_2(msr_i_spsel, void, env, i32) +DEF_HELPER_2(msr_i_daifset, void, env, i32) +DEF_HELPER_2(msr_i_daifclear, void, env, i32) DEF_HELPER_3(vfp_cmph_a64, i64, f16, f16, ptr) DEF_HELPER_3(vfp_cmpeh_a64, i64, f16, f16, ptr) DEF_HELPER_3(vfp_cmps_a64, i64, f32, f32, ptr) diff --git a/target/arm/helper.h b/target/arm/helper.h index 53a38188c6..28b1dd6252 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -77,7 +77,6 @@ DEF_HELPER_2(get_cp_reg, i32, env, ptr) DEF_HELPER_3(set_cp_reg64, void, env, ptr, i64) DEF_HELPER_2(get_cp_reg64, i64, env, ptr) -DEF_HELPER_3(msr_i_pstate, void, env, i32, i32) DEF_HELPER_1(clear_pstate_ss, void, env) DEF_HELPER_2(get_r13_banked, i32, env, i32) diff --git a/target/arm/internals.h b/target/arm/internals.h index a4bd1becb7..587a1ddf58 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -968,4 +968,19 @@ ARMVAParameters aa64_va_parameters_both(CPUARMState *env, uint64_t va, ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va, ARMMMUIdx mmu_idx, bool data); +static inline int exception_target_el(CPUARMState *env) +{ +int target_el = MAX(1, arm_current_el(env)); + +/* + * No such thing as secure EL1 if EL3 is aarch32, + * so update the target EL to EL3 in this case. + */ +if (arm_is_secure(env) && !arm_el_is_aa64(env, 3) && target_el == 1) { +target_el = 3; +} + +return target_el; +} + #endif diff --git a/target/arm/helper-a64.c b/target/arm/helper-a64.c index 101fa6d3ea..87b8f36122 100644 --- a/target/arm/helper-a64.c +++ b/target/arm/helper-a64.c @@ -61,6 +61,36 @@ uint64_t HELPER(rbit64)(uint64_t x) return revbit64(x); } +void HELPER(msr_i_spsel)(CPUARMState *env, uint32_t imm) +{ +update_spsel(env, imm); +} + +static void daif_check(CPUARMState *env, uint32_t op, + uint32_t imm, uintptr_t ra) +{ +/* DAIF update to PSTATE. This is OK from EL0 only if UMA is set. */ +if (arm_current_el(env) == 0 && !(env->cp15.sctlr_el[1] & SCTLR_UMA)) { +raise_exception_ra(env, EXCP_UDEF, + syn_aa64_sysregtrap(0, extract32(op, 0, 3), + extract32(op, 3, 3), 4, + imm, 0x1f, 0), + exception_target_el(env), ra); +} +} + +void HELPER(msr_i_daifset)(CPUARMState *env, uint32_t imm) +{ +daif_check(env, 0x1e, imm, GETPC()); +env->daif |= (imm << 6) & PSTATE_DAIF; +} + +void HELPER(msr_i_daifclear)(CPUARMState *env, uint32_t imm) +{ +daif_check(env, 0x1f, imm, GETPC()); +env->daif &= ~((imm << 6) & PSTATE_DAIF); +} + /* Convert a softfloat float_relation_ (as returned by * the float*_compare functions) to the correct ARM * NZCV flag state. diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c index c998eadfaa..c5721a866d 100644 --- a/target/arm/op_helper.c +++ b/target/arm/op_helper.c @@ -68,20 +68,6 @@ void raise_exception_ra(CPUARMState *env, uint32_t excp, uint32_t syndrome, cpu_loop_exit_restore(cs, ra); } -static int exception_target_el(CPUARMState *env) -{ -int target_el = MAX(1, arm_current_el(env)); - -/* No such thing as secure EL1 if EL3 is aarch32, so update the target EL - * to EL3 in this case. - */ -if (arm_is_secure(env) && !arm_el_is_aa64(env, 3) && target_el == 1) { -target_el = 3; -} - -return target_el; -} - uint32_t HELPER(neon_tbl)(uint32_t ireg, uint32_t def, void *vn, uint32_t maxindex) { @@ -875,34 +861,6 @@ uint64_t HELPER(get_cp_reg64)(CPUARMState *env, void *rip) return res; } -void HELPER(msr_i_pstate)(CPUARMState *env, uint32_t op, uint32_t imm) -{ -/* MSR_i to update PSTATE. This is OK from EL0 only if UMA is set. - * Note that SPSel is never OK from EL0; we rely on handle_msr_i() - * to catch that case
[Qemu-devel] [PATCH v2 07/26] target/arm: Assert no manual change to CACHED_PSTATE_BITS
These bits are stored elsewhere; changing env->pstate has no effect. Suggested-by: Peter Maydell Signed-off-by: Richard Henderson --- target/arm/translate.h | 4 1 file changed, 4 insertions(+) diff --git a/target/arm/translate.h b/target/arm/translate.h index a24757d3d7..296d1ac72c 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -209,6 +209,8 @@ static inline void set_pstate_bits(uint32_t bits) { TCGv_i32 p = tcg_temp_new_i32(); +tcg_debug_assert(!(bits & CACHED_PSTATE_BITS)); + tcg_gen_ld_i32(p, cpu_env, offsetof(CPUARMState, pstate)); tcg_gen_ori_i32(p, p, bits); tcg_gen_st_i32(p, cpu_env, offsetof(CPUARMState, pstate)); @@ -220,6 +222,8 @@ static inline void clear_pstate_bits(uint32_t bits) { TCGv_i32 p = tcg_temp_new_i32(); +tcg_debug_assert(!(bits & CACHED_PSTATE_BITS)); + tcg_gen_ld_i32(p, cpu_env, offsetof(CPUARMState, pstate)); tcg_gen_andi_i32(p, p, ~bits); tcg_gen_st_i32(p, cpu_env, offsetof(CPUARMState, pstate)); -- 2.17.2
[Qemu-devel] [PATCH v2 06/26] target/arm: Add MTE system registers
This is TFSRE0_EL1, TFSR_EL1, TFSR_EL2, TFSR_EL3, RGSR_EL1, GCR_EL1, and PSTATE.TCO. Signed-off-by: Richard Henderson --- target/arm/cpu.h | 5 + target/arm/translate.h | 11 ++ target/arm/helper.c| 45 ++ target/arm/translate-a64.c | 11 ++ 4 files changed, 72 insertions(+) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 2776df6981..74633a7a78 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -495,6 +495,11 @@ typedef struct CPUARMState { uint64_t pmccfiltr_el0; /* Performance Monitor Filter Register */ uint64_t vpidr_el2; /* Virtualization Processor ID Register */ uint64_t vmpidr_el2; /* Virtualization Multiprocessor ID Register */ +#ifdef TARGET_AARCH64 +uint64_t tfsr_el[4]; /* tfsrel0_el1 is index 0. */ +uint64_t gcr_el1; +uint64_t rgsr_el1; +#endif } cp15; struct { diff --git a/target/arm/translate.h b/target/arm/translate.h index 5a101e1c6d..a24757d3d7 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -204,6 +204,17 @@ static inline TCGv_i32 get_ahp_flag(void) return ret; } +/* Set bits within PSTATE. */ +static inline void set_pstate_bits(uint32_t bits) +{ +TCGv_i32 p = tcg_temp_new_i32(); + +tcg_gen_ld_i32(p, cpu_env, offsetof(CPUARMState, pstate)); +tcg_gen_ori_i32(p, p, bits); +tcg_gen_st_i32(p, cpu_env, offsetof(CPUARMState, pstate)); +tcg_temp_free_i32(p); +} + /* Clear bits within PSTATE. */ static inline void clear_pstate_bits(uint32_t bits) { diff --git a/target/arm/helper.c b/target/arm/helper.c index cbe3500f78..2d9c070bb3 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -5732,6 +5732,48 @@ static const ARMCPRegInfo pauth_reginfo[] = { .fieldoffset = offsetof(CPUARMState, apib_key.hi) }, REGINFO_SENTINEL }; + +static uint64_t tco_read(CPUARMState *env, const ARMCPRegInfo *ri) +{ +return env->pstate & PSTATE_TCO; +} + +static void tco_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t val) +{ +env->pstate = (env->pstate & ~PSTATE_TCO) | (val & PSTATE_TCO); +} + +static const ARMCPRegInfo mte_reginfo[] = { +{ .name = "TFSRE0_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 6, .crm = 6, .opc2 = 1, + .access = PL1_RW, + .fieldoffset = offsetof(CPUARMState, cp15.tfsr_el[0]) }, +{ .name = "TFSR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 6, .crm = 5, .opc2 = 0, + .access = PL1_RW, + .fieldoffset = offsetof(CPUARMState, cp15.tfsr_el[1]) }, +{ .name = "TFSR_EL2", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 4, .crn = 6, .crm = 5, .opc2 = 0, + .access = PL2_RW, + .fieldoffset = offsetof(CPUARMState, cp15.tfsr_el[2]) }, +{ .name = "TFSR_EL3", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 6, .crn = 6, .crm = 6, .opc2 = 0, + .access = PL3_RW, + .fieldoffset = offsetof(CPUARMState, cp15.tfsr_el[3]) }, +{ .name = "RGSR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 1, .crm = 0, .opc2 = 5, + .access = PL1_RW, + .fieldoffset = offsetof(CPUARMState, cp15.rgsr_el1) }, +{ .name = "GCR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 1, .crm = 0, .opc2 = 6, + .access = PL1_RW, + .fieldoffset = offsetof(CPUARMState, cp15.gcr_el1) }, +{ .name = "TCO", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 3, .crn = 4, .crm = 2, .opc2 = 7, + .type = ARM_CP_NO_RAW, + .access = PL0_RW, .readfn = tco_read, .writefn = tco_write }, +REGINFO_SENTINEL +}; #endif void register_cp_regs_for_features(ARMCPU *cpu) @@ -6577,6 +6619,9 @@ void register_cp_regs_for_features(ARMCPU *cpu) if (cpu_isar_feature(aa64_pauth, cpu)) { define_arm_cp_regs(cpu, pauth_reginfo); } +if (cpu_isar_feature(aa64_mte_insn_reg, cpu)) { +define_arm_cp_regs(cpu, mte_reginfo); +} #endif } diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index e782a0e579..8e9f40f2a6 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -1672,6 +1672,17 @@ static void handle_msr_i(DisasContext *s, uint32_t insn, s->base.is_jmp = DISAS_UPDATE; break; +case 0x1c: /* TCO */ +if (!dc_isar_feature(aa64_mte_insn_reg, s)) { +goto do_unallocated; +} +if (crm & 1) { +set_pstate_bits(PSTATE_TCO); +} else { +clear_pstate_bits(PSTATE_TCO); +} +break; + default: do_unallocated: unallocated_encoding(s); -- 2.17.2
[Qemu-devel] [PATCH v2 14/26] target/arm: Define arm_cpu_do_unaligned_access for CONFIG_USER_ONLY
We will need this to raise unaligned exceptions from user mode. Signed-off-by: Richard Henderson --- target/arm/op_helper.c | 33 - 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c index 8698b4dc83..d3cf362e4b 100644 --- a/target/arm/op_helper.c +++ b/target/arm/op_helper.c @@ -87,8 +87,6 @@ uint32_t HELPER(neon_tbl)(uint32_t ireg, uint32_t def, void *vn, return val; } -#if !defined(CONFIG_USER_ONLY) - static inline uint32_t merge_syn_data_abort(uint32_t template_syn, unsigned int target_el, bool same_el, bool ea, @@ -179,6 +177,22 @@ static void deliver_fault(ARMCPU *cpu, vaddr addr, MMUAccessType access_type, raise_exception(env, exc, syn, target_el); } +/* Raise a data fault alignment exception for the specified virtual address */ +void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, + MMUAccessType access_type, + int mmu_idx, uintptr_t retaddr) +{ +ARMCPU *cpu = ARM_CPU(cs); +ARMMMUFaultInfo fi = {}; + +/* now we have a real cpu fault */ +cpu_restore_state(cs, retaddr, true); + +fi.type = ARMFault_Alignment; +deliver_fault(cpu, vaddr, access_type, mmu_idx, &fi); +} + +#ifndef CONFIG_USER_ONLY /* try to fill the TLB and return an exception if error. If retaddr is * NULL, it means that the function was called in C code (i.e. not * from generated code or from helper.c) @@ -200,21 +214,6 @@ void tlb_fill(CPUState *cs, target_ulong addr, int size, } } -/* Raise a data fault alignment exception for the specified virtual address */ -void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, - MMUAccessType access_type, - int mmu_idx, uintptr_t retaddr) -{ -ARMCPU *cpu = ARM_CPU(cs); -ARMMMUFaultInfo fi = {}; - -/* now we have a real cpu fault */ -cpu_restore_state(cs, retaddr, true); - -fi.type = ARMFault_Alignment; -deliver_fault(cpu, vaddr, access_type, mmu_idx, &fi); -} - /* arm_cpu_do_transaction_failed: handle a memory system error response * (eg "no device/memory present at address") by raising an external abort * exception -- 2.17.2
[Qemu-devel] [PATCH v2 01/26] target/arm: Split out arm_sctlr
Minimize the number of places that will need updating when the virtual host extensions are added. Signed-off-by: Richard Henderson --- target/arm/cpu.h| 26 -- target/arm/helper.c | 8 ++-- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 29663a264d..20be9fb53a 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -2987,11 +2987,20 @@ static inline bool arm_sctlr_b(CPUARMState *env) (env->cp15.sctlr_el[1] & SCTLR_B) != 0; } +static inline uint64_t arm_sctlr(CPUARMState *env, int el) +{ +if (el == 0) { +/* FIXME: ARMv8.1-VHE S2 translation regime. */ +return env->cp15.sctlr_el[1]; +} else { +return env->cp15.sctlr_el[el]; +} +} + + /* Return true if the processor is in big-endian mode. */ static inline bool arm_cpu_data_is_big_endian(CPUARMState *env) { -int cur_el; - /* In 32bit endianness is determined by looking at CPSR's E bit */ if (!is_a64(env)) { return @@ -3010,15 +3019,12 @@ static inline bool arm_cpu_data_is_big_endian(CPUARMState *env) arm_sctlr_b(env) || #endif ((env->uncached_cpsr & CPSR_E) ? 1 : 0); +} else { +int cur_el = arm_current_el(env); +uint64_t sctlr = arm_sctlr(env, cur_el); + +return (sctlr & (cur_el ? SCTLR_EE : SCTLR_E0E)) != 0; } - -cur_el = arm_current_el(env); - -if (cur_el == 0) { -return (env->cp15.sctlr_el[1] & SCTLR_E0E) != 0; -} - -return (env->cp15.sctlr_el[cur_el] & SCTLR_EE) != 0; } #include "exec/cpu-all.h" diff --git a/target/arm/helper.c b/target/arm/helper.c index 520ceea7a4..d4abbb5076 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -13796,12 +13796,8 @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc, flags = FIELD_DP32(flags, TBFLAG_A64, ZCR_LEN, zcr_len); } -if (current_el == 0) { -/* FIXME: ARMv8.1-VHE S2 translation regime. */ -sctlr = env->cp15.sctlr_el[1]; -} else { -sctlr = env->cp15.sctlr_el[current_el]; -} +sctlr = arm_sctlr(env, current_el); + if (cpu_isar_feature(aa64_pauth, cpu)) { /* * In order to save space in flags, we record only whether -- 2.17.2
[Qemu-devel] [PATCH v2 26/26] tests/tcg/aarch64: Add mte smoke tests
Signed-off-by: Richard Henderson --- tests/tcg/aarch64/mte-1.c | 27 + tests/tcg/aarch64/mte-2.c | 39 +++ tests/tcg/aarch64/Makefile.target | 4 3 files changed, 70 insertions(+) create mode 100644 tests/tcg/aarch64/mte-1.c create mode 100644 tests/tcg/aarch64/mte-2.c diff --git a/tests/tcg/aarch64/mte-1.c b/tests/tcg/aarch64/mte-1.c new file mode 100644 index 00..740bf506f1 --- /dev/null +++ b/tests/tcg/aarch64/mte-1.c @@ -0,0 +1,27 @@ +/* + * Memory tagging, basic pass cases. + */ + +#include + +asm(".arch armv8.5-a+memtag"); + +int data[16 / sizeof(int)] __attribute__((aligned(16))); + +int main(int ac, char **av) +{ +int *p0 = data; +int *p1, *p2; +long c; + +asm("irg %0,%1,%2" : "=r"(p1) : "r"(p0), "r"(1)); +assert(p1 != p0); +asm("subp %0,%1,%2" : "=r"(c) : "r"(p0), "r"(p1)); +assert(c == 0); + +asm("stg [%0]" : : "r"(p1)); +asm("ldg %0, [%1]" : "=r"(p2) : "r"(p0)); +assert(p1 == p2); + +return 0; +} diff --git a/tests/tcg/aarch64/mte-2.c b/tests/tcg/aarch64/mte-2.c new file mode 100644 index 00..4d2004ab41 --- /dev/null +++ b/tests/tcg/aarch64/mte-2.c @@ -0,0 +1,39 @@ +/* + * Memory tagging, basic fail cases. + */ + +#include +#include +#include + +asm(".arch armv8.5-a+memtag"); + +int data[16 / sizeof(int)] __attribute__((aligned(16))); + +void pass(int sig) +{ +exit(0); +} + +int main(int ac, char **av) +{ +int *p0 = data; +int *p1, *p2; +long excl = 1; + +/* Create two differently tagged pointers. */ +asm("irg %0,%1,%2" : "=r"(p1) : "r"(p0), "r"(excl)); +asm("gmi %0,%1,%0" : "+r"(excl) : "r" (p1)); +assert(excl != 1); +asm("irg %0,%1,%2" : "=r"(p2) : "r"(p0), "r"(excl)); +assert(p1 != p2); + +/* Store the tag from the first pointer. */ +asm("stg [%0]" : : "r"(p1)); + +*p1 = 0; +signal(SIGSEGV, pass); +*p2 = 0; + +assert(0); +} diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target index 55420aeea6..614dfcd14d 100644 --- a/tests/tcg/aarch64/Makefile.target +++ b/tests/tcg/aarch64/Makefile.target @@ -22,4 +22,8 @@ AARCH64_TESTS += bti-1 bti-1: LDFLAGS += -nostartfiles -nodefaultlibs -nostdlib run-bti-1: QEMU += -cpu max,x-guarded-pages=on +AARCH64_TESTS += mte-1 mte-2 +mte-%: CFLAGS += -O -g +run-mte-%: QEMU += -cpu max,x-tagged-pages=on + TESTS:=$(AARCH64_TESTS) -- 2.17.2
[Qemu-devel] [PATCH v2 09/26] target/arm: Suppress tag check for sp+offset
R0078 specifies that base register, or base register plus immediate offset, is unchecked when the base register is SP. Signed-off-by: Richard Henderson --- v2: Include writeback addresses as checked. --- target/arm/translate-a64.c | 37 ++--- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 8e9f40f2a6..d0f8c314c9 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -340,12 +340,11 @@ static void gen_a64_set_pc(DisasContext *s, TCGv_i64 src) * This is always a fresh temporary, as we need to be able to * increment this independently of a dirty write-back address. */ -static TCGv_i64 clean_data_tbi(DisasContext *s, TCGv_i64 addr) +static TCGv_i64 clean_data_tbi(DisasContext *s, TCGv_i64 addr, bool check) { TCGv_i64 clean = new_tmp_a64(s); -/* FIXME: SP+OFS is always unchecked. */ -if (s->tbid && s->mte_active) { +if (check && s->mte_active) { gen_helper_mte_check(clean, cpu_env, addr); } else { gen_top_byte_ignore(s, clean, addr, s->tbid); @@ -2379,7 +2378,7 @@ static void gen_compare_and_swap(DisasContext *s, int rs, int rt, if (rn == 31) { gen_check_sp_alignment(s); } -clean_addr = clean_data_tbi(s, cpu_reg_sp(s, rn)); +clean_addr = clean_data_tbi(s, cpu_reg_sp(s, rn), rn != 31); tcg_gen_atomic_cmpxchg_i64(tcg_rs, clean_addr, tcg_rs, tcg_rt, memidx, size | MO_ALIGN | s->be_data); } @@ -2397,7 +2396,7 @@ static void gen_compare_and_swap_pair(DisasContext *s, int rs, int rt, if (rn == 31) { gen_check_sp_alignment(s); } -clean_addr = clean_data_tbi(s, cpu_reg_sp(s, rn)); +clean_addr = clean_data_tbi(s, cpu_reg_sp(s, rn), rn != 31); if (size == 2) { TCGv_i64 cmp = tcg_temp_new_i64(); @@ -2522,7 +2521,7 @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn) if (is_lasr) { tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL); } -clean_addr = clean_data_tbi(s, cpu_reg_sp(s, rn)); +clean_addr = clean_data_tbi(s, cpu_reg_sp(s, rn), rn != 31); gen_store_exclusive(s, rs, rt, rt2, clean_addr, size, false); return; @@ -2531,7 +2530,7 @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn) if (rn == 31) { gen_check_sp_alignment(s); } -clean_addr = clean_data_tbi(s, cpu_reg_sp(s, rn)); +clean_addr = clean_data_tbi(s, cpu_reg_sp(s, rn), rn != 31); s->is_ldex = true; gen_load_exclusive(s, rt, rt2, clean_addr, size, false); if (is_lasr) { @@ -2551,7 +2550,7 @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn) gen_check_sp_alignment(s); } tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL); -clean_addr = clean_data_tbi(s, cpu_reg_sp(s, rn)); +clean_addr = clean_data_tbi(s, cpu_reg_sp(s, rn), rn != 31); do_gpr_st(s, cpu_reg(s, rt), clean_addr, size, true, rt, disas_ldst_compute_iss_sf(size, false, 0), is_lasr); return; @@ -2567,7 +2566,7 @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn) if (rn == 31) { gen_check_sp_alignment(s); } -clean_addr = clean_data_tbi(s, cpu_reg_sp(s, rn)); +clean_addr = clean_data_tbi(s, cpu_reg_sp(s, rn), rn != 31); do_gpr_ld(s, cpu_reg(s, rt), clean_addr, size, false, false, true, rt, disas_ldst_compute_iss_sf(size, false, 0), is_lasr); tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ); @@ -2581,7 +2580,7 @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn) if (is_lasr) { tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL); } -clean_addr = clean_data_tbi(s, cpu_reg_sp(s, rn)); +clean_addr = clean_data_tbi(s, cpu_reg_sp(s, rn), rn != 31); gen_store_exclusive(s, rs, rt, rt2, clean_addr, size, true); return; } @@ -2599,7 +2598,7 @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn) if (rn == 31) { gen_check_sp_alignment(s); } -clean_addr = clean_data_tbi(s, cpu_reg_sp(s, rn)); +clean_addr = clean_data_tbi(s, cpu_reg_sp(s, rn), rn != 31); s->is_ldex = true; gen_load_exclusive(s, rt, rt2, clean_addr, size, true); if (is_lasr) { @@ -2789,7 +2788,7 @@ static void disas_ldst_pair(DisasContext *s, uint32_t insn) if (!postindex) { tcg_gen_addi_i64(dirty_addr, dirty_addr, offset); } -clean_addr = clean_data_tbi(s, dirty_addr); +clean_addr = clean_data_tbi(s, dirty_addr, wback || rn != 31); if (is_vector) { if (is_load) { @@ -2927,7 +2926,7 @@ static void disas_ldst_reg_imm9(DisasContext *s, uint32_t insn, if (!post_index) { tcg_gen_addi_i64(dirty_a
[Qemu-devel] [PATCH v2 03/26] target/arm: Add clear_pstate_bits, share gen_ss_advance
We do not need an out-of-line helper for clearing bits in pstate. While changing things, share the implementation of gen_ss_advance. Signed-off-by: Richard Henderson --- target/arm/helper.h| 2 -- target/arm/translate.h | 19 +++ target/arm/op_helper.c | 5 - target/arm/translate-a64.c | 11 --- target/arm/translate.c | 11 --- 5 files changed, 19 insertions(+), 29 deletions(-) diff --git a/target/arm/helper.h b/target/arm/helper.h index 28b1dd6252..c21fa2edfe 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -77,8 +77,6 @@ DEF_HELPER_2(get_cp_reg, i32, env, ptr) DEF_HELPER_3(set_cp_reg64, void, env, ptr, i64) DEF_HELPER_2(get_cp_reg64, i64, env, ptr) -DEF_HELPER_1(clear_pstate_ss, void, env) - DEF_HELPER_2(get_r13_banked, i32, env, i32) DEF_HELPER_3(set_r13_banked, void, env, i32, i32) diff --git a/target/arm/translate.h b/target/arm/translate.h index 17748ddfb9..33af50a13f 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -202,6 +202,25 @@ static inline TCGv_i32 get_ahp_flag(void) return ret; } +/* Clear bits within PSTATE. */ +static inline void clear_pstate_bits(uint32_t bits) +{ +TCGv_i32 p = tcg_temp_new_i32(); + +tcg_gen_ld_i32(p, cpu_env, offsetof(CPUARMState, pstate)); +tcg_gen_andi_i32(p, p, ~bits); +tcg_gen_st_i32(p, cpu_env, offsetof(CPUARMState, pstate)); +tcg_temp_free_i32(p); +} + +/* If the singlestep state is Active-not-pending, advance to Active-pending. */ +static inline void gen_ss_advance(DisasContext *s) +{ +if (s->ss_active) { +s->pstate_ss = 0; +clear_pstate_bits(PSTATE_SS); +} +} /* Vector operations shared between ARM and AArch64. */ extern const GVecGen3 bsl_op; diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c index c5721a866d..8698b4dc83 100644 --- a/target/arm/op_helper.c +++ b/target/arm/op_helper.c @@ -861,11 +861,6 @@ uint64_t HELPER(get_cp_reg64)(CPUARMState *env, void *rip) return res; } -void HELPER(clear_pstate_ss)(CPUARMState *env) -{ -env->pstate &= ~PSTATE_SS; -} - void HELPER(pre_hvc)(CPUARMState *env) { ARMCPU *cpu = arm_env_get_cpu(env); diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 13e010d27b..ba139bba26 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -421,17 +421,6 @@ static void gen_exception_bkpt_insn(DisasContext *s, int offset, s->base.is_jmp = DISAS_NORETURN; } -static void gen_ss_advance(DisasContext *s) -{ -/* If the singlestep state is Active-not-pending, advance to - * Active-pending. - */ -if (s->ss_active) { -s->pstate_ss = 0; -gen_helper_clear_pstate_ss(cpu_env); -} -} - static void gen_step_complete_exception(DisasContext *s) { /* We just completed step of an insn. Move from Active-not-pending diff --git a/target/arm/translate.c b/target/arm/translate.c index 66cf28c8cb..baf6068ec1 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -298,17 +298,6 @@ static void gen_exception(int excp, uint32_t syndrome, uint32_t target_el) tcg_temp_free_i32(tcg_excp); } -static void gen_ss_advance(DisasContext *s) -{ -/* If the singlestep state is Active-not-pending, advance to - * Active-pending. - */ -if (s->ss_active) { -s->pstate_ss = 0; -gen_helper_clear_pstate_ss(cpu_env); -} -} - static void gen_step_complete_exception(DisasContext *s) { /* We just completed step of an insn. Move from Active-not-pending -- 2.17.2
[Qemu-devel] [PATCH v2 04/26] target/arm: Add MTE_ACTIVE to tb_flags
When MTE is fully enabled, i.e. access to tags are enabled and tag checks affect the PE, then arrange to perform the check while stripping the TBI. The check is not yet implemented, just the plumbing to that point. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- v2: Clean TBI bits exactly. Fix license to lgpl 2.1. --- target/arm/cpu.h | 12 target/arm/helper-a64.h| 2 ++ target/arm/internals.h | 18 target/arm/translate.h | 2 ++ target/arm/helper.c| 51 ++ target/arm/mte_helper.c| 57 ++ target/arm/translate-a64.c | 9 +- target/arm/Makefile.objs | 2 +- 8 files changed, 140 insertions(+), 13 deletions(-) create mode 100644 target/arm/mte_helper.c diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 20be9fb53a..2776df6981 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -1215,6 +1215,7 @@ void pmu_init(ARMCPU *cpu); #define PSTATE_BTYPE (3U << 10) #define PSTATE_IL (1U << 20) #define PSTATE_SS (1U << 21) +#define PSTATE_TCO (1U << 25) #define PSTATE_V (1U << 28) #define PSTATE_C (1U << 29) #define PSTATE_Z (1U << 30) @@ -3071,6 +3072,7 @@ FIELD(TBFLAG_A64, PAUTH_ACTIVE, 8, 1) FIELD(TBFLAG_A64, BT, 9, 1) FIELD(TBFLAG_A64, BTYPE, 10, 2) FIELD(TBFLAG_A64, TBID, 12, 2) +FIELD(TBFLAG_A64, MTE_ACTIVE, 14, 1) static inline bool bswap_code(bool sctlr_b) { @@ -3361,6 +3363,16 @@ static inline bool isar_feature_aa64_bti(const ARMISARegisters *id) return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, BT) != 0; } +static inline bool isar_feature_aa64_mte_insn_reg(const ARMISARegisters *id) +{ +return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, MTE) != 0; +} + +static inline bool isar_feature_aa64_mte(const ARMISARegisters *id) +{ +return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, MTE) >= 2; +} + /* * Forward to the above feature tests given an ARMCPU pointer. */ diff --git a/target/arm/helper-a64.h b/target/arm/helper-a64.h index a915c1247f..fa4c371a47 100644 --- a/target/arm/helper-a64.h +++ b/target/arm/helper-a64.h @@ -102,3 +102,5 @@ DEF_HELPER_FLAGS_3(autda, TCG_CALL_NO_WG, i64, env, i64, i64) DEF_HELPER_FLAGS_3(autdb, TCG_CALL_NO_WG, i64, env, i64, i64) DEF_HELPER_FLAGS_2(xpaci, TCG_CALL_NO_RWG_SE, i64, env, i64) DEF_HELPER_FLAGS_2(xpacd, TCG_CALL_NO_RWG_SE, i64, env, i64) + +DEF_HELPER_FLAGS_2(mte_check, TCG_CALL_NO_WG, i64, env, i64) diff --git a/target/arm/internals.h b/target/arm/internals.h index 587a1ddf58..6c018e773c 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -983,4 +983,22 @@ static inline int exception_target_el(CPUARMState *env) return target_el; } +/* Determine if allocation tags are available. */ +static inline bool allocation_tag_access_enabled(CPUARMState *env, int el, + uint64_t sctlr) +{ +if (el < 3 +&& arm_feature(env, ARM_FEATURE_EL3) +&& !(env->cp15.scr_el3 & SCR_ATA)) { +return false; +} +if (el < 2 +&& arm_feature(env, ARM_FEATURE_EL2) +&& !(arm_hcr_el2_eff(env) & HCR_ATA)) { +return false; +} +sctlr &= (el == 0 ? SCTLR_ATA0 : SCTLR_ATA); +return sctlr != 0; +} + #endif diff --git a/target/arm/translate.h b/target/arm/translate.h index 33af50a13f..5a101e1c6d 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -70,6 +70,8 @@ typedef struct DisasContext { bool ss_same_el; /* True if v8.3-PAuth is active. */ bool pauth_active; +/* True if v8.5-MTE tag checks affect the PE. */ +bool mte_active; /* True with v8.5-BTI and SCTLR_ELx.BT* set. */ bool bt; /* diff --git a/target/arm/helper.c b/target/arm/helper.c index d4abbb5076..e73bdbf041 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -1862,6 +1862,9 @@ static void scr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) if (cpu_isar_feature(aa64_pauth, cpu)) { valid_mask |= SCR_API | SCR_APK; } +if (cpu_isar_feature(aa64_mte, cpu)) { +valid_mask |= SCR_ATA; +} /* Clear all-context RES0 bits. */ value &= valid_mask; @@ -4056,22 +4059,31 @@ static void sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri, { ARMCPU *cpu = arm_env_get_cpu(env); -if (raw_read(env, ri) == value) { -/* Skip the TLB flush if nothing actually changed; Linux likes - * to do a lot of pointless SCTLR writes. - */ -return; -} - if (arm_feature(env, ARM_FEATURE_PMSA) && !cpu->has_mpu) { /* M bit is RAZ/WI for PMSA with no MPU implemented */ value &= ~SCTLR_M; } -raw_write(env, ri, value); +if (!cpu_isar_feature(aa64_mte, cpu)) { +if (ri->opc1 == 6) { /* SCTLR_EL3 */ +value &= ~(SCTLR_ITFSB | SCTLR_TCF | SCTLR_ATA); +} else { +value &= ~(SCTLR_ITFSB | SCTLR_TCF0 | SCTLR_TCF | +
[Qemu-devel] [PATCH v2 24/26] target/arm: Add allocation tag storage for system mode
Signed-off-by: Richard Henderson --- target/arm/mte_helper.c | 96 + 1 file changed, 87 insertions(+), 9 deletions(-) diff --git a/target/arm/mte_helper.c b/target/arm/mte_helper.c index ad2902472d..3abed62018 100644 --- a/target/arm/mte_helper.c +++ b/target/arm/mte_helper.c @@ -53,19 +53,19 @@ static uint64_t strip_tbi(CPUARMState *env, uint64_t ptr) static uint8_t *allocation_tag_mem(CPUARMState *env, uint64_t ptr, bool write, uintptr_t ra) { -#ifdef CONFIG_USER_ONLY ARMCPU *cpu = arm_env_get_cpu(env); +CPUState *cs = CPU(cpu); uint64_t clean_ptr = strip_tbi(env, ptr); uint8_t *tags; uintptr_t index; -int flags; -flags = page_get_flags(clean_ptr); +#ifdef CONFIG_USER_ONLY +int flags = page_get_flags(clean_ptr); if (!(flags & PAGE_VALID) || !(flags & (write ? PAGE_WRITE : PAGE_READ))) { /* SIGSEGV */ env->exception.vaddress = ptr; -cpu_restore_state(CPU(cpu), ra, true); +cpu_restore_state(cs, ra, true); raise_exception(env, EXCP_DATA_ABORT, 0, 1); } @@ -82,16 +82,94 @@ static uint8_t *allocation_tag_mem(CPUARMState *env, uint64_t ptr, if (tags == NULL) { size_t alloc_size = TARGET_PAGE_SIZE >> (LOG2_TAG_GRANULE + 1); tags = page_alloc_target_data(clean_ptr, alloc_size); -assert(tags != NULL); +} +#else +int mmu_idx; +AddressSpace *as; +CPUTLBEntry *te; +CPUIOTLBEntry *iotlbentry; +MemoryRegionSection *section; +MemoryRegion *mr; +FlatView *fv; +hwaddr physaddr, tag_physaddr, tag_len, xlat; + +/* + * Find the TLB entry for this access. + * As a side effect, this also raises an exception for invalid access. + */ +mmu_idx = cpu_mmu_index(env, false); +index = tlb_index(env, mmu_idx, clean_ptr); +te = tlb_entry(env, mmu_idx, clean_ptr); +if (!tlb_hit(write ? tlb_addr_write(te) : te->addr_read, clean_ptr)) { +/* ??? Expose VICTIM_TLB_HIT from accel/tcg/cputlb.c. */ +tlb_fill(cs, ptr, 16, write ? MMU_DATA_STORE : MMU_DATA_LOAD, + mmu_idx, ra); +index = tlb_index(env, mmu_idx, clean_ptr); +te = tlb_entry(env, mmu_idx, clean_ptr); } +/* If the virtual page MemAttr != Tagged, nothing to do. */ +iotlbentry = &env->iotlb[mmu_idx][index]; +if (!iotlbentry->attrs.target_tlb_bit1) { +return NULL; +} + +/* If the board did not allocate tag memory, nothing to do. */ +as = cpu_get_address_space(cs, ARMASIdx_TAG); +if (!as) { +return NULL; +} + +/* Find the physical address for the virtual access. */ +section = iotlb_to_section(cs, iotlbentry->addr, iotlbentry->attrs); +physaddr = ((iotlbentry->addr & TARGET_PAGE_MASK) + clean_ptr ++ section->offset_within_address_space +- section->offset_within_region); + +/* Convert to the physical address in tag space. */ +tag_physaddr = physaddr >> (LOG2_TAG_GRANULE + 1); +tag_len = TARGET_PAGE_SIZE >> (LOG2_TAG_GRANULE + 1); + +/* + * Find the tag physical address within the tag address space. + * + * ??? Create a new mmu_idx to cache the rest of this. + * + * ??? If we were assured of exactly one block of normal ram, + * and thus exactly one block of tag ram, then we could validate + * section->mr as ram, use the section offset vs cpu->tag_memory, + * and finish with memory_region_get_ram_ptr. + */ +rcu_read_lock(); +fv = address_space_to_flatview(as); +mr = flatview_translate(fv, tag_physaddr, &xlat, &tag_len, +write, MEMTXATTRS_UNSPECIFIED); +if (!memory_access_is_direct(mr, write)) { +/* + * This would seem to imply that the guest has marked a + * virtual page as Tagged when the physical page is not RAM. + * Should this raise some sort of bus error? + */ +rcu_read_unlock(); +qemu_log_mask(LOG_GUEST_ERROR, "Tagged virtual page 0x%" PRIx64 + " maps to physical page 0x%" PRIx64 " without RAM\n", + clean_ptr, physaddr); +return NULL; +} +rcu_read_unlock(); + +/* The board should have created tag ram sized correctly. */ +assert(tag_len == TARGET_PAGE_SIZE >> (LOG2_TAG_GRANULE + 1)); + +/* FIXME: Mark the tag page dirty for migration. */ + +tags = qemu_map_ram_ptr(mr->ram_block, xlat); +#endif + +assert(tags != NULL); index = extract32(clean_ptr, LOG2_TAG_GRANULE + 1, TARGET_PAGE_BITS - LOG2_TAG_GRANULE - 1); return tags + index; -#else -/* Tag storage not implemented. */ -return NULL; -#endif } static int get_allocation_tag(CPUARMState *env, uint64_t ptr, uintptr_t ra) -- 2.17.2
[Qemu-devel] [PATCH v2 05/26] target/arm: Extract TCMA with ARMVAParameters
Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- target/arm/internals.h | 1 + target/arm/helper.c| 8 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/target/arm/internals.h b/target/arm/internals.h index 6c018e773c..2922324f63 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -959,6 +959,7 @@ typedef struct ARMVAParameters { bool tbid : 1; bool epd: 1; bool hpd: 1; +bool tcma : 1; bool using16k : 1; bool using64k : 1; } ARMVAParameters; diff --git a/target/arm/helper.c b/target/arm/helper.c index e73bdbf041..cbe3500f78 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -10447,7 +10447,7 @@ ARMVAParameters aa64_va_parameters_both(CPUARMState *env, uint64_t va, { uint64_t tcr = regime_tcr(env, mmu_idx)->raw_tcr; uint32_t el = regime_el(env, mmu_idx); -bool tbi, tbid, epd, hpd, using16k, using64k; +bool tbi, tbid, epd, hpd, tcma, using16k, using64k; int select, tsz; /* @@ -10462,11 +10462,12 @@ ARMVAParameters aa64_va_parameters_both(CPUARMState *env, uint64_t va, using16k = extract32(tcr, 15, 1); if (mmu_idx == ARMMMUIdx_S2NS) { /* VTCR_EL2 */ -tbi = tbid = hpd = false; +tbi = tbid = hpd = tcma = false; } else { tbi = extract32(tcr, 20, 1); hpd = extract32(tcr, 24, 1); tbid = extract32(tcr, 29, 1); +tcma = extract32(tcr, 30, 1); } epd = false; } else if (!select) { @@ -10477,6 +10478,7 @@ ARMVAParameters aa64_va_parameters_both(CPUARMState *env, uint64_t va, tbi = extract64(tcr, 37, 1); hpd = extract64(tcr, 41, 1); tbid = extract64(tcr, 51, 1); +tcma = extract64(tcr, 57, 1); } else { int tg = extract32(tcr, 30, 2); using16k = tg == 1; @@ -10486,6 +10488,7 @@ ARMVAParameters aa64_va_parameters_both(CPUARMState *env, uint64_t va, tbi = extract64(tcr, 38, 1); hpd = extract64(tcr, 42, 1); tbid = extract64(tcr, 52, 1); +tcma = extract64(tcr, 58, 1); } tsz = MIN(tsz, 39); /* TODO: ARMv8.4-TTST */ tsz = MAX(tsz, 16); /* TODO: ARMv8.2-LVA */ @@ -10497,6 +10500,7 @@ ARMVAParameters aa64_va_parameters_both(CPUARMState *env, uint64_t va, .tbid = tbid, .epd = epd, .hpd = hpd, +.tcma = tcma, .using16k = using16k, .using64k = using64k, }; -- 2.17.2
[Qemu-devel] [PATCH v2 13/26] target/arm: Implement the SUBP instruction
Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- v2: Fix extraction length. --- target/arm/translate-a64.c | 24 ++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 2e0d797294..3e46ee6f69 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -5132,19 +5132,39 @@ static void handle_crc32(DisasContext *s, */ static void disas_data_proc_2src(DisasContext *s, uint32_t insn) { -unsigned int sf, rm, opcode, rn, rd; +unsigned int sf, rm, opcode, rn, rd, setflag; sf = extract32(insn, 31, 1); +setflag = extract32(insn, 29, 1); rm = extract32(insn, 16, 5); opcode = extract32(insn, 10, 6); rn = extract32(insn, 5, 5); rd = extract32(insn, 0, 5); -if (extract32(insn, 29, 1)) { +if (setflag && opcode != 0) { unallocated_encoding(s); return; } switch (opcode) { +case 0: /* SUBP(S) */ +if (sf == 0 || !dc_isar_feature(aa64_mte_insn_reg, s)) { +goto do_unallocated; +} else { +TCGv_i64 tcg_n, tcg_m, tcg_d; + +tcg_n = read_cpu_reg_sp(s, rn, true); +tcg_m = read_cpu_reg_sp(s, rm, true); +tcg_gen_sextract_i64(tcg_n, tcg_n, 0, 56); +tcg_gen_sextract_i64(tcg_m, tcg_m, 0, 56); +tcg_d = cpu_reg(s, rd); + +if (setflag) { +gen_sub_CC(true, tcg_d, tcg_n, tcg_m); +} else { +tcg_gen_sub_i64(tcg_d, tcg_n, tcg_m); +} +} +break; case 2: /* UDIV */ handle_div(s, false, sf, rm, rn, rd); break; -- 2.17.2
[Qemu-devel] [PATCH v2 08/26] target/arm: Fill in helper_mte_check
Implements the rules of "PE generation of Checked and Unchecked accesses" which aren't already implied by TB_FLAGS_MTE_ACTIVE. Implements the rules of "PE handling of Tag Check Failure". Does not implement tag physical address space, so all operations reduce to unchecked so far. Signed-off-by: Richard Henderson --- v2: Fix TFSR update. --- target/arm/mte_helper.c | 94 - 1 file changed, 92 insertions(+), 2 deletions(-) diff --git a/target/arm/mte_helper.c b/target/arm/mte_helper.c index f1174d6f9f..d086925a91 100644 --- a/target/arm/mte_helper.c +++ b/target/arm/mte_helper.c @@ -25,6 +25,8 @@ #include "exec/helper-proto.h" +#if 0 +/* Don't break bisect. This will gain another user before we're done. */ static uint64_t strip_tbi(CPUARMState *env, uint64_t ptr) { /* @@ -49,9 +51,97 @@ static uint64_t strip_tbi(CPUARMState *env, uint64_t ptr) return ptr; } } +#endif + +static int get_allocation_tag(CPUARMState *env, uint64_t ptr, uintptr_t ra) +{ +/* Tag storage not implemented. */ +return -1; +} + +static int allocation_tag_from_addr(uint64_t ptr) +{ +ptr += 1ULL << 55; /* carry ptr[55] into ptr[59:56]. */ +return extract64(ptr, 56, 4); +} uint64_t HELPER(mte_check)(CPUARMState *env, uint64_t ptr) { -/* Only unchecked implemented so far. */ -return strip_tbi(env, ptr); +ARMMMUIdx mmu_idx = arm_stage1_mmu_idx(env); +ARMVAParameters param = aa64_va_parameters(env, ptr, mmu_idx, true); +int el = arm_current_el(env); +int ptr_tag, mem_tag; +uintptr_t ra = GETPC(); + +/* + * If TBI is disabled, then the access is unchecked. + * While we filtered out TBI0==0 && TBI1==0 in cpu_get_tb_cpu_state, + * we did not save separate bits for TBI0 != TBI1. + */ +if (!param.tbi) { +/* Do not ignore the top byte. */ +return ptr; +} + +/* + * If TCMA is enabled, then physical tag 0 is unchecked. + * Note the rules R0076 & R0077 are written with logical tags, + * and we need the physical tag below anyway. + */ +ptr_tag = allocation_tag_from_addr(ptr); +if (param.tcma && ptr_tag == 0) { +goto pass; +} + +/* + * If an access is made to an address that does not provide tag storage, + * the result is implementation defined (R0006). We choose to treat the + * access as unchecked. + * This is similar to MemAttr != Tagged, which are also unchecked. + */ +mem_tag = get_allocation_tag(env, ptr, ra); +if (mem_tag < 0) { +goto pass; +} + +/* If the tags do not match, the tag check operation fails. */ +if (ptr_tag != mem_tag) { +int tcf; + +if (el == 0) { +/* FIXME: ARMv8.1-VHE S2 translation regime. */ +tcf = extract64(env->cp15.sctlr_el[1], 38, 2); +} else { +tcf = extract64(env->cp15.sctlr_el[el], 40, 2); +} +if (tcf == 1) { +/* + * Tag check fail causes a synchronous exception. + * + * In restore_state_to_opc, we set the exception syndrome + * for the load or store operation. Do that first so we + * may overwrite that with the syndrome for the tag check. + */ +cpu_restore_state(ENV_GET_CPU(env), ra, true); +env->exception.vaddress = ptr; +raise_exception(env, EXCP_DATA_ABORT, +syn_data_abort_no_iss(el != 0, 0, 0, 0, 0, 0x11), +exception_target_el(env)); +} else if (tcf == 2) { +/* Tag check fail causes asynchronous flag set. */ +env->cp15.tfsr_el[el] |= 1 << param.select; +} +} + + pass: +/* + * Unchecked, tag check pass, or tag check fail does not trap. + * Ignore the top byte. + */ +if (el >= 2) { +/* FIXME: ARMv8.1-VHE S2 translation regime. */ +return extract64(ptr, 0, 56); +} else { +return sextract64(ptr, 0, 56); +} } -- 2.17.2
[Qemu-devel] [PATCH v2 21/26] target/arm: Cache the Tagged bit for a page in MemTxAttrs
This "bit" is a particular value of the page's MemAttr. Signed-off-by: Richard Henderson --- target/arm/helper.c | 25 +++-- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index a3ad5bc54e..3d7a51f8a2 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -10719,6 +10719,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, uint64_t descaddrmask; bool aarch64 = arm_el_is_aa64(env, el); bool guarded = false; +uint8_t memattr; /* TODO: * This code does not handle the different format TCR for VTCR_EL2. @@ -10949,17 +10950,21 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, txattrs->target_tlb_bit0 = true; } +if (mmu_idx == ARMMMUIdx_S2NS) { +memattr = convert_stage2_attrs(env, extract32(attrs, 0, 4)); +} else { +/* Index into MAIR registers for cache attributes */ +uint64_t mair = env->cp15.mair_el[el]; +memattr = extract64(mair, extract32(attrs, 0, 3) * 8, 8); +} + +/* When in aarch64 mode, and MTE is enabled, remember Tagged in IOTLB. */ +if (aarch64 && memattr == 0xf0 && cpu_isar_feature(aa64_mte, cpu)) { +txattrs->target_tlb_bit1 = true; +} + if (cacheattrs != NULL) { -if (mmu_idx == ARMMMUIdx_S2NS) { -cacheattrs->attrs = convert_stage2_attrs(env, - extract32(attrs, 0, 4)); -} else { -/* Index into MAIR registers for cache attributes */ -uint8_t attrindx = extract32(attrs, 0, 3); -uint64_t mair = env->cp15.mair_el[regime_el(env, mmu_idx)]; -assert(attrindx <= 7); -cacheattrs->attrs = extract64(mair, attrindx * 8, 8); -} +cacheattrs->attrs = memattr; cacheattrs->shareability = extract32(attrs, 6, 2); } -- 2.17.2
[Qemu-devel] [PATCH v2 25/26] target/arm: Enable MTE
Signed-off-by: Richard Henderson --- target/arm/cpu.c | 10 ++ target/arm/cpu64.c | 1 + 2 files changed, 11 insertions(+) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index decf95de3e..a5599ae19f 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -206,6 +206,16 @@ static void arm_cpu_reset(CPUState *s) * make no difference to the user-level emulation. */ env->cp15.tcr_el[1].raw_tcr = (3ULL << 37); +/* Enable MTE allocation tags. */ +env->cp15.hcr_el2 |= HCR_ATA; +env->cp15.scr_el3 |= SCR_ATA; +env->cp15.sctlr_el[1] |= SCTLR_ATA0; +/* Enable synchronous tag check failures. */ +env->cp15.sctlr_el[1] |= 1ull << 38; +#ifdef TARGET_AARCH64 +/* Set MTE seed to non-zero value, otherwise RandomTag fails. */ +env->cp15.rgsr_el1 = 0x123400; +#endif #else /* Reset into the highest available EL */ if (arm_feature(env, ARM_FEATURE_EL3)) { diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 53a7d92c95..7bd761b8f5 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -352,6 +352,7 @@ static void aarch64_max_initfn(Object *obj) t = cpu->isar.id_aa64pfr1; t = FIELD_DP64(t, ID_AA64PFR1, BT, 1); +t = FIELD_DP64(t, ID_AA64PFR1, MTE, 2); cpu->isar.id_aa64pfr1 = t; t = cpu->isar.id_aa64mmfr1; -- 2.17.2
[Qemu-devel] [PATCH v2 10/26] target/arm: Implement the IRG instruction
Signed-off-by: Richard Henderson --- v2: Update to 00eac5. Merge choose_random_nonexcluded_tag into helper_irg since that pseudo function no longer exists separately. --- target/arm/helper-a64.h| 1 + target/arm/mte_helper.c| 57 ++ target/arm/translate-a64.c | 7 + 3 files changed, 65 insertions(+) diff --git a/target/arm/helper-a64.h b/target/arm/helper-a64.h index fa4c371a47..7a6051fdab 100644 --- a/target/arm/helper-a64.h +++ b/target/arm/helper-a64.h @@ -104,3 +104,4 @@ DEF_HELPER_FLAGS_2(xpaci, TCG_CALL_NO_RWG_SE, i64, env, i64) DEF_HELPER_FLAGS_2(xpacd, TCG_CALL_NO_RWG_SE, i64, env, i64) DEF_HELPER_FLAGS_2(mte_check, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_3(irg, TCG_CALL_NO_RWG, i64, env, i64, i64) diff --git a/target/arm/mte_helper.c b/target/arm/mte_helper.c index d086925a91..493c2f7bb2 100644 --- a/target/arm/mte_helper.c +++ b/target/arm/mte_helper.c @@ -65,6 +65,31 @@ static int allocation_tag_from_addr(uint64_t ptr) return extract64(ptr, 56, 4); } +static int choose_nonexcluded_tag(int tag, int offset, uint16_t exclude) +{ +if (exclude == 0x) { +return 0; +} +if (offset == 0) { +while (exclude & (1 << tag)) { +tag = (tag + 1) & 15; +} +} else { +do { +do { +tag = (tag + 1) & 15; +} while (exclude & (1 << tag)); +} while (--offset > 0); +} +return tag; +} + +static uint64_t address_with_allocation_tag(uint64_t ptr, int rtag) +{ +rtag -= extract64(ptr, 55, 1); +return deposit64(ptr, 56, 4, rtag); +} + uint64_t HELPER(mte_check)(CPUARMState *env, uint64_t ptr) { ARMMMUIdx mmu_idx = arm_stage1_mmu_idx(env); @@ -145,3 +170,35 @@ uint64_t HELPER(mte_check)(CPUARMState *env, uint64_t ptr) return sextract64(ptr, 0, 56); } } + +uint64_t HELPER(irg)(CPUARMState *env, uint64_t rn, uint64_t rm) +{ +int el = arm_current_el(env); +uint64_t sctlr = arm_sctlr(env, el); +int rtag = 0; + +if (allocation_tag_access_enabled(env, el, sctlr)) { +/* + * Our IMPDEF choice for GCR_EL1.RRND==1 is to behave as if + * GCR_EL1.RRND==0, always producing deterministic results. + */ +uint16_t exclude = extract32(rm | env->cp15.gcr_el1, 0, 16); +int start = extract32(env->cp15.rgsr_el1, 0, 4); +int seed = extract32(env->cp15.rgsr_el1, 8, 16); +int offset, i; + +/* RandomTag */ +for (i = offset = 0; i < 4; ++i) { +/* NextRandomTagBit */ +int top = (extract32(seed, 5, 1) ^ extract32(seed, 3, 1) ^ + extract32(seed, 2, 1) ^ extract32(seed, 0, 1)); +seed = (top << 15) | (seed >> 1); +offset |= top << i; +} +rtag = choose_nonexcluded_tag(start, offset, exclude); + +env->cp15.rgsr_el1 = rtag | (seed << 8); +} + +return address_with_allocation_tag(rn, rtag); +} diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index d0f8c314c9..5e7d7f2d5e 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -5126,6 +5126,13 @@ static void disas_data_proc_2src(DisasContext *s, uint32_t insn) case 3: /* SDIV */ handle_div(s, true, sf, rm, rn, rd); break; +case 4: /* IRG */ +if (sf == 0 || !dc_isar_feature(aa64_mte_insn_reg, s)) { +goto do_unallocated; +} +gen_helper_irg(cpu_reg_sp(s, rd), cpu_env, + cpu_reg_sp(s, rn), cpu_reg(s, rm)); +break; case 8: /* LSLV */ handle_shift_reg(s, A64_SHIFT_TYPE_LSL, sf, rm, rn, rd); break; -- 2.17.2
[Qemu-devel] [PATCH v2 20/26] tcg: Introduce target-specific page data for user-only
At the same time, remember MAP_SHARED as PAGE_SHARED. When mapping new pages, make sure that old target-specific page data is removed. Signed-off-by: Richard Henderson --- include/exec/cpu-all.h| 10 -- accel/tcg/translate-all.c | 28 linux-user/mmap.c | 10 -- linux-user/syscall.c | 4 ++-- 4 files changed, 46 insertions(+), 6 deletions(-) diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index b16c9ec513..e88ecad0b3 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -244,10 +244,14 @@ extern intptr_t qemu_host_page_mask; #define PAGE_WRITE_ORG 0x0010 /* Invalidate the TLB entry immediately, helpful for s390x * Low-Address-Protection. Used with PAGE_WRITE in tlb_set_page_with_attrs() */ -#define PAGE_WRITE_INV 0x0040 +#define PAGE_WRITE_INV 0x0020 +/* Page is mapped shared. */ +#define PAGE_SHARED0x0040 +/* For use with page_set_flags: page is being replaced; target_data cleared. */ +#define PAGE_RESET 0x0080 #if defined(CONFIG_BSD) && defined(CONFIG_USER_ONLY) /* FIXME: Code that sets/uses this is broken and needs to go away. */ -#define PAGE_RESERVED 0x0020 +#define PAGE_RESERVED 0x0100 #endif #if defined(CONFIG_USER_ONLY) @@ -260,6 +264,8 @@ int walk_memory_regions(void *, walk_memory_regions_fn); int page_get_flags(target_ulong address); void page_set_flags(target_ulong start, target_ulong end, int flags); int page_check_range(target_ulong start, target_ulong len, int flags); +void *page_get_target_data(target_ulong address); +void *page_alloc_target_data(target_ulong address, size_t size); #endif CPUArchState *cpu_copy(CPUArchState *env); diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 8f593b926f..6cc266428d 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -107,6 +107,7 @@ typedef struct PageDesc { unsigned int code_write_count; #else unsigned long flags; +void *target_data; #endif #ifndef CONFIG_USER_ONLY QemuSpin lock; @@ -2476,6 +2477,7 @@ int page_get_flags(target_ulong address) void page_set_flags(target_ulong start, target_ulong end, int flags) { target_ulong addr, len; +bool reset_target_data; /* This function should never be called with addresses outside the guest address space. If this assert fires, it probably indicates @@ -2492,6 +2494,8 @@ void page_set_flags(target_ulong start, target_ulong end, int flags) if (flags & PAGE_WRITE) { flags |= PAGE_WRITE_ORG; } +reset_target_data = !(flags & PAGE_VALID) || (flags & PAGE_RESET); +flags &= ~PAGE_RESET; for (addr = start, len = end - start; len != 0; @@ -2505,10 +2509,34 @@ void page_set_flags(target_ulong start, target_ulong end, int flags) p->first_tb) { tb_invalidate_phys_page(addr, 0); } +if (reset_target_data && p->target_data) { +g_free(p->target_data); +p->target_data = NULL; +} p->flags = flags; } } +void *page_get_target_data(target_ulong address) +{ +PageDesc *p = page_find(address >> TARGET_PAGE_BITS); +return p ? p->target_data : NULL; +} + +void *page_alloc_target_data(target_ulong address, size_t size) +{ +PageDesc *p = page_find(address >> TARGET_PAGE_BITS); +void *ret = NULL; + +if (p) { +ret = p->target_data; +if (!ret && (p->flags & PAGE_VALID)) { +p->target_data = ret = g_malloc0(size); +} +} +return ret; +} + int page_check_range(target_ulong start, target_ulong len, int flags) { PageDesc *p; diff --git a/linux-user/mmap.c b/linux-user/mmap.c index e0249efe4f..0b786b87a2 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -562,7 +562,11 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, } } the_end1: -page_set_flags(start, start + len, prot | PAGE_VALID); +if ((flags & MAP_TYPE) == MAP_SHARED) { +prot |= PAGE_SHARED; +} +prot |= PAGE_RESET | PAGE_VALID; +page_set_flags(start, start + len, prot); the_end: #ifdef DEBUG_MMAP printf("ret=0x" TARGET_ABI_FMT_lx "\n", start); @@ -754,9 +758,11 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size, new_addr = -1; } else { new_addr = h2g(host_addr); +/* FIXME: Move page flags (and target_data?) for each page. */ prot = page_get_flags(old_addr); page_set_flags(old_addr, old_addr + old_size, 0); -page_set_flags(new_addr, new_addr + new_size, prot | PAGE_VALID); +page_set_flags(new_addr, new_addr + new_size, + prot | PAGE_VALID | PAGE_RESET); } tb_invalidate_phys_range(new_addr, new_addr + new_size); mmap_unlock(); diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 5bbb72f3d5..9d89b40321 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -3884,8 +3884
[Qemu-devel] [PATCH v2 17/26] target/arm: Implement the access tag cache flushes
Like the regular data cache flushes, these are nops within qemu. Signed-off-by: Richard Henderson --- target/arm/helper.c | 48 + 1 file changed, 48 insertions(+) diff --git a/target/arm/helper.c b/target/arm/helper.c index 2d9c070bb3..74bace81e4 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -5772,6 +5772,54 @@ static const ARMCPRegInfo mte_reginfo[] = { .opc0 = 3, .opc1 = 3, .crn = 4, .crm = 2, .opc2 = 7, .type = ARM_CP_NO_RAW, .access = PL0_RW, .readfn = tco_read, .writefn = tco_write }, +{ .name = "IGVAC", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 6, .opc2 = 3, + .type = ARM_CP_NOP, .access = PL1_W }, +{ .name = "IGSW", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 6, .opc2 = 4, + .type = ARM_CP_NOP, .access = PL1_W }, +{ .name = "CGSW", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 10, .opc2 = 4, + .type = ARM_CP_NOP, .access = PL1_W }, +{ .name = "CIGSW", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 14, .opc2 = 4, + .type = ARM_CP_NOP, .access = PL1_W }, +{ .name = "CGVAC", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 10, .opc2 = 3, + .type = ARM_CP_NOP, .access = PL1_W }, +{ .name = "CGVAP", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 12, .opc2 = 3, + .type = ARM_CP_NOP, .access = PL1_W }, +{ .name = "CGVADP", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 13, .opc2 = 3, + .type = ARM_CP_NOP, .access = PL1_W }, +{ .name = "CIGVAC", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 14, .opc2 = 3, + .type = ARM_CP_NOP, .access = PL1_W }, +{ .name = "IGDVAC", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 6, .opc2 = 5, + .type = ARM_CP_NOP, .access = PL1_W }, +{ .name = "IGDSW", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 6, .opc2 = 6, + .type = ARM_CP_NOP, .access = PL1_W }, +{ .name = "CGDSW", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 10, .opc2 = 6, + .type = ARM_CP_NOP, .access = PL1_W }, +{ .name = "CIGDSW", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 14, .opc2 = 6, + .type = ARM_CP_NOP, .access = PL1_W }, +{ .name = "CGDVAC", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 10, .opc2 = 5, + .type = ARM_CP_NOP, .access = PL1_W }, +{ .name = "CGDVAP", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 12, .opc2 = 5, + .type = ARM_CP_NOP, .access = PL1_W }, +{ .name = "CGDVADP", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 13, .opc2 = 5, + .type = ARM_CP_NOP, .access = PL1_W }, +{ .name = "CIGDVAC", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 14, .opc2 = 5, + .type = ARM_CP_NOP, .access = PL1_W }, REGINFO_SENTINEL }; #endif -- 2.17.2
[Qemu-devel] [PATCH v2 11/26] target/arm: Implement ADDG, SUBG instructions
Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- v2: Shift offset in translate; use extract32. --- target/arm/helper-a64.h| 2 ++ target/arm/internals.h | 3 ++ target/arm/mte_helper.c| 32 + target/arm/translate-a64.c | 71 ++ 4 files changed, 85 insertions(+), 23 deletions(-) diff --git a/target/arm/helper-a64.h b/target/arm/helper-a64.h index 7a6051fdab..47577207b2 100644 --- a/target/arm/helper-a64.h +++ b/target/arm/helper-a64.h @@ -105,3 +105,5 @@ DEF_HELPER_FLAGS_2(xpacd, TCG_CALL_NO_RWG_SE, i64, env, i64) DEF_HELPER_FLAGS_2(mte_check, TCG_CALL_NO_WG, i64, env, i64) DEF_HELPER_FLAGS_3(irg, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_4(addg, TCG_CALL_NO_RWG_SE, i64, env, i64, i32, i32) +DEF_HELPER_FLAGS_4(subg, TCG_CALL_NO_RWG_SE, i64, env, i64, i32, i32) diff --git a/target/arm/internals.h b/target/arm/internals.h index 2922324f63..a5a249b001 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -1002,4 +1002,7 @@ static inline bool allocation_tag_access_enabled(CPUARMState *env, int el, return sctlr != 0; } +/* We associate one allocation tag per 16 bytes, the minimum. */ +#define LOG2_TAG_GRANULE 4 + #endif diff --git a/target/arm/mte_helper.c b/target/arm/mte_helper.c index 493c2f7bb2..3eb5d622fc 100644 --- a/target/arm/mte_helper.c +++ b/target/arm/mte_helper.c @@ -202,3 +202,35 @@ uint64_t HELPER(irg)(CPUARMState *env, uint64_t rn, uint64_t rm) return address_with_allocation_tag(rn, rtag); } + +uint64_t HELPER(addg)(CPUARMState *env, uint64_t ptr, + uint32_t offset, uint32_t tag_offset) +{ +int el = arm_current_el(env); +uint64_t sctlr = arm_sctlr(env, el); +int rtag = 0; + +if (allocation_tag_access_enabled(env, el, sctlr)) { +int start_tag = allocation_tag_from_addr(ptr); +uint16_t exclude = extract32(env->cp15.gcr_el1, 0, 16); +rtag = choose_nonexcluded_tag(start_tag, tag_offset, exclude); +} + +return address_with_allocation_tag(ptr + offset, rtag); +} + +uint64_t HELPER(subg)(CPUARMState *env, uint64_t ptr, + uint32_t offset, uint32_t tag_offset) +{ +int el = arm_current_el(env); +uint64_t sctlr = arm_sctlr(env, el); +int rtag = 0; + +if (allocation_tag_access_enabled(env, el, sctlr)) { +int start_tag = allocation_tag_from_addr(ptr); +uint16_t exclude = extract32(env->cp15.gcr_el1, 0, 16); +rtag = choose_nonexcluded_tag(start_tag, tag_offset, exclude); +} + +return address_with_allocation_tag(ptr - offset, rtag); +} diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 5e7d7f2d5e..3d71a9701f 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -3672,7 +3672,9 @@ static void disas_pc_rel_adr(DisasContext *s, uint32_t insn) *sf: 0 -> 32bit, 1 -> 64bit *op: 0 -> add , 1 -> sub * S: 1 -> set flags - * shift: 00 -> LSL imm by 0, 01 -> LSL imm by 12 + * shift: 00 -> LSL imm by 0, + *01 -> LSL imm by 12 + *10 -> ADDG, SUBG */ static void disas_add_sub_imm(DisasContext *s, uint32_t insn) { @@ -3683,10 +3685,10 @@ static void disas_add_sub_imm(DisasContext *s, uint32_t insn) bool setflags = extract32(insn, 29, 1); bool sub_op = extract32(insn, 30, 1); bool is_64bit = extract32(insn, 31, 1); +bool is_tag = false; TCGv_i64 tcg_rn = cpu_reg_sp(s, rn); TCGv_i64 tcg_rd = setflags ? cpu_reg(s, rd) : cpu_reg_sp(s, rd); -TCGv_i64 tcg_result; switch (shift) { case 0x0: @@ -3694,35 +3696,58 @@ static void disas_add_sub_imm(DisasContext *s, uint32_t insn) case 0x1: imm <<= 12; break; +case 0x2: +/* ADDG, SUBG */ +if (!is_64bit || setflags || (imm & 0x30) || +!dc_isar_feature(aa64_mte_insn_reg, s)) { +goto do_unallocated; +} +is_tag = true; +break; default: +do_unallocated: unallocated_encoding(s); return; } -tcg_result = tcg_temp_new_i64(); -if (!setflags) { -if (sub_op) { -tcg_gen_subi_i64(tcg_result, tcg_rn, imm); -} else { -tcg_gen_addi_i64(tcg_result, tcg_rn, imm); -} -} else { -TCGv_i64 tcg_imm = tcg_const_i64(imm); -if (sub_op) { -gen_sub_CC(is_64bit, tcg_result, tcg_rn, tcg_imm); -} else { -gen_add_CC(is_64bit, tcg_result, tcg_rn, tcg_imm); -} -tcg_temp_free_i64(tcg_imm); -} +if (is_tag) { +TCGv_i32 tag_offset = tcg_const_i32(imm & 15); +TCGv_i32 offset = tcg_const_i32((imm >> 6) << LOG2_TAG_GRANULE); -if (is_64bit) { -tcg_gen_mov_i64(tcg_rd, tcg_result); +if (sub_op) { +gen_helper_subg(tcg_rd, cpu_env, tcg_rn, offset, tag_offset); +} else { +gen_helper_addg(tcg_rd, cpu_env, tcg_rn, o
[Qemu-devel] [PATCH v2 22/26] target/arm: Create tagged ram when MTE is enabled
Signed-off-by: Richard Henderson --- target/arm/cpu.h | 4 hw/arm/virt.c| 33 + target/arm/cpu.c | 21 ++--- 3 files changed, 55 insertions(+), 3 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index ca32939483..2626af4a9c 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -768,6 +768,9 @@ struct ARMCPU { /* MemoryRegion to use for secure physical accesses */ MemoryRegion *secure_memory; +/* MemoryRegion to use for allocation tag accesses */ +MemoryRegion *tag_memory; + /* For v8M, pointer to the IDAU interface provided by board/SoC */ Object *idau; @@ -2850,6 +2853,7 @@ int cpu_mmu_index(CPUARMState *env, bool ifetch); typedef enum ARMASIdx { ARMASIdx_NS = 0, ARMASIdx_S = 1, +ARMASIdx_TAG = 2, } ARMASIdx; /* Return the Exception Level targeted by debug exceptions. */ diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 99c2b6e60d..dccd1345a1 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -1260,6 +1260,21 @@ static void create_secure_ram(VirtMachineState *vms, g_free(nodename); } +static void create_tag_ram(VirtMachineState *vms, MachineState *machine, + MemoryRegion *tag_sysmem) +{ +MemoryRegion *tagram = g_new(MemoryRegion, 1); +hwaddr base = vms->memmap[VIRT_MEM].base / 32; +hwaddr size = machine->ram_size / 32; + +memory_region_init_ram(tagram, NULL, "mach-virt.tag", size, &error_fatal); +memory_region_add_subregion(tag_sysmem, base, tagram); + +/* ??? Do we really need an fdt entry, or is MemTag enabled sufficient. */ +/* ??? We appear to need secure tag mem to go with secure mem. */ +/* ??? Does that imply we need a fourth address space? */ +} + static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size) { const VirtMachineState *board = container_of(binfo, VirtMachineState, @@ -1362,6 +1377,7 @@ static void machvirt_init(MachineState *machine) qemu_irq pic[NUM_IRQS]; MemoryRegion *sysmem = get_system_memory(); MemoryRegion *secure_sysmem = NULL; +MemoryRegion *tag_sysmem = NULL; int n, virt_max_cpus; MemoryRegion *ram = g_new(MemoryRegion, 1); bool firmware_loaded = bios_name || drive_get(IF_PFLASH, 0, 0); @@ -1518,6 +1534,20 @@ static void machvirt_init(MachineState *machine) "secure-memory", &error_abort); } +/* + * The cpu adds the property iff MemTag is supported. + * If it is, we must allocate the ram to back that up. + */ +if (object_property_find(cpuobj, "tag-memory", NULL)) { +if (!tag_sysmem) { +tag_sysmem = g_new(MemoryRegion, 1); +memory_region_init(tag_sysmem, OBJECT(machine), + "tag-memory", UINT64_MAX / 32); +} +object_property_set_link(cpuobj, OBJECT(tag_sysmem), + "tag-memory", &error_abort); +} + object_property_set_bool(cpuobj, true, "realized", &error_fatal); object_unref(cpuobj); } @@ -1540,6 +1570,9 @@ static void machvirt_init(MachineState *machine) create_secure_ram(vms, secure_sysmem); create_uart(vms, pic, VIRT_SECURE_UART, secure_sysmem, serial_hd(1)); } +if (tag_sysmem) { +create_tag_ram(vms, machine, tag_sysmem); +} vms->highmem_ecam &= vms->highmem && (!firmware_loaded || aarch64); diff --git a/target/arm/cpu.c b/target/arm/cpu.c index edf6e0e1f1..decf95de3e 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -851,6 +851,18 @@ void arm_cpu_post_init(Object *obj) qdev_property_add_static(DEVICE(obj), &arm_cpu_cfgend_property, &error_abort); + +#ifndef CONFIG_USER_ONLY +if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64) && +cpu_isar_feature(aa64_mte, cpu)) { +object_property_add_link(obj, "tag-memory", + TYPE_MEMORY_REGION, + (Object **)&cpu->tag_memory, + qdev_prop_allow_set_link_before_realize, + OBJ_PROP_LINK_STRONG, + &error_abort); +} +#endif } static void arm_cpu_finalizefn(Object *obj) @@ -1164,16 +1176,19 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) init_cpreg_list(cpu); #ifndef CONFIG_USER_ONLY +cs->num_ases = 1; if (cpu->has_el3 || arm_feature(env, ARM_FEATURE_M_SECURITY)) { cs->num_ases = 2; - if (!cpu->secure_memory) { cpu->secure_memory = cs->memory; } cpu_address_space_init(cs, ARMASIdx_S, "cpu-secure-memory", cpu->secure_memory); -} else { -cs->num_ases = 1; +} +if (cpu->tag_memory != NULL) { +cs->num_ases = 3; +cpu_address_space_ini
[Qemu-devel] [PATCH v2 12/26] target/arm: Implement the GMI instruction
Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- target/arm/helper-a64.h| 1 + target/arm/mte_helper.c| 6 ++ target/arm/translate-a64.c | 6 ++ 3 files changed, 13 insertions(+) diff --git a/target/arm/helper-a64.h b/target/arm/helper-a64.h index 47577207b2..ef340cb6f9 100644 --- a/target/arm/helper-a64.h +++ b/target/arm/helper-a64.h @@ -107,3 +107,4 @@ DEF_HELPER_FLAGS_2(mte_check, TCG_CALL_NO_WG, i64, env, i64) DEF_HELPER_FLAGS_3(irg, TCG_CALL_NO_RWG, i64, env, i64, i64) DEF_HELPER_FLAGS_4(addg, TCG_CALL_NO_RWG_SE, i64, env, i64, i32, i32) DEF_HELPER_FLAGS_4(subg, TCG_CALL_NO_RWG_SE, i64, env, i64, i32, i32) +DEF_HELPER_FLAGS_2(gmi, TCG_CALL_NO_RWG_SE, i64, i64, i64) diff --git a/target/arm/mte_helper.c b/target/arm/mte_helper.c index 3eb5d622fc..fc9e172c95 100644 --- a/target/arm/mte_helper.c +++ b/target/arm/mte_helper.c @@ -234,3 +234,9 @@ uint64_t HELPER(subg)(CPUARMState *env, uint64_t ptr, return address_with_allocation_tag(ptr - offset, rtag); } + +uint64_t HELPER(gmi)(uint64_t ptr, uint64_t mask) +{ +int tag = allocation_tag_from_addr(ptr); +return mask | (1ULL << tag); +} diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 3d71a9701f..2e0d797294 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -5158,6 +5158,12 @@ static void disas_data_proc_2src(DisasContext *s, uint32_t insn) gen_helper_irg(cpu_reg_sp(s, rd), cpu_env, cpu_reg_sp(s, rn), cpu_reg(s, rm)); break; +case 5: /* GMI */ +if (sf == 0 || !dc_isar_feature(aa64_mte_insn_reg, s)) { +goto do_unallocated; +} +gen_helper_gmi(cpu_reg(s, rd), cpu_reg_sp(s, rn), cpu_reg(s, rm)); +break; case 8: /* LSLV */ handle_shift_reg(s, A64_SHIFT_TYPE_LSL, sf, rm, rn, rd); break; -- 2.17.2
[Qemu-devel] [PATCH v2 19/26] target/arm: Set PSTATE.TCO on exception entry
R0085 specifies that exception handlers begin with tag checks overridden. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- v2: Only set if MTE feature present. --- target/arm/helper.c | 7 ++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 9fac3628e5..a3ad5bc54e 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -9455,6 +9455,7 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs) target_ulong addr = env->cp15.vbar_el[new_el]; unsigned int new_mode = aarch64_pstate_mode(new_el, true); unsigned int cur_el = arm_current_el(env); +unsigned int new_pstate; /* * Note that new_el can never be 0. If cur_el is 0, then @@ -9548,7 +9549,11 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs) qemu_log_mask(CPU_LOG_INT, "...with ELR 0x%" PRIx64 "\n", env->elr_el[new_el]); -pstate_write(env, PSTATE_DAIF | new_mode); +new_pstate = new_mode | PSTATE_DAIF; +if (cpu_isar_feature(aa64_mte, cpu)) { +new_pstate |= PSTATE_TCO; +} +pstate_write(env, new_pstate); env->aarch64 = 1; aarch64_restore_sp(env, new_el); -- 2.17.2
[Qemu-devel] [PATCH v2 15/26] target/arm: Implement LDG, STG, ST2G instructions
Signed-off-by: Richard Henderson --- v2: Split out allocation_tag_mem. Handle atomicity of stores. --- target/arm/helper-a64.h| 5 ++ target/arm/mte_helper.c| 152 - target/arm/translate-a64.c | 114 3 files changed, 268 insertions(+), 3 deletions(-) diff --git a/target/arm/helper-a64.h b/target/arm/helper-a64.h index ef340cb6f9..a00364fb4c 100644 --- a/target/arm/helper-a64.h +++ b/target/arm/helper-a64.h @@ -108,3 +108,8 @@ DEF_HELPER_FLAGS_3(irg, TCG_CALL_NO_RWG, i64, env, i64, i64) DEF_HELPER_FLAGS_4(addg, TCG_CALL_NO_RWG_SE, i64, env, i64, i32, i32) DEF_HELPER_FLAGS_4(subg, TCG_CALL_NO_RWG_SE, i64, env, i64, i32, i32) DEF_HELPER_FLAGS_2(gmi, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(ldg, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_2(stg, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_2(st2g, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_2(stg_parallel, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_2(st2g_parallel, TCG_CALL_NO_WG, i64, env, i64) diff --git a/target/arm/mte_helper.c b/target/arm/mte_helper.c index fc9e172c95..13befdbf86 100644 --- a/target/arm/mte_helper.c +++ b/target/arm/mte_helper.c @@ -25,8 +25,6 @@ #include "exec/helper-proto.h" -#if 0 -/* Don't break bisect. This will gain another user before we're done. */ static uint64_t strip_tbi(CPUARMState *env, uint64_t ptr) { /* @@ -51,10 +49,22 @@ static uint64_t strip_tbi(CPUARMState *env, uint64_t ptr) return ptr; } } -#endif + +static uint8_t *allocation_tag_mem(CPUARMState *env, uint64_t ptr, + bool write, uintptr_t ra) +{ +/* Tag storage not implemented. */ +return NULL; +} static int get_allocation_tag(CPUARMState *env, uint64_t ptr, uintptr_t ra) { +uint8_t *mem = allocation_tag_mem(env, ptr, false, ra); + +if (mem) { +int ofs = extract32(ptr, LOG2_TAG_GRANULE, 1) * 4; +return extract32(atomic_read(mem), ofs, 4); +} /* Tag storage not implemented. */ return -1; } @@ -240,3 +250,139 @@ uint64_t HELPER(gmi)(uint64_t ptr, uint64_t mask) int tag = allocation_tag_from_addr(ptr); return mask | (1ULL << tag); } + +uint64_t HELPER(ldg)(CPUARMState *env, uint64_t ptr) +{ +int el = arm_current_el(env); +uint64_t sctlr = arm_sctlr(env, el); +int rtag; + +/* Trap if accessing an invalid page. */ +rtag = get_allocation_tag(env, ptr, GETPC()); + +/* + * The tag is squashed to zero if the page does not support tags, + * or if the OS is denying access to the tags. + */ +if (rtag < 0 || !allocation_tag_access_enabled(env, el, sctlr)) { +rtag = 0; +} + +return address_with_allocation_tag(ptr, rtag); +} + +static void check_tag_aligned(CPUARMState *env, uint64_t ptr, uintptr_t ra) +{ +if (unlikely(ptr & MAKE_64BIT_MASK(0, LOG2_TAG_GRANULE))) { +arm_cpu_do_unaligned_access(ENV_GET_CPU(env), ptr, MMU_DATA_STORE, +cpu_mmu_index(env, false), ra); +g_assert_not_reached(); +} +} + +/* For use in a non-parallel context, store to the given nibble. */ +static void store_tag1(uint64_t ptr, uint8_t *mem, int tag) +{ +int ofs = extract32(ptr, LOG2_TAG_GRANULE, 1) * 4; +uint8_t old = atomic_read(mem); +uint8_t new = deposit32(old, ofs, 4, tag); + +atomic_set(mem, new); +} + +/* For use in a parallel context, atomically store to the given nibble. */ +static void store_tag1_parallel(uint64_t ptr, uint8_t *mem, int tag) +{ +int ofs = extract32(ptr, LOG2_TAG_GRANULE, 1) * 4; +uint8_t old = atomic_read(mem); + +while (1) { +uint8_t new = deposit32(old, ofs, 4, tag); +uint8_t cmp = atomic_cmpxchg(mem, old, new); +if (likely(cmp == old)) { +return; +} +old = cmp; +} +} + +static uint64_t do_stg(CPUARMState *env, uint64_t ptr, uintptr_t ra, + void (*store1)(uint64_t, uint8_t *, int)) +{ +int el = arm_current_el(env); +uint64_t sctlr = arm_sctlr(env, el); +uint8_t *mem; + +check_tag_aligned(env, ptr, ra); + +/* Trap if accessing an invalid page. */ +mem = allocation_tag_mem(env, ptr, true, ra); + +/* Store if page supports tags and access is enabled. */ +if (mem && allocation_tag_access_enabled(env, el, sctlr)) { +store1(ptr, mem, allocation_tag_from_addr(ptr)); +} + +/* Clean the pointer for use by stzg. */ +return strip_tbi(env, ptr); +} + +uint64_t HELPER(stg)(CPUARMState *env, uint64_t ptr) +{ +return do_stg(env, ptr, GETPC(), store_tag1); +} + +uint64_t HELPER(stg_parallel)(CPUARMState *env, uint64_t ptr) +{ +return do_stg(env, ptr, GETPC(), store_tag1_parallel); +} + +static uint64_t do_st2g(CPUARMState *env, uint64_t ptr1, uintptr_t ra, +void (*store1)(uint64_t, uint8_t *, int)) +{ +int el = arm_current_el(env); +uint64_t
[Qemu-devel] [PATCH v2 16/26] target/arm: Implement the STGP instruction
Signed-off-by: Richard Henderson --- target/arm/translate-a64.c | 18 -- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 539c25a80b..9bd68d522c 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -2701,7 +2701,7 @@ static void disas_ld_lit(DisasContext *s, uint32_t insn) * +-+---+---+---+---+---+---+---+--+--+ * * opc: LDP/STP/LDNP/STNP00 -> 32 bit, 10 -> 64 bit - * LDPSW01 + * LDPSW/STGP 01 * LDP/STP/LDNP/STNP (SIMD) 00 -> 32 bit, 01 -> 64 bit, 10 -> 128 bit * V: 0 -> GPR, 1 -> Vector * idx: 00 -> signed offset with non-temporal hint, 01 -> post-index, @@ -2726,6 +2726,7 @@ static void disas_ldst_pair(DisasContext *s, uint32_t insn) bool is_signed = false; bool postindex = false; bool wback = false; +bool set_tag = false; TCGv_i64 clean_addr, dirty_addr; @@ -2738,6 +2739,14 @@ static void disas_ldst_pair(DisasContext *s, uint32_t insn) if (is_vector) { size = 2 + opc; +} else if (opc == 1 && !is_load) { +/* STGP */ +if (!dc_isar_feature(aa64_mte_insn_reg, s) || index == 0) { +unallocated_encoding(s); +return; +} +size = 3; +set_tag = true; } else { size = 2 + extract32(opc, 1, 1); is_signed = extract32(opc, 0, 1); @@ -2788,7 +2797,12 @@ static void disas_ldst_pair(DisasContext *s, uint32_t insn) if (!postindex) { tcg_gen_addi_i64(dirty_addr, dirty_addr, offset); } -clean_addr = clean_data_tbi(s, dirty_addr, wback || rn != 31); +if (set_tag) { +clean_addr = new_tmp_a64(s); +gen_helper_stg(clean_addr, cpu_env, dirty_addr); +} else { +clean_addr = clean_data_tbi(s, dirty_addr, wback || rn != 31); +} if (is_vector) { if (is_load) { -- 2.17.2
[Qemu-devel] [PATCH v2 23/26] target/arm: Add allocation tag storage for user mode
Control this with x-tagged-pages, which is off by default. The limitation to non-shared pages is not part of a future kernel API, but a limitation of linux-user not being able to map virtual pages back to physical pages. Signed-off-by: Richard Henderson --- v2: Add the x-tagged-pages cpu property --- target/arm/cpu.h| 1 + target/arm/cpu64.c | 18 ++ target/arm/mte_helper.c | 37 + 3 files changed, 56 insertions(+) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 2626af4a9c..ec5ddfbacc 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -910,6 +910,7 @@ struct ARMCPU { #ifdef CONFIG_USER_ONLY bool guarded_pages; +bool tagged_pages; #endif QLIST_HEAD(, ARMELChangeHook) pre_el_change_hooks; diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index c5675fe7d1..53a7d92c95 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -293,6 +293,18 @@ static void aarch64_cpu_set_guarded_pages(Object *obj, bool val, Error **errp) ARMCPU *cpu = ARM_CPU(obj); cpu->guarded_pages = val; } + +static bool aarch64_cpu_get_tagged_pages(Object *obj, Error **errp) +{ +ARMCPU *cpu = ARM_CPU(obj); +return cpu->tagged_pages; +} + +static void aarch64_cpu_set_tagged_pages(Object *obj, bool val, Error **errp) +{ +ARMCPU *cpu = ARM_CPU(obj); +cpu->tagged_pages = val; +} #endif /* -cpu max: if KVM is enabled, like -cpu host (best possible with this host); @@ -380,6 +392,12 @@ static void aarch64_max_initfn(Object *obj) aarch64_cpu_set_guarded_pages, NULL); object_property_set_description(obj, "x-guarded-pages", "Set on/off GuardPage bit for all pages", NULL); + +object_property_add_bool(obj, "x-tagged-pages", + aarch64_cpu_get_tagged_pages, + aarch64_cpu_set_tagged_pages, NULL); +object_property_set_description(obj, "x-tagged-pages", +"Set on/off MemAttr Tagged for all pages", NULL); #endif cpu->sve_max_vq = ARM_MAX_VQ; diff --git a/target/arm/mte_helper.c b/target/arm/mte_helper.c index 93f7cccee2..ad2902472d 100644 --- a/target/arm/mte_helper.c +++ b/target/arm/mte_helper.c @@ -53,8 +53,45 @@ static uint64_t strip_tbi(CPUARMState *env, uint64_t ptr) static uint8_t *allocation_tag_mem(CPUARMState *env, uint64_t ptr, bool write, uintptr_t ra) { +#ifdef CONFIG_USER_ONLY +ARMCPU *cpu = arm_env_get_cpu(env); +uint64_t clean_ptr = strip_tbi(env, ptr); +uint8_t *tags; +uintptr_t index; +int flags; + +flags = page_get_flags(clean_ptr); + +if (!(flags & PAGE_VALID) || !(flags & (write ? PAGE_WRITE : PAGE_READ))) { +/* SIGSEGV */ +env->exception.vaddress = ptr; +cpu_restore_state(CPU(cpu), ra, true); +raise_exception(env, EXCP_DATA_ABORT, 0, 1); +} + +if (!cpu->tagged_pages) { +/* Tag storage is disabled. */ +return NULL; +} +if (flags & PAGE_SHARED) { +/* There may be multiple mappings; pretend not implemented. */ +return NULL; +} + +tags = page_get_target_data(clean_ptr); +if (tags == NULL) { +size_t alloc_size = TARGET_PAGE_SIZE >> (LOG2_TAG_GRANULE + 1); +tags = page_alloc_target_data(clean_ptr, alloc_size); +assert(tags != NULL); +} + +index = extract32(clean_ptr, LOG2_TAG_GRANULE + 1, + TARGET_PAGE_BITS - LOG2_TAG_GRANULE - 1); +return tags + index; +#else /* Tag storage not implemented. */ return NULL; +#endif } static int get_allocation_tag(CPUARMState *env, uint64_t ptr, uintptr_t ra) -- 2.17.2
[Qemu-devel] [PATCH v2 18/26] target/arm: Implement data cache set allocation tags
This is DC GVA and DC GZVA. Signed-off-by: Richard Henderson --- v2: Use allocation_tag_mem + memset. --- target/arm/cpu.h | 4 +++- target/arm/helper-a64.h| 1 + target/arm/helper.c| 16 target/arm/mte_helper.c| 26 ++ target/arm/translate-a64.c | 9 + 5 files changed, 55 insertions(+), 1 deletion(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 74633a7a78..ca32939483 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -2160,7 +2160,9 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid) #define ARM_CP_NZCV (ARM_CP_SPECIAL | 0x0300) #define ARM_CP_CURRENTEL (ARM_CP_SPECIAL | 0x0400) #define ARM_CP_DC_ZVA(ARM_CP_SPECIAL | 0x0500) -#define ARM_LAST_SPECIAL ARM_CP_DC_ZVA +#define ARM_CP_DC_GVA(ARM_CP_SPECIAL | 0x0600) +#define ARM_CP_DC_GZVA (ARM_CP_SPECIAL | 0x0700) +#define ARM_LAST_SPECIAL ARM_CP_DC_GZVA #define ARM_CP_FPU 0x1000 #define ARM_CP_SVE 0x2000 #define ARM_CP_NO_GDB0x4000 diff --git a/target/arm/helper-a64.h b/target/arm/helper-a64.h index a00364fb4c..4ad900d36e 100644 --- a/target/arm/helper-a64.h +++ b/target/arm/helper-a64.h @@ -113,3 +113,4 @@ DEF_HELPER_FLAGS_2(stg, TCG_CALL_NO_WG, i64, env, i64) DEF_HELPER_FLAGS_2(st2g, TCG_CALL_NO_WG, i64, env, i64) DEF_HELPER_FLAGS_2(stg_parallel, TCG_CALL_NO_WG, i64, env, i64) DEF_HELPER_FLAGS_2(st2g_parallel, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_2(dc_gva, TCG_CALL_NO_RWG, void, env, i64) diff --git a/target/arm/helper.c b/target/arm/helper.c index 74bace81e4..9fac3628e5 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -5820,6 +5820,22 @@ static const ARMCPRegInfo mte_reginfo[] = { { .name = "CIGDVAC", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 14, .opc2 = 5, .type = ARM_CP_NOP, .access = PL1_W }, +{ .name = "GVA", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 4, .opc2 = 3, + .access = PL0_W, .type = ARM_CP_DC_GVA, +#ifndef CONFIG_USER_ONLY + /* Avoid overhead of an access check that always passes in user-mode */ + .accessfn = aa64_zva_access, +#endif +}, +{ .name = "GZVA", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 4, .opc2 = 4, + .access = PL0_W, .type = ARM_CP_DC_GZVA, +#ifndef CONFIG_USER_ONLY + /* Avoid overhead of an access check that always passes in user-mode */ + .accessfn = aa64_zva_access, +#endif +}, REGINFO_SENTINEL }; #endif diff --git a/target/arm/mte_helper.c b/target/arm/mte_helper.c index 13befdbf86..93f7cccee2 100644 --- a/target/arm/mte_helper.c +++ b/target/arm/mte_helper.c @@ -386,3 +386,29 @@ uint64_t HELPER(st2g_parallel)(CPUARMState *env, uint64_t ptr) { return do_st2g(env, ptr, GETPC(), store_tag1_parallel); } + +void HELPER(dc_gva)(CPUARMState *env, uint64_t ptr) +{ +ARMCPU *cpu = arm_env_get_cpu(env); +int el = arm_current_el(env); +uint64_t sctlr = arm_sctlr(env, el); +size_t blocklen = 4 << cpu->dcz_blocksize; +uint8_t *mem; +int rtag; + +ptr = QEMU_ALIGN_DOWN(ptr, blocklen); + +/* Trap if accessing an invalid page. */ +mem = allocation_tag_mem(env, ptr, true, GETPC()); + +/* No action if page does not support tags, or if access is disabled. */ +if (!mem || !allocation_tag_access_enabled(env, el, sctlr)) { +return; +} + +rtag = allocation_tag_from_addr(ptr); +rtag |= rtag << 4; + +assert(blocklen % (2 << LOG2_TAG_GRANULE) == 0); +memset(mem, rtag, blocklen / (2 << LOG2_TAG_GRANULE)); +} diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 9bd68d522c..a3bd2e27ef 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -1811,6 +1811,15 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread, tcg_rt = cpu_reg(s, rt); gen_helper_dc_zva(cpu_env, tcg_rt); return; +case ARM_CP_DC_GVA: +tcg_rt = cpu_reg(s, rt); +gen_helper_dc_gva(cpu_env, tcg_rt); +return; +case ARM_CP_DC_GZVA: +tcg_rt = cpu_reg(s, rt); +gen_helper_dc_zva(cpu_env, tcg_rt); +gen_helper_dc_gva(cpu_env, tcg_rt); +return; default: break; } -- 2.17.2
Re: [Qemu-devel] [Qemu-block] [PATCH 1/1] Introduce a Python module structure
On Wed, Feb 06, 2019 at 11:29:01AM -0500, Cleber Rosa wrote: > This is a simple move of Python code that wraps common QEMU > functionality, and are used by a number of different tests > and scripts. > > By treating that code as a real Python module, we can more easily: > * reuse code > * have a proper place for the module's own unittests > * apply a more consistent style > * generate documentation > > Signed-off-by: Cleber Rosa > --- > configure | 1 + > scripts/qemu.py => python/qemu/__init__.py | 11 ++- > {scripts/qmp => python/qemu}/qmp.py| 0 > {scripts => python/qemu}/qtest.py | 5 +++-- > scripts/device-crash-test | 2 ++ > scripts/qmp/__init__.py| 0 > scripts/qmp/qemu-ga-client | 5 - > scripts/qmp/qmp-shell | 4 +++- > scripts/render_block_graph.py | 2 ++ > tests/acceptance/avocado_qemu/__init__.py | 5 ++--- > tests/acceptance/virtio_version.py | 2 +- > tests/migration/guestperf/engine.py| 7 --- > tests/qemu-iotests/235 | 2 +- > tests/qemu-iotests/238 | 2 +- > tests/qemu-iotests/iotests.py | 4 ++-- > tests/vm/basevm.py | 2 +- > 16 files changed, 33 insertions(+), 21 deletions(-) > rename scripts/qemu.py => python/qemu/__init__.py (98%) > rename {scripts/qmp => python/qemu}/qmp.py (100%) > rename {scripts => python/qemu}/qtest.py (98%) > delete mode 100644 scripts/qmp/__init__.py Reviewed-by: Stefan Hajnoczi signature.asc Description: PGP signature
Re: [Qemu-devel] [Qemu-block] Guest unresponsive after Virtqueue size exceeded error
On Wed, Feb 06, 2019 at 04:47:19PM +, Fernando Casas Schössow wrote: > I could also repro the same with virtio-scsi on the same guest a couple of > hours later: > > 2019-02-06 07:10:37.672+: starting up libvirt version: 4.10.0, qemu > version: 3.1.0, kernel: 4.19.18-0-vanilla, hostname: vmsvr01.homenet.local > LC_ALL=C > PATH=/bin:/sbin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin > HOME=/root USER=root QEMU_AUDIO_DRV=spice /home/fernando/qemu-system-x86_64 > -name guest=DOCKER01,debug-threads=on -S -object > secret,id=masterKey0,format=raw,file=/var/lib/libvirt/qemu/domain-32-DOCKER01/master-key.aes > -machine pc-i440fx-3.1,accel=kvm,usb=off,dump-guest-core=off -cpu > IvyBridge,ss=on,vmx=on,pcid=on,hypervisor=on,arat=on,tsc_adjust=on,umip=on,xsaveopt=on > -drive > file=/usr/share/edk2.git/ovmf-x64/OVMF_CODE-pure-efi.fd,if=pflash,format=raw,unit=0,readonly=on > -drive > file=/var/lib/libvirt/qemu/nvram/DOCKER01_VARS.fd,if=pflash,format=raw,unit=1 > -m 2048 -realtime mlock=off -smp 2,sockets=2,cores=1,threads=1 -uuid > 4705b146-3b14-4c20-923c-42105d47e7fc -no-user-config -nodefaults -chardev > socket,id=charmonitor,fd=46,server,nowait -mon > chardev=charmonitor,id=monitor,mode=control -rtc base=utc,driftfix=slew > -global kvm-pit.lost_tick_policy=delay -no-hpet -no-shutdown -global > PIIX4_PM.disable_s3=1 -global PIIX4_PM.disable_s4=1 -boot strict=on -device > ich9-usb-ehci1,id=usb,bus=pci.0,addr=0x4.0x7 -device > ich9-usb-uhci1,masterbus=usb.0,firstport=0,bus=pci.0,multifunction=on,addr=0x4 > -device ich9-usb-uhci2,masterbus=usb.0,firstport=2,bus=pci.0,addr=0x4.0x1 > -device ich9-usb-uhci3,masterbus=usb.0,firstport=4,bus=pci.0,addr=0x4.0x2 > -device virtio-scsi-pci,id=scsi0,bus=pci.0,addr=0x6 -device > virtio-serial-pci,id=virtio-serial0,bus=pci.0,addr=0x5 -drive > file=/storage/storage-ssd-vms/virtual_machines_ssd/docker01.qcow2,format=qcow2,if=none,id=drive-scsi0-0-0-0,cache=none,aio=threads > -device > scsi-hd,bus=scsi0.0,channel=0,scsi-id=0,lun=0,drive=drive-scsi0-0-0-0,id=scsi0-0-0-0,bootindex=1,write-cache=on > -netdev tap,fd=48,id=hostnet0,vhost=on,vhostfd=50 -device > virtio-net-pci,netdev=hostnet0,id=net0,mac=52:54:00:1c:af:ce,bus=pci.0,addr=0x3 > -chardev pty,id=charserial0 -device > isa-serial,chardev=charserial0,id=serial0 -chardev > socket,id=charchannel0,fd=51,server,nowait -device > virtserialport,bus=virtio-serial0.0,nr=1,chardev=charchannel0,id=channel0,name=org.qemu.guest_agent.0 > -chardev spicevmc,id=charchannel1,name=vdagent -device > virtserialport,bus=virtio-serial0.0,nr=2,chardev=charchannel1,id=channel1,name=com.redhat.spice.0 > -spice port=5904,addr=127.0.0.1,disable-ticketing,seamless-migration=on > -device > qxl-vga,id=video0,ram_size=67108864,vram_size=67108864,vram64_size_mb=0,vgamem_mb=16,max_outputs=1,bus=pci.0,addr=0x2 > -chardev spicevmc,id=charredir0,name=usbredir -device > usb-redir,chardev=charredir0,id=redir0,bus=usb.0,port=2 -chardev > spicevmc,id=charredir1,name=usbredir -device > usb-redir,chardev=charredir1,id=redir1,bus=usb.0,port=3 -device > virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x7 -object > rng-random,id=objrng0,filename=/dev/random -device > virtio-rng-pci,rng=objrng0,id=rng0,bus=pci.0,addr=0x8 -sandbox > on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny -msg > timestamp=on > 2019-02-06 07:10:37.672+: Domain id=32 is tainted: high-privileges > char device redirected to /dev/pts/5 (label charserial0) > vdev 0x5585456ef6b0 ("virtio-scsi") > vq 0x5585456f90a0 (idx 2) > inuse 128 vring.num 128 > 2019-02-06T13:00:46.942424Z qemu-system-x86_64: Virtqueue size exceeded > > > I'm open to any tests or suggestions that can move the investigation forward > and find the cause of this issue. Thanks for collecting the data! The fact that both virtio-blk and virtio-scsi failed suggests it's not a virtqueue element leak in the virtio-blk or virtio-scsi device emulation code. The hung task error messages from inside the guest are a consequence of QEMU hitting the "Virtqueue size exceeded" error. QEMU refuses to process further requests after the error, causing tasks inside the guest to get stuck on I/O. I don't have a good theory regarding the root cause. Two ideas: 1. The guest is corrupting the vring or submitting more requests than will fit into the ring. Somewhat unlikely because it happens with both Windows and Linux guests. 2. QEMU's virtqueue code is buggy, maybe the memory region cache which is used for fast guest RAM accesses. Here is an expanded version of the debug patch which might help identify which of these scenarios is likely. Sorry, it requires running the guest again! This time let's make QEMU dump core so both QEMU state and guest RAM are captured for further debugging. That way it will be possible to extract more information using gdb without rerunning. Stefan --- diff --git a/hw/virtio/virtio.c b/hw/virtio/vir
Re: [Qemu-devel] should we try to stop using variable length arrays?
On Thu, Feb 07, 2019 at 07:30:59PM +, Peter Maydell wrote: > Should we be looking to get rid of these and turn on the -Wvla > warning? I know the Linux kernel has recently decided to do this > (some rationale at the start of https://lwn.net/Articles/749064/). I'm in favor of avoiding variable-length arrays just so reviewers don't need to catch instances where the size comes from the untrusted guest. Stefan signature.asc Description: PGP signature
Re: [Qemu-devel] [Qemu-block] [RFC PATCH] coroutines: generate wrapper code
On Fri, Feb 08, 2019 at 05:11:22PM +0300, Vladimir Sementsov-Ogievskiy wrote: > Hi all! > > We have a very frequent pattern of wrapping a coroutine_fn function > to be called from non-coroutine context: > > - create structure to pack parameters > - create function to call original function taking parameters from > struct > - create wrapper, which in case of non-coroutine context will > create a coroutine, enter it and start poll-loop. > > Here is a draft of template code + example how it can be used to drop a > lot of similar code. > > Hope someone like it except me) My 2 cents. Cons: * Synchronous poll loops are an anti-pattern. They block all of QEMU with the big mutex held. Making them easier to write is questionable because we should aim to have as few of these as possible. * Code generation makes the code easier to write but harder to read. Code is read more than written. In this case I think open coding isn't too bad and I prefer it to reading a code generation script to understand how it works. If we were planning to add lots more of these then I agree code generation would help. But in this case I'd rather not. signature.asc Description: PGP signature
Re: [Qemu-devel] [PATCH qemu 0/3] spapr_pci, vfio: NVIDIA V100 + P9 passthrough
On 08/02/2019 16:28, David Gibson wrote: > On Thu, Feb 07, 2019 at 08:26:20PM -0700, Alex Williamson wrote: >> On Fri, 8 Feb 2019 13:29:37 +1100 >> Alexey Kardashevskiy wrote: >> >>> On 08/02/2019 02:18, Alex Williamson wrote: On Thu, 7 Feb 2019 15:43:18 +1100 Alexey Kardashevskiy wrote: > On 07/02/2019 04:22, Daniel Henrique Barboza wrote: >> Based on this series, I've sent a Libvirt patch to allow a QEMU process >> to inherit IPC_LOCK when using VFIO passthrough with the Tesla V100 >> GPU: >> >> https://www.redhat.com/archives/libvir-list/2019-February/msg00219.html >> >> >> In that thread, Alex raised concerns about allowing QEMU to freely lock >> all the memory it wants. Is this an issue to be considered in the review >> of this series here? >> >> Reading the patches, specially patch 3/3, it seems to me that QEMU is >> going to lock the KVM memory to populate the NUMA node with memory >> of the GPU itself, so at first there is no risk of not taking over the >> host RAM. >> Am I missing something? > > > The GPU memory belongs to the device and not visible to the host as > memory blocks and not covered by page structs, for the host it is more > like MMIO which is passed through to the guest without that locked > accounting, I'd expect libvirt to keep working as usual except that: > > when libvirt calculates the amount of memory needed for TCE tables > (which is guestRAM/64k*8), now it needs to use the end of the last GPU > RAM window as a guest RAM size. For example, in QEMU HMP "info mtree -f": > > FlatView #2 > AS "memory", root: system > AS "cpu-memory-0", root: system > Root memory region: system > -7fff (prio 0, ram): ppc_spapr.ram > 0100-011f (prio 0, ram): nvlink2-mr > > So previously the DMA window would cover 0x7fff+1, now it has to > cover 0x11f+1. This looks like a chicken and egg problem, you're saying libvirt needs to query mtree to understand the extent of the GPU layout, but we need to specify the locked memory limits in order for QEMU to start? Is libvirt supposed to start the VM with unlimited locked memory and fix it at some indeterminate point in the future? Run a dummy VM with unlimited locked memory in order to determine the limits for the real VM? Neither of these sound practical. Thanks, >>> >>> >>> QEMU maps GPU RAM at known locations (which only depends on the vPHB's >>> index or can be set explicitely) and libvirt knows how many GPUs are >>> passed so it is quite easy to calculate the required amount of memory. >>> >>> Here is the window start calculation: >>> https://github.com/aik/qemu/commit/7073cad3ae7708d657e01672bcf53092808b54fb#diff-662409c2a5a150fe231d07ea8384b920R3812 >>> >>> We do not exactly know the GPU RAM window size until QEMU reads it from >>> VFIO/nvlink2 but we know that all existing hardware has a window of >>> 128GB (the adapters I have access to only have 16/32GB on board). >> >> So you're asking that libvirt add 128GB per GPU with magic nvlink >> properties, which may be 8x what's actually necessary and libvirt >> determines which GPUs to apply this to how? Does libvirt need to sort >> through device tree properties for this? Thanks, > > Hm. If the GPU memory is really separate from main RAM, which it > sounds like, I don't think it makes sense to account it against the > same locked memory limit as regular RAM. This is accounting for TCE table to cover GPU RAM, not for GPU RAM itself. So I am asking libvirt to add 128GB/64k*8=16MB to the locked_vm. It already does so for the guest RAM. -- Alexey
Re: [Qemu-devel] [Qemu-block] [PATCH] virtio-blk: cleanup using VirtIOBlock *s and VirtIODevice *vdev
On Fri, Feb 08, 2019 at 03:23:47PM +0100, Stefano Garzarella wrote: > In several part we still using req->dev or VIRTIO_DEVICE(req->dev) > when we have already defined s and vdev pointers: > VirtIOBlock *s = req->dev; > VirtIODevice *vdev = VIRTIO_DEVICE(s); > > Signed-off-by: Stefano Garzarella > --- > hw/block/virtio-blk.c | 22 +- > 1 file changed, 9 insertions(+), 13 deletions(-) Thanks, applied to my block tree: https://github.com/stefanha/qemu/commits/block Stefan signature.asc Description: PGP signature
Re: [Qemu-devel] [PATCH] memory: Do not update coalesced IO range in the case of NOP
ping > On Feb 5, 2019, at 5:50 PM, Jagannathan Raman wrote: > > Do not add/del coalesced IO ranges in the case where the > same FlatRanges are present in both old and new FlatViews > > Fixes: 3ac7d43a6fbb ("memory: update coalesced_range on transaction_commit") > Signed-off-by: Jagannathan Raman > --- > memory.c | 5 + > 1 file changed, 1 insertion(+), 4 deletions(-) > > diff --git a/memory.c b/memory.c > index 61d66e4..e49369d 100644 > --- a/memory.c > +++ b/memory.c > @@ -932,9 +932,7 @@ static void > address_space_update_topology_pass(AddressSpace *as, > } else if (frold && frnew && flatrange_equal(frold, frnew)) { > /* In both and unchanged (except logging may have changed) */ > > -if (!adding) { > -flat_range_coalesced_io_del(frold, as); > -} else { > +if (adding) { > MEMORY_LISTENER_UPDATE_REGION(frnew, as, Forward, region_nop); > if (frnew->dirty_log_mask & ~frold->dirty_log_mask) { > MEMORY_LISTENER_UPDATE_REGION(frnew, as, Forward, > log_start, > @@ -946,7 +944,6 @@ static void > address_space_update_topology_pass(AddressSpace *as, > frold->dirty_log_mask, > frnew->dirty_log_mask); > } > -flat_range_coalesced_io_add(frnew, as); > } > > ++iold; > -- > 1.8.3.1 > >
[Qemu-devel] [PATCH] hw/display: Add basic ATI VGA emulation
At least two machines, the PPC mac99 and MIPS fulong2e, have an ATI gfx chip by default (Rage 128 Pro and M6/RV100 respectively) and guests running on these and the PMON2000 firmware of the fulong2e expect this to be available. Fortunately these are very similar chips so they can be mostly emulated in the same device model. This patch adds basic emulation of these ATI VGA chips. While this is incomplete and currently only enough to run the MIPS firmware and get console output with Linux, it allows the fulong2e board to work more like the real hardware and having it in QEMU in this state provides a way to experiment with it and allows others to contribute to improve it (e.g. implement more 2D features to get X running). It is only enabled for mips64le and ppc now but only the fulong2e (which currently has no display output at all) is set to use it by default (in a separate patch). Tested with Debian 8.11.0 powerpc on mac99 and the pmon_2e.bin fulong2e firmware from https://mirrors.cloud.tencent.com/loongson/pmon/ Signed-off-by: BALATON Zoltan --- default-configs/mips64el-softmmu.mak | 1 + default-configs/ppc-softmmu.mak | 1 + hw/display/Makefile.objs | 2 + hw/display/ati.c | 582 +++ hw/display/ati_2d.c | 44 +++ hw/display/ati_int.h | 67 hw/display/ati_regs.h| 452 +++ hw/display/trace-events | 4 + 8 files changed, 1153 insertions(+) create mode 100644 hw/display/ati.c create mode 100644 hw/display/ati_2d.c create mode 100644 hw/display/ati_int.h create mode 100644 hw/display/ati_regs.h diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak index 9eb1208b58..231f81eca2 100644 --- a/default-configs/mips64el-softmmu.mak +++ b/default-configs/mips64el-softmmu.mak @@ -13,3 +13,4 @@ CONFIG_VT82C686=y CONFIG_MIPS_BOSTON=y CONFIG_FITLOADER=y CONFIG_PCI_EXPRESS_XILINX=y +CONFIG_ATI_VGA=y diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak index 52acb7cf39..75024b298e 100644 --- a/default-configs/ppc-softmmu.mak +++ b/default-configs/ppc-softmmu.mak @@ -56,6 +56,7 @@ CONFIG_DEC_PCI=y CONFIG_IDE_MACIO=y CONFIG_MAC_OLDWORLD=y CONFIG_MAC_NEWWORLD=y +CONFIG_ATI_VGA=y # For PReP CONFIG_PREP=y diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs index 7c4ae9a0fd..e58947e6f3 100644 --- a/hw/display/Makefile.objs +++ b/hw/display/Makefile.objs @@ -53,3 +53,5 @@ virtio-gpu-3d.o-cflags := $(VIRGL_CFLAGS) virtio-gpu-3d.o-libs += $(VIRGL_LIBS) obj-$(CONFIG_DPCD) += dpcd.o obj-$(CONFIG_XLNX_ZYNQMP_ARM) += xlnx_dp.o + +obj-$(CONFIG_ATI_VGA) += ati.o ati_2d.o diff --git a/hw/display/ati.c b/hw/display/ati.c new file mode 100644 index 00..18458110b2 --- /dev/null +++ b/hw/display/ati.c @@ -0,0 +1,582 @@ +/* + * QEMU ATI SVGA emulation + * + * Copyright (c) 2019 BALATON Zoltan + * + * This work is licensed under the GNU GPL license version 2 or later. + */ + +/* + * WARNING: + * This is very incomplete and only enough to get Linux console output yet. + * At the moment it's little more than a frame buffer with minimal functions, + * other more advanced features of the hardware are yet to be implemented. + * We only aim for Rage 128 Pro (and some RV100) and 2D only at first, + * No 3D at all yet (maybe after 2D works, but feel free to improve it) + */ + +#include "ati_int.h" +#include "ati_regs.h" +#include "vga_regs.h" +#include "qemu/log.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "hw/hw.h" +#include "ui/console.h" +#include "trace.h" + +#define PCI_VENDOR_ID_ATI 0x1002 +/* Rage128 Pro GL */ +#define PCI_DEVICE_ID_ATI_RAGE128_PF 0x5046 +/* Radeon RV100 (VE) */ +#define PCI_DEVICE_ID_ATI_RADEON_QY 0x5159 + +enum { VGA_MODE, EXT_MODE }; + +static void ati_vga_switch_mode(ATIVGAState *s) +{ +DPRINTF("%d -> %d\n", +s->mode, !!(s->regs.crtc_gen_cntl & CRTC2_EXT_DISP_EN)); +if (s->regs.crtc_gen_cntl & CRTC2_EXT_DISP_EN) { +/* Extended mode enabled */ +s->mode = EXT_MODE; +if (s->regs.crtc_gen_cntl & CRTC2_EN) { +/* CRT controller enabled, use CRTC values */ +uint32_t offs = s->regs.crtc_offset & 0x07ff; +int stride = (s->regs.crtc_pitch & 0x7ff) * 8; +int bpp = 0; +int h, v; + +if (s->regs.crtc_h_total_disp == 0) { +s->regs.crtc_h_total_disp = ((640 / 8) - 1) << 16; +} +if (s->regs.crtc_v_total_disp == 0) { +s->regs.crtc_v_total_disp = (480 - 1) << 16; +} +h = ((s->regs.crtc_h_total_disp >> 16) + 1) * 8; +v = (s->regs.crtc_v_total_disp >> 16) + 1; +switch (s->regs.crtc_gen_cntl & CRTC_PIX_WIDTH_MASK) { +case CRTC_PIX_WIDTH_4BPP: +bpp = 4; +break; +case CRTC_PIX_W
Re: [Qemu-devel] [v3 PATCH] hw/arm/bcm2835_peripherals: add bcm283x sp804-alike timer
Hi Mark, > From: Mark > Sent: Sunday, 10 February 2019 08:58 > Subject: [v3 PATCH] hw/arm/bcm2835_peripherals: add bcm283x sp804-alike > timer Thanks for the patch. The integration with bcm2835_peripherals looks good, but hopefully one of the QEMU maintainers can give you a review of the timer implementation as I'm really short on time at the moment. If you didn't already see it, you may want to compare with the implementation here, which originates from Gregory Estrade: https://github.com/0xabu/qemu/blob/raspi/hw/timer/bcm2835_timer.c ... sadly I never got around to merging it upstream with the rest of the raspi emulation. ☹ Cheers, Andrew
Re: [Qemu-devel] [Qemu-block] [PATCH v4 0/6] virtio-blk: add DISCARD and WRITE_ZEROES features
On Fri, Feb 08, 2019 at 02:49:44PM +0100, Stefano Garzarella wrote: > This series adds the support of DISCARD and WRITE_ZEROES commands > and extends the virtio-blk-test to test WRITE_ZEROES command when > the feature is enabled. > > v4: > - fixed error with mingw compiler in patch 4 > gcc and clang want %lu, but mingw wants %llu for BDRV_REQUEST_MAX_SECTORS. > Since is less than INT_MAX, I casted it to integer and I used %d in the > format string of error_setg. (mingw now is happy) > > v3: > - rebased on master (I removed Based-on tag since the new virtio headers from > linux v5.0-rc1 are merged) > - added patch 2 to add host_features field (as in virtio-net) [Michael] > - fixed patch 3 (previously 2/5) using the new host_features field > - fixed patch 4 (previously 3/5) following the Stefan's comments: > - fixed name of functions and fields > - used vdev and s pointers > - removed "wz-may-unmap" property > - split "dwz-max-sectors" in two properties > > v2: > - added patch 1 to use virtio_blk_handle_rw_error() with discard operation > - added patch 2 to make those new features machine-type dependent (thanks > David) > - fixed patch 3 (previously patch 1/2) adding more checks, block_acct_start() > for WRITE_ZEROES requests, and configurable parameters to > initialize the limits (max_sectors, wzeroes_may_unmap). > (thanks Stefan) > I moved in a new function the code to handle a single segment, > in order to simplify the support of multiple segments in the > future. > - added patch 4 to change the assert on data_size following the discussion > with > Thomas, Changpeng, Michael, and Stefan (thanks all) > - fixed patch 5 (previously patch 2/2) using local dwz_hdr variable instead of > dynamic allocation (thanks Thomas) > > Thanks, > Stefano > > Stefano Garzarella (6): > virtio-blk: add acct_failed param to virtio_blk_handle_rw_error() > virtio-blk: add host_features field in VirtIOBlock > virtio-blk: add "discard" and "write-zeroes" properties > virtio-blk: add DISCARD and WRITE_ZEROES features > tests/virtio-blk: change assert on data_size in virtio_blk_request() > tests/virtio-blk: add test for WRITE_ZEROES command > > hw/block/virtio-blk.c | 214 +++-- > hw/core/machine.c | 2 + > include/hw/virtio/virtio-blk.h | 5 +- > tests/virtio-blk-test.c| 75 +++- > 4 files changed, 282 insertions(+), 14 deletions(-) > > -- > 2.20.1 > > Thanks, applied to my block tree: https://github.com/stefanha/qemu/commits/block Stefan signature.asc Description: PGP signature
[Qemu-devel] [Bug 1528214] Re: qemu 1.7.0 vhost_net crash
[Expired for QEMU because there has been no activity for 60 days.] ** Changed in: qemu Status: Incomplete => Expired -- You received this bug notification because you are a member of qemu- devel-ml, which is subscribed to QEMU. https://bugs.launchpad.net/bugs/1528214 Title: qemu 1.7.0 vhost_net crash Status in QEMU: Expired Bug description: i find the crash in /var/crash the crash content is : <4>Pid: 6949, comm: qemu-system-x86 Not tainted 2.6.32-431.el6.x86_64 #1 Powerleader PR2530G2/SC612DI-8F <4>RIP: 0010:[] [] fput+0x9/0x30 <4>RSP: 0018:88015b601d98 EFLAGS: 00010292 <4>RAX: 0382 RBX: 881e4659 RCX: 01c3 <4>RDX: RSI: 881e46590130 RDI: <4>RBP: 88015b601d98 R08: 881e46598518 R09: <4>R10: R11: 0246 R12: 881e46590010 <4>R13: R14: 880c29812748 R15: <4>FS: 7f6a74d20700() GS:8810b884() knlGS: <4>CS: 0010 DS: 002b ES: 002b CR0: 8005003b <4>CR2: 0030 CR3: 001c544cc000 CR4: 001427e0 <4>DR0: DR1: DR2: <4>DR3: DR6: 0ff0 DR7: 0400 <4>Process qemu-system-x86 (pid: 6949, threadinfo 88015b60, task 880c1ed9c040) <4>Stack: <4> 88015b601e58 a02ac3c8 881e4659 <4> 881e46590080 881e46590078 88015b601e38 0286 <4> 0001 88015b601e58 0282 <4>Call Trace: <4> [] vhost_net_ioctl+0x328/0x5d0 [vhost_net] <4> [] vfs_ioctl+0x22/0xa0 <4> [] do_vfs_ioctl+0x84/0x580 <4> [] ? __fput+0x1a1/0x210 <4> [] sys_ioctl+0x81/0xa0 <4> [] ? __audit_syscall_exit+0x25e/0x290 <4> [] system_call_fastpath+0x16/0x1b <4>Code: fe ff ff 31 d2 48 89 de 83 cf ff ff d0 e9 da fe ff ff 48 89 df e8 28 64 04 00 e9 bb fe ff ff 0f 1f 00 55 48 89 e5 0f 1f 44 00 00 48 ff 4f 30 0f 94 c0 84 c0 75 0b c9 c3 66 0f 1f 84 00 00 00 <1>RIP [] fput+0x9/0x30 <4> RSP <4>CR2: 0030 how the bug occure To manage notifications about this bug go to: https://bugs.launchpad.net/qemu/+bug/1528214/+subscriptions
[Qemu-devel] [PATCH 3/4] mips_fulong2e: Dynamically generate SPD EEPROM data
The machine comes with 256M memory module by default but it's upgradable so it could have different memory size. There was a TODO comment to replace static SPD EEPROM data with dynamically generated one to support this. Now that we have a function for that, it's easy to do. Although this would allow larger RAM sizes, the peculiar memory map of the machine may need some special handling to map it as low and high memory. Because I don't know what the correct place would be for highmem, I've left memory size fixed at 256M for now and TODO is moved there instead. Signed-off-by: BALATON Zoltan --- hw/mips/mips_fulong2e.c | 31 +-- 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/hw/mips/mips_fulong2e.c b/hw/mips/mips_fulong2e.c index 10e6ed585a..eec6fd02c8 100644 --- a/hw/mips/mips_fulong2e.c +++ b/hw/mips/mips_fulong2e.c @@ -214,20 +214,6 @@ static void main_cpu_reset(void *opaque) } } -static const uint8_t eeprom_spd[0x80] = { -0x80,0x08,0x07,0x0d,0x09,0x02,0x40,0x00,0x04,0x70, -0x70,0x00,0x82,0x10,0x00,0x01,0x0e,0x04,0x0c,0x01, -0x02,0x20,0x80,0x75,0x70,0x00,0x00,0x50,0x3c,0x50, -0x2d,0x20,0xb0,0xb0,0x50,0x50,0x00,0x00,0x00,0x00, -0x00,0x41,0x48,0x3c,0x32,0x75,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x9c,0x7b,0x07,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x48,0x42,0x35,0x34,0x41,0x32, -0x35,0x36,0x38,0x4b,0x4e,0x2d,0x41,0x37,0x35,0x42, -0x20,0x30,0x20 -}; - static void vt82c686b_southbridge_init(PCIBus *pci_bus, int slot, qemu_irq intc, I2CBus **i2c_bus, ISABus **p_isa_bus) { @@ -284,7 +270,6 @@ static void network_init (PCIBus *pci_bus) static void mips_fulong2e_init(MachineState *machine) { -ram_addr_t ram_size = machine->ram_size; const char *kernel_filename = machine->kernel_filename; const char *kernel_cmdline = machine->kernel_cmdline; const char *initrd_filename = machine->initrd_filename; @@ -292,7 +277,10 @@ static void mips_fulong2e_init(MachineState *machine) MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); MemoryRegion *bios = g_new(MemoryRegion, 1); +ram_addr_t ram_size = machine->ram_size; long bios_size; +uint8_t *spd_data; +Error *err = NULL; int64_t kernel_entry; PCIBus *pci_bus; ISABus *isa_bus; @@ -306,7 +294,7 @@ static void mips_fulong2e_init(MachineState *machine) qemu_register_reset(main_cpu_reset, cpu); -/* fulong 2e has 256M ram. */ +/* TODO: support more than 256M RAM as highmem */ ram_size = 256 * MiB; /* allocate RAM */ @@ -359,8 +347,14 @@ static void mips_fulong2e_init(MachineState *machine) vt82c686b_southbridge_init(pci_bus, FULONG2E_VIA_SLOT, env->irq[5], &smbus, &isa_bus); -/* TODO: Populate SPD eeprom data. */ -smbus_eeprom_init(smbus, 1, eeprom_spd, sizeof(eeprom_spd)); +/* Populate SPD eeprom data */ +spd_data = spd_data_generate(DDR, ram_size, &err); +if (err) { +warn_report_err(err); +} +if (spd_data) { +smbus_eeprom_init_one(smbus, 0x50, spd_data); +} mc146818_rtc_init(isa_bus, 2000, NULL); @@ -374,6 +368,7 @@ static void mips_fulong2e_machine_init(MachineClass *mc) mc->init = mips_fulong2e_init; mc->block_default_type = IF_IDE; mc->default_cpu_type = MIPS_CPU_TYPE_NAME("Loongson-2E"); +mc->default_ram_size = 256 * MiB; } DEFINE_MACHINE("fulong2e", mips_fulong2e_machine_init) -- 2.13.7
[Qemu-devel] [PATCH 1/4] hw/pci-host/bonito.c: Add PCI mem region mapped at the correct address
Stop using system memory as PCI memory otherwise devices such as VGA that have regions mapped to PCI memory clash with RAM. Use a separate memory region for PCI memory and map it to the correct address in system memory which allows PCI mem regions to show at the correct address where clients expect them. Signed-off-by: BALATON Zoltan --- hw/pci-host/bonito.c | 5 - 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hw/pci-host/bonito.c b/hw/pci-host/bonito.c index 9f33582706..c940ec6e48 100644 --- a/hw/pci-host/bonito.c +++ b/hw/pci-host/bonito.c @@ -598,11 +598,14 @@ static const VMStateDescription vmstate_bonito = { static void bonito_pcihost_realize(DeviceState *dev, Error **errp) { PCIHostState *phb = PCI_HOST_BRIDGE(dev); +MemoryRegion *mr = g_new0(MemoryRegion, 1); +memory_region_init(mr, OBJECT(dev), "pci.mem", BONITO_PCILO_SIZE); phb->bus = pci_register_root_bus(DEVICE(dev), "pci", pci_bonito_set_irq, pci_bonito_map_irq, - dev, get_system_memory(), get_system_io(), + dev, mr, get_system_io(), 0x28, 32, TYPE_PCI_BUS); +memory_region_add_subregion(get_system_memory(), BONITO_PCILO_BASE, mr); } static void bonito_realize(PCIDevice *dev, Error **errp) -- 2.13.7
[Qemu-devel] [PATCH 4/4] mips_fulong2e: Add on-board graphics chip
Add (partial) emulation of the on-board GPU of the machine. This allows the PMON2000 firmware to run and should also work with Linux console but probably not with X yet. Signed-off-by: BALATON Zoltan --- Depends on hw/display: Add basic ATI VGA emulation hw/mips/mips_fulong2e.c | 6 ++ 1 file changed, 6 insertions(+) diff --git a/hw/mips/mips_fulong2e.c b/hw/mips/mips_fulong2e.c index eec6fd02c8..68bd030fc1 100644 --- a/hw/mips/mips_fulong2e.c +++ b/hw/mips/mips_fulong2e.c @@ -287,6 +287,7 @@ static void mips_fulong2e_init(MachineState *machine) I2CBus *smbus; MIPSCPU *cpu; CPUMIPSState *env; +DeviceState *dev; /* init CPUs */ cpu = MIPS_CPU(cpu_create(machine->cpu_type)); @@ -347,6 +348,11 @@ static void mips_fulong2e_init(MachineState *machine) vt82c686b_southbridge_init(pci_bus, FULONG2E_VIA_SLOT, env->irq[5], &smbus, &isa_bus); +/* GPU */ +dev = DEVICE(pci_create(pci_bus, -1, "ati-vga")); +qdev_prop_set_uint16(dev, "device_id", 0x5159); +qdev_init_nofail(dev); + /* Populate SPD eeprom data */ spd_data = spd_data_generate(DDR, ram_size, &err); if (err) { -- 2.13.7
[Qemu-devel] [PATCH 0/4] Misc MIPS fulong2e improvements
Hello, These are some misc patches to get the fulong2e emulation in a better shape. With my recent via-ide changes and the separately submitted hw/display: Add basic ATI VGA emulation patch and after this series the pmon_2e.bin firmware from https://mirrors.cloud.tencent.com/loongson/pmon/ can actually run and appears to work. I could not find an image to boot so I could not test that further but this appears to be an improvement that worth submitting now. Regards, BALATON Zoltan BALATON Zoltan (4): hw/pci-host/bonito.c: Add PCI mem region mapped at the correct address mips_fulong2e: Fix bios flash size mips_fulong2e: Dynamically generate SPD EEPROM data mips_fulong2e: Add on-board graphics chip hw/mips/mips_fulong2e.c | 46 +++--- hw/pci-host/bonito.c| 5 - 2 files changed, 27 insertions(+), 24 deletions(-) -- 2.13.7
[Qemu-devel] [PATCH 2/4] mips_fulong2e: Fix bios flash size
According to both the specifications on linux-mips.org referenced in a comment at the beginning of the file and the flash chip part number the bios size should be 512k not 1M. Signed-off-by: BALATON Zoltan --- hw/mips/mips_fulong2e.c | 9 - 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/hw/mips/mips_fulong2e.c b/hw/mips/mips_fulong2e.c index 02549d5c7e..10e6ed585a 100644 --- a/hw/mips/mips_fulong2e.c +++ b/hw/mips/mips_fulong2e.c @@ -21,6 +21,7 @@ #include "qemu/osdep.h" #include "qemu/units.h" #include "qapi/error.h" +#include "cpu.h" #include "hw/hw.h" #include "hw/i386/pc.h" #include "hw/dma/i8257.h" @@ -35,7 +36,6 @@ #include "audio/audio.h" #include "qemu/log.h" #include "hw/loader.h" -#include "hw/mips/bios.h" #include "hw/ide.h" #include "elf.h" #include "hw/isa/vt82c686.h" @@ -51,6 +51,8 @@ #define ENVP_NB_ENTRIES16 #define ENVP_ENTRY_SIZE256 +/* fulong 2e has a 512k flash: Winbond W39L040AP70Z */ +#define BIOS_SIZE (512 * KiB) #define MAX_IDE_BUS 2 /* @@ -307,12 +309,9 @@ static void mips_fulong2e_init(MachineState *machine) /* fulong 2e has 256M ram. */ ram_size = 256 * MiB; -/* fulong 2e has a 1M flash.Winbond W39L040AP70Z */ -bios_size = 1 * MiB; - /* allocate RAM */ memory_region_allocate_system_memory(ram, NULL, "fulong2e.ram", ram_size); -memory_region_init_ram(bios, NULL, "fulong2e.bios", bios_size, +memory_region_init_ram(bios, NULL, "fulong2e.bios", BIOS_SIZE, &error_fatal); memory_region_set_readonly(bios, true); -- 2.13.7
Re: [Qemu-devel] [PATCH qemu v2] hmp: Print if memory section is registered with an accelerator
On 09/02/2019 04:26, Paolo Bonzini wrote: > On 07/02/19 12:49, Dr. David Alan Gilbert wrote: >> //#define DEBUG_UNASSIGNED >> @@ -2924,6 +2926,8 @@ struct FlatViewInfo { >> int counter; >> bool dispatch_tree; >> bool owner; >> +AccelClass *ac; >> +const char *ac_name; >> }; >> >> static void mtree_print_flatview(gpointer key, gpointer value, >> @@ -2939,6 +2943,7 @@ static void mtree_print_flatview(gpointer key, >> gpointer value, >> int n = view->nr; >> int i; >> AddressSpace *as; >> +bool system_as = false; >> >> p(f, "FlatView #%d\n", fvi->counter); >> ++fvi->counter; >> @@ -2950,6 +2955,9 @@ static void mtree_print_flatview(gpointer key, >> gpointer value, >> p(f, ", alias %s", memory_region_name(as->root->alias)); >> } >> p(f, "\n"); >> +if (as == &address_space_memory) { >> +system_as = true; >> +} >> } >> >> p(f, " Root memory region: %s\n", >> @@ -2985,6 +2993,13 @@ static void mtree_print_flatview(gpointer key, >> gpointer value, >> if (fvi->owner) { >> mtree_print_mr_owner(p, f, mr); >> } >> + >> +if (system_as && fvi->ac && >> +fvi->ac->has_memory(current_machine, >> +int128_get64(range->addr.start), >> +MR_SIZE(range->addr.size) + 1)) { >> +p(f, " %s", fvi->ac_name); > > I don't understand this. This doesn't check that the memory range > actually matches the memory registered with the accelerator, only that > there is something in that range. It is checking that a flat range (i.e. what actually works) has a corresponding KVM slot: https://git.qemu.org/?p=qemu.git;a=blob;f=accel/kvm/kvm-all.c;h=4e1de942ce554c734ac2673030031c228a752ac9;hb=HEAD#l201 > Why isn't it enough to use "info > mtree" and look at the KVM address space? There is no such thing in my QEMU, did you mean "KVM-SMRAM" (which is missing on spapr)? I am not sure I understand its purpose for the task - it prints all same ranges on my x86 laptop, not just ones which we told KVM about. My task is that if let's say ":00:1a.0 BAR 0 mmaps[0]" is split into several sections because MSIX happens to be in a middle of that BAR and it is not system page size aligned, then it is going to be several ranges with no clear indication whether or not these were registered as KVM slots. A memory chunk can be "ram" and not a KVM slot if it is 4K on PPC with 64K system pages, for example. FlatView #0 AS "memory", root: system AS "cpu-memory-0", root: system AS "cpu-memory-1", root: system AS "cpu-memory-2", root: system AS "cpu-memory-3", root: system AS "piix3-ide", root: bus master container AS "virtio-net-pci", root: bus master container AS "vfio-pci", root: bus master container Root memory region: system -000b (prio 0, ram): pc.ram kvm 000c-000c0fff (prio 0, rom): pc.ram @000c kvm 000c1000-000c3fff (prio 0, ram): pc.ram @000c1000 kvm 000c4000-000e7fff (prio 0, rom): pc.ram @000c4000 kvm 000e8000-000e (prio 0, ram): pc.ram @000e8000 kvm 000f-000f (prio 0, rom): pc.ram @000f kvm 0010-bfff (prio 0, ram): pc.ram @0010 kvm febc-febc0fff (prio 0, ramd): :00:1a.0 BAR 0 mmaps[0] kvm febc1000-febc102f (prio 0, i/o): msix-table febc1800-febc1807 (prio 0, i/o): msix-pba febfc000-febfcfff (prio 0, i/o): virtio-pci-common febfd000-febfdfff (prio 0, i/o): virtio-pci-isr febfe000-febfefff (prio 0, i/o): virtio-pci-device febff000-febf (prio 0, i/o): virtio-pci-notify fec0-fec00fff (prio 0, i/o): kvm-ioapic fed0-fed003ff (prio 0, i/o): hpet fee0-feef (prio 4096, i/o): kvm-apic-msi fffc- (prio 0, rom): pc.bios kvm 0001-00013fff (prio 0, ram): pc.ram @c000 kvm FlatView #3 AS "KVM-SMRAM", root: mem-container-smram Root memory region: mem-container-smram -000b (prio 0, ram): pc.ram 000c-000c0fff (prio 0, rom): pc.ram @000c 000c1000-000c3fff (prio 0, ram): pc.ram @000c1000 000c4000-000e7fff (prio 0, rom): pc.ram @000c4000 000e8000-000e (prio 0, ram): pc.ram @000e8000 000f-000f (prio 0, rom): pc.ram @000f 0010-bfff (prio 0, ram): pc.ram @0010 febc-febc0fff (prio 0, ramd): :00:1a.0 BAR 0 mmaps[0] febc1000-febc102f (prio 0, i/o): msix-tabl
Re: [Qemu-devel] [PATCH] mips: implement qmp query-cpu-definitions command
Ping. Pavel Dovgalyuk > -Original Message- > From: Pavel Dovgalyuk [mailto:pavel.dovga...@ispras.ru] > Sent: Tuesday, February 05, 2019 4:08 PM > To: qemu-devel@nongnu.org > Cc: pavel.dovga...@ispras.ru; arik...@wavecomp.com; mdr...@linux.vnet.ibm.com; > arm...@redhat.com; dovga...@ispras.ru; natalia.furs...@ispras.ru; > ebl...@redhat.com; > aurel...@aurel32.net > Subject: [PATCH] mips: implement qmp query-cpu-definitions command > > This patch enables QMP-based querying of the available CPU types for MIPS > and MIPS64 platforms. > > Signed-off-by: Pavel Dovgalyuk > --- > monitor.c|2 +- > target/mips/helper.c | 33 + > 2 files changed, 34 insertions(+), 1 deletion(-) > > diff --git a/monitor.c b/monitor.c > index c09fa63940..25d3b141ad 100644 > --- a/monitor.c > +++ b/monitor.c > @@ -1165,7 +1165,7 @@ static void qmp_unregister_commands_hack(void) > qmp_unregister_command(&qmp_commands, "query-cpu-model-comparison"); > #endif > #if !defined(TARGET_PPC) && !defined(TARGET_ARM) && !defined(TARGET_I386) \ > -&& !defined(TARGET_S390X) > +&& !defined(TARGET_S390X) && !defined(TARGET_MIPS) > qmp_unregister_command(&qmp_commands, "query-cpu-definitions"); > #endif > } > diff --git a/target/mips/helper.c b/target/mips/helper.c > index 8988452dbd..c84d056c09 100644 > --- a/target/mips/helper.c > +++ b/target/mips/helper.c > @@ -24,6 +24,7 @@ > #include "exec/cpu_ldst.h" > #include "exec/log.h" > #include "hw/mips/cpudevs.h" > +#include "sysemu/arch_init.h" > > enum { > TLBRET_XI = -6, > @@ -1472,3 +1473,35 @@ void QEMU_NORETURN do_raise_exception_err(CPUMIPSState > *env, > > cpu_loop_exit_restore(cs, pc); > } > + > +static void mips_cpu_add_definition(gpointer data, gpointer user_data) > +{ > +ObjectClass *oc = data; > +CpuDefinitionInfoList **cpu_list = user_data; > +CpuDefinitionInfoList *entry; > +CpuDefinitionInfo *info; > +const char *typename; > + > +typename = object_class_get_name(oc); > +info = g_malloc0(sizeof(*info)); > +info->name = g_strndup(typename, > + strlen(typename) - strlen("-" TYPE_MIPS_CPU)); > +info->q_typename = g_strdup(typename); > + > +entry = g_malloc0(sizeof(*entry)); > +entry->value = info; > +entry->next = *cpu_list; > +*cpu_list = entry; > +} > + > +CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp) > +{ > +CpuDefinitionInfoList *cpu_list = NULL; > +GSList *list; > + > +list = object_class_get_list(TYPE_MIPS_CPU, false); > +g_slist_foreach(list, mips_cpu_add_definition, &cpu_list); > +g_slist_free(list); > + > +return cpu_list; > +}
[Qemu-devel] [PULL 4/9] virtio-blk: add acct_failed param to virtio_blk_handle_rw_error()
From: Stefano Garzarella We add acct_failed param in order to use virtio_blk_handle_rw_error() also when is not required to call block_acct_failed(). (eg. a discard operation is failed) Reviewed-by: Michael S. Tsirkin Reviewed-by: Stefan Hajnoczi Signed-off-by: Stefano Garzarella Acked-by: Pankaj Gupta Message-id: 20190208134950.187665-2-sgarz...@redhat.com Signed-off-by: Stefan Hajnoczi --- hw/block/virtio-blk.c | 10 ++ 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index 843bb2bec8..c95a6f4c9b 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -61,7 +61,7 @@ static void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status) } static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error, -bool is_read) +bool is_read, bool acct_failed) { VirtIOBlock *s = req->dev; BlockErrorAction action = blk_get_error_action(s->blk, is_read, error); @@ -74,7 +74,9 @@ static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error, s->rq = req; } else if (action == BLOCK_ERROR_ACTION_REPORT) { virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR); -block_acct_failed(blk_get_stats(s->blk), &req->acct); +if (acct_failed) { +block_acct_failed(blk_get_stats(s->blk), &req->acct); +} virtio_blk_free_request(req); } @@ -112,7 +114,7 @@ static void virtio_blk_rw_complete(void *opaque, int ret) * the memory until the request is completed (which will * happen on the other side of the migration). */ -if (virtio_blk_handle_rw_error(req, -ret, is_read)) { +if (virtio_blk_handle_rw_error(req, -ret, is_read, true)) { continue; } } @@ -131,7 +133,7 @@ static void virtio_blk_flush_complete(void *opaque, int ret) aio_context_acquire(blk_get_aio_context(s->conf.conf.blk)); if (ret) { -if (virtio_blk_handle_rw_error(req, -ret, 0)) { +if (virtio_blk_handle_rw_error(req, -ret, 0, true)) { goto out; } } -- 2.20.1
[Qemu-devel] [PULL 3/9] virtio-blk: cleanup using VirtIOBlock *s and VirtIODevice *vdev
From: Stefano Garzarella In several part we still using req->dev or VIRTIO_DEVICE(req->dev) when we have already defined s and vdev pointers: VirtIOBlock *s = req->dev; VirtIODevice *vdev = VIRTIO_DEVICE(s); Signed-off-by: Stefano Garzarella Reviewed-by: Liam Merwick Message-id: 20190208142347.214815-1-sgarz...@redhat.com Signed-off-by: Stefan Hajnoczi --- hw/block/virtio-blk.c | 22 +- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index 9a87b3bfac..843bb2bec8 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -63,9 +63,8 @@ static void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status) static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error, bool is_read) { -BlockErrorAction action = blk_get_error_action(req->dev->blk, - is_read, error); VirtIOBlock *s = req->dev; +BlockErrorAction action = blk_get_error_action(s->blk, is_read, error); if (action == BLOCK_ERROR_ACTION_STOP) { /* Break the link as the next request is going to be parsed from the @@ -138,7 +137,7 @@ static void virtio_blk_flush_complete(void *opaque, int ret) } virtio_blk_req_complete(req, VIRTIO_BLK_S_OK); -block_acct_done(blk_get_stats(req->dev->blk), &req->acct); +block_acct_done(blk_get_stats(s->blk), &req->acct); virtio_blk_free_request(req); out: @@ -513,7 +512,7 @@ static int virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb) - sizeof(struct virtio_blk_inhdr); iov_discard_back(in_iov, &in_num, sizeof(struct virtio_blk_inhdr)); -type = virtio_ldl_p(VIRTIO_DEVICE(req->dev), &req->out.type); +type = virtio_ldl_p(vdev, &req->out.type); /* VIRTIO_BLK_T_OUT defines the command direction. VIRTIO_BLK_T_BARRIER * is an optional flag. Although a guest should not send this flag if @@ -522,8 +521,7 @@ static int virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb) case VIRTIO_BLK_T_IN: { bool is_write = type & VIRTIO_BLK_T_OUT; -req->sector_num = virtio_ldq_p(VIRTIO_DEVICE(req->dev), - &req->out.sector); +req->sector_num = virtio_ldq_p(vdev, &req->out.sector); if (is_write) { qemu_iovec_init_external(&req->qiov, out_iov, out_num); @@ -535,25 +533,23 @@ static int virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb) req->qiov.size / BDRV_SECTOR_SIZE); } -if (!virtio_blk_sect_range_ok(req->dev, req->sector_num, - req->qiov.size)) { +if (!virtio_blk_sect_range_ok(s, req->sector_num, req->qiov.size)) { virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR); -block_acct_invalid(blk_get_stats(req->dev->blk), +block_acct_invalid(blk_get_stats(s->blk), is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ); virtio_blk_free_request(req); return 0; } -block_acct_start(blk_get_stats(req->dev->blk), - &req->acct, req->qiov.size, +block_acct_start(blk_get_stats(s->blk), &req->acct, req->qiov.size, is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ); /* merge would exceed maximum number of requests or IO direction * changes */ if (mrb->num_reqs > 0 && (mrb->num_reqs == VIRTIO_BLK_MAX_MERGE_REQS || is_write != mrb->is_write || - !req->dev->conf.request_merging)) { -virtio_blk_submit_multireq(req->dev->blk, mrb); + !s->conf.request_merging)) { +virtio_blk_submit_multireq(s->blk, mrb); } assert(mrb->num_reqs < VIRTIO_BLK_MAX_MERGE_REQS); -- 2.20.1
[Qemu-devel] [PULL 2/9] qemugdb/coroutine: fix arch_prctl has unknown return type
From: Vladimir Sementsov-Ogievskiy qemu coroutine command results in following error output: Python Exception 'arch_prctl' has unknown return type; cast the call to its declared return type: Error occurred in Python command: 'arch_prctl' has unknown return type; cast the call to its declared return type Fix it by giving it what it wants: arch_prctl return type. Information on the topic: https://sourceware.org/gdb/onlinedocs/gdb/Calling.html Signed-off-by: Vladimir Sementsov-Ogievskiy Message-id: 20190206151425.105871-1-vsement...@virtuozzo.com Signed-off-by: Stefan Hajnoczi --- scripts/qemugdb/coroutine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/qemugdb/coroutine.py b/scripts/qemugdb/coroutine.py index ab699794ab..81f811ac00 100644 --- a/scripts/qemugdb/coroutine.py +++ b/scripts/qemugdb/coroutine.py @@ -22,7 +22,7 @@ def get_fs_base(): pthread_self().''' # %rsp - 120 is scratch space according to the SystemV ABI old = gdb.parse_and_eval('*(uint64_t*)($rsp - 120)') -gdb.execute('call arch_prctl(0x1003, $rsp - 120)', False, True) +gdb.execute('call (int)arch_prctl(0x1003, $rsp - 120)', False, True) fs_base = gdb.parse_and_eval('*(uint64_t*)($rsp - 120)') gdb.execute('set *(uint64_t*)($rsp - 120) = %s' % old, False, True) return fs_base -- 2.20.1
[Qemu-devel] [PULL 7/9] virtio-blk: add DISCARD and WRITE_ZEROES features
From: Stefano Garzarella This patch adds the support of DISCARD and WRITE_ZEROES commands, that have been introduced in the virtio-blk protocol to have better performance when using SSD backend. We support only one segment per request since multiple segments are not widely used and there are no userspace APIs that allow applications to submit multiple segments in a single call. Reviewed-by: Michael S. Tsirkin Reviewed-by: Stefan Hajnoczi Signed-off-by: Stefano Garzarella Acked-by: Pankaj Gupta Message-id: 20190208134950.187665-5-sgarz...@redhat.com Signed-off-by: Stefan Hajnoczi --- include/hw/virtio/virtio-blk.h | 2 + hw/block/virtio-blk.c | 184 + 2 files changed, 186 insertions(+) diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h index f7345b0511..015b523fe0 100644 --- a/include/hw/virtio/virtio-blk.h +++ b/include/hw/virtio/virtio-blk.h @@ -38,6 +38,8 @@ struct VirtIOBlkConf uint32_t request_merging; uint16_t num_queues; uint16_t queue_size; +uint32_t max_discard_sectors; +uint32_t max_write_zeroes_sectors; }; struct VirtIOBlockDataPlane; diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index feeaf77965..f2b73bb8cf 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -146,6 +146,30 @@ out: aio_context_release(blk_get_aio_context(s->conf.conf.blk)); } +static void virtio_blk_discard_write_zeroes_complete(void *opaque, int ret) +{ +VirtIOBlockReq *req = opaque; +VirtIOBlock *s = req->dev; +bool is_write_zeroes = (virtio_ldl_p(VIRTIO_DEVICE(s), &req->out.type) & +~VIRTIO_BLK_T_BARRIER) == VIRTIO_BLK_T_WRITE_ZEROES; + +aio_context_acquire(blk_get_aio_context(s->conf.conf.blk)); +if (ret) { +if (virtio_blk_handle_rw_error(req, -ret, false, is_write_zeroes)) { +goto out; +} +} + +virtio_blk_req_complete(req, VIRTIO_BLK_S_OK); +if (is_write_zeroes) { +block_acct_done(blk_get_stats(s->blk), &req->acct); +} +virtio_blk_free_request(req); + +out: +aio_context_release(blk_get_aio_context(s->conf.conf.blk)); +} + #ifdef __linux__ typedef struct { @@ -479,6 +503,84 @@ static bool virtio_blk_sect_range_ok(VirtIOBlock *dev, return true; } +static uint8_t virtio_blk_handle_discard_write_zeroes(VirtIOBlockReq *req, +struct virtio_blk_discard_write_zeroes *dwz_hdr, bool is_write_zeroes) +{ +VirtIOBlock *s = req->dev; +VirtIODevice *vdev = VIRTIO_DEVICE(s); +uint64_t sector; +uint32_t num_sectors, flags, max_sectors; +uint8_t err_status; +int bytes; + +sector = virtio_ldq_p(vdev, &dwz_hdr->sector); +num_sectors = virtio_ldl_p(vdev, &dwz_hdr->num_sectors); +flags = virtio_ldl_p(vdev, &dwz_hdr->flags); +max_sectors = is_write_zeroes ? s->conf.max_write_zeroes_sectors : + s->conf.max_discard_sectors; + +/* + * max_sectors is at most BDRV_REQUEST_MAX_SECTORS, this check + * make us sure that "num_sectors << BDRV_SECTOR_BITS" can fit in + * the integer variable. + */ +if (unlikely(num_sectors > max_sectors)) { +err_status = VIRTIO_BLK_S_IOERR; +goto err; +} + +bytes = num_sectors << BDRV_SECTOR_BITS; + +if (unlikely(!virtio_blk_sect_range_ok(s, sector, bytes))) { +err_status = VIRTIO_BLK_S_IOERR; +goto err; +} + +/* + * The device MUST set the status byte to VIRTIO_BLK_S_UNSUPP for discard + * and write zeroes commands if any unknown flag is set. + */ +if (unlikely(flags & ~VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP)) { +err_status = VIRTIO_BLK_S_UNSUPP; +goto err; +} + +if (is_write_zeroes) { /* VIRTIO_BLK_T_WRITE_ZEROES */ +int blk_aio_flags = 0; + +if (flags & VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP) { +blk_aio_flags |= BDRV_REQ_MAY_UNMAP; +} + +block_acct_start(blk_get_stats(s->blk), &req->acct, bytes, + BLOCK_ACCT_WRITE); + +blk_aio_pwrite_zeroes(s->blk, sector << BDRV_SECTOR_BITS, + bytes, blk_aio_flags, + virtio_blk_discard_write_zeroes_complete, req); +} else { /* VIRTIO_BLK_T_DISCARD */ +/* + * The device MUST set the status byte to VIRTIO_BLK_S_UNSUPP for + * discard commands if the unmap flag is set. + */ +if (unlikely(flags & VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP)) { +err_status = VIRTIO_BLK_S_UNSUPP; +goto err; +} + +blk_aio_pdiscard(s->blk, sector << BDRV_SECTOR_BITS, bytes, + virtio_blk_discard_write_zeroes_complete, req); +} + +return VIRTIO_BLK_S_OK; + +err: +if (is_write_zeroes) { +block_acct_invalid(blk_get_stats(s->blk), BLOCK_ACCT_WRITE); +} +return err_status; +} + static int virtio_blk_handle_request(VirtIOBlockReq *req, Mu
[Qemu-devel] [PULL 8/9] tests/virtio-blk: change assert on data_size in virtio_blk_request()
From: Stefano Garzarella The size of data in the virtio_blk_request must be a multiple of 512 bytes for IN and OUT requests, or a multiple of the size of struct virtio_blk_discard_write_zeroes for DISCARD and WRITE_ZEROES requests. Reviewed-by: Michael S. Tsirkin Reviewed-by: Stefan Hajnoczi Reviewed-by: Thomas Huth Signed-off-by: Stefano Garzarella Acked-by: Pankaj Gupta Message-id: 20190208134950.187665-6-sgarz...@redhat.com Signed-off-by: Stefan Hajnoczi --- tests/virtio-blk-test.c | 15 ++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c index 04c608764b..0739498da7 100644 --- a/tests/virtio-blk-test.c +++ b/tests/virtio-blk-test.c @@ -144,7 +144,20 @@ static uint64_t virtio_blk_request(QGuestAllocator *alloc, QVirtioDevice *d, uint64_t addr; uint8_t status = 0xFF; -g_assert_cmpuint(data_size % 512, ==, 0); +switch (req->type) { +case VIRTIO_BLK_T_IN: +case VIRTIO_BLK_T_OUT: +g_assert_cmpuint(data_size % 512, ==, 0); +break; +case VIRTIO_BLK_T_DISCARD: +case VIRTIO_BLK_T_WRITE_ZEROES: +g_assert_cmpuint(data_size % + sizeof(struct virtio_blk_discard_write_zeroes), ==, 0); +break; +default: +g_assert_cmpuint(data_size, ==, 0); +} + addr = guest_alloc(alloc, sizeof(*req) + data_size); virtio_blk_fix_request(d, req); -- 2.20.1
[Qemu-devel] [PULL 5/9] virtio-blk: add host_features field in VirtIOBlock
From: Stefano Garzarella Since configurable features for virtio-blk are growing, this patch adds host_features field in the struct VirtIOBlock. (as in virtio-net) In this way, we can avoid to add new fields for new properties and we can directly set VIRTIO_BLK_F* flags in the host_features. We update "config-wce" and "scsi" property definition to use the new host_features field without change the behaviour. Suggested-by: Michael S. Tsirkin Reviewed-by: Stefan Hajnoczi Signed-off-by: Stefano Garzarella Acked-by: Pankaj Gupta Message-id: 20190208134950.187665-3-sgarz...@redhat.com Signed-off-by: Stefan Hajnoczi --- include/hw/virtio/virtio-blk.h | 3 +-- hw/block/virtio-blk.c | 16 +--- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h index 5117431d96..f7345b0511 100644 --- a/include/hw/virtio/virtio-blk.h +++ b/include/hw/virtio/virtio-blk.h @@ -35,8 +35,6 @@ struct VirtIOBlkConf BlockConf conf; IOThread *iothread; char *serial; -uint32_t scsi; -uint32_t config_wce; uint32_t request_merging; uint16_t num_queues; uint16_t queue_size; @@ -57,6 +55,7 @@ typedef struct VirtIOBlock { bool dataplane_disabled; bool dataplane_started; struct VirtIOBlockDataPlane *dataplane; +uint64_t host_features; } VirtIOBlock; typedef struct VirtIOBlockReq { diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index c95a6f4c9b..6526b94910 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -241,7 +241,7 @@ static int virtio_blk_handle_scsi_req(VirtIOBlockReq *req) */ scsi = (void *)elem->in_sg[elem->in_num - 2].iov_base; -if (!blk->conf.scsi) { +if (!virtio_has_feature(blk->host_features, VIRTIO_BLK_F_SCSI)) { status = VIRTIO_BLK_S_UNSUPP; goto fail; } @@ -779,12 +779,15 @@ static uint64_t virtio_blk_get_features(VirtIODevice *vdev, uint64_t features, { VirtIOBlock *s = VIRTIO_BLK(vdev); +/* Firstly sync all virtio-blk possible supported features */ +features |= s->host_features; + virtio_add_feature(&features, VIRTIO_BLK_F_SEG_MAX); virtio_add_feature(&features, VIRTIO_BLK_F_GEOMETRY); virtio_add_feature(&features, VIRTIO_BLK_F_TOPOLOGY); virtio_add_feature(&features, VIRTIO_BLK_F_BLK_SIZE); if (virtio_has_feature(features, VIRTIO_F_VERSION_1)) { -if (s->conf.scsi) { +if (virtio_has_feature(s->host_features, VIRTIO_BLK_F_SCSI)) { error_setg(errp, "Please set scsi=off for virtio-blk devices in order to use virtio 1.0"); return 0; } @@ -793,9 +796,6 @@ static uint64_t virtio_blk_get_features(VirtIODevice *vdev, uint64_t features, virtio_add_feature(&features, VIRTIO_BLK_F_SCSI); } -if (s->conf.config_wce) { -virtio_add_feature(&features, VIRTIO_BLK_F_CONFIG_WCE); -} if (blk_enable_write_cache(s->blk)) { virtio_add_feature(&features, VIRTIO_BLK_F_WCE); } @@ -1010,9 +1010,11 @@ static Property virtio_blk_properties[] = { DEFINE_BLOCK_ERROR_PROPERTIES(VirtIOBlock, conf.conf), DEFINE_BLOCK_CHS_PROPERTIES(VirtIOBlock, conf.conf), DEFINE_PROP_STRING("serial", VirtIOBlock, conf.serial), -DEFINE_PROP_BIT("config-wce", VirtIOBlock, conf.config_wce, 0, true), +DEFINE_PROP_BIT64("config-wce", VirtIOBlock, host_features, + VIRTIO_BLK_F_CONFIG_WCE, true), #ifdef __linux__ -DEFINE_PROP_BIT("scsi", VirtIOBlock, conf.scsi, 0, false), +DEFINE_PROP_BIT64("scsi", VirtIOBlock, host_features, + VIRTIO_BLK_F_SCSI, false), #endif DEFINE_PROP_BIT("request-merging", VirtIOBlock, conf.request_merging, 0, true), -- 2.20.1
[Qemu-devel] [PULL 6/9] virtio-blk: add "discard" and "write-zeroes" properties
From: Stefano Garzarella In order to avoid migration issues, we enable DISCARD and WRITE_ZEROES features only for machine type >= 4.0 As discussed with Michael S. Tsirkin and Stefan Hajnoczi on the list [1], DISCARD operation should not have security implications (eg. page cache attacks), so we can enable it by default. [1] https://lists.gnu.org/archive/html/qemu-devel/2019-02/msg00504.html Suggested-by: Dr. David Alan Gilbert Reviewed-by: Michael S. Tsirkin Reviewed-by: Stefan Hajnoczi Signed-off-by: Stefano Garzarella Acked-by: Pankaj Gupta Message-id: 20190208134950.187665-4-sgarz...@redhat.com Signed-off-by: Stefan Hajnoczi --- hw/block/virtio-blk.c | 4 hw/core/machine.c | 2 ++ 2 files changed, 6 insertions(+) diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index 6526b94910..feeaf77965 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -1022,6 +1022,10 @@ static Property virtio_blk_properties[] = { DEFINE_PROP_UINT16("queue-size", VirtIOBlock, conf.queue_size, 128), DEFINE_PROP_LINK("iothread", VirtIOBlock, conf.iothread, TYPE_IOTHREAD, IOThread *), +DEFINE_PROP_BIT64("discard", VirtIOBlock, host_features, + VIRTIO_BLK_F_DISCARD, true), +DEFINE_PROP_BIT64("write-zeroes", VirtIOBlock, host_features, + VIRTIO_BLK_F_WRITE_ZEROES, true), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/core/machine.c b/hw/core/machine.c index 077fbd182a..766ca5899d 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -33,6 +33,8 @@ GlobalProperty hw_compat_3_1[] = { { "usb-kbd", "serial", "42" }, { "usb-mouse", "serial", "42" }, { "usb-kbd", "serial", "42" }, +{ "virtio-blk-device", "discard", "false" }, +{ "virtio-blk-device", "write-zeroes", "false" }, }; const size_t hw_compat_3_1_len = G_N_ELEMENTS(hw_compat_3_1); -- 2.20.1
[Qemu-devel] [PULL 9/9] tests/virtio-blk: add test for WRITE_ZEROES command
From: Stefano Garzarella If the WRITE_ZEROES feature is enabled, we check this command in the test_basic(). Reviewed-by: Michael S. Tsirkin Reviewed-by: Stefan Hajnoczi Acked-by: Thomas Huth Signed-off-by: Stefano Garzarella Acked-by: Pankaj Gupta Message-id: 20190208134950.187665-7-sgarz...@redhat.com Signed-off-by: Stefan Hajnoczi --- tests/virtio-blk-test.c | 60 + 1 file changed, 60 insertions(+) diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c index 0739498da7..35bd92dbfc 100644 --- a/tests/virtio-blk-test.c +++ b/tests/virtio-blk-test.c @@ -244,6 +244,66 @@ static void test_basic(QVirtioDevice *dev, QGuestAllocator *alloc, guest_free(alloc, req_addr); +if (features & (1u << VIRTIO_BLK_F_WRITE_ZEROES)) { +struct virtio_blk_discard_write_zeroes dwz_hdr; +void *expected; + +/* + * WRITE_ZEROES request on the same sector of previous test where + * we wrote "TEST". + */ +req.type = VIRTIO_BLK_T_WRITE_ZEROES; +req.data = (char *) &dwz_hdr; +dwz_hdr.sector = 0; +dwz_hdr.num_sectors = 1; +dwz_hdr.flags = 0; + +req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr)); + +free_head = qvirtqueue_add(vq, req_addr, 16, false, true); +qvirtqueue_add(vq, req_addr + 16, sizeof(dwz_hdr), false, true); +qvirtqueue_add(vq, req_addr + 16 + sizeof(dwz_hdr), 1, true, false); + +qvirtqueue_kick(dev, vq, free_head); + +qvirtio_wait_used_elem(dev, vq, free_head, NULL, + QVIRTIO_BLK_TIMEOUT_US); +status = readb(req_addr + 16 + sizeof(dwz_hdr)); +g_assert_cmpint(status, ==, 0); + +guest_free(alloc, req_addr); + +/* Read request to check if the sector contains all zeroes */ +req.type = VIRTIO_BLK_T_IN; +req.ioprio = 1; +req.sector = 0; +req.data = g_malloc0(512); + +req_addr = virtio_blk_request(alloc, dev, &req, 512); + +g_free(req.data); + +free_head = qvirtqueue_add(vq, req_addr, 16, false, true); +qvirtqueue_add(vq, req_addr + 16, 512, true, true); +qvirtqueue_add(vq, req_addr + 528, 1, true, false); + +qvirtqueue_kick(dev, vq, free_head); + +qvirtio_wait_used_elem(dev, vq, free_head, NULL, + QVIRTIO_BLK_TIMEOUT_US); +status = readb(req_addr + 528); +g_assert_cmpint(status, ==, 0); + +data = g_malloc(512); +expected = g_malloc0(512); +memread(req_addr + 16, data, 512); +g_assert_cmpmem(data, 512, expected, 512); +g_free(expected); +g_free(data); + +guest_free(alloc, req_addr); +} + if (features & (1u << VIRTIO_F_ANY_LAYOUT)) { /* Write and read with 2 descriptor layout */ /* Write request */ -- 2.20.1
[Qemu-devel] [PULL 0/9] Block patches
The following changes since commit e47f81b617684c4546af286d307b69014a83538a: Merge remote-tracking branch 'remotes/thibault/tags/samuel-thibault' into staging (2019-02-07 18:53:25 +) are available in the Git repository at: git://github.com/stefanha/qemu.git tags/block-pull-request for you to fetch changes up to 5514017bb555c5d05165b93b25557d2e6397: tests/virtio-blk: add test for WRITE_ZEROES command (2019-02-11 11:58:17 +0800) Pull request User-visible changes: * virtio-blk: DISCARD and WRITE_ZEROES support Peter Xu (1): iothread: fix iothread hang when stop too soon Stefano Garzarella (7): virtio-blk: cleanup using VirtIOBlock *s and VirtIODevice *vdev virtio-blk: add acct_failed param to virtio_blk_handle_rw_error() virtio-blk: add host_features field in VirtIOBlock virtio-blk: add "discard" and "write-zeroes" properties virtio-blk: add DISCARD and WRITE_ZEROES features tests/virtio-blk: change assert on data_size in virtio_blk_request() tests/virtio-blk: add test for WRITE_ZEROES command Vladimir Sementsov-Ogievskiy (1): qemugdb/coroutine: fix arch_prctl has unknown return type include/hw/virtio/virtio-blk.h | 5 +- hw/block/virtio-blk.c | 236 + hw/core/machine.c | 2 + iothread.c | 6 +- tests/virtio-blk-test.c| 75 ++- scripts/qemugdb/coroutine.py | 2 +- 6 files changed, 297 insertions(+), 29 deletions(-) -- 2.20.1
[Qemu-devel] [PULL 1/9] iothread: fix iothread hang when stop too soon
From: Peter Xu Lukas reported an hard to reproduce QMP iothread hang on s390 that QEMU might hang at pthread_join() of the QMP monitor iothread before quitting: Thread 1 #0 0x03ffad10932c in pthread_join #1 0x000109e95750 in qemu_thread_join at /home/thuth/devel/qemu/util/qemu-thread-posix.c:570 #2 0x000109c95a1c in iothread_stop #3 0x000109bb0874 in monitor_cleanup #4 0x000109b55042 in main While the iothread is still in the main loop: Thread 4 #0 0x03ffad0010e4 in ?? #1 0x03ffad553958 in g_main_context_iterate.isra.19 #2 0x03ffad553d90 in g_main_loop_run #3 0x000109c9585a in iothread_run at /home/thuth/devel/qemu/iothread.c:74 #4 0x000109e94752 in qemu_thread_start at /home/thuth/devel/qemu/util/qemu-thread-posix.c:502 #5 0x03ffad10825a in start_thread #6 0x03ffad00dcf2 in thread_start IMHO it's because there's a race between the main thread and iothread when stopping the thread in following sequence: main thread iothread === == aio_poll() iothread_get_g_main_context set iothread->worker_context iothread_stop schedule iothread_stop_bh execute iothread_stop_bh [1] set iothread->running=false (since main_loop==NULL so skip to quit main loop. Note: although main_loop is NULL but worker_context is not!) atomic_read(&iothread->worker_context) [2] create main_loop object g_main_loop_run() [3] pthread_join() [4] We can see that when execute iothread_stop_bh() at [1] it's possible that main_loop is still NULL because it's only created until the first check of the worker_context later at [2]. Then the iothread will hang in the main loop [3] and it'll starve the main thread too [4]. Here the simple solution should be that we check again the "running" variable before check against worker_context. CC: Thomas Huth CC: Dr. David Alan Gilbert CC: Stefan Hajnoczi CC: Lukáš Doktor CC: Markus Armbruster CC: Eric Blake CC: Paolo Bonzini Reported-by: Lukáš Doktor Signed-off-by: Peter Xu Tested-by: Thomas Huth Message-id: 20190129051432.22023-1-pet...@redhat.com Signed-off-by: Stefan Hajnoczi --- iothread.c | 6 +- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/iothread.c b/iothread.c index 2fb1cdf55d..e615b7ae52 100644 --- a/iothread.c +++ b/iothread.c @@ -63,7 +63,11 @@ static void *iothread_run(void *opaque) while (iothread->running) { aio_poll(iothread->ctx, true); -if (atomic_read(&iothread->worker_context)) { +/* + * We must check the running state again in case it was + * changed in previous aio_poll() + */ +if (iothread->running && atomic_read(&iothread->worker_context)) { GMainLoop *loop; g_main_context_push_thread_default(iothread->worker_context); -- 2.20.1