From cd723b85601baa7a0eeffbac83421357a70d81ee Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 14 Sep 2016 18:17:03 +0800 Subject: [PATCH 001/723] scsi-disk: Cleaning up around tray open state Even if tray is not open, it can be empty (blk_is_inserted() == false). Handle both cases correctly by replacing the s->tray_open checks with blk_is_available(), which is an AND of the two. Also simplify successive checks of them into blk_is_available(), in a couple cases. Signed-off-by: Fam Zheng Message-Id: <1473848224-24809-2-git-send-email-famz@redhat.com> Signed-off-by: Paolo Bonzini --- hw/scsi/scsi-disk.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 77cba31e30c..88beaf4bb80 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -396,7 +396,7 @@ static void scsi_read_data(SCSIRequest *req) return; } - if (s->tray_open) { + if (!blk_is_available(req->dev->conf.blk)) { scsi_read_complete(r, -ENOMEDIUM); return; } @@ -519,7 +519,7 @@ static void scsi_write_data(SCSIRequest *req) scsi_write_complete_noio(r, 0); return; } - if (s->tray_open) { + if (!blk_is_available(req->dev->conf.blk)) { scsi_write_complete_noio(r, -ENOMEDIUM); return; } @@ -792,10 +792,7 @@ static inline bool media_is_dvd(SCSIDiskState *s) if (s->qdev.type != TYPE_ROM) { return false; } - if (!blk_is_inserted(s->qdev.conf.blk)) { - return false; - } - if (s->tray_open) { + if (!blk_is_available(s->qdev.conf.blk)) { return false; } blk_get_geometry(s->qdev.conf.blk, &nb_sectors); @@ -808,10 +805,7 @@ static inline bool media_is_cd(SCSIDiskState *s) if (s->qdev.type != TYPE_ROM) { return false; } - if (!blk_is_inserted(s->qdev.conf.blk)) { - return false; - } - if (s->tray_open) { + if (!blk_is_available(s->qdev.conf.blk)) { return false; } blk_get_geometry(s->qdev.conf.blk, &nb_sectors); @@ -875,7 +869,7 @@ static int scsi_read_dvd_structure(SCSIDiskState *s, SCSIDiskReq *r, } if (format != 0xff) { - if (s->tray_open || !blk_is_inserted(s->qdev.conf.blk)) { + if (!blk_is_available(s->qdev.conf.blk)) { scsi_check_condition(r, SENSE_CODE(NO_MEDIUM)); return -1; } @@ -1857,7 +1851,7 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf) break; default: - if (s->tray_open || !blk_is_inserted(s->qdev.conf.blk)) { + if (!blk_is_available(s->qdev.conf.blk)) { scsi_check_condition(r, SENSE_CODE(NO_MEDIUM)); return 0; } @@ -1886,7 +1880,7 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf) memset(outbuf, 0, r->buflen); switch (req->cmd.buf[0]) { case TEST_UNIT_READY: - assert(!s->tray_open && blk_is_inserted(s->qdev.conf.blk)); + assert(blk_is_available(s->qdev.conf.blk)); break; case INQUIRY: buflen = scsi_disk_emulate_inquiry(req, outbuf); @@ -2126,7 +2120,7 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf) command = buf[0]; - if (s->tray_open || !blk_is_inserted(s->qdev.conf.blk)) { + if (!blk_is_available(s->qdev.conf.blk)) { scsi_check_condition(r, SENSE_CODE(NO_MEDIUM)); return 0; } From 2a2d69f490c1b1dc6b6d2aef385ee7b654497a77 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 14 Sep 2016 18:17:04 +0800 Subject: [PATCH 002/723] virtio-scsi: Don't abort when media is ejected With an ejected block backend, blk_get_aio_context() would return qemu_aio_context. In this case don't assert. Signed-off-by: Fam Zheng Message-Id: <1473848224-24809-3-git-send-email-famz@redhat.com> Signed-off-by: Paolo Bonzini --- hw/scsi/virtio-scsi.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index ce57ef62487..e596b647413 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -236,6 +236,13 @@ static void virtio_scsi_cancel_notify(Notifier *notifier, void *data) g_free(n); } +static inline void virtio_scsi_ctx_check(VirtIOSCSI *s, SCSIDevice *d) +{ + if (s->dataplane_started && d && blk_is_available(d->conf.blk)) { + assert(blk_get_aio_context(d->conf.blk) == s->ctx); + } +} + /* Return 0 if the request is ready to be completed and return to guest; * -EINPROGRESS if the request is submitted and will be completed later, in the * case of async cancellation. */ @@ -247,9 +254,7 @@ static int virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) int target; int ret = 0; - if (s->dataplane_started && d) { - assert(blk_get_aio_context(d->conf.blk) == s->ctx); - } + virtio_scsi_ctx_check(s, d); /* Here VIRTIO_SCSI_S_OK means "FUNCTION COMPLETE". */ req->resp.tmf.response = VIRTIO_SCSI_S_OK; @@ -539,9 +544,7 @@ static bool virtio_scsi_handle_cmd_req_prepare(VirtIOSCSI *s, VirtIOSCSIReq *req virtio_scsi_complete_cmd_req(req); return false; } - if (s->dataplane_started) { - assert(blk_get_aio_context(d->conf.blk) == s->ctx); - } + virtio_scsi_ctx_check(s, d); req->sreq = scsi_req_new(d, req->req.cmd.tag, virtio_scsi_get_lun(req->req.cmd.lun), req->req.cmd.cdb, req); From 670e56d3ed2918b3861d9216f2c0540d9e9ae0d5 Mon Sep 17 00:00:00 2001 From: Li Qiang Date: Mon, 12 Sep 2016 18:14:11 +0530 Subject: [PATCH 003/723] scsi: mptsas: use g_new0 to allocate MPTSASRequest object When processing IO request in mptsas, it uses g_new to allocate a 'req' object. If an error occurs before 'req->sreq' is allocated, It could lead to an OOB write in mptsas_free_request function. Use g_new0 to avoid it. Reported-by: Li Qiang Signed-off-by: Prasad J Pandit Message-Id: <1473684251-17476-1-git-send-email-ppandit@redhat.com> Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini --- hw/scsi/mptsas.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/scsi/mptsas.c b/hw/scsi/mptsas.c index 0e0a22f6968..eaae1bb1825 100644 --- a/hw/scsi/mptsas.c +++ b/hw/scsi/mptsas.c @@ -304,7 +304,7 @@ static int mptsas_process_scsi_io_request(MPTSASState *s, goto bad; } - req = g_new(MPTSASRequest, 1); + req = g_new0(MPTSASRequest, 1); QTAILQ_INSERT_TAIL(&s->pending, req, next); req->scsi_io = *scsi_io; req->dev = s; From d9911d14e01f5e97c6ac1fe681ef15334250d149 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 13 Sep 2016 13:57:19 -0700 Subject: [PATCH 004/723] cutils: Rewrite x86 buffer zero checking Handle alignment of buffers, so that the vector paths can be used more often. Signed-off-by: Richard Henderson Signed-off-by: Paolo Bonzini Message-Id: <1473800239-13841-1-git-send-email-rth@twiddle.net> Signed-off-by: Paolo Bonzini --- util/bufferiszero.c | 231 ++++++++++++++++++++++++++++++-------------- 1 file changed, 156 insertions(+), 75 deletions(-) diff --git a/util/bufferiszero.c b/util/bufferiszero.c index abe65f9d88e..eb974b7849f 100644 --- a/util/bufferiszero.c +++ b/util/bufferiszero.c @@ -26,38 +26,6 @@ #include "qemu/cutils.h" #include "qemu/bswap.h" - -/* vector definitions */ - -extern void link_error(void); - -#define ACCEL_BUFFER_ZERO(NAME, SIZE, VECTYPE, NONZERO) \ -static bool NAME(const void *buf, size_t len) \ -{ \ - const void *end = buf + len; \ - do { \ - const VECTYPE *p = buf; \ - VECTYPE t; \ - __builtin_prefetch(buf + SIZE); \ - barrier(); \ - if (SIZE == sizeof(VECTYPE) * 4) { \ - t = (p[0] | p[1]) | (p[2] | p[3]); \ - } else if (SIZE == sizeof(VECTYPE) * 8) { \ - t = p[0] | p[1]; \ - t |= p[2] | p[3]; \ - t |= p[4] | p[5]; \ - t |= p[6] | p[7]; \ - } else { \ - link_error(); \ - } \ - if (unlikely(NONZERO(t))) { \ - return false; \ - } \ - buf += SIZE; \ - } while (buf < end); \ - return true; \ -} - static bool buffer_zero_int(const void *buf, size_t len) { @@ -96,47 +64,174 @@ buffer_zero_int(const void *buf, size_t len) } } -#if defined(CONFIG_AVX2_OPT) || (defined(CONFIG_CPUID_H) && defined(__SSE2__)) -#include - +#if defined(CONFIG_AVX2_OPT) || defined(__SSE2__) /* Do not use push_options pragmas unnecessarily, because clang * does not support them. */ -#ifndef __SSE2__ +#ifdef CONFIG_AVX2_OPT #pragma GCC push_options #pragma GCC target("sse2") #endif #include -#define SSE2_NONZERO(X) \ - (_mm_movemask_epi8(_mm_cmpeq_epi8((X), _mm_setzero_si128())) != 0xFFFF) -ACCEL_BUFFER_ZERO(buffer_zero_sse2, 64, __m128i, SSE2_NONZERO) -#ifndef __SSE2__ + +/* Note that each of these vectorized functions require len >= 64. */ + +static bool +buffer_zero_sse2(const void *buf, size_t len) +{ + __m128i t = _mm_loadu_si128(buf); + __m128i *p = (__m128i *)(((uintptr_t)buf + 5 * 16) & -16); + __m128i *e = (__m128i *)(((uintptr_t)buf + len) & -16); + __m128i zero = _mm_setzero_si128(); + + /* Loop over 16-byte aligned blocks of 64. */ + while (likely(p <= e)) { + __builtin_prefetch(p); + t = _mm_cmpeq_epi8(t, zero); + if (unlikely(_mm_movemask_epi8(t) != 0xFFFF)) { + return false; + } + t = p[-4] | p[-3] | p[-2] | p[-1]; + p += 4; + } + + /* Finish the aligned tail. */ + t |= e[-3]; + t |= e[-2]; + t |= e[-1]; + + /* Finish the unaligned tail. */ + t |= _mm_loadu_si128(buf + len - 16); + + return _mm_movemask_epi8(_mm_cmpeq_epi8(t, zero)) == 0xFFFF; +} +#ifdef CONFIG_AVX2_OPT #pragma GCC pop_options #endif #ifdef CONFIG_AVX2_OPT +/* Note that due to restrictions/bugs wrt __builtin functions in gcc <= 4.8, + * the includes have to be within the corresponding push_options region, and + * therefore the regions themselves have to be ordered with increasing ISA. + */ #pragma GCC push_options #pragma GCC target("sse4") #include -#define SSE4_NONZERO(X) !_mm_testz_si128((X), (X)) -ACCEL_BUFFER_ZERO(buffer_zero_sse4, 64, __m128i, SSE4_NONZERO) -#pragma GCC pop_options +static bool +buffer_zero_sse4(const void *buf, size_t len) +{ + __m128i t = _mm_loadu_si128(buf); + __m128i *p = (__m128i *)(((uintptr_t)buf + 5 * 16) & -16); + __m128i *e = (__m128i *)(((uintptr_t)buf + len) & -16); + + /* Loop over 16-byte aligned blocks of 64. */ + while (likely(p <= e)) { + __builtin_prefetch(p); + if (unlikely(!_mm_testz_si128(t, t))) { + return false; + } + t = p[-4] | p[-3] | p[-2] | p[-1]; + p += 4; + } + + /* Finish the aligned tail. */ + t |= e[-3]; + t |= e[-2]; + t |= e[-1]; + + /* Finish the unaligned tail. */ + t |= _mm_loadu_si128(buf + len - 16); + + return _mm_testz_si128(t, t); +} + +#pragma GCC pop_options #pragma GCC push_options #pragma GCC target("avx2") #include -#define AVX2_NONZERO(X) !_mm256_testz_si256((X), (X)) -ACCEL_BUFFER_ZERO(buffer_zero_avx2, 128, __m256i, AVX2_NONZERO) + +static bool +buffer_zero_avx2(const void *buf, size_t len) +{ + /* Begin with an unaligned head of 32 bytes. */ + __m256i t = _mm256_loadu_si256(buf); + __m256i *p = (__m256i *)(((uintptr_t)buf + 5 * 32) & -32); + __m256i *e = (__m256i *)(((uintptr_t)buf + len) & -32); + + if (likely(p <= e)) { + /* Loop over 32-byte aligned blocks of 128. */ + do { + __builtin_prefetch(p); + if (unlikely(!_mm256_testz_si256(t, t))) { + return false; + } + t = p[-4] | p[-3] | p[-2] | p[-1]; + p += 4; + } while (p <= e); + } else { + t |= _mm256_loadu_si256(buf + 32); + if (len <= 128) { + goto last2; + } + } + + /* Finish the last block of 128 unaligned. */ + t |= _mm256_loadu_si256(buf + len - 4 * 32); + t |= _mm256_loadu_si256(buf + len - 3 * 32); + last2: + t |= _mm256_loadu_si256(buf + len - 2 * 32); + t |= _mm256_loadu_si256(buf + len - 1 * 32); + + return _mm256_testz_si256(t, t); +} #pragma GCC pop_options +#endif /* CONFIG_AVX2_OPT */ + +/* Note that for test_buffer_is_zero_next_accel, the most preferred + * ISA must have the least significant bit. + */ +#define CACHE_AVX2 1 +#define CACHE_SSE4 2 +#define CACHE_SSE2 4 + +/* Make sure that these variables are appropriately initialized when + * SSE2 is enabled on the compiler command-line, but the compiler is + * too old to support . + */ +#ifdef CONFIG_AVX2_OPT +# define INIT_CACHE 0 +# define INIT_ACCEL buffer_zero_int +#else +# ifndef __SSE2__ +# error "ISA selection confusion" +# endif +# define INIT_CACHE CACHE_SSE2 +# define INIT_ACCEL buffer_zero_sse2 #endif -#define CACHE_AVX2 2 -#define CACHE_AVX1 4 -#define CACHE_SSE4 8 -#define CACHE_SSE2 16 +static unsigned cpuid_cache = INIT_CACHE; +static bool (*buffer_accel)(const void *, size_t) = INIT_ACCEL; -static unsigned cpuid_cache; +static void init_accel(unsigned cache) +{ + bool (*fn)(const void *, size_t) = buffer_zero_int; + if (cache & CACHE_SSE2) { + fn = buffer_zero_sse2; + } +#ifdef CONFIG_AVX2_OPT + if (cache & CACHE_SSE4) { + fn = buffer_zero_sse4; + } + if (cache & CACHE_AVX2) { + fn = buffer_zero_avx2; + } +#endif + buffer_accel = fn; +} +#ifdef CONFIG_AVX2_OPT +#include static void __attribute__((constructor)) init_cpuid_cache(void) { int max = __get_cpuid_max(0, NULL); @@ -154,24 +249,21 @@ static void __attribute__((constructor)) init_cpuid_cache(void) } /* We must check that AVX is not just available, but usable. */ - if ((c & bit_OSXSAVE) && (c & bit_AVX)) { - __asm("xgetbv" : "=a"(a), "=d"(d) : "c"(0)); - if ((a & 6) == 6) { - cache |= CACHE_AVX1; - if (max >= 7) { - __cpuid_count(7, 0, a, b, c, d); - if (b & bit_AVX2) { - cache |= CACHE_AVX2; - } - } + if ((c & bit_OSXSAVE) && (c & bit_AVX) && max >= 7) { + int bv; + __asm("xgetbv" : "=a"(bv), "=d"(d) : "c"(0)); + __cpuid_count(7, 0, a, b, c, d); + if ((bv & 6) == 6 && (b & bit_AVX2)) { + cache |= CACHE_AVX2; } } #endif } cpuid_cache = cache; + init_accel(cache); } +#endif /* CONFIG_AVX2_OPT */ -#define HAVE_NEXT_ACCEL bool test_buffer_is_zero_next_accel(void) { /* If no bits set, we just tested buffer_zero_int, and there @@ -181,31 +273,20 @@ bool test_buffer_is_zero_next_accel(void) } /* Disable the accelerator we used before and select a new one. */ cpuid_cache &= cpuid_cache - 1; + init_accel(cpuid_cache); return true; } static bool select_accel_fn(const void *buf, size_t len) { - uintptr_t ibuf = (uintptr_t)buf; -#ifdef CONFIG_AVX2_OPT - if (len % 128 == 0 && ibuf % 32 == 0 && (cpuid_cache & CACHE_AVX2)) { - return buffer_zero_avx2(buf, len); - } - if (len % 64 == 0 && ibuf % 16 == 0 && (cpuid_cache & CACHE_SSE4)) { - return buffer_zero_sse4(buf, len); - } -#endif - if (len % 64 == 0 && ibuf % 16 == 0 && (cpuid_cache & CACHE_SSE2)) { - return buffer_zero_sse2(buf, len); + if (likely(len >= 64)) { + return buffer_accel(buf, len); } return buffer_zero_int(buf, len); } #else #define select_accel_fn buffer_zero_int -#endif - -#ifndef HAVE_NEXT_ACCEL bool test_buffer_is_zero_next_accel(void) { return false; From 883e4f7624e10b98d16d9adaffb8b1795664d899 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Sat, 18 Jun 2016 13:24:02 +0530 Subject: [PATCH 005/723] Change net/socket.c to use socket_*() functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use socket_*() functions from include/qemu/sockets.h instead of listen()/bind()/connect()/parse_host_port(). socket_*() fucntions are QAPI based and this patch performs this api conversion since everything will be using QAPI based sockets in the future. Also add a helper function socket_address_to_string() in util/qemu-sockets.c which returns the string representation of socket address. The task was listed on http://wiki.qemu.org/BiteSizedTasks page. Signed-off-by: Ashijeet Acharya Signed-off-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- net/socket.c | 127 ++++++++++++++++++++++++++++----------------------- 1 file changed, 71 insertions(+), 56 deletions(-) diff --git a/net/socket.c b/net/socket.c index 3f98eefb347..982c8debe43 100644 --- a/net/socket.c +++ b/net/socket.c @@ -489,90 +489,105 @@ static int net_socket_listen_init(NetClientState *peer, { NetClientState *nc; NetSocketState *s; - struct sockaddr_in saddr; - int fd, ret; - - if (parse_host_port(&saddr, host_str) < 0) - return -1; + SocketAddress *saddr; + int ret; + Error *local_error = NULL; - fd = qemu_socket(PF_INET, SOCK_STREAM, 0); - if (fd < 0) { - perror("socket"); + saddr = socket_parse(host_str, &local_error); + if (saddr == NULL) { + error_report_err(local_error); return -1; } - qemu_set_nonblock(fd); - - socket_set_fast_reuse(fd); - ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)); + ret = socket_listen(saddr, &local_error); if (ret < 0) { - perror("bind"); - closesocket(fd); - return -1; - } - ret = listen(fd, 0); - if (ret < 0) { - perror("listen"); - closesocket(fd); + qapi_free_SocketAddress(saddr); + error_report_err(local_error); return -1; } nc = qemu_new_net_client(&net_socket_info, peer, model, name); s = DO_UPCAST(NetSocketState, nc, nc); s->fd = -1; - s->listen_fd = fd; + s->listen_fd = ret; s->nc.link_down = true; qemu_set_fd_handler(s->listen_fd, net_socket_accept, NULL, s); + qapi_free_SocketAddress(saddr); return 0; } +typedef struct { + NetClientState *peer; + SocketAddress *saddr; + char *model; + char *name; +} socket_connect_data; + +static void socket_connect_data_free(socket_connect_data *c) +{ + qapi_free_SocketAddress(c->saddr); + g_free(c->model); + g_free(c->name); + g_free(c); +} + +static void net_socket_connected(int fd, Error *err, void *opaque) +{ + socket_connect_data *c = opaque; + NetSocketState *s; + char *addr_str = NULL; + Error *local_error = NULL; + + addr_str = socket_address_to_string(c->saddr, &local_error); + if (addr_str == NULL) { + error_report_err(local_error); + closesocket(fd); + goto end; + } + + s = net_socket_fd_init(c->peer, c->model, c->name, fd, true); + if (!s) { + closesocket(fd); + goto end; + } + + snprintf(s->nc.info_str, sizeof(s->nc.info_str), + "socket: connect to %s", addr_str); + +end: + g_free(addr_str); + socket_connect_data_free(c); +} + static int net_socket_connect_init(NetClientState *peer, const char *model, const char *name, const char *host_str) { - NetSocketState *s; - int fd, connected, ret; - struct sockaddr_in saddr; + socket_connect_data *c = g_new0(socket_connect_data, 1); + int fd = -1; + Error *local_error = NULL; - if (parse_host_port(&saddr, host_str) < 0) - return -1; + c->peer = peer; + c->model = g_strdup(model); + c->name = g_strdup(name); + c->saddr = socket_parse(host_str, &local_error); + if (c->saddr == NULL) { + goto err; + } - fd = qemu_socket(PF_INET, SOCK_STREAM, 0); + fd = socket_connect(c->saddr, &local_error, net_socket_connected, c); if (fd < 0) { - perror("socket"); - return -1; + goto err; } - qemu_set_nonblock(fd); - connected = 0; - for(;;) { - ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr)); - if (ret < 0) { - if (errno == EINTR || errno == EWOULDBLOCK) { - /* continue */ - } else if (errno == EINPROGRESS || - errno == EALREADY || - errno == EINVAL) { - break; - } else { - perror("connect"); - closesocket(fd); - return -1; - } - } else { - connected = 1; - break; - } - } - s = net_socket_fd_init(peer, model, name, fd, connected); - if (!s) - return -1; - snprintf(s->nc.info_str, sizeof(s->nc.info_str), - "socket: connect to %s:%d", - inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); return 0; + +err: + error_report_err(local_error); + socket_connect_data_free(c); + return -1; } static int net_socket_mcast_init(NetClientState *peer, From 58268c8d3d051f7fe329dcd42a9284cb4e3b3e31 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 14 Sep 2016 11:05:59 +0200 Subject: [PATCH 006/723] memory: remove memory_region_destructor_rom_device It is equivalent to memory_region_destructor_ram, use that one. Reviewed-by: Igor Mammedov Signed-off-by: Paolo Bonzini --- memory.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/memory.c b/memory.c index 0eb6895fe6a..1a1baf574cb 100644 --- a/memory.c +++ b/memory.c @@ -944,11 +944,6 @@ static void memory_region_destructor_ram(MemoryRegion *mr) qemu_ram_free(mr->ram_block); } -static void memory_region_destructor_rom_device(MemoryRegion *mr) -{ - qemu_ram_free(mr->ram_block); -} - static bool memory_region_need_escape(char c) { return c == '/' || c == '[' || c == '\\' || c == ']'; @@ -1405,7 +1400,7 @@ void memory_region_init_rom_device(MemoryRegion *mr, mr->opaque = opaque; mr->terminates = true; mr->rom_device = true; - mr->destructor = memory_region_destructor_rom_device; + mr->destructor = memory_region_destructor_ram; mr->ram_block = qemu_ram_alloc(size, mr, errp); } From d251157ac1928191af851d199a9ff255d330bec9 Mon Sep 17 00:00:00 2001 From: Prasad J Pandit Date: Wed, 14 Sep 2016 15:09:12 +0530 Subject: [PATCH 007/723] scsi: pvscsi: limit process IO loop to ring size Vmware Paravirtual SCSI emulator while processing IO requests could run into an infinite loop if 'pvscsi_ring_pop_req_descr' always returned positive value. Limit IO loop to the ring size. Cc: qemu-stable@nongnu.org Reported-by: Li Qiang Signed-off-by: Prasad J Pandit Message-Id: <1473845952-30785-1-git-send-email-ppandit@redhat.com> Signed-off-by: Paolo Bonzini --- hw/scsi/vmw_pvscsi.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c index babac5a68a9..a5ce7dea8ea 100644 --- a/hw/scsi/vmw_pvscsi.c +++ b/hw/scsi/vmw_pvscsi.c @@ -247,8 +247,11 @@ static hwaddr pvscsi_ring_pop_req_descr(PVSCSIRingInfo *mgr) { uint32_t ready_ptr = RS_GET_FIELD(mgr, reqProdIdx); + uint32_t ring_size = PVSCSI_MAX_NUM_PAGES_REQ_RING + * PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE; - if (ready_ptr != mgr->consumed_ptr) { + if (ready_ptr != mgr->consumed_ptr + && ready_ptr - mgr->consumed_ptr < ring_size) { uint32_t next_ready_ptr = mgr->consumed_ptr++ & mgr->txr_len_mask; uint32_t next_ready_page = From bb93e099888e8e7e959aa610ac783f41036bcc94 Mon Sep 17 00:00:00 2001 From: Wanpeng Li Date: Wed, 14 Sep 2016 13:54:24 +0800 Subject: [PATCH 008/723] pc: apic: fix touch LAPIC when irqchip is split MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add -kernel_irqchip=split ./x86-run x86/eventinj.flat qemu-system-x86_64 -enable-kvm -machine kernel_irqchip=split -cpu host -device pc-testdev -device isa-debug-exit,iobase=0xf4,iosize=0x4 -vnc none -serial stdio -device pci-testdev -kernel x86/eventinj.flat enabling apic paging enabled cr0 = 80010011 cr3 = 7fff000 cr4 = 20 Sending vec 33 and 62 and mask one with TPR irq1 running irq1 running After 33/62 TPR test FAIL: TPR irq0 running irq0 running Both irq1 and irq0 are executing twice. kvm_entry: vcpu 0 kvm_exit: reason MSR_WRITE rip 0x401f33 info 0 0 kvm_apic: apic_write APIC_EOI = 0x0 kvm_eoi: apicid 0 vector 62 kvm_msr: msr_write 80b = 0x0 kvm_entry: vcpu 0 kvm_exit: reason PENDING_INTERRUPT rip 0x401f35 info 0 0 kvm_userspace_exit: reason KVM_EXIT_IRQ_WINDOW_OPEN (7) kvm_inj_virq: irq 62 kvm_entry: vcpu 0 kvm_exit: reason IO_INSTRUCTION rip 0x4016ec info 3fd0008 0 From the trace we can see there is an interrupt window exit after the first interrupt EOI(irq 62), and the same irq(62) is injected duplicately after the interrupt window. QEMU does KVM_INTERRUPT(62) ioctl after KVM exits with KVM_EXIT_IRQ_WINDOW_OPEN, which QEMU requested while the guest was printing. The printing calls serial_update_irq() -> qemu_irq_lower() -> qemu_set_irq() -> gsi_handler() -> qemu_set_irq() -> pic_irq_request() -> apic_deliver_pic_intr() -> kvm_handle_interrupt() kvm_handle_interrupt() does interrupt_request |= CPU_INTERRUPT_HARD which later calls cpu_get_pic_interrupt() in kvm_arch_pre_run(), but that function uses stale information from APIC and injects 62 again. If we synchronized the APIC, then the test would #GP, because there would be no injectable interrupt in LAPIC or PIC, so pic_read_irq() would return 15, thinking it was spurious. This patch fix it by don't touch LAPIC if LAPIC is in kernel. Suggested-by: Paolo Bonzini Suggested-by: Radim Krčmář Cc: qemu-stable@nongnu.org Cc: Paolo Bonzini Cc: Radim Krčmář Cc: Michael S. Tsirkin Cc: Eduardo Habkost Signed-off-by: Wanpeng Li Message-Id: <1473832464-3478-1-git-send-email-wanpeng.li@hotmail.com> Signed-off-by: Paolo Bonzini --- hw/i386/pc.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index e31f70f428d..2d6d7920ffe 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -161,13 +161,15 @@ int cpu_get_pic_interrupt(CPUX86State *env) X86CPU *cpu = x86_env_get_cpu(env); int intno; - intno = apic_get_interrupt(cpu->apic_state); - if (intno >= 0) { - return intno; - } - /* read the irq from the PIC */ - if (!apic_accept_pic_intr(cpu->apic_state)) { - return -1; + if (!kvm_irqchip_in_kernel()) { + intno = apic_get_interrupt(cpu->apic_state); + if (intno >= 0) { + return intno; + } + /* read the irq from the PIC */ + if (!apic_accept_pic_intr(cpu->apic_state)) { + return -1; + } } intno = pic_read_irq(isa_pic); @@ -180,7 +182,7 @@ static void pic_irq_request(void *opaque, int irq, int level) X86CPU *cpu = X86_CPU(cs); DPRINTF("pic_irqs: %s irq %d\n", level? "raise" : "lower", irq); - if (cpu->apic_state) { + if (cpu->apic_state && !kvm_irqchip_in_kernel()) { CPU_FOREACH(cs) { cpu = X86_CPU(cs); if (apic_accept_pic_intr(cpu->apic_state)) { From 7616f1c2da1c0f336a474a56ad6d32e15ccd666e Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sun, 21 Aug 2016 23:16:12 +0200 Subject: [PATCH 009/723] target-i386: fix ordering of fields in CPUX86State Make sure reset zeroes TSC_AUX, XCR0, PKRU. Move XSTATE_BV from the "vmstate only" section to the "KVM only" section. Signed-off-by: Paolo Bonzini --- target-i386/cpu.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index bb3ffda2441..58e43b6f4b5 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -1035,6 +1035,9 @@ typedef struct CPUX86State { uint64_t tsc; uint64_t tsc_adjust; uint64_t tsc_deadline; + uint64_t tsc_aux; + + uint64_t xcr0; uint64_t mcg_status; uint64_t msr_ia32_misc_enable; @@ -1051,6 +1054,8 @@ typedef struct CPUX86State { uint64_t pat; uint32_t smbase; + uint32_t pkru; + /* End of state preserved by INIT (dummy marker). */ struct {} end_init_save; @@ -1135,20 +1140,15 @@ typedef struct CPUX86State { uint64_t mcg_ctl; uint64_t mcg_ext_ctl; uint64_t mce_banks[MCE_BANKS_DEF*4]; - - uint64_t tsc_aux; + uint64_t xstate_bv; /* vmstate */ uint16_t fpus_vmstate; uint16_t fptag_vmstate; uint16_t fpregs_format_vmstate; - uint64_t xstate_bv; - uint64_t xcr0; uint64_t xss; - uint32_t pkru; - TPRAccess tpr_access_type; } CPUX86State; From b8da57fa1537347f54a0864c61a68b14b02ce911 Mon Sep 17 00:00:00 2001 From: Wei Jiangang Date: Thu, 7 Apr 2016 10:46:23 +0800 Subject: [PATCH 010/723] linux-user: complete omission of removing uses of strdup The 900cfbc just removed two unchecked uses of strdup in fill_psinfo and missed the rest in core_dump_filename. This patch fixes it. Signed-off-by: Wei Jiangang Message-Id: <1459997185-15669-2-git-send-email-weijg.fnst@cn.fujitsu.com> Signed-off-by: Paolo Bonzini --- linux-user/elfload.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index f807baf3896..29455e4e478 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -2718,7 +2718,6 @@ static int core_dump_filename(const TaskState *ts, char *buf, size_t bufsize) { char timestamp[64]; - char *filename = NULL; char *base_filename = NULL; struct timeval tv; struct tm tm; @@ -2731,14 +2730,12 @@ static int core_dump_filename(const TaskState *ts, char *buf, return (-1); } - filename = strdup(ts->bprm->filename); - base_filename = strdup(basename(filename)); + base_filename = g_path_get_basename(ts->bprm->filename); (void) strftime(timestamp, sizeof (timestamp), "%Y%m%d-%H%M%S", localtime_r(&tv.tv_sec, &tm)); (void) snprintf(buf, bufsize, "qemu_%s_%s_%d.core", base_filename, timestamp, (int)getpid()); - free(base_filename); - free(filename); + g_free(base_filename); return (0); } From 0d8e065fc5f72462a4664cea501d45e508c5755c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 13 Sep 2016 18:20:33 +0400 Subject: [PATCH 011/723] build-sys: add make 'help' target MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a make 'help', to print a summary of the main Makefile targets. The format is loosely inspired by Linux make 'help' output. Signed-off-by: Marc-André Lureau Message-Id: <20160913142033.7705-1-marcandre.lureau@redhat.com> Signed-off-by: Paolo Bonzini --- Makefile | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/Makefile b/Makefile index 50b4b3afb96..1fad5b78e57 100644 --- a/Makefile +++ b/Makefile @@ -669,3 +669,40 @@ endif -include $(wildcard *.d tests/*.d) include $(SRC_PATH)/tests/docker/Makefile.include + +.PHONY: help +help: + @echo 'Generic targets:' + @echo ' all - Build all' + @echo ' dir/file.o - Build specified target only' + @echo ' install - Install QEMU, documentation and tools' + @echo ' ctags/TAGS - Generate tags file for editors' + @echo ' cscope - Generate cscope index' + @echo '' + @$(if $(TARGET_DIRS), \ + echo 'Architecture specific targets:'; \ + $(foreach t, $(TARGET_DIRS), \ + printf " %-30s - Build for %s\\n" $(patsubst %,subdir-%,$(t)) $(t);) \ + echo '') + @echo 'Cleaning targets:' + @echo ' clean - Remove most generated files but keep the config' + @echo ' distclean - Remove all generated files' + @echo ' dist - Build a distributable tarball' + @echo '' + @echo 'Test targets:' + @echo ' check - Run all tests (check-help for details)' + @echo ' docker - Help about targets running tests inside Docker containers' + @echo '' + @echo 'Documentation targets:' + @echo ' dvi html info pdf' + @echo ' - Build documentation in specified format' + @echo '' +ifdef CONFIG_WIN32 + @echo 'Windows targets:' + @echo ' installer - Build NSIS-based installer for qemu-ga' +ifdef QEMU_GA_MSI_ENABLED + @echo ' msi - Build MSI-based installer for qemu-ga' +endif + @echo '' +endif + @echo ' make V=0|1 [targets] 0 => quiet build (default), 1 => verbose build' From 71200fb9664c2967a1cdd22b68b0da3a8b2b3eb7 Mon Sep 17 00:00:00 2001 From: Lin Ma Date: Wed, 14 Sep 2016 14:22:50 +0800 Subject: [PATCH 012/723] qemu-char: avoid segfault if user lacks of permisson of a given logfile Function qemu_chr_alloc returns NULL if it failed to open logfile by any reason, says no write permission. For backends tty, stdio and msmouse, They need to check this return value to avoid segfault in this case. Signed-off-by: Lin Ma Cc: qemu-stable Message-Id: <20160914062250.22226-1-lma@suse.com> Signed-off-by: Paolo Bonzini --- backends/msmouse.c | 3 +++ qemu-char.c | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/backends/msmouse.c b/backends/msmouse.c index aeb905562d2..aceb6dc4757 100644 --- a/backends/msmouse.c +++ b/backends/msmouse.c @@ -159,6 +159,9 @@ static CharDriverState *qemu_chr_open_msmouse(const char *id, CharDriverState *chr; chr = qemu_chr_alloc(common, errp); + if (!chr) { + return NULL; + } chr->chr_write = msmouse_chr_write; chr->chr_close = msmouse_chr_close; chr->chr_accept_input = msmouse_chr_accept_input; diff --git a/qemu-char.c b/qemu-char.c index 7fa87a8b6ee..8826419d7d5 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -1230,6 +1230,9 @@ static CharDriverState *qemu_chr_open_stdio(const char *id, sigaction(SIGCONT, &act, NULL); chr = qemu_chr_open_fd(0, 1, common, errp); + if (!chr) { + return NULL; + } chr->chr_close = qemu_chr_close_stdio; chr->chr_set_echo = qemu_chr_set_echo_stdio; if (opts->has_signal) { @@ -1686,6 +1689,9 @@ static CharDriverState *qemu_chr_open_tty_fd(int fd, tty_serial_init(fd, 115200, 'N', 8, 1); chr = qemu_chr_open_fd(fd, fd, backend, errp); + if (!chr) { + return NULL; + } chr->chr_ioctl = tty_serial_ioctl; chr->chr_close = qemu_chr_close_tty; return chr; From 89d0a64f496fb4248885ebf75216c49337951540 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Tue, 6 Sep 2016 19:25:43 +0100 Subject: [PATCH 013/723] log: fix parsing of multiple trace:PATTERN log args If giving QEMU a log arg which asks to enable multiple different trace event patterns such as $QEMU -d trace:qio*,trace:qcrypto* the parser will then invoke trace_enable_events("qio*,trace:qcrypto*") trace_enable_events("qcrypto*") as when finding a 'trace:' prefix, it is not clever enough to strip anything after the next comma. As a result only the last 'trace:' match ever works. Rather than trying to be more clever with parsing the command line arg in place, simplify the code by using g_strsplit to break it into individual strings on ','. These resulting pieces can be directly used without worrying about trailing data from the next option. Signed-off-by: Daniel P. Berrange Message-Id: <1473186343-16704-1-git-send-email-berrange@redhat.com> Signed-off-by: Paolo Bonzini --- util/log.c | 41 +++++++++++++++-------------------------- 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/util/log.c b/util/log.c index 54b54e868aa..e077340ae16 100644 --- a/util/log.c +++ b/util/log.c @@ -275,53 +275,42 @@ const QEMULogItem qemu_log_items[] = { { 0, NULL, NULL }, }; -static int cmp1(const char *s1, int n, const char *s2) -{ - if (strlen(s2) != n) { - return 0; - } - return memcmp(s1, s2, n) == 0; -} - /* takes a comma separated list of log masks. Return 0 if error. */ int qemu_str_to_log_mask(const char *str) { const QEMULogItem *item; - int mask; - const char *p, *p1; + int mask = 0; + char **parts = g_strsplit(str, ",", 0); + char **tmp; - p = str; - mask = 0; - for (;;) { - p1 = strchr(p, ','); - if (!p1) { - p1 = p + strlen(p); - } - if (cmp1(p,p1-p,"all")) { + for (tmp = parts; tmp && *tmp; tmp++) { + if (g_str_equal(*tmp, "all")) { for (item = qemu_log_items; item->mask != 0; item++) { mask |= item->mask; } #ifdef CONFIG_TRACE_LOG - } else if (strncmp(p, "trace:", 6) == 0 && p + 6 != p1) { - trace_enable_events(p + 6); + } else if (g_str_has_prefix(*tmp, "trace:") && (*tmp)[6] != '\0') { + trace_enable_events((*tmp) + 6); mask |= LOG_TRACE; #endif } else { for (item = qemu_log_items; item->mask != 0; item++) { - if (cmp1(p, p1 - p, item->name)) { + if (g_str_equal(*tmp, item->name)) { goto found; } } - return 0; + goto error; found: mask |= item->mask; } - if (*p1 != ',') { - break; - } - p = p1 + 1; } + + g_strfreev(parts); return mask; + + error: + g_strfreev(parts); + return 0; } void qemu_print_log_usage(FILE *f) From 885b7c44e4f8b7a012a92770a0dba8b238662caa Mon Sep 17 00:00:00 2001 From: Stanislav Shmarov Date: Tue, 13 Sep 2016 16:23:28 +0300 Subject: [PATCH 014/723] target-i386: Fixed syscall posssible segfault In user-mode emulation env->idt.base memory is allocated in linux-user/main.c with size 8*512 = 4096 (for 64-bit). When fake interrupt EXCP_SYSCALL is thrown do_interrupt_user checks destination privilege level for this fake exception, and tries to read 4 bytes at address base + (256 * 2^4)=4096, that causes segfault. Privlege level was checked only for int's, so lets read dpl from memory only for this case. Signed-off-by: Stanislav Shmarov Message-Id: <1473773008-2588376-1-git-send-email-snarpix@gmail.com> Signed-off-by: Paolo Bonzini --- target-i386/seg_helper.c | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/target-i386/seg_helper.c b/target-i386/seg_helper.c index 6cbdf17426e..fb79f3180d1 100644 --- a/target-i386/seg_helper.c +++ b/target-i386/seg_helper.c @@ -1137,25 +1137,27 @@ static void do_interrupt_real(CPUX86State *env, int intno, int is_int, static void do_interrupt_user(CPUX86State *env, int intno, int is_int, int error_code, target_ulong next_eip) { - SegmentCache *dt; - target_ulong ptr; - int dpl, cpl, shift; - uint32_t e2; + if (is_int) { + SegmentCache *dt; + target_ulong ptr; + int dpl, cpl, shift; + uint32_t e2; - dt = &env->idt; - if (env->hflags & HF_LMA_MASK) { - shift = 4; - } else { - shift = 3; - } - ptr = dt->base + (intno << shift); - e2 = cpu_ldl_kernel(env, ptr + 4); + dt = &env->idt; + if (env->hflags & HF_LMA_MASK) { + shift = 4; + } else { + shift = 3; + } + ptr = dt->base + (intno << shift); + e2 = cpu_ldl_kernel(env, ptr + 4); - dpl = (e2 >> DESC_DPL_SHIFT) & 3; - cpl = env->hflags & HF_CPL_MASK; - /* check privilege if software int */ - if (is_int && dpl < cpl) { - raise_exception_err(env, EXCP0D_GPF, (intno << shift) + 2); + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + cpl = env->hflags & HF_CPL_MASK; + /* check privilege if software int */ + if (dpl < cpl) { + raise_exception_err(env, EXCP0D_GPF, (intno << shift) + 2); + } } /* Since we emulate only user space, we cannot do more than From d41f3c3cc7a5fb9de144cc4022da14a9ff010671 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 13 Sep 2016 16:25:52 +0200 Subject: [PATCH 015/723] Remove remainders of HPPA backend The HPPA backend has been removed by the following commit: 802b5081233a6b643a8b135a5facaf14bafaa77d tcg-hppa: Remove tcg backend But some small pieces of the HPPA backend still survived until today. Since we also do not have support for a HPPA target in QEMU, we can nowadays safely remove the remaining HPPA parts (like the disassembler code, or the detection of HPPA in the configure script). Signed-off-by: Thomas Huth Signed-off-by: Michael Tokarev --- configure | 5 - disas.c | 2 - disas/Makefile.objs | 1 - disas/hppa.c | 2832 ------------------------------------- linux-user/syscall_defs.h | 4 +- qemu-tech.texi | 3 +- tcg/tci/README | 2 +- 7 files changed, 4 insertions(+), 2845 deletions(-) delete mode 100644 disas/hppa.c diff --git a/configure b/configure index bafc4c16632..48593280a92 100755 --- a/configure +++ b/configure @@ -511,8 +511,6 @@ elif check_define __arm__ ; then cpu="arm" elif check_define __aarch64__ ; then cpu="aarch64" -elif check_define __hppa__ ; then - cpu="hppa" else cpu=$(uname -m) fi @@ -5899,9 +5897,6 @@ for i in $ARCH $TARGET_BASE_ARCH ; do cris) disas_config "CRIS" ;; - hppa) - disas_config "HPPA" - ;; i386|x86_64|x32) disas_config "I386" ;; diff --git a/disas.c b/disas.c index 05a7a1260ac..67f116a19b0 100644 --- a/disas.c +++ b/disas.c @@ -310,8 +310,6 @@ void disas(FILE *out, void *code, unsigned long size) print_insn = print_insn_m68k; #elif defined(__s390__) print_insn = print_insn_s390; -#elif defined(__hppa__) - print_insn = print_insn_hppa; #elif defined(__ia64__) print_insn = print_insn_ia64; #endif diff --git a/disas/Makefile.objs b/disas/Makefile.objs index abeba846617..09bc9928834 100644 --- a/disas/Makefile.objs +++ b/disas/Makefile.objs @@ -9,7 +9,6 @@ libvixldir = $(SRC_PATH)/disas/libvixl # versions do not. arm-a64.o-cflags := -I$(libvixldir) -Wno-sign-compare common-obj-$(CONFIG_CRIS_DIS) += cris.o -common-obj-$(CONFIG_HPPA_DIS) += hppa.o common-obj-$(CONFIG_I386_DIS) += i386.o common-obj-$(CONFIG_IA64_DIS) += ia64.o common-obj-$(CONFIG_M68K_DIS) += m68k.o diff --git a/disas/hppa.c b/disas/hppa.c deleted file mode 100644 index 43facdc47bd..00000000000 --- a/disas/hppa.c +++ /dev/null @@ -1,2832 +0,0 @@ -/* Disassembler for the PA-RISC. Somewhat derived from sparc-pinsn.c. - Copyright 1989, 1990, 1992, 1993, 1994, 1995, 1998, 1999, 2000, 2001, 2003, - 2005 Free Software Foundation, Inc. - - Contributed by the Center for Software Science at the - University of Utah (pa-gdb-bugs@cs.utah.edu). - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, see . */ - -#include "qemu/osdep.h" -#include "disas/bfd.h" - -/* HP PA-RISC SOM object file format: definitions internal to BFD. - Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, - 2003 Free Software Foundation, Inc. - - Contributed by the Center for Software Science at the - University of Utah (pa-gdb-bugs@cs.utah.edu). - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, see . */ - -#ifndef _LIBHPPA_H -#define _LIBHPPA_H - -#define BYTES_IN_WORD 4 -#define PA_PAGESIZE 0x1000 - -/* The PA instruction set variants. */ -enum pa_arch {pa10 = 10, pa11 = 11, pa20 = 20, pa20w = 25}; - -/* HP PA-RISC relocation types */ - -enum hppa_reloc_field_selector_type - { - R_HPPA_FSEL = 0x0, - R_HPPA_LSSEL = 0x1, - R_HPPA_RSSEL = 0x2, - R_HPPA_LSEL = 0x3, - R_HPPA_RSEL = 0x4, - R_HPPA_LDSEL = 0x5, - R_HPPA_RDSEL = 0x6, - R_HPPA_LRSEL = 0x7, - R_HPPA_RRSEL = 0x8, - R_HPPA_NSEL = 0x9, - R_HPPA_NLSEL = 0xa, - R_HPPA_NLRSEL = 0xb, - R_HPPA_PSEL = 0xc, - R_HPPA_LPSEL = 0xd, - R_HPPA_RPSEL = 0xe, - R_HPPA_TSEL = 0xf, - R_HPPA_LTSEL = 0x10, - R_HPPA_RTSEL = 0x11, - R_HPPA_LTPSEL = 0x12, - R_HPPA_RTPSEL = 0x13 - }; - -/* /usr/include/reloc.h defines these to constants. We want to use - them in enums, so #undef them before we start using them. We might - be able to fix this another way by simply managing not to include - /usr/include/reloc.h, but currently GDB picks up these defines - somewhere. */ -#undef e_fsel -#undef e_lssel -#undef e_rssel -#undef e_lsel -#undef e_rsel -#undef e_ldsel -#undef e_rdsel -#undef e_lrsel -#undef e_rrsel -#undef e_nsel -#undef e_nlsel -#undef e_nlrsel -#undef e_psel -#undef e_lpsel -#undef e_rpsel -#undef e_tsel -#undef e_ltsel -#undef e_rtsel -#undef e_one -#undef e_two -#undef e_pcrel -#undef e_con -#undef e_plabel -#undef e_abs - -/* for compatibility */ -enum hppa_reloc_field_selector_type_alt - { - e_fsel = R_HPPA_FSEL, - e_lssel = R_HPPA_LSSEL, - e_rssel = R_HPPA_RSSEL, - e_lsel = R_HPPA_LSEL, - e_rsel = R_HPPA_RSEL, - e_ldsel = R_HPPA_LDSEL, - e_rdsel = R_HPPA_RDSEL, - e_lrsel = R_HPPA_LRSEL, - e_rrsel = R_HPPA_RRSEL, - e_nsel = R_HPPA_NSEL, - e_nlsel = R_HPPA_NLSEL, - e_nlrsel = R_HPPA_NLRSEL, - e_psel = R_HPPA_PSEL, - e_lpsel = R_HPPA_LPSEL, - e_rpsel = R_HPPA_RPSEL, - e_tsel = R_HPPA_TSEL, - e_ltsel = R_HPPA_LTSEL, - e_rtsel = R_HPPA_RTSEL, - e_ltpsel = R_HPPA_LTPSEL, - e_rtpsel = R_HPPA_RTPSEL - }; - -enum hppa_reloc_expr_type - { - R_HPPA_E_ONE = 0, - R_HPPA_E_TWO = 1, - R_HPPA_E_PCREL = 2, - R_HPPA_E_CON = 3, - R_HPPA_E_PLABEL = 7, - R_HPPA_E_ABS = 18 - }; - -/* for compatibility */ -enum hppa_reloc_expr_type_alt - { - e_one = R_HPPA_E_ONE, - e_two = R_HPPA_E_TWO, - e_pcrel = R_HPPA_E_PCREL, - e_con = R_HPPA_E_CON, - e_plabel = R_HPPA_E_PLABEL, - e_abs = R_HPPA_E_ABS - }; - - -/* Relocations for function calls must be accompanied by parameter - relocation bits. These bits describe exactly where the caller has - placed the function's arguments and where it expects to find a return - value. - - Both ELF and SOM encode this information within the addend field - of the call relocation. (Note this could break very badly if one - was to make a call like bl foo + 0x12345678). - - The high order 10 bits contain parameter relocation information, - the low order 22 bits contain the constant offset. */ - -#define HPPA_R_ARG_RELOC(a) \ - (((a) >> 22) & 0x3ff) -#define HPPA_R_CONSTANT(a) \ - ((((bfd_signed_vma)(a)) << (BFD_ARCH_SIZE-22)) >> (BFD_ARCH_SIZE-22)) -#define HPPA_R_ADDEND(r, c) \ - (((r) << 22) + ((c) & 0x3fffff)) - - -/* Some functions to manipulate PA instructions. */ - -/* Declare the functions with the unused attribute to avoid warnings. */ -static inline int sign_extend (int, int) ATTRIBUTE_UNUSED; -static inline int low_sign_extend (int, int) ATTRIBUTE_UNUSED; -static inline int sign_unext (int, int) ATTRIBUTE_UNUSED; -static inline int low_sign_unext (int, int) ATTRIBUTE_UNUSED; -static inline int re_assemble_3 (int) ATTRIBUTE_UNUSED; -static inline int re_assemble_12 (int) ATTRIBUTE_UNUSED; -static inline int re_assemble_14 (int) ATTRIBUTE_UNUSED; -static inline int re_assemble_16 (int) ATTRIBUTE_UNUSED; -static inline int re_assemble_17 (int) ATTRIBUTE_UNUSED; -static inline int re_assemble_21 (int) ATTRIBUTE_UNUSED; -static inline int re_assemble_22 (int) ATTRIBUTE_UNUSED; -static inline bfd_signed_vma hppa_field_adjust - (bfd_vma, bfd_signed_vma, enum hppa_reloc_field_selector_type_alt) - ATTRIBUTE_UNUSED; -static inline int hppa_rebuild_insn (int, int, int) ATTRIBUTE_UNUSED; - - -/* The *sign_extend functions are used to assemble various bitfields - taken from an instruction and return the resulting immediate - value. */ - -static inline int -sign_extend (int x, int len) -{ - int signbit = (1 << (len - 1)); - int mask = (signbit << 1) - 1; - return ((x & mask) ^ signbit) - signbit; -} - -static inline int -low_sign_extend (int x, int len) -{ - return (x >> 1) - ((x & 1) << (len - 1)); -} - - -/* The re_assemble_* functions prepare an immediate value for - insertion into an opcode. pa-risc uses all sorts of weird bitfields - in the instruction to hold the value. */ - -static inline int -sign_unext (int x, int len) -{ - int len_ones; - - len_ones = (1 << len) - 1; - - return x & len_ones; -} - -static inline int -low_sign_unext (int x, int len) -{ - int temp; - int sign; - - sign = (x >> (len-1)) & 1; - - temp = sign_unext (x, len-1); - - return (temp << 1) | sign; -} - -static inline int -re_assemble_3 (int as3) -{ - return (( (as3 & 4) << (13-2)) - | ((as3 & 3) << (13+1))); -} - -static inline int -re_assemble_12 (int as12) -{ - return (( (as12 & 0x800) >> 11) - | ((as12 & 0x400) >> (10 - 2)) - | ((as12 & 0x3ff) << (1 + 2))); -} - -static inline int -re_assemble_14 (int as14) -{ - return (( (as14 & 0x1fff) << 1) - | ((as14 & 0x2000) >> 13)); -} - -static inline int -re_assemble_16 (int as16) -{ - int s, t; - - /* Unusual 16-bit encoding, for wide mode only. */ - t = (as16 << 1) & 0xffff; - s = (as16 & 0x8000); - return (t ^ s ^ (s >> 1)) | (s >> 15); -} - -static inline int -re_assemble_17 (int as17) -{ - return (( (as17 & 0x10000) >> 16) - | ((as17 & 0x0f800) << (16 - 11)) - | ((as17 & 0x00400) >> (10 - 2)) - | ((as17 & 0x003ff) << (1 + 2))); -} - -static inline int -re_assemble_21 (int as21) -{ - return (( (as21 & 0x100000) >> 20) - | ((as21 & 0x0ffe00) >> 8) - | ((as21 & 0x000180) << 7) - | ((as21 & 0x00007c) << 14) - | ((as21 & 0x000003) << 12)); -} - -static inline int -re_assemble_22 (int as22) -{ - return (( (as22 & 0x200000) >> 21) - | ((as22 & 0x1f0000) << (21 - 16)) - | ((as22 & 0x00f800) << (16 - 11)) - | ((as22 & 0x000400) >> (10 - 2)) - | ((as22 & 0x0003ff) << (1 + 2))); -} - - -/* Handle field selectors for PA instructions. - The L and R (and LS, RS etc.) selectors are used in pairs to form a - full 32 bit address. eg. - - LDIL L'start,%r1 ; put left part into r1 - LDW R'start(%r1),%r2 ; add r1 and right part to form address - - This function returns sign extended values in all cases. -*/ - -static inline bfd_signed_vma -hppa_field_adjust (bfd_vma sym_val, - bfd_signed_vma addend, - enum hppa_reloc_field_selector_type_alt r_field) -{ - bfd_signed_vma value; - - value = sym_val + addend; - switch (r_field) - { - case e_fsel: - /* F: No change. */ - break; - - case e_nsel: - /* N: null selector. I don't really understand what this is all - about, but HP's documentation says "this indicates that zero - bits are to be used for the displacement on the instruction. - This fixup is used to identify three-instruction sequences to - access data (for importing shared library data)." */ - value = 0; - break; - - case e_lsel: - case e_nlsel: - /* L: Select top 21 bits. */ - value = value >> 11; - break; - - case e_rsel: - /* R: Select bottom 11 bits. */ - value = value & 0x7ff; - break; - - case e_lssel: - /* LS: Round to nearest multiple of 2048 then select top 21 bits. */ - value = value + 0x400; - value = value >> 11; - break; - - case e_rssel: - /* RS: Select bottom 11 bits for LS. - We need to return a value such that 2048 * LS'x + RS'x == x. - ie. RS'x = x - ((x + 0x400) & -0x800) - this is just a sign extension from bit 21. */ - value = ((value & 0x7ff) ^ 0x400) - 0x400; - break; - - case e_ldsel: - /* LD: Round to next multiple of 2048 then select top 21 bits. - Yes, if we are already on a multiple of 2048, we go up to the - next one. RD in this case will be -2048. */ - value = value + 0x800; - value = value >> 11; - break; - - case e_rdsel: - /* RD: Set bits 0-20 to one. */ - value = value | -0x800; - break; - - case e_lrsel: - case e_nlrsel: - /* LR: L with rounding of the addend to nearest 8k. */ - value = sym_val + ((addend + 0x1000) & -0x2000); - value = value >> 11; - break; - - case e_rrsel: - /* RR: R with rounding of the addend to nearest 8k. - We need to return a value such that 2048 * LR'x + RR'x == x - ie. RR'x = s+a - (s + (((a + 0x1000) & -0x2000) & -0x800)) - . = s+a - ((s & -0x800) + ((a + 0x1000) & -0x2000)) - . = (s & 0x7ff) + a - ((a + 0x1000) & -0x2000) */ - value = (sym_val & 0x7ff) + (((addend & 0x1fff) ^ 0x1000) - 0x1000); - break; - - default: - abort (); - } - return value; -} - -/* PA-RISC OPCODES */ -#define get_opcode(insn) (((insn) >> 26) & 0x3f) - -enum hppa_opcode_type -{ - /* None of the opcodes in the first group generate relocs, so we - aren't too concerned about them. */ - OP_SYSOP = 0x00, - OP_MEMMNG = 0x01, - OP_ALU = 0x02, - OP_NDXMEM = 0x03, - OP_SPOP = 0x04, - OP_DIAG = 0x05, - OP_FMPYADD = 0x06, - OP_UNDEF07 = 0x07, - OP_COPRW = 0x09, - OP_COPRDW = 0x0b, - OP_COPR = 0x0c, - OP_FLOAT = 0x0e, - OP_PRDSPEC = 0x0f, - OP_UNDEF15 = 0x15, - OP_UNDEF1d = 0x1d, - OP_FMPYSUB = 0x26, - OP_FPFUSED = 0x2e, - OP_SHEXDP0 = 0x34, - OP_SHEXDP1 = 0x35, - OP_SHEXDP2 = 0x36, - OP_UNDEF37 = 0x37, - OP_SHEXDP3 = 0x3c, - OP_SHEXDP4 = 0x3d, - OP_MULTMED = 0x3e, - OP_UNDEF3f = 0x3f, - - OP_LDIL = 0x08, - OP_ADDIL = 0x0a, - - OP_LDO = 0x0d, - OP_LDB = 0x10, - OP_LDH = 0x11, - OP_LDW = 0x12, - OP_LDWM = 0x13, - OP_STB = 0x18, - OP_STH = 0x19, - OP_STW = 0x1a, - OP_STWM = 0x1b, - - OP_LDD = 0x14, - OP_STD = 0x1c, - - OP_FLDW = 0x16, - OP_LDWL = 0x17, - OP_FSTW = 0x1e, - OP_STWL = 0x1f, - - OP_COMBT = 0x20, - OP_COMIBT = 0x21, - OP_COMBF = 0x22, - OP_COMIBF = 0x23, - OP_CMPBDT = 0x27, - OP_ADDBT = 0x28, - OP_ADDIBT = 0x29, - OP_ADDBF = 0x2a, - OP_ADDIBF = 0x2b, - OP_CMPBDF = 0x2f, - OP_BVB = 0x30, - OP_BB = 0x31, - OP_MOVB = 0x32, - OP_MOVIB = 0x33, - OP_CMPIBD = 0x3b, - - OP_COMICLR = 0x24, - OP_SUBI = 0x25, - OP_ADDIT = 0x2c, - OP_ADDI = 0x2d, - - OP_BE = 0x38, - OP_BLE = 0x39, - OP_BL = 0x3a -}; - - -/* Insert VALUE into INSN using R_FORMAT to determine exactly what - bits to change. */ - -static inline int -hppa_rebuild_insn (int insn, int value, int r_format) -{ - switch (r_format) - { - case 11: - return (insn & ~ 0x7ff) | low_sign_unext (value, 11); - - case 12: - return (insn & ~ 0x1ffd) | re_assemble_12 (value); - - - case 10: - return (insn & ~ 0x3ff1) | re_assemble_14 (value & -8); - - case -11: - return (insn & ~ 0x3ff9) | re_assemble_14 (value & -4); - - case 14: - return (insn & ~ 0x3fff) | re_assemble_14 (value); - - - case -10: - return (insn & ~ 0xfff1) | re_assemble_16 (value & -8); - - case -16: - return (insn & ~ 0xfff9) | re_assemble_16 (value & -4); - - case 16: - return (insn & ~ 0xffff) | re_assemble_16 (value); - - - case 17: - return (insn & ~ 0x1f1ffd) | re_assemble_17 (value); - - case 21: - return (insn & ~ 0x1fffff) | re_assemble_21 (value); - - case 22: - return (insn & ~ 0x3ff1ffd) | re_assemble_22 (value); - - case 32: - return value; - - default: - abort (); - } - return insn; -} - -#endif /* _LIBHPPA_H */ -/* Table of opcodes for the PA-RISC. - Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, - 2001, 2002, 2003, 2004, 2005 - Free Software Foundation, Inc. - - Contributed by the Center for Software Science at the - University of Utah (pa-gdb-bugs@cs.utah.edu). - -This file is part of GAS, the GNU Assembler, and GDB, the GNU disassembler. - -GAS/GDB is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 1, or (at your option) -any later version. - -GAS/GDB is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GAS or GDB; see the file COPYING. -If not, see . */ - -#if !defined(__STDC__) && !defined(const) -#define const -#endif - -/* - * Structure of an opcode table entry. - */ - -/* There are two kinds of delay slot nullification: normal which is - * controlled by the nullification bit, and conditional, which depends - * on the direction of the branch and its success or failure. - * - * NONE is unfortunately #defined in the hiux system include files. - * #undef it away. - */ -#undef NONE -struct pa_opcode -{ - const char *name; - unsigned long int match; /* Bits that must be set... */ - unsigned long int mask; /* ... in these bits. */ - const char *args; - enum pa_arch arch; - char flags; -}; - -/* Enables strict matching. Opcodes with match errors are skipped - when this bit is set. */ -#define FLAG_STRICT 0x1 - -/* - All hppa opcodes are 32 bits. - - The match component is a mask saying which bits must match a - particular opcode in order for an instruction to be an instance - of that opcode. - - The args component is a string containing one character for each operand of - the instruction. Characters used as a prefix allow any second character to - be used without conflicting with the main operand characters. - - Bit positions in this description follow HP usage of lsb = 31, - "at" is lsb of field. - - In the args field, the following characters must match exactly: - - '+,() ' - - In the args field, the following characters are unused: - - ' " - / 34 6789:; ' - '@ C M [\] ' - '` e g } ' - - Here are all the characters: - - ' !"#$%&'()*+-,./0123456789:;<=>?' - '@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_' - '`abcdefghijklmnopqrstuvwxyz{|}~ ' - -Kinds of operands: - x integer register field at 15. - b integer register field at 10. - t integer register field at 31. - a integer register field at 10 and 15 (for PERMH) - 5 5 bit immediate at 15. - s 2 bit space specifier at 17. - S 3 bit space specifier at 18. - V 5 bit immediate value at 31 - i 11 bit immediate value at 31 - j 14 bit immediate value at 31 - k 21 bit immediate value at 31 - l 16 bit immediate value at 31 (wide mode only, unusual encoding). - n nullification for branch instructions - N nullification for spop and copr instructions - w 12 bit branch displacement - W 17 bit branch displacement (PC relative) - X 22 bit branch displacement (PC relative) - z 17 bit branch displacement (just a number, not an address) - -Also these: - - . 2 bit shift amount at 25 - * 4 bit shift amount at 25 - p 5 bit shift count at 26 (to support the SHD instruction) encoded as - 31-p - ~ 6 bit shift count at 20,22:26 encoded as 63-~. - P 5 bit bit position at 26 - q 6 bit bit position at 20,22:26 - T 5 bit field length at 31 (encoded as 32-T) - % 6 bit field length at 23,27:31 (variable extract/deposit) - | 6 bit field length at 19,27:31 (fixed extract/deposit) - A 13 bit immediate at 18 (to support the BREAK instruction) - ^ like b, but describes a control register - ! sar (cr11) register - D 26 bit immediate at 31 (to support the DIAG instruction) - $ 9 bit immediate at 28 (to support POPBTS) - - v 3 bit Special Function Unit identifier at 25 - O 20 bit Special Function Unit operation split between 15 bits at 20 - and 5 bits at 31 - o 15 bit Special Function Unit operation at 20 - 2 22 bit Special Function Unit operation split between 17 bits at 20 - and 5 bits at 31 - 1 15 bit Special Function Unit operation split between 10 bits at 20 - and 5 bits at 31 - 0 10 bit Special Function Unit operation split between 5 bits at 20 - and 5 bits at 31 - u 3 bit coprocessor unit identifier at 25 - F Source Floating Point Operand Format Completer encoded 2 bits at 20 - I Source Floating Point Operand Format Completer encoded 1 bits at 20 - (for 0xe format FP instructions) - G Destination Floating Point Operand Format Completer encoded 2 bits at 18 - H Floating Point Operand Format at 26 for 'fmpyadd' and 'fmpysub' - (very similar to 'F') - - r 5 bit immediate value at 31 (for the break instruction) - (very similar to V above, except the value is unsigned instead of - low_sign_ext) - R 5 bit immediate value at 15 (for the ssm, rsm, probei instructions) - (same as r above, except the value is in a different location) - U 10 bit immediate value at 15 (for SSM, RSM on pa2.0) - Q 5 bit immediate value at 10 (a bit position specified in - the bb instruction. It's the same as r above, except the - value is in a different location) - B 5 bit immediate value at 10 (a bit position specified in - the bb instruction. Similar to Q, but 64 bit handling is - different. - Z %r1 -- implicit target of addil instruction. - L ,%r2 completer for new syntax branch - { Source format completer for fcnv - _ Destination format completer for fcnv - h cbit for fcmp - = gfx tests for ftest - d 14 bit offset for single precision FP long load/store. - # 14 bit offset for double precision FP load long/store. - J Yet another 14 bit offset for load/store with ma,mb completers. - K Yet another 14 bit offset for load/store with ma,mb completers. - y 16 bit offset for word aligned load/store (PA2.0 wide). - & 16 bit offset for dword aligned load/store (PA2.0 wide). - < 16 bit offset for load/store with ma,mb completers (PA2.0 wide). - > 16 bit offset for load/store with ma,mb completers (PA2.0 wide). - Y %sr0,%r31 -- implicit target of be,l instruction. - @ implicit immediate value of 0 - -Completer operands all have 'c' as the prefix: - - cx indexed load and store completer. - cX indexed load and store completer. Like cx, but emits a space - after in disassembler. - cm short load and store completer. - cM short load and store completer. Like cm, but emits a space - after in disassembler. - cq long load and store completer (like cm, but inserted into a - different location in the target instruction). - cs store bytes short completer. - cA store bytes short completer. Like cs, but emits a space - after in disassembler. - ce long load/store completer for LDW/STW with a different encoding - than the others - cc load cache control hint - cd load and clear cache control hint - cC store cache control hint - co ordered access - - cp branch link and push completer - cP branch pop completer - cl branch link completer - cg branch gate completer - - cw read/write completer for PROBE - cW wide completer for MFCTL - cL local processor completer for cache control - cZ System Control Completer (to support LPA, LHA, etc.) - - ci correction completer for DCOR - ca add completer - cy 32 bit add carry completer - cY 64 bit add carry completer - cv signed overflow trap completer - ct trap on condition completer for ADDI, SUB - cT trap on condition completer for UADDCM - cb 32 bit borrow completer for SUB - cB 64 bit borrow completer for SUB - - ch left/right half completer - cH signed/unsigned saturation completer - cS signed/unsigned completer at 21 - cz zero/sign extension completer. - c* permutation completer - -Condition operands all have '?' as the prefix: - - ?f Floating point compare conditions (encoded as 5 bits at 31) - - ?a add conditions - ?A 64 bit add conditions - ?@ add branch conditions followed by nullify - ?d non-negated add branch conditions - ?D negated add branch conditions - ?w wide mode non-negated add branch conditions - ?W wide mode negated add branch conditions - - ?s compare/subtract conditions - ?S 64 bit compare/subtract conditions - ?t non-negated compare and branch conditions - ?n 32 bit compare and branch conditions followed by nullify - ?N 64 bit compare and branch conditions followed by nullify - ?Q 64 bit compare and branch conditions for CMPIB instruction - - ?l logical conditions - ?L 64 bit logical conditions - - ?b branch on bit conditions - ?B 64 bit branch on bit conditions - - ?x shift/extract/deposit conditions - ?X 64 bit shift/extract/deposit conditions - ?y shift/extract/deposit conditions followed by nullify for conditional - branches - - ?u unit conditions - ?U 64 bit unit conditions - -Floating point registers all have 'f' as a prefix: - - ft target register at 31 - fT target register with L/R halves at 31 - fa operand 1 register at 10 - fA operand 1 register with L/R halves at 10 - fX Same as fA, except prints a space before register during disasm - fb operand 2 register at 15 - fB operand 2 register with L/R halves at 15 - fC operand 3 register with L/R halves at 16:18,21:23 - fe Like fT, but encoding is different. - fE Same as fe, except prints a space before register during disasm. - fx target register at 15 (only for PA 2.0 long format FLDD/FSTD). - -Float registers for fmpyadd and fmpysub: - - fi mult operand 1 register at 10 - fj mult operand 2 register at 15 - fk mult target register at 20 - fl add/sub operand register at 25 - fm add/sub target register at 31 - -*/ - - -#if 0 -/* List of characters not to put a space after. Note that - "," is included, as the "spopN" operations use literal - commas in their completer sections. */ -static const char *const completer_chars = ",CcY<>?!@+&U~FfGHINnOoZMadu|/=0123%e$m}"; -#endif - -/* The order of the opcodes in this table is significant: - - * The assembler requires that all instances of the same mnemonic be - consecutive. If they aren't, the assembler will bomb at runtime. - - * Immediate fields use pa_get_absolute_expression to parse the - string. It will generate a "bad expression" error if passed - a register name. Thus, register index variants of an opcode - need to precede immediate variants. - - * The disassembler does not care about the order of the opcodes - except in cases where implicit addressing is used. - - Here are the rules for ordering the opcodes of a mnemonic: - - 1) Opcodes with FLAG_STRICT should precede opcodes without - FLAG_STRICT. - - 2) Opcodes with FLAG_STRICT should be ordered as follows: - register index opcodes, short immediate opcodes, and finally - long immediate opcodes. When both pa10 and pa11 variants - of the same opcode are available, the pa10 opcode should - come first for correct architectural promotion. - - 3) When implicit addressing is available for an opcode, the - implicit opcode should precede the explicit opcode. - - 4) Opcodes without FLAG_STRICT should be ordered as follows: - register index opcodes, long immediate opcodes, and finally - short immediate opcodes. */ - -static const struct pa_opcode pa_opcodes[] = -{ - -/* Pseudo-instructions. */ - -{ "ldi", 0x34000000, 0xffe00000, "l,x", pa20w, 0},/* ldo val(r0),r */ -{ "ldi", 0x34000000, 0xffe0c000, "j,x", pa10, 0},/* ldo val(r0),r */ - -{ "cmpib", 0xec000000, 0xfc000000, "?Qn5,b,w", pa20, FLAG_STRICT}, -{ "cmpib", 0x84000000, 0xf4000000, "?nn5,b,w", pa10, FLAG_STRICT}, -{ "comib", 0x84000000, 0xfc000000, "?nn5,b,w", pa10, 0}, /* comib{tf}*/ -/* This entry is for the disassembler only. It will never be used by - assembler. */ -{ "comib", 0x8c000000, 0xfc000000, "?nn5,b,w", pa10, 0}, /* comib{tf}*/ -{ "cmpb", 0x9c000000, 0xdc000000, "?Nnx,b,w", pa20, FLAG_STRICT}, -{ "cmpb", 0x80000000, 0xf4000000, "?nnx,b,w", pa10, FLAG_STRICT}, -{ "comb", 0x80000000, 0xfc000000, "?nnx,b,w", pa10, 0}, /* comb{tf} */ -/* This entry is for the disassembler only. It will never be used by - assembler. */ -{ "comb", 0x88000000, 0xfc000000, "?nnx,b,w", pa10, 0}, /* comb{tf} */ -{ "addb", 0xa0000000, 0xf4000000, "?Wnx,b,w", pa20w, FLAG_STRICT}, -{ "addb", 0xa0000000, 0xfc000000, "?@nx,b,w", pa10, 0}, /* addb{tf} */ -/* This entry is for the disassembler only. It will never be used by - assembler. */ -{ "addb", 0xa8000000, 0xfc000000, "?@nx,b,w", pa10, 0}, -{ "addib", 0xa4000000, 0xf4000000, "?Wn5,b,w", pa20w, FLAG_STRICT}, -{ "addib", 0xa4000000, 0xfc000000, "?@n5,b,w", pa10, 0}, /* addib{tf}*/ -/* This entry is for the disassembler only. It will never be used by - assembler. */ -{ "addib", 0xac000000, 0xfc000000, "?@n5,b,w", pa10, 0}, /* addib{tf}*/ -{ "nop", 0x08000240, 0xffffffff, "", pa10, 0}, /* or 0,0,0 */ -{ "copy", 0x08000240, 0xffe0ffe0, "x,t", pa10, 0}, /* or r,0,t */ -{ "mtsar", 0x01601840, 0xffe0ffff, "x", pa10, 0}, /* mtctl r,cr11 */ - -/* Loads and Stores for integer registers. */ - -{ "ldd", 0x0c0000c0, 0xfc00d3c0, "cxccx(b),t", pa20, FLAG_STRICT}, -{ "ldd", 0x0c0000c0, 0xfc0013c0, "cxccx(s,b),t", pa20, FLAG_STRICT}, -{ "ldd", 0x0c0010e0, 0xfc1ff3e0, "cocc@(b),t", pa20, FLAG_STRICT}, -{ "ldd", 0x0c0010e0, 0xfc1f33e0, "cocc@(s,b),t", pa20, FLAG_STRICT}, -{ "ldd", 0x0c0010c0, 0xfc00d3c0, "cmcc5(b),t", pa20, FLAG_STRICT}, -{ "ldd", 0x0c0010c0, 0xfc0013c0, "cmcc5(s,b),t", pa20, FLAG_STRICT}, -{ "ldd", 0x50000000, 0xfc000002, "cq&(b),x", pa20w, FLAG_STRICT}, -{ "ldd", 0x50000000, 0xfc00c002, "cq#(b),x", pa20, FLAG_STRICT}, -{ "ldd", 0x50000000, 0xfc000002, "cq#(s,b),x", pa20, FLAG_STRICT}, -{ "ldw", 0x0c000080, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, -{ "ldw", 0x0c000080, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT}, -{ "ldw", 0x0c000080, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT}, -{ "ldw", 0x0c000080, 0xfc0013c0, "cxccx(s,b),t", pa11, FLAG_STRICT}, -{ "ldw", 0x0c0010a0, 0xfc1ff3e0, "cocc@(b),t", pa20, FLAG_STRICT}, -{ "ldw", 0x0c0010a0, 0xfc1f33e0, "cocc@(s,b),t", pa20, FLAG_STRICT}, -{ "ldw", 0x0c001080, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, -{ "ldw", 0x0c001080, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT}, -{ "ldw", 0x0c001080, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT}, -{ "ldw", 0x0c001080, 0xfc0013c0, "cmcc5(s,b),t", pa11, FLAG_STRICT}, -{ "ldw", 0x4c000000, 0xfc000000, "ce<(b),x", pa20w, FLAG_STRICT}, -{ "ldw", 0x5c000004, 0xfc000006, "ce>(b),x", pa20w, FLAG_STRICT}, -{ "ldw", 0x48000000, 0xfc000000, "l(b),x", pa20w, FLAG_STRICT}, -{ "ldw", 0x5c000004, 0xfc00c006, "ceK(b),x", pa20, FLAG_STRICT}, -{ "ldw", 0x5c000004, 0xfc000006, "ceK(s,b),x", pa20, FLAG_STRICT}, -{ "ldw", 0x4c000000, 0xfc00c000, "ceJ(b),x", pa10, FLAG_STRICT}, -{ "ldw", 0x4c000000, 0xfc000000, "ceJ(s,b),x", pa10, FLAG_STRICT}, -{ "ldw", 0x48000000, 0xfc00c000, "j(b),x", pa10, 0}, -{ "ldw", 0x48000000, 0xfc000000, "j(s,b),x", pa10, 0}, -{ "ldh", 0x0c000040, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, -{ "ldh", 0x0c000040, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT}, -{ "ldh", 0x0c000040, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT}, -{ "ldh", 0x0c000040, 0xfc0013c0, "cxccx(s,b),t", pa11, FLAG_STRICT}, -{ "ldh", 0x0c001060, 0xfc1ff3e0, "cocc@(b),t", pa20, FLAG_STRICT}, -{ "ldh", 0x0c001060, 0xfc1f33e0, "cocc@(s,b),t", pa20, FLAG_STRICT}, -{ "ldh", 0x0c001040, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, -{ "ldh", 0x0c001040, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT}, -{ "ldh", 0x0c001040, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT}, -{ "ldh", 0x0c001040, 0xfc0013c0, "cmcc5(s,b),t", pa11, FLAG_STRICT}, -{ "ldh", 0x44000000, 0xfc000000, "l(b),x", pa20w, FLAG_STRICT}, -{ "ldh", 0x44000000, 0xfc00c000, "j(b),x", pa10, 0}, -{ "ldh", 0x44000000, 0xfc000000, "j(s,b),x", pa10, 0}, -{ "ldb", 0x0c000000, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, -{ "ldb", 0x0c000000, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT}, -{ "ldb", 0x0c000000, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT}, -{ "ldb", 0x0c000000, 0xfc0013c0, "cxccx(s,b),t", pa11, FLAG_STRICT}, -{ "ldb", 0x0c001020, 0xfc1ff3e0, "cocc@(b),t", pa20, FLAG_STRICT}, -{ "ldb", 0x0c001020, 0xfc1f33e0, "cocc@(s,b),t", pa20, FLAG_STRICT}, -{ "ldb", 0x0c001000, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, -{ "ldb", 0x0c001000, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT}, -{ "ldb", 0x0c001000, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT}, -{ "ldb", 0x0c001000, 0xfc0013c0, "cmcc5(s,b),t", pa11, FLAG_STRICT}, -{ "ldb", 0x40000000, 0xfc000000, "l(b),x", pa20w, FLAG_STRICT}, -{ "ldb", 0x40000000, 0xfc00c000, "j(b),x", pa10, 0}, -{ "ldb", 0x40000000, 0xfc000000, "j(s,b),x", pa10, 0}, -{ "std", 0x0c0012e0, 0xfc00f3ff, "cocCx,@(b)", pa20, FLAG_STRICT}, -{ "std", 0x0c0012e0, 0xfc0033ff, "cocCx,@(s,b)", pa20, FLAG_STRICT}, -{ "std", 0x0c0012c0, 0xfc00d3c0, "cmcCx,V(b)", pa20, FLAG_STRICT}, -{ "std", 0x0c0012c0, 0xfc0013c0, "cmcCx,V(s,b)", pa20, FLAG_STRICT}, -{ "std", 0x70000000, 0xfc000002, "cqx,&(b)", pa20w, FLAG_STRICT}, -{ "std", 0x70000000, 0xfc00c002, "cqx,#(b)", pa20, FLAG_STRICT}, -{ "std", 0x70000000, 0xfc000002, "cqx,#(s,b)", pa20, FLAG_STRICT}, -{ "stw", 0x0c0012a0, 0xfc00f3ff, "cocCx,@(b)", pa20, FLAG_STRICT}, -{ "stw", 0x0c0012a0, 0xfc0033ff, "cocCx,@(s,b)", pa20, FLAG_STRICT}, -{ "stw", 0x0c001280, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT}, -{ "stw", 0x0c001280, 0xfc001fc0, "cMx,V(s,b)", pa10, FLAG_STRICT}, -{ "stw", 0x0c001280, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT}, -{ "stw", 0x0c001280, 0xfc0013c0, "cmcCx,V(s,b)", pa11, FLAG_STRICT}, -{ "stw", 0x6c000000, 0xfc000000, "cex,<(b)", pa20w, FLAG_STRICT}, -{ "stw", 0x7c000004, 0xfc000006, "cex,>(b)", pa20w, FLAG_STRICT}, -{ "stw", 0x68000000, 0xfc000000, "x,l(b)", pa20w, FLAG_STRICT}, -{ "stw", 0x7c000004, 0xfc00c006, "cex,K(b)", pa20, FLAG_STRICT}, -{ "stw", 0x7c000004, 0xfc000006, "cex,K(s,b)", pa20, FLAG_STRICT}, -{ "stw", 0x6c000000, 0xfc00c000, "cex,J(b)", pa10, FLAG_STRICT}, -{ "stw", 0x6c000000, 0xfc000000, "cex,J(s,b)", pa10, FLAG_STRICT}, -{ "stw", 0x68000000, 0xfc00c000, "x,j(b)", pa10, 0}, -{ "stw", 0x68000000, 0xfc000000, "x,j(s,b)", pa10, 0}, -{ "sth", 0x0c001260, 0xfc00f3ff, "cocCx,@(b)", pa20, FLAG_STRICT}, -{ "sth", 0x0c001260, 0xfc0033ff, "cocCx,@(s,b)", pa20, FLAG_STRICT}, -{ "sth", 0x0c001240, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT}, -{ "sth", 0x0c001240, 0xfc001fc0, "cMx,V(s,b)", pa10, FLAG_STRICT}, -{ "sth", 0x0c001240, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT}, -{ "sth", 0x0c001240, 0xfc0013c0, "cmcCx,V(s,b)", pa11, FLAG_STRICT}, -{ "sth", 0x64000000, 0xfc000000, "x,l(b)", pa20w, FLAG_STRICT}, -{ "sth", 0x64000000, 0xfc00c000, "x,j(b)", pa10, 0}, -{ "sth", 0x64000000, 0xfc000000, "x,j(s,b)", pa10, 0}, -{ "stb", 0x0c001220, 0xfc00f3ff, "cocCx,@(b)", pa20, FLAG_STRICT}, -{ "stb", 0x0c001220, 0xfc0033ff, "cocCx,@(s,b)", pa20, FLAG_STRICT}, -{ "stb", 0x0c001200, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT}, -{ "stb", 0x0c001200, 0xfc001fc0, "cMx,V(s,b)", pa10, FLAG_STRICT}, -{ "stb", 0x0c001200, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT}, -{ "stb", 0x0c001200, 0xfc0013c0, "cmcCx,V(s,b)", pa11, FLAG_STRICT}, -{ "stb", 0x60000000, 0xfc000000, "x,l(b)", pa20w, FLAG_STRICT}, -{ "stb", 0x60000000, 0xfc00c000, "x,j(b)", pa10, 0}, -{ "stb", 0x60000000, 0xfc000000, "x,j(s,b)", pa10, 0}, -{ "ldwm", 0x4c000000, 0xfc00c000, "j(b),x", pa10, 0}, -{ "ldwm", 0x4c000000, 0xfc000000, "j(s,b),x", pa10, 0}, -{ "stwm", 0x6c000000, 0xfc00c000, "x,j(b)", pa10, 0}, -{ "stwm", 0x6c000000, 0xfc000000, "x,j(s,b)", pa10, 0}, -{ "ldwx", 0x0c000080, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, -{ "ldwx", 0x0c000080, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT}, -{ "ldwx", 0x0c000080, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT}, -{ "ldwx", 0x0c000080, 0xfc0013c0, "cxccx(s,b),t", pa11, FLAG_STRICT}, -{ "ldwx", 0x0c000080, 0xfc00dfc0, "cXx(b),t", pa10, 0}, -{ "ldwx", 0x0c000080, 0xfc001fc0, "cXx(s,b),t", pa10, 0}, -{ "ldhx", 0x0c000040, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, -{ "ldhx", 0x0c000040, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT}, -{ "ldhx", 0x0c000040, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT}, -{ "ldhx", 0x0c000040, 0xfc0013c0, "cxccx(s,b),t", pa11, FLAG_STRICT}, -{ "ldhx", 0x0c000040, 0xfc00dfc0, "cXx(b),t", pa10, 0}, -{ "ldhx", 0x0c000040, 0xfc001fc0, "cXx(s,b),t", pa10, 0}, -{ "ldbx", 0x0c000000, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, -{ "ldbx", 0x0c000000, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT}, -{ "ldbx", 0x0c000000, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT}, -{ "ldbx", 0x0c000000, 0xfc0013c0, "cxccx(s,b),t", pa11, FLAG_STRICT}, -{ "ldbx", 0x0c000000, 0xfc00dfc0, "cXx(b),t", pa10, 0}, -{ "ldbx", 0x0c000000, 0xfc001fc0, "cXx(s,b),t", pa10, 0}, -{ "ldwa", 0x0c000180, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, -{ "ldwa", 0x0c000180, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT}, -{ "ldwa", 0x0c0011a0, 0xfc1ff3e0, "cocc@(b),t", pa20, FLAG_STRICT}, -{ "ldwa", 0x0c001180, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, -{ "ldwa", 0x0c001180, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT}, -{ "ldcw", 0x0c0001c0, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, -{ "ldcw", 0x0c0001c0, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT}, -{ "ldcw", 0x0c0001c0, 0xfc00d3c0, "cxcdx(b),t", pa11, FLAG_STRICT}, -{ "ldcw", 0x0c0001c0, 0xfc0013c0, "cxcdx(s,b),t", pa11, FLAG_STRICT}, -{ "ldcw", 0x0c0011c0, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, -{ "ldcw", 0x0c0011c0, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT}, -{ "ldcw", 0x0c0011c0, 0xfc00d3c0, "cmcd5(b),t", pa11, FLAG_STRICT}, -{ "ldcw", 0x0c0011c0, 0xfc0013c0, "cmcd5(s,b),t", pa11, FLAG_STRICT}, -{ "stwa", 0x0c0013a0, 0xfc00d3ff, "cocCx,@(b)", pa20, FLAG_STRICT}, -{ "stwa", 0x0c001380, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT}, -{ "stwa", 0x0c001380, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT}, -{ "stby", 0x0c001300, 0xfc00dfc0, "cAx,V(b)", pa10, FLAG_STRICT}, -{ "stby", 0x0c001300, 0xfc001fc0, "cAx,V(s,b)", pa10, FLAG_STRICT}, -{ "stby", 0x0c001300, 0xfc00d3c0, "cscCx,V(b)", pa11, FLAG_STRICT}, -{ "stby", 0x0c001300, 0xfc0013c0, "cscCx,V(s,b)", pa11, FLAG_STRICT}, -{ "ldda", 0x0c000100, 0xfc00d3c0, "cxccx(b),t", pa20, FLAG_STRICT}, -{ "ldda", 0x0c001120, 0xfc1ff3e0, "cocc@(b),t", pa20, FLAG_STRICT}, -{ "ldda", 0x0c001100, 0xfc00d3c0, "cmcc5(b),t", pa20, FLAG_STRICT}, -{ "ldcd", 0x0c000140, 0xfc00d3c0, "cxcdx(b),t", pa20, FLAG_STRICT}, -{ "ldcd", 0x0c000140, 0xfc0013c0, "cxcdx(s,b),t", pa20, FLAG_STRICT}, -{ "ldcd", 0x0c001140, 0xfc00d3c0, "cmcd5(b),t", pa20, FLAG_STRICT}, -{ "ldcd", 0x0c001140, 0xfc0013c0, "cmcd5(s,b),t", pa20, FLAG_STRICT}, -{ "stda", 0x0c0013e0, 0xfc00f3ff, "cocCx,@(b)", pa20, FLAG_STRICT}, -{ "stda", 0x0c0013c0, 0xfc00d3c0, "cmcCx,V(b)", pa20, FLAG_STRICT}, -{ "ldwax", 0x0c000180, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, -{ "ldwax", 0x0c000180, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT}, -{ "ldwax", 0x0c000180, 0xfc00dfc0, "cXx(b),t", pa10, 0}, -{ "ldcwx", 0x0c0001c0, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT}, -{ "ldcwx", 0x0c0001c0, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT}, -{ "ldcwx", 0x0c0001c0, 0xfc00d3c0, "cxcdx(b),t", pa11, FLAG_STRICT}, -{ "ldcwx", 0x0c0001c0, 0xfc0013c0, "cxcdx(s,b),t", pa11, FLAG_STRICT}, -{ "ldcwx", 0x0c0001c0, 0xfc00dfc0, "cXx(b),t", pa10, 0}, -{ "ldcwx", 0x0c0001c0, 0xfc001fc0, "cXx(s,b),t", pa10, 0}, -{ "ldws", 0x0c001080, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, -{ "ldws", 0x0c001080, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT}, -{ "ldws", 0x0c001080, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT}, -{ "ldws", 0x0c001080, 0xfc0013c0, "cmcc5(s,b),t", pa11, FLAG_STRICT}, -{ "ldws", 0x0c001080, 0xfc00dfc0, "cM5(b),t", pa10, 0}, -{ "ldws", 0x0c001080, 0xfc001fc0, "cM5(s,b),t", pa10, 0}, -{ "ldhs", 0x0c001040, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, -{ "ldhs", 0x0c001040, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT}, -{ "ldhs", 0x0c001040, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT}, -{ "ldhs", 0x0c001040, 0xfc0013c0, "cmcc5(s,b),t", pa11, FLAG_STRICT}, -{ "ldhs", 0x0c001040, 0xfc00dfc0, "cM5(b),t", pa10, 0}, -{ "ldhs", 0x0c001040, 0xfc001fc0, "cM5(s,b),t", pa10, 0}, -{ "ldbs", 0x0c001000, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, -{ "ldbs", 0x0c001000, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT}, -{ "ldbs", 0x0c001000, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT}, -{ "ldbs", 0x0c001000, 0xfc0013c0, "cmcc5(s,b),t", pa11, FLAG_STRICT}, -{ "ldbs", 0x0c001000, 0xfc00dfc0, "cM5(b),t", pa10, 0}, -{ "ldbs", 0x0c001000, 0xfc001fc0, "cM5(s,b),t", pa10, 0}, -{ "ldwas", 0x0c001180, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, -{ "ldwas", 0x0c001180, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT}, -{ "ldwas", 0x0c001180, 0xfc00dfc0, "cM5(b),t", pa10, 0}, -{ "ldcws", 0x0c0011c0, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT}, -{ "ldcws", 0x0c0011c0, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT}, -{ "ldcws", 0x0c0011c0, 0xfc00d3c0, "cmcd5(b),t", pa11, FLAG_STRICT}, -{ "ldcws", 0x0c0011c0, 0xfc0013c0, "cmcd5(s,b),t", pa11, FLAG_STRICT}, -{ "ldcws", 0x0c0011c0, 0xfc00dfc0, "cM5(b),t", pa10, 0}, -{ "ldcws", 0x0c0011c0, 0xfc001fc0, "cM5(s,b),t", pa10, 0}, -{ "stws", 0x0c001280, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT}, -{ "stws", 0x0c001280, 0xfc001fc0, "cMx,V(s,b)", pa10, FLAG_STRICT}, -{ "stws", 0x0c001280, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT}, -{ "stws", 0x0c001280, 0xfc0013c0, "cmcCx,V(s,b)", pa11, FLAG_STRICT}, -{ "stws", 0x0c001280, 0xfc00dfc0, "cMx,V(b)", pa10, 0}, -{ "stws", 0x0c001280, 0xfc001fc0, "cMx,V(s,b)", pa10, 0}, -{ "sths", 0x0c001240, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT}, -{ "sths", 0x0c001240, 0xfc001fc0, "cMx,V(s,b)", pa10, FLAG_STRICT}, -{ "sths", 0x0c001240, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT}, -{ "sths", 0x0c001240, 0xfc0013c0, "cmcCx,V(s,b)", pa11, FLAG_STRICT}, -{ "sths", 0x0c001240, 0xfc00dfc0, "cMx,V(b)", pa10, 0}, -{ "sths", 0x0c001240, 0xfc001fc0, "cMx,V(s,b)", pa10, 0}, -{ "stbs", 0x0c001200, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT}, -{ "stbs", 0x0c001200, 0xfc001fc0, "cMx,V(s,b)", pa10, FLAG_STRICT}, -{ "stbs", 0x0c001200, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT}, -{ "stbs", 0x0c001200, 0xfc0013c0, "cmcCx,V(s,b)", pa11, FLAG_STRICT}, -{ "stbs", 0x0c001200, 0xfc00dfc0, "cMx,V(b)", pa10, 0}, -{ "stbs", 0x0c001200, 0xfc001fc0, "cMx,V(s,b)", pa10, 0}, -{ "stwas", 0x0c001380, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT}, -{ "stwas", 0x0c001380, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT}, -{ "stwas", 0x0c001380, 0xfc00dfc0, "cMx,V(b)", pa10, 0}, -{ "stdby", 0x0c001340, 0xfc00d3c0, "cscCx,V(b)", pa20, FLAG_STRICT}, -{ "stdby", 0x0c001340, 0xfc0013c0, "cscCx,V(s,b)", pa20, FLAG_STRICT}, -{ "stbys", 0x0c001300, 0xfc00dfc0, "cAx,V(b)", pa10, FLAG_STRICT}, -{ "stbys", 0x0c001300, 0xfc001fc0, "cAx,V(s,b)", pa10, FLAG_STRICT}, -{ "stbys", 0x0c001300, 0xfc00d3c0, "cscCx,V(b)", pa11, FLAG_STRICT}, -{ "stbys", 0x0c001300, 0xfc0013c0, "cscCx,V(s,b)", pa11, FLAG_STRICT}, -{ "stbys", 0x0c001300, 0xfc00dfc0, "cAx,V(b)", pa10, 0}, -{ "stbys", 0x0c001300, 0xfc001fc0, "cAx,V(s,b)", pa10, 0}, - -/* Immediate instructions. */ -{ "ldo", 0x34000000, 0xfc000000, "l(b),x", pa20w, 0}, -{ "ldo", 0x34000000, 0xfc00c000, "j(b),x", pa10, 0}, -{ "ldil", 0x20000000, 0xfc000000, "k,b", pa10, 0}, -{ "addil", 0x28000000, 0xfc000000, "k,b,Z", pa10, 0}, -{ "addil", 0x28000000, 0xfc000000, "k,b", pa10, 0}, - -/* Branching instructions. */ -{ "b", 0xe8008000, 0xfc00e000, "cpnXL", pa20, FLAG_STRICT}, -{ "b", 0xe800a000, 0xfc00e000, "clnXL", pa20, FLAG_STRICT}, -{ "b", 0xe8000000, 0xfc00e000, "clnW,b", pa10, FLAG_STRICT}, -{ "b", 0xe8002000, 0xfc00e000, "cgnW,b", pa10, FLAG_STRICT}, -{ "b", 0xe8000000, 0xffe0e000, "nW", pa10, 0}, /* b,l foo,r0 */ -{ "bl", 0xe8000000, 0xfc00e000, "nW,b", pa10, 0}, -{ "gate", 0xe8002000, 0xfc00e000, "nW,b", pa10, 0}, -{ "blr", 0xe8004000, 0xfc00e001, "nx,b", pa10, 0}, -{ "bv", 0xe800c000, 0xfc00fffd, "nx(b)", pa10, 0}, -{ "bv", 0xe800c000, 0xfc00fffd, "n(b)", pa10, 0}, -{ "bve", 0xe800f001, 0xfc1ffffd, "cpn(b)L", pa20, FLAG_STRICT}, -{ "bve", 0xe800f000, 0xfc1ffffd, "cln(b)L", pa20, FLAG_STRICT}, -{ "bve", 0xe800d001, 0xfc1ffffd, "cPn(b)", pa20, FLAG_STRICT}, -{ "bve", 0xe800d000, 0xfc1ffffd, "n(b)", pa20, FLAG_STRICT}, -{ "be", 0xe4000000, 0xfc000000, "clnz(S,b),Y", pa10, FLAG_STRICT}, -{ "be", 0xe4000000, 0xfc000000, "clnz(b),Y", pa10, FLAG_STRICT}, -{ "be", 0xe0000000, 0xfc000000, "nz(S,b)", pa10, 0}, -{ "be", 0xe0000000, 0xfc000000, "nz(b)", pa10, 0}, -{ "ble", 0xe4000000, 0xfc000000, "nz(S,b)", pa10, 0}, -{ "movb", 0xc8000000, 0xfc000000, "?ynx,b,w", pa10, 0}, -{ "movib", 0xcc000000, 0xfc000000, "?yn5,b,w", pa10, 0}, -{ "combt", 0x80000000, 0xfc000000, "?tnx,b,w", pa10, 0}, -{ "combf", 0x88000000, 0xfc000000, "?tnx,b,w", pa10, 0}, -{ "comibt", 0x84000000, 0xfc000000, "?tn5,b,w", pa10, 0}, -{ "comibf", 0x8c000000, 0xfc000000, "?tn5,b,w", pa10, 0}, -{ "addbt", 0xa0000000, 0xfc000000, "?dnx,b,w", pa10, 0}, -{ "addbf", 0xa8000000, 0xfc000000, "?dnx,b,w", pa10, 0}, -{ "addibt", 0xa4000000, 0xfc000000, "?dn5,b,w", pa10, 0}, -{ "addibf", 0xac000000, 0xfc000000, "?dn5,b,w", pa10, 0}, -{ "bb", 0xc0004000, 0xffe06000, "?bnx,!,w", pa10, FLAG_STRICT}, -{ "bb", 0xc0006000, 0xffe06000, "?Bnx,!,w", pa20, FLAG_STRICT}, -{ "bb", 0xc4004000, 0xfc006000, "?bnx,Q,w", pa10, FLAG_STRICT}, -{ "bb", 0xc4004000, 0xfc004000, "?Bnx,B,w", pa20, FLAG_STRICT}, -{ "bvb", 0xc0004000, 0xffe04000, "?bnx,w", pa10, 0}, -{ "clrbts", 0xe8004005, 0xffffffff, "", pa20, FLAG_STRICT}, -{ "popbts", 0xe8004005, 0xfffff007, "$", pa20, FLAG_STRICT}, -{ "pushnom", 0xe8004001, 0xffffffff, "", pa20, FLAG_STRICT}, -{ "pushbts", 0xe8004001, 0xffe0ffff, "x", pa20, FLAG_STRICT}, - -/* Computation Instructions. */ - -{ "cmpclr", 0x080008a0, 0xfc000fe0, "?Sx,b,t", pa20, FLAG_STRICT}, -{ "cmpclr", 0x08000880, 0xfc000fe0, "?sx,b,t", pa10, FLAG_STRICT}, -{ "comclr", 0x08000880, 0xfc000fe0, "?sx,b,t", pa10, 0}, -{ "or", 0x08000260, 0xfc000fe0, "?Lx,b,t", pa20, FLAG_STRICT}, -{ "or", 0x08000240, 0xfc000fe0, "?lx,b,t", pa10, 0}, -{ "xor", 0x080002a0, 0xfc000fe0, "?Lx,b,t", pa20, FLAG_STRICT}, -{ "xor", 0x08000280, 0xfc000fe0, "?lx,b,t", pa10, 0}, -{ "and", 0x08000220, 0xfc000fe0, "?Lx,b,t", pa20, FLAG_STRICT}, -{ "and", 0x08000200, 0xfc000fe0, "?lx,b,t", pa10, 0}, -{ "andcm", 0x08000020, 0xfc000fe0, "?Lx,b,t", pa20, FLAG_STRICT}, -{ "andcm", 0x08000000, 0xfc000fe0, "?lx,b,t", pa10, 0}, -{ "uxor", 0x080003a0, 0xfc000fe0, "?Ux,b,t", pa20, FLAG_STRICT}, -{ "uxor", 0x08000380, 0xfc000fe0, "?ux,b,t", pa10, 0}, -{ "uaddcm", 0x080009a0, 0xfc000fa0, "cT?Ux,b,t", pa20, FLAG_STRICT}, -{ "uaddcm", 0x08000980, 0xfc000fa0, "cT?ux,b,t", pa10, FLAG_STRICT}, -{ "uaddcm", 0x08000980, 0xfc000fe0, "?ux,b,t", pa10, 0}, -{ "uaddcmt", 0x080009c0, 0xfc000fe0, "?ux,b,t", pa10, 0}, -{ "dcor", 0x08000ba0, 0xfc1f0fa0, "ci?Ub,t", pa20, FLAG_STRICT}, -{ "dcor", 0x08000b80, 0xfc1f0fa0, "ci?ub,t", pa10, FLAG_STRICT}, -{ "dcor", 0x08000b80, 0xfc1f0fe0, "?ub,t", pa10, 0}, -{ "idcor", 0x08000bc0, 0xfc1f0fe0, "?ub,t", pa10, 0}, -{ "addi", 0xb0000000, 0xfc000000, "ct?ai,b,x", pa10, FLAG_STRICT}, -{ "addi", 0xb4000000, 0xfc000000, "cv?ai,b,x", pa10, FLAG_STRICT}, -{ "addi", 0xb4000000, 0xfc000800, "?ai,b,x", pa10, 0}, -{ "addio", 0xb4000800, 0xfc000800, "?ai,b,x", pa10, 0}, -{ "addit", 0xb0000000, 0xfc000800, "?ai,b,x", pa10, 0}, -{ "addito", 0xb0000800, 0xfc000800, "?ai,b,x", pa10, 0}, -{ "add", 0x08000720, 0xfc0007e0, "cY?Ax,b,t", pa20, FLAG_STRICT}, -{ "add", 0x08000700, 0xfc0007e0, "cy?ax,b,t", pa10, FLAG_STRICT}, -{ "add", 0x08000220, 0xfc0003e0, "ca?Ax,b,t", pa20, FLAG_STRICT}, -{ "add", 0x08000200, 0xfc0003e0, "ca?ax,b,t", pa10, FLAG_STRICT}, -{ "add", 0x08000600, 0xfc000fe0, "?ax,b,t", pa10, 0}, -{ "addl", 0x08000a00, 0xfc000fe0, "?ax,b,t", pa10, 0}, -{ "addo", 0x08000e00, 0xfc000fe0, "?ax,b,t", pa10, 0}, -{ "addc", 0x08000700, 0xfc000fe0, "?ax,b,t", pa10, 0}, -{ "addco", 0x08000f00, 0xfc000fe0, "?ax,b,t", pa10, 0}, -{ "sub", 0x080004e0, 0xfc0007e0, "ct?Sx,b,t", pa20, FLAG_STRICT}, -{ "sub", 0x080004c0, 0xfc0007e0, "ct?sx,b,t", pa10, FLAG_STRICT}, -{ "sub", 0x08000520, 0xfc0007e0, "cB?Sx,b,t", pa20, FLAG_STRICT}, -{ "sub", 0x08000500, 0xfc0007e0, "cb?sx,b,t", pa10, FLAG_STRICT}, -{ "sub", 0x08000420, 0xfc0007e0, "cv?Sx,b,t", pa20, FLAG_STRICT}, -{ "sub", 0x08000400, 0xfc0007e0, "cv?sx,b,t", pa10, FLAG_STRICT}, -{ "sub", 0x08000400, 0xfc000fe0, "?sx,b,t", pa10, 0}, -{ "subo", 0x08000c00, 0xfc000fe0, "?sx,b,t", pa10, 0}, -{ "subb", 0x08000500, 0xfc000fe0, "?sx,b,t", pa10, 0}, -{ "subbo", 0x08000d00, 0xfc000fe0, "?sx,b,t", pa10, 0}, -{ "subt", 0x080004c0, 0xfc000fe0, "?sx,b,t", pa10, 0}, -{ "subto", 0x08000cc0, 0xfc000fe0, "?sx,b,t", pa10, 0}, -{ "ds", 0x08000440, 0xfc000fe0, "?sx,b,t", pa10, 0}, -{ "subi", 0x94000000, 0xfc000000, "cv?si,b,x", pa10, FLAG_STRICT}, -{ "subi", 0x94000000, 0xfc000800, "?si,b,x", pa10, 0}, -{ "subio", 0x94000800, 0xfc000800, "?si,b,x", pa10, 0}, -{ "cmpiclr", 0x90000800, 0xfc000800, "?Si,b,x", pa20, FLAG_STRICT}, -{ "cmpiclr", 0x90000000, 0xfc000800, "?si,b,x", pa10, FLAG_STRICT}, -{ "comiclr", 0x90000000, 0xfc000800, "?si,b,x", pa10, 0}, -{ "shladd", 0x08000220, 0xfc000320, "ca?Ax,.,b,t", pa20, FLAG_STRICT}, -{ "shladd", 0x08000200, 0xfc000320, "ca?ax,.,b,t", pa10, FLAG_STRICT}, -{ "sh1add", 0x08000640, 0xfc000fe0, "?ax,b,t", pa10, 0}, -{ "sh1addl", 0x08000a40, 0xfc000fe0, "?ax,b,t", pa10, 0}, -{ "sh1addo", 0x08000e40, 0xfc000fe0, "?ax,b,t", pa10, 0}, -{ "sh2add", 0x08000680, 0xfc000fe0, "?ax,b,t", pa10, 0}, -{ "sh2addl", 0x08000a80, 0xfc000fe0, "?ax,b,t", pa10, 0}, -{ "sh2addo", 0x08000e80, 0xfc000fe0, "?ax,b,t", pa10, 0}, -{ "sh3add", 0x080006c0, 0xfc000fe0, "?ax,b,t", pa10, 0}, -{ "sh3addl", 0x08000ac0, 0xfc000fe0, "?ax,b,t", pa10, 0}, -{ "sh3addo", 0x08000ec0, 0xfc000fe0, "?ax,b,t", pa10, 0}, - -/* Subword Operation Instructions. */ - -{ "hadd", 0x08000300, 0xfc00ff20, "cHx,b,t", pa20, FLAG_STRICT}, -{ "havg", 0x080002c0, 0xfc00ffe0, "x,b,t", pa20, FLAG_STRICT}, -{ "hshl", 0xf8008800, 0xffe0fc20, "x,*,t", pa20, FLAG_STRICT}, -{ "hshladd", 0x08000700, 0xfc00ff20, "x,.,b,t", pa20, FLAG_STRICT}, -{ "hshr", 0xf800c800, 0xfc1ff820, "cSb,*,t", pa20, FLAG_STRICT}, -{ "hshradd", 0x08000500, 0xfc00ff20, "x,.,b,t", pa20, FLAG_STRICT}, -{ "hsub", 0x08000100, 0xfc00ff20, "cHx,b,t", pa20, FLAG_STRICT}, -{ "mixh", 0xf8008400, 0xfc009fe0, "chx,b,t", pa20, FLAG_STRICT}, -{ "mixw", 0xf8008000, 0xfc009fe0, "chx,b,t", pa20, FLAG_STRICT}, -{ "permh", 0xf8000000, 0xfc009020, "c*a,t", pa20, FLAG_STRICT}, - - -/* Extract and Deposit Instructions. */ - -{ "shrpd", 0xd0000200, 0xfc001fe0, "?Xx,b,!,t", pa20, FLAG_STRICT}, -{ "shrpd", 0xd0000400, 0xfc001400, "?Xx,b,~,t", pa20, FLAG_STRICT}, -{ "shrpw", 0xd0000000, 0xfc001fe0, "?xx,b,!,t", pa10, FLAG_STRICT}, -{ "shrpw", 0xd0000800, 0xfc001c00, "?xx,b,p,t", pa10, FLAG_STRICT}, -{ "vshd", 0xd0000000, 0xfc001fe0, "?xx,b,t", pa10, 0}, -{ "shd", 0xd0000800, 0xfc001c00, "?xx,b,p,t", pa10, 0}, -{ "extrd", 0xd0001200, 0xfc001ae0, "cS?Xb,!,%,x", pa20, FLAG_STRICT}, -{ "extrd", 0xd8000000, 0xfc000000, "cS?Xb,q,|,x", pa20, FLAG_STRICT}, -{ "extrw", 0xd0001000, 0xfc001be0, "cS?xb,!,T,x", pa10, FLAG_STRICT}, -{ "extrw", 0xd0001800, 0xfc001800, "cS?xb,P,T,x", pa10, FLAG_STRICT}, -{ "vextru", 0xd0001000, 0xfc001fe0, "?xb,T,x", pa10, 0}, -{ "vextrs", 0xd0001400, 0xfc001fe0, "?xb,T,x", pa10, 0}, -{ "extru", 0xd0001800, 0xfc001c00, "?xb,P,T,x", pa10, 0}, -{ "extrs", 0xd0001c00, 0xfc001c00, "?xb,P,T,x", pa10, 0}, -{ "depd", 0xd4000200, 0xfc001ae0, "cz?Xx,!,%,b", pa20, FLAG_STRICT}, -{ "depd", 0xf0000000, 0xfc000000, "cz?Xx,~,|,b", pa20, FLAG_STRICT}, -{ "depdi", 0xd4001200, 0xfc001ae0, "cz?X5,!,%,b", pa20, FLAG_STRICT}, -{ "depdi", 0xf4000000, 0xfc000000, "cz?X5,~,|,b", pa20, FLAG_STRICT}, -{ "depw", 0xd4000000, 0xfc001be0, "cz?xx,!,T,b", pa10, FLAG_STRICT}, -{ "depw", 0xd4000800, 0xfc001800, "cz?xx,p,T,b", pa10, FLAG_STRICT}, -{ "depwi", 0xd4001000, 0xfc001be0, "cz?x5,!,T,b", pa10, FLAG_STRICT}, -{ "depwi", 0xd4001800, 0xfc001800, "cz?x5,p,T,b", pa10, FLAG_STRICT}, -{ "zvdep", 0xd4000000, 0xfc001fe0, "?xx,T,b", pa10, 0}, -{ "vdep", 0xd4000400, 0xfc001fe0, "?xx,T,b", pa10, 0}, -{ "zdep", 0xd4000800, 0xfc001c00, "?xx,p,T,b", pa10, 0}, -{ "dep", 0xd4000c00, 0xfc001c00, "?xx,p,T,b", pa10, 0}, -{ "zvdepi", 0xd4001000, 0xfc001fe0, "?x5,T,b", pa10, 0}, -{ "vdepi", 0xd4001400, 0xfc001fe0, "?x5,T,b", pa10, 0}, -{ "zdepi", 0xd4001800, 0xfc001c00, "?x5,p,T,b", pa10, 0}, -{ "depi", 0xd4001c00, 0xfc001c00, "?x5,p,T,b", pa10, 0}, - -/* System Control Instructions. */ - -{ "break", 0x00000000, 0xfc001fe0, "r,A", pa10, 0}, -{ "rfi", 0x00000c00, 0xffffff1f, "cr", pa10, FLAG_STRICT}, -{ "rfi", 0x00000c00, 0xffffffff, "", pa10, 0}, -{ "rfir", 0x00000ca0, 0xffffffff, "", pa11, 0}, -{ "ssm", 0x00000d60, 0xfc00ffe0, "U,t", pa20, FLAG_STRICT}, -{ "ssm", 0x00000d60, 0xffe0ffe0, "R,t", pa10, 0}, -{ "rsm", 0x00000e60, 0xfc00ffe0, "U,t", pa20, FLAG_STRICT}, -{ "rsm", 0x00000e60, 0xffe0ffe0, "R,t", pa10, 0}, -{ "mtsm", 0x00001860, 0xffe0ffff, "x", pa10, 0}, -{ "ldsid", 0x000010a0, 0xfc1fffe0, "(b),t", pa10, 0}, -{ "ldsid", 0x000010a0, 0xfc1f3fe0, "(s,b),t", pa10, 0}, -{ "mtsp", 0x00001820, 0xffe01fff, "x,S", pa10, 0}, -{ "mtctl", 0x00001840, 0xfc00ffff, "x,^", pa10, 0}, -{ "mtsarcm", 0x016018C0, 0xffe0ffff, "x", pa20, FLAG_STRICT}, -{ "mfia", 0x000014A0, 0xffffffe0, "t", pa20, FLAG_STRICT}, -{ "mfsp", 0x000004a0, 0xffff1fe0, "S,t", pa10, 0}, -{ "mfctl", 0x016048a0, 0xffffffe0, "cW!,t", pa20, FLAG_STRICT}, -{ "mfctl", 0x000008a0, 0xfc1fffe0, "^,t", pa10, 0}, -{ "sync", 0x00000400, 0xffffffff, "", pa10, 0}, -{ "syncdma", 0x00100400, 0xffffffff, "", pa10, 0}, -{ "probe", 0x04001180, 0xfc00ffa0, "cw(b),x,t", pa10, FLAG_STRICT}, -{ "probe", 0x04001180, 0xfc003fa0, "cw(s,b),x,t", pa10, FLAG_STRICT}, -{ "probei", 0x04003180, 0xfc00ffa0, "cw(b),R,t", pa10, FLAG_STRICT}, -{ "probei", 0x04003180, 0xfc003fa0, "cw(s,b),R,t", pa10, FLAG_STRICT}, -{ "prober", 0x04001180, 0xfc00ffe0, "(b),x,t", pa10, 0}, -{ "prober", 0x04001180, 0xfc003fe0, "(s,b),x,t", pa10, 0}, -{ "proberi", 0x04003180, 0xfc00ffe0, "(b),R,t", pa10, 0}, -{ "proberi", 0x04003180, 0xfc003fe0, "(s,b),R,t", pa10, 0}, -{ "probew", 0x040011c0, 0xfc00ffe0, "(b),x,t", pa10, 0}, -{ "probew", 0x040011c0, 0xfc003fe0, "(s,b),x,t", pa10, 0}, -{ "probewi", 0x040031c0, 0xfc00ffe0, "(b),R,t", pa10, 0}, -{ "probewi", 0x040031c0, 0xfc003fe0, "(s,b),R,t", pa10, 0}, -{ "lpa", 0x04001340, 0xfc00ffc0, "cZx(b),t", pa10, 0}, -{ "lpa", 0x04001340, 0xfc003fc0, "cZx(s,b),t", pa10, 0}, -{ "lci", 0x04001300, 0xfc00ffe0, "x(b),t", pa11, 0}, -{ "lci", 0x04001300, 0xfc003fe0, "x(s,b),t", pa11, 0}, -{ "pdtlb", 0x04001600, 0xfc00ffdf, "cLcZx(b)", pa20, FLAG_STRICT}, -{ "pdtlb", 0x04001600, 0xfc003fdf, "cLcZx(s,b)", pa20, FLAG_STRICT}, -{ "pdtlb", 0x04001600, 0xfc1fffdf, "cLcZ@(b)", pa20, FLAG_STRICT}, -{ "pdtlb", 0x04001600, 0xfc1f3fdf, "cLcZ@(s,b)", pa20, FLAG_STRICT}, -{ "pdtlb", 0x04001200, 0xfc00ffdf, "cZx(b)", pa10, 0}, -{ "pdtlb", 0x04001200, 0xfc003fdf, "cZx(s,b)", pa10, 0}, -{ "pitlb", 0x04000600, 0xfc001fdf, "cLcZx(S,b)", pa20, FLAG_STRICT}, -{ "pitlb", 0x04000600, 0xfc1f1fdf, "cLcZ@(S,b)", pa20, FLAG_STRICT}, -{ "pitlb", 0x04000200, 0xfc001fdf, "cZx(S,b)", pa10, 0}, -{ "pdtlbe", 0x04001240, 0xfc00ffdf, "cZx(b)", pa10, 0}, -{ "pdtlbe", 0x04001240, 0xfc003fdf, "cZx(s,b)", pa10, 0}, -{ "pitlbe", 0x04000240, 0xfc001fdf, "cZx(S,b)", pa10, 0}, -{ "idtlba", 0x04001040, 0xfc00ffff, "x,(b)", pa10, 0}, -{ "idtlba", 0x04001040, 0xfc003fff, "x,(s,b)", pa10, 0}, -{ "iitlba", 0x04000040, 0xfc001fff, "x,(S,b)", pa10, 0}, -{ "idtlbp", 0x04001000, 0xfc00ffff, "x,(b)", pa10, 0}, -{ "idtlbp", 0x04001000, 0xfc003fff, "x,(s,b)", pa10, 0}, -{ "iitlbp", 0x04000000, 0xfc001fff, "x,(S,b)", pa10, 0}, -{ "pdc", 0x04001380, 0xfc00ffdf, "cZx(b)", pa10, 0}, -{ "pdc", 0x04001380, 0xfc003fdf, "cZx(s,b)", pa10, 0}, -{ "fdc", 0x04001280, 0xfc00ffdf, "cZx(b)", pa10, FLAG_STRICT}, -{ "fdc", 0x04001280, 0xfc003fdf, "cZx(s,b)", pa10, FLAG_STRICT}, -{ "fdc", 0x04003280, 0xfc00ffff, "5(b)", pa20, FLAG_STRICT}, -{ "fdc", 0x04003280, 0xfc003fff, "5(s,b)", pa20, FLAG_STRICT}, -{ "fdc", 0x04001280, 0xfc00ffdf, "cZx(b)", pa10, 0}, -{ "fdc", 0x04001280, 0xfc003fdf, "cZx(s,b)", pa10, 0}, -{ "fic", 0x040013c0, 0xfc00dfdf, "cZx(b)", pa20, FLAG_STRICT}, -{ "fic", 0x04000280, 0xfc001fdf, "cZx(S,b)", pa10, 0}, -{ "fdce", 0x040012c0, 0xfc00ffdf, "cZx(b)", pa10, 0}, -{ "fdce", 0x040012c0, 0xfc003fdf, "cZx(s,b)", pa10, 0}, -{ "fice", 0x040002c0, 0xfc001fdf, "cZx(S,b)", pa10, 0}, -{ "diag", 0x14000000, 0xfc000000, "D", pa10, 0}, -{ "idtlbt", 0x04001800, 0xfc00ffff, "x,b", pa20, FLAG_STRICT}, -{ "iitlbt", 0x04000800, 0xfc00ffff, "x,b", pa20, FLAG_STRICT}, - -/* These may be specific to certain versions of the PA. Joel claimed - they were 72000 (7200?) specific. However, I'm almost certain the - mtcpu/mfcpu were undocumented, but available in the older 700 machines. */ -{ "mtcpu", 0x14001600, 0xfc00ffff, "x,^", pa10, 0}, -{ "mfcpu", 0x14001A00, 0xfc00ffff, "^,x", pa10, 0}, -{ "tocen", 0x14403600, 0xffffffff, "", pa10, 0}, -{ "tocdis", 0x14401620, 0xffffffff, "", pa10, 0}, -{ "shdwgr", 0x14402600, 0xffffffff, "", pa10, 0}, -{ "grshdw", 0x14400620, 0xffffffff, "", pa10, 0}, - -/* gfw and gfr are not in the HP PA 1.1 manual, but they are in either - the Timex FPU or the Mustang ERS (not sure which) manual. */ -{ "gfw", 0x04001680, 0xfc00ffdf, "cZx(b)", pa11, 0}, -{ "gfw", 0x04001680, 0xfc003fdf, "cZx(s,b)", pa11, 0}, -{ "gfr", 0x04001a80, 0xfc00ffdf, "cZx(b)", pa11, 0}, -{ "gfr", 0x04001a80, 0xfc003fdf, "cZx(s,b)", pa11, 0}, - -/* Floating Point Coprocessor Instructions. */ - -{ "fldw", 0x24000000, 0xfc00df80, "cXx(b),fT", pa10, FLAG_STRICT}, -{ "fldw", 0x24000000, 0xfc001f80, "cXx(s,b),fT", pa10, FLAG_STRICT}, -{ "fldw", 0x24000000, 0xfc00d380, "cxccx(b),fT", pa11, FLAG_STRICT}, -{ "fldw", 0x24000000, 0xfc001380, "cxccx(s,b),fT", pa11, FLAG_STRICT}, -{ "fldw", 0x24001020, 0xfc1ff3a0, "cocc@(b),fT", pa20, FLAG_STRICT}, -{ "fldw", 0x24001020, 0xfc1f33a0, "cocc@(s,b),fT", pa20, FLAG_STRICT}, -{ "fldw", 0x24001000, 0xfc00df80, "cM5(b),fT", pa10, FLAG_STRICT}, -{ "fldw", 0x24001000, 0xfc001f80, "cM5(s,b),fT", pa10, FLAG_STRICT}, -{ "fldw", 0x24001000, 0xfc00d380, "cmcc5(b),fT", pa11, FLAG_STRICT}, -{ "fldw", 0x24001000, 0xfc001380, "cmcc5(s,b),fT", pa11, FLAG_STRICT}, -{ "fldw", 0x5c000000, 0xfc000004, "y(b),fe", pa20w, FLAG_STRICT}, -{ "fldw", 0x58000000, 0xfc000000, "cJy(b),fe", pa20w, FLAG_STRICT}, -{ "fldw", 0x5c000000, 0xfc00c004, "d(b),fe", pa20, FLAG_STRICT}, -{ "fldw", 0x5c000000, 0xfc000004, "d(s,b),fe", pa20, FLAG_STRICT}, -{ "fldw", 0x58000000, 0xfc00c000, "cJd(b),fe", pa20, FLAG_STRICT}, -{ "fldw", 0x58000000, 0xfc000000, "cJd(s,b),fe", pa20, FLAG_STRICT}, -{ "fldd", 0x2c000000, 0xfc00dfc0, "cXx(b),ft", pa10, FLAG_STRICT}, -{ "fldd", 0x2c000000, 0xfc001fc0, "cXx(s,b),ft", pa10, FLAG_STRICT}, -{ "fldd", 0x2c000000, 0xfc00d3c0, "cxccx(b),ft", pa11, FLAG_STRICT}, -{ "fldd", 0x2c000000, 0xfc0013c0, "cxccx(s,b),ft", pa11, FLAG_STRICT}, -{ "fldd", 0x2c001020, 0xfc1ff3e0, "cocc@(b),ft", pa20, FLAG_STRICT}, -{ "fldd", 0x2c001020, 0xfc1f33e0, "cocc@(s,b),ft", pa20, FLAG_STRICT}, -{ "fldd", 0x2c001000, 0xfc00dfc0, "cM5(b),ft", pa10, FLAG_STRICT}, -{ "fldd", 0x2c001000, 0xfc001fc0, "cM5(s,b),ft", pa10, FLAG_STRICT}, -{ "fldd", 0x2c001000, 0xfc00d3c0, "cmcc5(b),ft", pa11, FLAG_STRICT}, -{ "fldd", 0x2c001000, 0xfc0013c0, "cmcc5(s,b),ft", pa11, FLAG_STRICT}, -{ "fldd", 0x50000002, 0xfc000002, "cq&(b),fx", pa20w, FLAG_STRICT}, -{ "fldd", 0x50000002, 0xfc00c002, "cq#(b),fx", pa20, FLAG_STRICT}, -{ "fldd", 0x50000002, 0xfc000002, "cq#(s,b),fx", pa20, FLAG_STRICT}, -{ "fstw", 0x24000200, 0xfc00df80, "cXfT,x(b)", pa10, FLAG_STRICT}, -{ "fstw", 0x24000200, 0xfc001f80, "cXfT,x(s,b)", pa10, FLAG_STRICT}, -{ "fstw", 0x24000200, 0xfc00d380, "cxcCfT,x(b)", pa11, FLAG_STRICT}, -{ "fstw", 0x24000200, 0xfc001380, "cxcCfT,x(s,b)", pa11, FLAG_STRICT}, -{ "fstw", 0x24001220, 0xfc1ff3a0, "cocCfT,@(b)", pa20, FLAG_STRICT}, -{ "fstw", 0x24001220, 0xfc1f33a0, "cocCfT,@(s,b)", pa20, FLAG_STRICT}, -{ "fstw", 0x24001200, 0xfc00df80, "cMfT,5(b)", pa10, FLAG_STRICT}, -{ "fstw", 0x24001200, 0xfc001f80, "cMfT,5(s,b)", pa10, FLAG_STRICT}, -{ "fstw", 0x24001200, 0xfc00df80, "cMfT,5(b)", pa10, FLAG_STRICT}, -{ "fstw", 0x24001200, 0xfc001f80, "cMfT,5(s,b)", pa10, FLAG_STRICT}, -{ "fstw", 0x7c000000, 0xfc000004, "fE,y(b)", pa20w, FLAG_STRICT}, -{ "fstw", 0x78000000, 0xfc000000, "cJfE,y(b)", pa20w, FLAG_STRICT}, -{ "fstw", 0x7c000000, 0xfc00c004, "fE,d(b)", pa20, FLAG_STRICT}, -{ "fstw", 0x7c000000, 0xfc000004, "fE,d(s,b)", pa20, FLAG_STRICT}, -{ "fstw", 0x78000000, 0xfc00c000, "cJfE,d(b)", pa20, FLAG_STRICT}, -{ "fstw", 0x78000000, 0xfc000000, "cJfE,d(s,b)", pa20, FLAG_STRICT}, -{ "fstd", 0x2c000200, 0xfc00dfc0, "cXft,x(b)", pa10, FLAG_STRICT}, -{ "fstd", 0x2c000200, 0xfc001fc0, "cXft,x(s,b)", pa10, FLAG_STRICT}, -{ "fstd", 0x2c000200, 0xfc00d3c0, "cxcCft,x(b)", pa11, FLAG_STRICT}, -{ "fstd", 0x2c000200, 0xfc0013c0, "cxcCft,x(s,b)", pa11, FLAG_STRICT}, -{ "fstd", 0x2c001220, 0xfc1ff3e0, "cocCft,@(b)", pa20, FLAG_STRICT}, -{ "fstd", 0x2c001220, 0xfc1f33e0, "cocCft,@(s,b)", pa20, FLAG_STRICT}, -{ "fstd", 0x2c001200, 0xfc00dfc0, "cMft,5(b)", pa10, FLAG_STRICT}, -{ "fstd", 0x2c001200, 0xfc001fc0, "cMft,5(s,b)", pa10, FLAG_STRICT}, -{ "fstd", 0x2c001200, 0xfc00d3c0, "cmcCft,5(b)", pa11, FLAG_STRICT}, -{ "fstd", 0x2c001200, 0xfc0013c0, "cmcCft,5(s,b)", pa11, FLAG_STRICT}, -{ "fstd", 0x70000002, 0xfc000002, "cqfx,&(b)", pa20w, FLAG_STRICT}, -{ "fstd", 0x70000002, 0xfc00c002, "cqfx,#(b)", pa20, FLAG_STRICT}, -{ "fstd", 0x70000002, 0xfc000002, "cqfx,#(s,b)", pa20, FLAG_STRICT}, -{ "fldwx", 0x24000000, 0xfc00df80, "cXx(b),fT", pa10, FLAG_STRICT}, -{ "fldwx", 0x24000000, 0xfc001f80, "cXx(s,b),fT", pa10, FLAG_STRICT}, -{ "fldwx", 0x24000000, 0xfc00d380, "cxccx(b),fT", pa11, FLAG_STRICT}, -{ "fldwx", 0x24000000, 0xfc001380, "cxccx(s,b),fT", pa11, FLAG_STRICT}, -{ "fldwx", 0x24000000, 0xfc00df80, "cXx(b),fT", pa10, 0}, -{ "fldwx", 0x24000000, 0xfc001f80, "cXx(s,b),fT", pa10, 0}, -{ "flddx", 0x2c000000, 0xfc00dfc0, "cXx(b),ft", pa10, FLAG_STRICT}, -{ "flddx", 0x2c000000, 0xfc001fc0, "cXx(s,b),ft", pa10, FLAG_STRICT}, -{ "flddx", 0x2c000000, 0xfc00d3c0, "cxccx(b),ft", pa11, FLAG_STRICT}, -{ "flddx", 0x2c000000, 0xfc0013c0, "cxccx(s,b),ft", pa11, FLAG_STRICT}, -{ "flddx", 0x2c000000, 0xfc00dfc0, "cXx(b),ft", pa10, 0}, -{ "flddx", 0x2c000000, 0xfc001fc0, "cXx(s,b),ft", pa10, 0}, -{ "fstwx", 0x24000200, 0xfc00df80, "cxfT,x(b)", pa10, FLAG_STRICT}, -{ "fstwx", 0x24000200, 0xfc001f80, "cxfT,x(s,b)", pa10, FLAG_STRICT}, -{ "fstwx", 0x24000200, 0xfc00d380, "cxcCfT,x(b)", pa11, FLAG_STRICT}, -{ "fstwx", 0x24000200, 0xfc001380, "cxcCfT,x(s,b)", pa11, FLAG_STRICT}, -{ "fstwx", 0x24000200, 0xfc00df80, "cxfT,x(b)", pa10, 0}, -{ "fstwx", 0x24000200, 0xfc001f80, "cxfT,x(s,b)", pa10, 0}, -{ "fstdx", 0x2c000200, 0xfc00dfc0, "cxft,x(b)", pa10, FLAG_STRICT}, -{ "fstdx", 0x2c000200, 0xfc001fc0, "cxft,x(s,b)", pa10, FLAG_STRICT}, -{ "fstdx", 0x2c000200, 0xfc00d3c0, "cxcCft,x(b)", pa11, FLAG_STRICT}, -{ "fstdx", 0x2c000200, 0xfc0013c0, "cxcCft,x(s,b)", pa11, FLAG_STRICT}, -{ "fstdx", 0x2c000200, 0xfc00dfc0, "cxft,x(b)", pa10, 0}, -{ "fstdx", 0x2c000200, 0xfc001fc0, "cxft,x(s,b)", pa10, 0}, -{ "fstqx", 0x3c000200, 0xfc00dfc0, "cxft,x(b)", pa10, 0}, -{ "fstqx", 0x3c000200, 0xfc001fc0, "cxft,x(s,b)", pa10, 0}, -{ "fldws", 0x24001000, 0xfc00df80, "cm5(b),fT", pa10, FLAG_STRICT}, -{ "fldws", 0x24001000, 0xfc001f80, "cm5(s,b),fT", pa10, FLAG_STRICT}, -{ "fldws", 0x24001000, 0xfc00d380, "cmcc5(b),fT", pa11, FLAG_STRICT}, -{ "fldws", 0x24001000, 0xfc001380, "cmcc5(s,b),fT", pa11, FLAG_STRICT}, -{ "fldws", 0x24001000, 0xfc00df80, "cm5(b),fT", pa10, 0}, -{ "fldws", 0x24001000, 0xfc001f80, "cm5(s,b),fT", pa10, 0}, -{ "fldds", 0x2c001000, 0xfc00dfc0, "cm5(b),ft", pa10, FLAG_STRICT}, -{ "fldds", 0x2c001000, 0xfc001fc0, "cm5(s,b),ft", pa10, FLAG_STRICT}, -{ "fldds", 0x2c001000, 0xfc00d3c0, "cmcc5(b),ft", pa11, FLAG_STRICT}, -{ "fldds", 0x2c001000, 0xfc0013c0, "cmcc5(s,b),ft", pa11, FLAG_STRICT}, -{ "fldds", 0x2c001000, 0xfc00dfc0, "cm5(b),ft", pa10, 0}, -{ "fldds", 0x2c001000, 0xfc001fc0, "cm5(s,b),ft", pa10, 0}, -{ "fstws", 0x24001200, 0xfc00df80, "cmfT,5(b)", pa10, FLAG_STRICT}, -{ "fstws", 0x24001200, 0xfc001f80, "cmfT,5(s,b)", pa10, FLAG_STRICT}, -{ "fstws", 0x24001200, 0xfc00d380, "cmcCfT,5(b)", pa11, FLAG_STRICT}, -{ "fstws", 0x24001200, 0xfc001380, "cmcCfT,5(s,b)", pa11, FLAG_STRICT}, -{ "fstws", 0x24001200, 0xfc00df80, "cmfT,5(b)", pa10, 0}, -{ "fstws", 0x24001200, 0xfc001f80, "cmfT,5(s,b)", pa10, 0}, -{ "fstds", 0x2c001200, 0xfc00dfc0, "cmft,5(b)", pa10, FLAG_STRICT}, -{ "fstds", 0x2c001200, 0xfc001fc0, "cmft,5(s,b)", pa10, FLAG_STRICT}, -{ "fstds", 0x2c001200, 0xfc00d3c0, "cmcCft,5(b)", pa11, FLAG_STRICT}, -{ "fstds", 0x2c001200, 0xfc0013c0, "cmcCft,5(s,b)", pa11, FLAG_STRICT}, -{ "fstds", 0x2c001200, 0xfc00dfc0, "cmft,5(b)", pa10, 0}, -{ "fstds", 0x2c001200, 0xfc001fc0, "cmft,5(s,b)", pa10, 0}, -{ "fstqs", 0x3c001200, 0xfc00dfc0, "cmft,5(b)", pa10, 0}, -{ "fstqs", 0x3c001200, 0xfc001fc0, "cmft,5(s,b)", pa10, 0}, -{ "fadd", 0x30000600, 0xfc00e7e0, "Ffa,fb,fT", pa10, 0}, -{ "fadd", 0x38000600, 0xfc00e720, "IfA,fB,fT", pa10, 0}, -{ "fsub", 0x30002600, 0xfc00e7e0, "Ffa,fb,fT", pa10, 0}, -{ "fsub", 0x38002600, 0xfc00e720, "IfA,fB,fT", pa10, 0}, -{ "fmpy", 0x30004600, 0xfc00e7e0, "Ffa,fb,fT", pa10, 0}, -{ "fmpy", 0x38004600, 0xfc00e720, "IfA,fB,fT", pa10, 0}, -{ "fdiv", 0x30006600, 0xfc00e7e0, "Ffa,fb,fT", pa10, 0}, -{ "fdiv", 0x38006600, 0xfc00e720, "IfA,fB,fT", pa10, 0}, -{ "fsqrt", 0x30008000, 0xfc1fe7e0, "Ffa,fT", pa10, 0}, -{ "fsqrt", 0x38008000, 0xfc1fe720, "FfA,fT", pa10, 0}, -{ "fabs", 0x30006000, 0xfc1fe7e0, "Ffa,fT", pa10, 0}, -{ "fabs", 0x38006000, 0xfc1fe720, "FfA,fT", pa10, 0}, -{ "frem", 0x30008600, 0xfc00e7e0, "Ffa,fb,fT", pa10, 0}, -{ "frem", 0x38008600, 0xfc00e720, "FfA,fB,fT", pa10, 0}, -{ "frnd", 0x3000a000, 0xfc1fe7e0, "Ffa,fT", pa10, 0}, -{ "frnd", 0x3800a000, 0xfc1fe720, "FfA,fT", pa10, 0}, -{ "fcpy", 0x30004000, 0xfc1fe7e0, "Ffa,fT", pa10, 0}, -{ "fcpy", 0x38004000, 0xfc1fe720, "FfA,fT", pa10, 0}, -{ "fcnvff", 0x30000200, 0xfc1f87e0, "FGfa,fT", pa10, 0}, -{ "fcnvff", 0x38000200, 0xfc1f8720, "FGfA,fT", pa10, 0}, -{ "fcnvxf", 0x30008200, 0xfc1f87e0, "FGfa,fT", pa10, 0}, -{ "fcnvxf", 0x38008200, 0xfc1f8720, "FGfA,fT", pa10, 0}, -{ "fcnvfx", 0x30010200, 0xfc1f87e0, "FGfa,fT", pa10, 0}, -{ "fcnvfx", 0x38010200, 0xfc1f8720, "FGfA,fT", pa10, 0}, -{ "fcnvfxt", 0x30018200, 0xfc1f87e0, "FGfa,fT", pa10, 0}, -{ "fcnvfxt", 0x38018200, 0xfc1f8720, "FGfA,fT", pa10, 0}, -{ "fmpyfadd", 0xb8000000, 0xfc000020, "IfA,fB,fC,fT", pa20, FLAG_STRICT}, -{ "fmpynfadd", 0xb8000020, 0xfc000020, "IfA,fB,fC,fT", pa20, FLAG_STRICT}, -{ "fneg", 0x3000c000, 0xfc1fe7e0, "Ffa,fT", pa20, FLAG_STRICT}, -{ "fneg", 0x3800c000, 0xfc1fe720, "IfA,fT", pa20, FLAG_STRICT}, -{ "fnegabs", 0x3000e000, 0xfc1fe7e0, "Ffa,fT", pa20, FLAG_STRICT}, -{ "fnegabs", 0x3800e000, 0xfc1fe720, "IfA,fT", pa20, FLAG_STRICT}, -{ "fcnv", 0x30000200, 0xfc1c0720, "{_fa,fT", pa20, FLAG_STRICT}, -{ "fcnv", 0x38000200, 0xfc1c0720, "FGfA,fT", pa20, FLAG_STRICT}, -{ "fcmp", 0x30000400, 0xfc00e7e0, "F?ffa,fb", pa10, FLAG_STRICT}, -{ "fcmp", 0x38000400, 0xfc00e720, "I?ffA,fB", pa10, FLAG_STRICT}, -{ "fcmp", 0x30000400, 0xfc0007e0, "F?ffa,fb,h", pa20, FLAG_STRICT}, -{ "fcmp", 0x38000400, 0xfc000720, "I?ffA,fB,h", pa20, FLAG_STRICT}, -{ "fcmp", 0x30000400, 0xfc00e7e0, "F?ffa,fb", pa10, 0}, -{ "fcmp", 0x38000400, 0xfc00e720, "I?ffA,fB", pa10, 0}, -{ "xmpyu", 0x38004700, 0xfc00e720, "fX,fB,fT", pa11, 0}, -{ "fmpyadd", 0x18000000, 0xfc000000, "Hfi,fj,fk,fl,fm", pa11, 0}, -{ "fmpysub", 0x98000000, 0xfc000000, "Hfi,fj,fk,fl,fm", pa11, 0}, -{ "ftest", 0x30002420, 0xffffffff, "", pa10, FLAG_STRICT}, -{ "ftest", 0x30002420, 0xffffffe0, ",=", pa20, FLAG_STRICT}, -{ "ftest", 0x30000420, 0xffff1fff, "m", pa20, FLAG_STRICT}, -{ "fid", 0x30000000, 0xffffffff, "", pa11, 0}, - -/* Performance Monitor Instructions. */ - -{ "pmdis", 0x30000280, 0xffffffdf, "N", pa20, FLAG_STRICT}, -{ "pmenb", 0x30000680, 0xffffffff, "", pa20, FLAG_STRICT}, - -/* Assist Instructions. */ - -{ "spop0", 0x10000000, 0xfc000600, "v,ON", pa10, 0}, -{ "spop1", 0x10000200, 0xfc000600, "v,oNt", pa10, 0}, -{ "spop2", 0x10000400, 0xfc000600, "v,1Nb", pa10, 0}, -{ "spop3", 0x10000600, 0xfc000600, "v,0Nx,b", pa10, 0}, -{ "copr", 0x30000000, 0xfc000000, "u,2N", pa10, 0}, -{ "cldw", 0x24000000, 0xfc00de00, "ucXx(b),t", pa10, FLAG_STRICT}, -{ "cldw", 0x24000000, 0xfc001e00, "ucXx(s,b),t", pa10, FLAG_STRICT}, -{ "cldw", 0x24000000, 0xfc00d200, "ucxccx(b),t", pa11, FLAG_STRICT}, -{ "cldw", 0x24000000, 0xfc001200, "ucxccx(s,b),t", pa11, FLAG_STRICT}, -{ "cldw", 0x24001000, 0xfc00d200, "ucocc@(b),t", pa20, FLAG_STRICT}, -{ "cldw", 0x24001000, 0xfc001200, "ucocc@(s,b),t", pa20, FLAG_STRICT}, -{ "cldw", 0x24001000, 0xfc00de00, "ucM5(b),t", pa10, FLAG_STRICT}, -{ "cldw", 0x24001000, 0xfc001e00, "ucM5(s,b),t", pa10, FLAG_STRICT}, -{ "cldw", 0x24001000, 0xfc00d200, "ucmcc5(b),t", pa11, FLAG_STRICT}, -{ "cldw", 0x24001000, 0xfc001200, "ucmcc5(s,b),t", pa11, FLAG_STRICT}, -{ "cldd", 0x2c000000, 0xfc00de00, "ucXx(b),t", pa10, FLAG_STRICT}, -{ "cldd", 0x2c000000, 0xfc001e00, "ucXx(s,b),t", pa10, FLAG_STRICT}, -{ "cldd", 0x2c000000, 0xfc00d200, "ucxccx(b),t", pa11, FLAG_STRICT}, -{ "cldd", 0x2c000000, 0xfc001200, "ucxccx(s,b),t", pa11, FLAG_STRICT}, -{ "cldd", 0x2c001000, 0xfc00d200, "ucocc@(b),t", pa20, FLAG_STRICT}, -{ "cldd", 0x2c001000, 0xfc001200, "ucocc@(s,b),t", pa20, FLAG_STRICT}, -{ "cldd", 0x2c001000, 0xfc00de00, "ucM5(b),t", pa10, FLAG_STRICT}, -{ "cldd", 0x2c001000, 0xfc001e00, "ucM5(s,b),t", pa10, FLAG_STRICT}, -{ "cldd", 0x2c001000, 0xfc00d200, "ucmcc5(b),t", pa11, FLAG_STRICT}, -{ "cldd", 0x2c001000, 0xfc001200, "ucmcc5(s,b),t", pa11, FLAG_STRICT}, -{ "cstw", 0x24000200, 0xfc00de00, "ucXt,x(b)", pa10, FLAG_STRICT}, -{ "cstw", 0x24000200, 0xfc001e00, "ucXt,x(s,b)", pa10, FLAG_STRICT}, -{ "cstw", 0x24000200, 0xfc00d200, "ucxcCt,x(b)", pa11, FLAG_STRICT}, -{ "cstw", 0x24000200, 0xfc001200, "ucxcCt,x(s,b)", pa11, FLAG_STRICT}, -{ "cstw", 0x24001200, 0xfc00d200, "ucocCt,@(b)", pa20, FLAG_STRICT}, -{ "cstw", 0x24001200, 0xfc001200, "ucocCt,@(s,b)", pa20, FLAG_STRICT}, -{ "cstw", 0x24001200, 0xfc00de00, "ucMt,5(b)", pa10, FLAG_STRICT}, -{ "cstw", 0x24001200, 0xfc001e00, "ucMt,5(s,b)", pa10, FLAG_STRICT}, -{ "cstw", 0x24001200, 0xfc00d200, "ucmcCt,5(b)", pa11, FLAG_STRICT}, -{ "cstw", 0x24001200, 0xfc001200, "ucmcCt,5(s,b)", pa11, FLAG_STRICT}, -{ "cstd", 0x2c000200, 0xfc00de00, "ucXt,x(b)", pa10, FLAG_STRICT}, -{ "cstd", 0x2c000200, 0xfc001e00, "ucXt,x(s,b)", pa10, FLAG_STRICT}, -{ "cstd", 0x2c000200, 0xfc00d200, "ucxcCt,x(b)", pa11, FLAG_STRICT}, -{ "cstd", 0x2c000200, 0xfc001200, "ucxcCt,x(s,b)", pa11, FLAG_STRICT}, -{ "cstd", 0x2c001200, 0xfc00d200, "ucocCt,@(b)", pa20, FLAG_STRICT}, -{ "cstd", 0x2c001200, 0xfc001200, "ucocCt,@(s,b)", pa20, FLAG_STRICT}, -{ "cstd", 0x2c001200, 0xfc00de00, "ucMt,5(b)", pa10, FLAG_STRICT}, -{ "cstd", 0x2c001200, 0xfc001e00, "ucMt,5(s,b)", pa10, FLAG_STRICT}, -{ "cstd", 0x2c001200, 0xfc00d200, "ucmcCt,5(b)", pa11, FLAG_STRICT}, -{ "cstd", 0x2c001200, 0xfc001200, "ucmcCt,5(s,b)", pa11, FLAG_STRICT}, -{ "cldwx", 0x24000000, 0xfc00de00, "ucXx(b),t", pa10, FLAG_STRICT}, -{ "cldwx", 0x24000000, 0xfc001e00, "ucXx(s,b),t", pa10, FLAG_STRICT}, -{ "cldwx", 0x24000000, 0xfc00d200, "ucxccx(b),t", pa11, FLAG_STRICT}, -{ "cldwx", 0x24000000, 0xfc001200, "ucxccx(s,b),t", pa11, FLAG_STRICT}, -{ "cldwx", 0x24000000, 0xfc00de00, "ucXx(b),t", pa10, 0}, -{ "cldwx", 0x24000000, 0xfc001e00, "ucXx(s,b),t", pa10, 0}, -{ "clddx", 0x2c000000, 0xfc00de00, "ucXx(b),t", pa10, FLAG_STRICT}, -{ "clddx", 0x2c000000, 0xfc001e00, "ucXx(s,b),t", pa10, FLAG_STRICT}, -{ "clddx", 0x2c000000, 0xfc00d200, "ucxccx(b),t", pa11, FLAG_STRICT}, -{ "clddx", 0x2c000000, 0xfc001200, "ucxccx(s,b),t", pa11, FLAG_STRICT}, -{ "clddx", 0x2c000000, 0xfc00de00, "ucXx(b),t", pa10, 0}, -{ "clddx", 0x2c000000, 0xfc001e00, "ucXx(s,b),t", pa10, 0}, -{ "cstwx", 0x24000200, 0xfc00de00, "ucXt,x(b)", pa10, FLAG_STRICT}, -{ "cstwx", 0x24000200, 0xfc001e00, "ucXt,x(s,b)", pa10, FLAG_STRICT}, -{ "cstwx", 0x24000200, 0xfc00d200, "ucxcCt,x(b)", pa11, FLAG_STRICT}, -{ "cstwx", 0x24000200, 0xfc001200, "ucxcCt,x(s,b)", pa11, FLAG_STRICT}, -{ "cstwx", 0x24000200, 0xfc00de00, "ucXt,x(b)", pa10, 0}, -{ "cstwx", 0x24000200, 0xfc001e00, "ucXt,x(s,b)", pa10, 0}, -{ "cstdx", 0x2c000200, 0xfc00de00, "ucXt,x(b)", pa10, FLAG_STRICT}, -{ "cstdx", 0x2c000200, 0xfc001e00, "ucXt,x(s,b)", pa10, FLAG_STRICT}, -{ "cstdx", 0x2c000200, 0xfc00d200, "ucxcCt,x(b)", pa11, FLAG_STRICT}, -{ "cstdx", 0x2c000200, 0xfc001200, "ucxcCt,x(s,b)", pa11, FLAG_STRICT}, -{ "cstdx", 0x2c000200, 0xfc00de00, "ucXt,x(b)", pa10, 0}, -{ "cstdx", 0x2c000200, 0xfc001e00, "ucXt,x(s,b)", pa10, 0}, -{ "cldws", 0x24001000, 0xfc00de00, "ucM5(b),t", pa10, FLAG_STRICT}, -{ "cldws", 0x24001000, 0xfc001e00, "ucM5(s,b),t", pa10, FLAG_STRICT}, -{ "cldws", 0x24001000, 0xfc00d200, "ucmcc5(b),t", pa11, FLAG_STRICT}, -{ "cldws", 0x24001000, 0xfc001200, "ucmcc5(s,b),t", pa11, FLAG_STRICT}, -{ "cldws", 0x24001000, 0xfc00de00, "ucM5(b),t", pa10, 0}, -{ "cldws", 0x24001000, 0xfc001e00, "ucM5(s,b),t", pa10, 0}, -{ "cldds", 0x2c001000, 0xfc00de00, "ucM5(b),t", pa10, FLAG_STRICT}, -{ "cldds", 0x2c001000, 0xfc001e00, "ucM5(s,b),t", pa10, FLAG_STRICT}, -{ "cldds", 0x2c001000, 0xfc00d200, "ucmcc5(b),t", pa11, FLAG_STRICT}, -{ "cldds", 0x2c001000, 0xfc001200, "ucmcc5(s,b),t", pa11, FLAG_STRICT}, -{ "cldds", 0x2c001000, 0xfc00de00, "ucM5(b),t", pa10, 0}, -{ "cldds", 0x2c001000, 0xfc001e00, "ucM5(s,b),t", pa10, 0}, -{ "cstws", 0x24001200, 0xfc00de00, "ucMt,5(b)", pa10, FLAG_STRICT}, -{ "cstws", 0x24001200, 0xfc001e00, "ucMt,5(s,b)", pa10, FLAG_STRICT}, -{ "cstws", 0x24001200, 0xfc00d200, "ucmcCt,5(b)", pa11, FLAG_STRICT}, -{ "cstws", 0x24001200, 0xfc001200, "ucmcCt,5(s,b)", pa11, FLAG_STRICT}, -{ "cstws", 0x24001200, 0xfc00de00, "ucMt,5(b)", pa10, 0}, -{ "cstws", 0x24001200, 0xfc001e00, "ucMt,5(s,b)", pa10, 0}, -{ "cstds", 0x2c001200, 0xfc00de00, "ucMt,5(b)", pa10, FLAG_STRICT}, -{ "cstds", 0x2c001200, 0xfc001e00, "ucMt,5(s,b)", pa10, FLAG_STRICT}, -{ "cstds", 0x2c001200, 0xfc00d200, "ucmcCt,5(b)", pa11, FLAG_STRICT}, -{ "cstds", 0x2c001200, 0xfc001200, "ucmcCt,5(s,b)", pa11, FLAG_STRICT}, -{ "cstds", 0x2c001200, 0xfc00de00, "ucMt,5(b)", pa10, 0}, -{ "cstds", 0x2c001200, 0xfc001e00, "ucMt,5(s,b)", pa10, 0}, - -/* More pseudo instructions which must follow the main table. */ -{ "call", 0xe800f000, 0xfc1ffffd, "n(b)", pa20, FLAG_STRICT}, -{ "call", 0xe800a000, 0xffe0e000, "nW", pa10, FLAG_STRICT}, -{ "ret", 0xe840d000, 0xfffffffd, "n", pa20, FLAG_STRICT}, - -}; - -#define NUMOPCODES ((sizeof pa_opcodes)/(sizeof pa_opcodes[0])) - -/* SKV 12/18/92. Added some denotations for various operands. */ - -#define PA_IMM11_AT_31 'i' -#define PA_IMM14_AT_31 'j' -#define PA_IMM21_AT_31 'k' -#define PA_DISP12 'w' -#define PA_DISP17 'W' - -#define N_HPPA_OPERAND_FORMATS 5 - -/* Integer register names, indexed by the numbers which appear in the - opcodes. */ -static const char *const reg_names[] = -{ - "flags", "r1", "rp", "r3", "r4", "r5", "r6", "r7", "r8", "r9", - "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", - "r20", "r21", "r22", "r23", "r24", "r25", "r26", "dp", "ret0", "ret1", - "sp", "r31" -}; - -/* Floating point register names, indexed by the numbers which appear in the - opcodes. */ -static const char *const fp_reg_names[] = -{ - "fpsr", "fpe2", "fpe4", "fpe6", - "fr4", "fr5", "fr6", "fr7", "fr8", - "fr9", "fr10", "fr11", "fr12", "fr13", "fr14", "fr15", - "fr16", "fr17", "fr18", "fr19", "fr20", "fr21", "fr22", "fr23", - "fr24", "fr25", "fr26", "fr27", "fr28", "fr29", "fr30", "fr31" -}; - -typedef unsigned int CORE_ADDR; - -/* Get at various relevant fields of an instruction word. */ - -#define MASK_5 0x1f -#define MASK_10 0x3ff -#define MASK_11 0x7ff -#define MASK_14 0x3fff -#define MASK_16 0xffff -#define MASK_21 0x1fffff - -/* These macros get bit fields using HP's numbering (MSB = 0). */ - -#define GET_FIELD(X, FROM, TO) \ - ((X) >> (31 - (TO)) & ((1 << ((TO) - (FROM) + 1)) - 1)) - -#define GET_BIT(X, WHICH) \ - GET_FIELD (X, WHICH, WHICH) - -/* Some of these have been converted to 2-d arrays because they - consume less storage this way. If the maintenance becomes a - problem, convert them back to const 1-d pointer arrays. */ -static const char *const control_reg[] = -{ - "rctr", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", - "pidr1", "pidr2", "ccr", "sar", "pidr3", "pidr4", - "iva", "eiem", "itmr", "pcsq", "pcoq", "iir", "isr", - "ior", "ipsw", "eirr", "tr0", "tr1", "tr2", "tr3", - "tr4", "tr5", "tr6", "tr7" -}; - -static const char *const compare_cond_names[] = -{ - "", ",=", ",<", ",<=", ",<<", ",<<=", ",sv", ",od", - ",tr", ",<>", ",>=", ",>", ",>>=", ",>>", ",nsv", ",ev" -}; -static const char *const compare_cond_64_names[] = -{ - "", ",*=", ",*<", ",*<=", ",*<<", ",*<<=", ",*sv", ",*od", - ",*tr", ",*<>", ",*>=", ",*>", ",*>>=", ",*>>", ",*nsv", ",*ev" -}; -static const char *const cmpib_cond_64_names[] = -{ - ",*<<", ",*=", ",*<", ",*<=", ",*>>=", ",*<>", ",*>=", ",*>" -}; -static const char *const add_cond_names[] = -{ - "", ",=", ",<", ",<=", ",nuv", ",znv", ",sv", ",od", - ",tr", ",<>", ",>=", ",>", ",uv", ",vnz", ",nsv", ",ev" -}; -static const char *const add_cond_64_names[] = -{ - "", ",*=", ",*<", ",*<=", ",*nuv", ",*znv", ",*sv", ",*od", - ",*tr", ",*<>", ",*>=", ",*>", ",*uv", ",*vnz", ",*nsv", ",*ev" -}; -static const char *const wide_add_cond_names[] = -{ - "", ",=", ",<", ",<=", ",nuv", ",*=", ",*<", ",*<=", - ",tr", ",<>", ",>=", ",>", ",uv", ",*<>", ",*>=", ",*>" -}; -static const char *const logical_cond_names[] = -{ - "", ",=", ",<", ",<=", 0, 0, 0, ",od", - ",tr", ",<>", ",>=", ",>", 0, 0, 0, ",ev"}; -static const char *const logical_cond_64_names[] = -{ - "", ",*=", ",*<", ",*<=", 0, 0, 0, ",*od", - ",*tr", ",*<>", ",*>=", ",*>", 0, 0, 0, ",*ev"}; -static const char *const unit_cond_names[] = -{ - "", ",swz", ",sbz", ",shz", ",sdc", ",swc", ",sbc", ",shc", - ",tr", ",nwz", ",nbz", ",nhz", ",ndc", ",nwc", ",nbc", ",nhc" -}; -static const char *const unit_cond_64_names[] = -{ - "", ",*swz", ",*sbz", ",*shz", ",*sdc", ",*swc", ",*sbc", ",*shc", - ",*tr", ",*nwz", ",*nbz", ",*nhz", ",*ndc", ",*nwc", ",*nbc", ",*nhc" -}; -static const char *const shift_cond_names[] = -{ - "", ",=", ",<", ",od", ",tr", ",<>", ",>=", ",ev" -}; -static const char *const shift_cond_64_names[] = -{ - "", ",*=", ",*<", ",*od", ",*tr", ",*<>", ",*>=", ",*ev" -}; -static const char *const bb_cond_64_names[] = -{ - ",*<", ",*>=" -}; -static const char *const index_compl_names[] = {"", ",m", ",s", ",sm"}; -static const char *const short_ldst_compl_names[] = {"", ",ma", "", ",mb"}; -static const char *const short_bytes_compl_names[] = -{ - "", ",b,m", ",e", ",e,m" -}; -static const char *const float_format_names[] = {",sgl", ",dbl", "", ",quad"}; -static const char *const fcnv_fixed_names[] = {",w", ",dw", "", ",qw"}; -static const char *const fcnv_ufixed_names[] = {",uw", ",udw", "", ",uqw"}; -static const char *const float_comp_names[] = -{ - ",false?", ",false", ",?", ",!<=>", ",=", ",=t", ",?=", ",!<>", - ",!?>=", ",<", ",?<", ",!>=", ",!?>", ",<=", ",?<=", ",!>", - ",!?<=", ",>", ",?>", ",!<=", ",!?<", ",>=", ",?>=", ",!<", - ",!?=", ",<>", ",!=", ",!=t", ",!?", ",<=>", ",true?", ",true" -}; -static const char *const signed_unsigned_names[] = {",u", ",s"}; -static const char *const mix_half_names[] = {",l", ",r"}; -static const char *const saturation_names[] = {",us", ",ss", 0, ""}; -static const char *const read_write_names[] = {",r", ",w"}; -static const char *const add_compl_names[] = { 0, "", ",l", ",tsv" }; - -/* For a bunch of different instructions form an index into a - completer name table. */ -#define GET_COMPL(insn) (GET_FIELD (insn, 26, 26) | \ - GET_FIELD (insn, 18, 18) << 1) - -#define GET_COND(insn) (GET_FIELD ((insn), 16, 18) + \ - (GET_FIELD ((insn), 19, 19) ? 8 : 0)) - -/* Utility function to print registers. Put these first, so gcc's function - inlining can do its stuff. */ - -#define fputs_filtered(STR,F) (*info->fprintf_func) (info->stream, "%s", STR) - -static void -fput_reg (unsigned reg, disassemble_info *info) -{ - (*info->fprintf_func) (info->stream, "%s", reg ? reg_names[reg] : "r0"); -} - -static void -fput_fp_reg (unsigned reg, disassemble_info *info) -{ - (*info->fprintf_func) (info->stream, "%s", reg ? fp_reg_names[reg] : "fr0"); -} - -static void -fput_fp_reg_r (unsigned reg, disassemble_info *info) -{ - /* Special case floating point exception registers. */ - if (reg < 4) - (*info->fprintf_func) (info->stream, "fpe%d", reg * 2 + 1); - else - (*info->fprintf_func) (info->stream, "%sR", - reg ? fp_reg_names[reg] : "fr0"); -} - -static void -fput_creg (unsigned reg, disassemble_info *info) -{ - (*info->fprintf_func) (info->stream, "%s", control_reg[reg]); -} - -/* Print constants with sign. */ - -static void -fput_const (unsigned num, disassemble_info *info) -{ - if ((int) num < 0) - (*info->fprintf_func) (info->stream, "-%x", - (int) num); - else - (*info->fprintf_func) (info->stream, "%x", num); -} - -/* Routines to extract various sized constants out of hppa - instructions. */ - -/* Extract a 3-bit space register number from a be, ble, mtsp or mfsp. */ -static int -extract_3 (unsigned word) -{ - return GET_FIELD (word, 18, 18) << 2 | GET_FIELD (word, 16, 17); -} - -static int -extract_5_load (unsigned word) -{ - return low_sign_extend (word >> 16 & MASK_5, 5); -} - -/* Extract the immediate field from a st{bhw}s instruction. */ - -static int -extract_5_store (unsigned word) -{ - return low_sign_extend (word & MASK_5, 5); -} - -/* Extract the immediate field from a break instruction. */ - -static unsigned -extract_5r_store (unsigned word) -{ - return (word & MASK_5); -} - -/* Extract the immediate field from a {sr}sm instruction. */ - -static unsigned -extract_5R_store (unsigned word) -{ - return (word >> 16 & MASK_5); -} - -/* Extract the 10 bit immediate field from a {sr}sm instruction. */ - -static unsigned -extract_10U_store (unsigned word) -{ - return (word >> 16 & MASK_10); -} - -/* Extract the immediate field from a bb instruction. */ - -static unsigned -extract_5Q_store (unsigned word) -{ - return (word >> 21 & MASK_5); -} - -/* Extract an 11 bit immediate field. */ - -static int -extract_11 (unsigned word) -{ - return low_sign_extend (word & MASK_11, 11); -} - -/* Extract a 14 bit immediate field. */ - -static int -extract_14 (unsigned word) -{ - return low_sign_extend (word & MASK_14, 14); -} - -/* Extract a 16 bit immediate field (PA2.0 wide only). */ - -static int -extract_16 (unsigned word) -{ - int m15, m0, m1; - - m0 = GET_BIT (word, 16); - m1 = GET_BIT (word, 17); - m15 = GET_BIT (word, 31); - word = (word >> 1) & 0x1fff; - word = word | (m15 << 15) | ((m15 ^ m0) << 14) | ((m15 ^ m1) << 13); - return sign_extend (word, 16); -} - -/* Extract a 21 bit constant. */ - -static int -extract_21 (unsigned word) -{ - int val; - - word &= MASK_21; - word <<= 11; - val = GET_FIELD (word, 20, 20); - val <<= 11; - val |= GET_FIELD (word, 9, 19); - val <<= 2; - val |= GET_FIELD (word, 5, 6); - val <<= 5; - val |= GET_FIELD (word, 0, 4); - val <<= 2; - val |= GET_FIELD (word, 7, 8); - return sign_extend (val, 21) << 11; -} - -/* Extract a 12 bit constant from branch instructions. */ - -static int -extract_12 (unsigned word) -{ - return sign_extend (GET_FIELD (word, 19, 28) - | GET_FIELD (word, 29, 29) << 10 - | (word & 0x1) << 11, 12) << 2; -} - -/* Extract a 17 bit constant from branch instructions, returning the - 19 bit signed value. */ - -static int -extract_17 (unsigned word) -{ - return sign_extend (GET_FIELD (word, 19, 28) - | GET_FIELD (word, 29, 29) << 10 - | GET_FIELD (word, 11, 15) << 11 - | (word & 0x1) << 16, 17) << 2; -} - -static int -extract_22 (unsigned word) -{ - return sign_extend (GET_FIELD (word, 19, 28) - | GET_FIELD (word, 29, 29) << 10 - | GET_FIELD (word, 11, 15) << 11 - | GET_FIELD (word, 6, 10) << 16 - | (word & 0x1) << 21, 22) << 2; -} - -/* Print one instruction. */ - -int -print_insn_hppa (bfd_vma memaddr, disassemble_info *info) -{ - bfd_byte buffer[4]; - unsigned int insn, i; - - { - int status = - (*info->read_memory_func) (memaddr, buffer, sizeof (buffer), info); - if (status != 0) - { - (*info->memory_error_func) (status, memaddr, info); - return -1; - } - } - - insn = bfd_getb32 (buffer); - - for (i = 0; i < NUMOPCODES; ++i) - { - const struct pa_opcode *opcode = &pa_opcodes[i]; - - if ((insn & opcode->mask) == opcode->match) - { - const char *s; -#ifndef BFD64 - if (opcode->arch == pa20w) - continue; -#endif - (*info->fprintf_func) (info->stream, "%s", opcode->name); - - if (!strchr ("cfCY?-+nHNZFIuv{", opcode->args[0])) - (*info->fprintf_func) (info->stream, " "); - for (s = opcode->args; *s != '\0'; ++s) - { - switch (*s) - { - case 'x': - fput_reg (GET_FIELD (insn, 11, 15), info); - break; - case 'a': - case 'b': - fput_reg (GET_FIELD (insn, 6, 10), info); - break; - case '^': - fput_creg (GET_FIELD (insn, 6, 10), info); - break; - case 't': - fput_reg (GET_FIELD (insn, 27, 31), info); - break; - - /* Handle floating point registers. */ - case 'f': - switch (*++s) - { - case 't': - fput_fp_reg (GET_FIELD (insn, 27, 31), info); - break; - case 'T': - if (GET_FIELD (insn, 25, 25)) - fput_fp_reg_r (GET_FIELD (insn, 27, 31), info); - else - fput_fp_reg (GET_FIELD (insn, 27, 31), info); - break; - case 'a': - if (GET_FIELD (insn, 25, 25)) - fput_fp_reg_r (GET_FIELD (insn, 6, 10), info); - else - fput_fp_reg (GET_FIELD (insn, 6, 10), info); - break; - - /* 'fA' will not generate a space before the regsiter - name. Normally that is fine. Except that it - causes problems with xmpyu which has no FP format - completer. */ - case 'X': - fputs_filtered (" ", info); - /* FALLTHRU */ - - case 'A': - if (GET_FIELD (insn, 24, 24)) - fput_fp_reg_r (GET_FIELD (insn, 6, 10), info); - else - fput_fp_reg (GET_FIELD (insn, 6, 10), info); - break; - case 'b': - if (GET_FIELD (insn, 25, 25)) - fput_fp_reg_r (GET_FIELD (insn, 11, 15), info); - else - fput_fp_reg (GET_FIELD (insn, 11, 15), info); - break; - case 'B': - if (GET_FIELD (insn, 19, 19)) - fput_fp_reg_r (GET_FIELD (insn, 11, 15), info); - else - fput_fp_reg (GET_FIELD (insn, 11, 15), info); - break; - case 'C': - { - int reg = GET_FIELD (insn, 21, 22); - reg |= GET_FIELD (insn, 16, 18) << 2; - if (GET_FIELD (insn, 23, 23) != 0) - fput_fp_reg_r (reg, info); - else - fput_fp_reg (reg, info); - break; - } - case 'i': - { - int reg = GET_FIELD (insn, 6, 10); - - reg |= (GET_FIELD (insn, 26, 26) << 4); - fput_fp_reg (reg, info); - break; - } - case 'j': - { - int reg = GET_FIELD (insn, 11, 15); - - reg |= (GET_FIELD (insn, 26, 26) << 4); - fput_fp_reg (reg, info); - break; - } - case 'k': - { - int reg = GET_FIELD (insn, 27, 31); - - reg |= (GET_FIELD (insn, 26, 26) << 4); - fput_fp_reg (reg, info); - break; - } - case 'l': - { - int reg = GET_FIELD (insn, 21, 25); - - reg |= (GET_FIELD (insn, 26, 26) << 4); - fput_fp_reg (reg, info); - break; - } - case 'm': - { - int reg = GET_FIELD (insn, 16, 20); - - reg |= (GET_FIELD (insn, 26, 26) << 4); - fput_fp_reg (reg, info); - break; - } - - /* 'fe' will not generate a space before the register - name. Normally that is fine. Except that it - causes problems with fstw fe,y(b) which has no FP - format completer. */ - case 'E': - fputs_filtered (" ", info); - /* FALLTHRU */ - - case 'e': - if (GET_FIELD (insn, 30, 30)) - fput_fp_reg_r (GET_FIELD (insn, 11, 15), info); - else - fput_fp_reg (GET_FIELD (insn, 11, 15), info); - break; - case 'x': - fput_fp_reg (GET_FIELD (insn, 11, 15), info); - break; - } - break; - - case '5': - fput_const (extract_5_load (insn), info); - break; - case 's': - { - int space = GET_FIELD (insn, 16, 17); - /* Zero means implicit addressing, not use of sr0. */ - if (space != 0) - (*info->fprintf_func) (info->stream, "sr%d", space); - } - break; - - case 'S': - (*info->fprintf_func) (info->stream, "sr%d", - extract_3 (insn)); - break; - - /* Handle completers. */ - case 'c': - switch (*++s) - { - case 'x': - (*info->fprintf_func) - (info->stream, "%s", - index_compl_names[GET_COMPL (insn)]); - break; - case 'X': - (*info->fprintf_func) - (info->stream, "%s ", - index_compl_names[GET_COMPL (insn)]); - break; - case 'm': - (*info->fprintf_func) - (info->stream, "%s", - short_ldst_compl_names[GET_COMPL (insn)]); - break; - case 'M': - (*info->fprintf_func) - (info->stream, "%s ", - short_ldst_compl_names[GET_COMPL (insn)]); - break; - case 'A': - (*info->fprintf_func) - (info->stream, "%s ", - short_bytes_compl_names[GET_COMPL (insn)]); - break; - case 's': - (*info->fprintf_func) - (info->stream, "%s", - short_bytes_compl_names[GET_COMPL (insn)]); - break; - case 'c': - case 'C': - switch (GET_FIELD (insn, 20, 21)) - { - case 1: - (*info->fprintf_func) (info->stream, ",bc "); - break; - case 2: - (*info->fprintf_func) (info->stream, ",sl "); - break; - default: - (*info->fprintf_func) (info->stream, " "); - } - break; - case 'd': - switch (GET_FIELD (insn, 20, 21)) - { - case 1: - (*info->fprintf_func) (info->stream, ",co "); - break; - default: - (*info->fprintf_func) (info->stream, " "); - } - break; - case 'o': - (*info->fprintf_func) (info->stream, ",o"); - break; - case 'g': - (*info->fprintf_func) (info->stream, ",gate"); - break; - case 'p': - (*info->fprintf_func) (info->stream, ",l,push"); - break; - case 'P': - (*info->fprintf_func) (info->stream, ",pop"); - break; - case 'l': - case 'L': - (*info->fprintf_func) (info->stream, ",l"); - break; - case 'w': - (*info->fprintf_func) - (info->stream, "%s ", - read_write_names[GET_FIELD (insn, 25, 25)]); - break; - case 'W': - (*info->fprintf_func) (info->stream, ",w "); - break; - case 'r': - if (GET_FIELD (insn, 23, 26) == 5) - (*info->fprintf_func) (info->stream, ",r"); - break; - case 'Z': - if (GET_FIELD (insn, 26, 26)) - (*info->fprintf_func) (info->stream, ",m "); - else - (*info->fprintf_func) (info->stream, " "); - break; - case 'i': - if (GET_FIELD (insn, 25, 25)) - (*info->fprintf_func) (info->stream, ",i"); - break; - case 'z': - if (!GET_FIELD (insn, 21, 21)) - (*info->fprintf_func) (info->stream, ",z"); - break; - case 'a': - (*info->fprintf_func) - (info->stream, "%s", - add_compl_names[GET_FIELD (insn, 20, 21)]); - break; - case 'Y': - (*info->fprintf_func) - (info->stream, ",dc%s", - add_compl_names[GET_FIELD (insn, 20, 21)]); - break; - case 'y': - (*info->fprintf_func) - (info->stream, ",c%s", - add_compl_names[GET_FIELD (insn, 20, 21)]); - break; - case 'v': - if (GET_FIELD (insn, 20, 20)) - (*info->fprintf_func) (info->stream, ",tsv"); - break; - case 't': - (*info->fprintf_func) (info->stream, ",tc"); - if (GET_FIELD (insn, 20, 20)) - (*info->fprintf_func) (info->stream, ",tsv"); - break; - case 'B': - (*info->fprintf_func) (info->stream, ",db"); - if (GET_FIELD (insn, 20, 20)) - (*info->fprintf_func) (info->stream, ",tsv"); - break; - case 'b': - (*info->fprintf_func) (info->stream, ",b"); - if (GET_FIELD (insn, 20, 20)) - (*info->fprintf_func) (info->stream, ",tsv"); - break; - case 'T': - if (GET_FIELD (insn, 25, 25)) - (*info->fprintf_func) (info->stream, ",tc"); - break; - case 'S': - /* EXTRD/W has a following condition. */ - if (*(s + 1) == '?') - (*info->fprintf_func) - (info->stream, "%s", - signed_unsigned_names[GET_FIELD (insn, 21, 21)]); - else - (*info->fprintf_func) - (info->stream, "%s ", - signed_unsigned_names[GET_FIELD (insn, 21, 21)]); - break; - case 'h': - (*info->fprintf_func) - (info->stream, "%s", - mix_half_names[GET_FIELD (insn, 17, 17)]); - break; - case 'H': - (*info->fprintf_func) - (info->stream, "%s ", - saturation_names[GET_FIELD (insn, 24, 25)]); - break; - case '*': - (*info->fprintf_func) - (info->stream, ",%d%d%d%d ", - GET_FIELD (insn, 17, 18), GET_FIELD (insn, 20, 21), - GET_FIELD (insn, 22, 23), GET_FIELD (insn, 24, 25)); - break; - - case 'q': - { - int m, a; - - m = GET_FIELD (insn, 28, 28); - a = GET_FIELD (insn, 29, 29); - - if (m && !a) - fputs_filtered (",ma ", info); - else if (m && a) - fputs_filtered (",mb ", info); - else - fputs_filtered (" ", info); - break; - } - - case 'J': - { - int opc = GET_FIELD (insn, 0, 5); - - if (opc == 0x16 || opc == 0x1e) - { - if (GET_FIELD (insn, 29, 29) == 0) - fputs_filtered (",ma ", info); - else - fputs_filtered (",mb ", info); - } - else - fputs_filtered (" ", info); - break; - } - - case 'e': - { - int opc = GET_FIELD (insn, 0, 5); - - if (opc == 0x13 || opc == 0x1b) - { - if (GET_FIELD (insn, 18, 18) == 1) - fputs_filtered (",mb ", info); - else - fputs_filtered (",ma ", info); - } - else if (opc == 0x17 || opc == 0x1f) - { - if (GET_FIELD (insn, 31, 31) == 1) - fputs_filtered (",ma ", info); - else - fputs_filtered (",mb ", info); - } - else - fputs_filtered (" ", info); - - break; - } - } - break; - - /* Handle conditions. */ - case '?': - { - s++; - switch (*s) - { - case 'f': - (*info->fprintf_func) - (info->stream, "%s ", - float_comp_names[GET_FIELD (insn, 27, 31)]); - break; - - /* These four conditions are for the set of instructions - which distinguish true/false conditions by opcode - rather than by the 'f' bit (sigh): comb, comib, - addb, addib. */ - case 't': - fputs_filtered - (compare_cond_names[GET_FIELD (insn, 16, 18)], info); - break; - case 'n': - fputs_filtered - (compare_cond_names[GET_FIELD (insn, 16, 18) - + GET_FIELD (insn, 4, 4) * 8], - info); - break; - case 'N': - fputs_filtered - (compare_cond_64_names[GET_FIELD (insn, 16, 18) - + GET_FIELD (insn, 2, 2) * 8], - info); - break; - case 'Q': - fputs_filtered - (cmpib_cond_64_names[GET_FIELD (insn, 16, 18)], - info); - break; - case '@': - fputs_filtered - (add_cond_names[GET_FIELD (insn, 16, 18) - + GET_FIELD (insn, 4, 4) * 8], - info); - break; - case 's': - (*info->fprintf_func) - (info->stream, "%s ", - compare_cond_names[GET_COND (insn)]); - break; - case 'S': - (*info->fprintf_func) - (info->stream, "%s ", - compare_cond_64_names[GET_COND (insn)]); - break; - case 'a': - (*info->fprintf_func) - (info->stream, "%s ", - add_cond_names[GET_COND (insn)]); - break; - case 'A': - (*info->fprintf_func) - (info->stream, "%s ", - add_cond_64_names[GET_COND (insn)]); - break; - case 'd': - (*info->fprintf_func) - (info->stream, "%s", - add_cond_names[GET_FIELD (insn, 16, 18)]); - break; - - case 'W': - (*info->fprintf_func) - (info->stream, "%s", - wide_add_cond_names[GET_FIELD (insn, 16, 18) + - GET_FIELD (insn, 4, 4) * 8]); - break; - - case 'l': - (*info->fprintf_func) - (info->stream, "%s ", - logical_cond_names[GET_COND (insn)]); - break; - case 'L': - (*info->fprintf_func) - (info->stream, "%s ", - logical_cond_64_names[GET_COND (insn)]); - break; - case 'u': - (*info->fprintf_func) - (info->stream, "%s ", - unit_cond_names[GET_COND (insn)]); - break; - case 'U': - (*info->fprintf_func) - (info->stream, "%s ", - unit_cond_64_names[GET_COND (insn)]); - break; - case 'y': - case 'x': - case 'b': - (*info->fprintf_func) - (info->stream, "%s", - shift_cond_names[GET_FIELD (insn, 16, 18)]); - - /* If the next character in args is 'n', it will handle - putting out the space. */ - if (s[1] != 'n') - (*info->fprintf_func) (info->stream, " "); - break; - case 'X': - (*info->fprintf_func) - (info->stream, "%s ", - shift_cond_64_names[GET_FIELD (insn, 16, 18)]); - break; - case 'B': - (*info->fprintf_func) - (info->stream, "%s", - bb_cond_64_names[GET_FIELD (insn, 16, 16)]); - - /* If the next character in args is 'n', it will handle - putting out the space. */ - if (s[1] != 'n') - (*info->fprintf_func) (info->stream, " "); - break; - } - break; - } - - case 'V': - fput_const (extract_5_store (insn), info); - break; - case 'r': - fput_const (extract_5r_store (insn), info); - break; - case 'R': - fput_const (extract_5R_store (insn), info); - break; - case 'U': - fput_const (extract_10U_store (insn), info); - break; - case 'B': - case 'Q': - fput_const (extract_5Q_store (insn), info); - break; - case 'i': - fput_const (extract_11 (insn), info); - break; - case 'j': - fput_const (extract_14 (insn), info); - break; - case 'k': - fputs_filtered ("L%", info); - fput_const (extract_21 (insn), info); - break; - case '<': - case 'l': - /* 16-bit long disp., PA2.0 wide only. */ - fput_const (extract_16 (insn), info); - break; - case 'n': - if (insn & 0x2) - (*info->fprintf_func) (info->stream, ",n "); - else - (*info->fprintf_func) (info->stream, " "); - break; - case 'N': - if ((insn & 0x20) && s[1]) - (*info->fprintf_func) (info->stream, ",n "); - else if (insn & 0x20) - (*info->fprintf_func) (info->stream, ",n"); - else if (s[1]) - (*info->fprintf_func) (info->stream, " "); - break; - case 'w': - (*info->print_address_func) - (memaddr + 8 + extract_12 (insn), info); - break; - case 'W': - /* 17 bit PC-relative branch. */ - (*info->print_address_func) - ((memaddr + 8 + extract_17 (insn)), info); - break; - case 'z': - /* 17 bit displacement. This is an offset from a register - so it gets disasssembled as just a number, not any sort - of address. */ - fput_const (extract_17 (insn), info); - break; - - case 'Z': - /* addil %r1 implicit output. */ - fputs_filtered ("r1", info); - break; - - case 'Y': - /* be,l %sr0,%r31 implicit output. */ - fputs_filtered ("sr0,r31", info); - break; - - case '@': - (*info->fprintf_func) (info->stream, "0"); - break; - - case '.': - (*info->fprintf_func) (info->stream, "%d", - GET_FIELD (insn, 24, 25)); - break; - case '*': - (*info->fprintf_func) (info->stream, "%d", - GET_FIELD (insn, 22, 25)); - break; - case '!': - fputs_filtered ("sar", info); - break; - case 'p': - (*info->fprintf_func) (info->stream, "%d", - 31 - GET_FIELD (insn, 22, 26)); - break; - case '~': - { - int num; - num = GET_FIELD (insn, 20, 20) << 5; - num |= GET_FIELD (insn, 22, 26); - (*info->fprintf_func) (info->stream, "%d", 63 - num); - break; - } - case 'P': - (*info->fprintf_func) (info->stream, "%d", - GET_FIELD (insn, 22, 26)); - break; - case 'q': - { - int num; - num = GET_FIELD (insn, 20, 20) << 5; - num |= GET_FIELD (insn, 22, 26); - (*info->fprintf_func) (info->stream, "%d", num); - break; - } - case 'T': - (*info->fprintf_func) (info->stream, "%d", - 32 - GET_FIELD (insn, 27, 31)); - break; - case '%': - { - int num; - num = (GET_FIELD (insn, 23, 23) + 1) * 32; - num -= GET_FIELD (insn, 27, 31); - (*info->fprintf_func) (info->stream, "%d", num); - break; - } - case '|': - { - int num; - num = (GET_FIELD (insn, 19, 19) + 1) * 32; - num -= GET_FIELD (insn, 27, 31); - (*info->fprintf_func) (info->stream, "%d", num); - break; - } - case '$': - fput_const (GET_FIELD (insn, 20, 28), info); - break; - case 'A': - fput_const (GET_FIELD (insn, 6, 18), info); - break; - case 'D': - fput_const (GET_FIELD (insn, 6, 31), info); - break; - case 'v': - (*info->fprintf_func) (info->stream, ",%d", - GET_FIELD (insn, 23, 25)); - break; - case 'O': - fput_const ((GET_FIELD (insn, 6,20) << 5 | - GET_FIELD (insn, 27, 31)), info); - break; - case 'o': - fput_const (GET_FIELD (insn, 6, 20), info); - break; - case '2': - fput_const ((GET_FIELD (insn, 6, 22) << 5 | - GET_FIELD (insn, 27, 31)), info); - break; - case '1': - fput_const ((GET_FIELD (insn, 11, 20) << 5 | - GET_FIELD (insn, 27, 31)), info); - break; - case '0': - fput_const ((GET_FIELD (insn, 16, 20) << 5 | - GET_FIELD (insn, 27, 31)), info); - break; - case 'u': - (*info->fprintf_func) (info->stream, ",%d", - GET_FIELD (insn, 23, 25)); - break; - case 'F': - /* If no destination completer and not before a completer - for fcmp, need a space here. */ - if (s[1] == 'G' || s[1] == '?') - fputs_filtered - (float_format_names[GET_FIELD (insn, 19, 20)], info); - else - (*info->fprintf_func) - (info->stream, "%s ", - float_format_names[GET_FIELD (insn, 19, 20)]); - break; - case 'G': - (*info->fprintf_func) - (info->stream, "%s ", - float_format_names[GET_FIELD (insn, 17, 18)]); - break; - case 'H': - if (GET_FIELD (insn, 26, 26) == 1) - (*info->fprintf_func) (info->stream, "%s ", - float_format_names[0]); - else - (*info->fprintf_func) (info->stream, "%s ", - float_format_names[1]); - break; - case 'I': - /* If no destination completer and not before a completer - for fcmp, need a space here. */ - if (s[1] == '?') - fputs_filtered - (float_format_names[GET_FIELD (insn, 20, 20)], info); - else - (*info->fprintf_func) - (info->stream, "%s ", - float_format_names[GET_FIELD (insn, 20, 20)]); - break; - - case 'J': - fput_const (extract_14 (insn), info); - break; - - case '#': - { - int sign = GET_FIELD (insn, 31, 31); - int imm10 = GET_FIELD (insn, 18, 27); - int disp; - - if (sign) - disp = (-1 << 10) | imm10; - else - disp = imm10; - - disp <<= 3; - fput_const (disp, info); - break; - } - case 'K': - case 'd': - { - int sign = GET_FIELD (insn, 31, 31); - int imm11 = GET_FIELD (insn, 18, 28); - int disp; - - if (sign) - disp = (-1 << 11) | imm11; - else - disp = imm11; - - disp <<= 2; - fput_const (disp, info); - break; - } - - case '>': - case 'y': - { - /* 16-bit long disp., PA2.0 wide only. */ - int disp = extract_16 (insn); - disp &= ~3; - fput_const (disp, info); - break; - } - - case '&': - { - /* 16-bit long disp., PA2.0 wide only. */ - int disp = extract_16 (insn); - disp &= ~7; - fput_const (disp, info); - break; - } - - case '_': - break; /* Dealt with by '{' */ - - case '{': - { - int sub = GET_FIELD (insn, 14, 16); - int df = GET_FIELD (insn, 17, 18); - int sf = GET_FIELD (insn, 19, 20); - const char * const * source = float_format_names; - const char * const * dest = float_format_names; - const char *t = ""; - - if (sub == 4) - { - fputs_filtered (",UND ", info); - break; - } - if ((sub & 3) == 3) - t = ",t"; - if ((sub & 3) == 1) - source = sub & 4 ? fcnv_ufixed_names : fcnv_fixed_names; - if (sub & 2) - dest = sub & 4 ? fcnv_ufixed_names : fcnv_fixed_names; - - (*info->fprintf_func) (info->stream, "%s%s%s ", - t, source[sf], dest[df]); - break; - } - - case 'm': - { - int y = GET_FIELD (insn, 16, 18); - - if (y != 1) - fput_const ((y ^ 1) - 1, info); - } - break; - - case 'h': - { - int cbit; - - cbit = GET_FIELD (insn, 16, 18); - - if (cbit > 0) - (*info->fprintf_func) (info->stream, ",%d", cbit - 1); - break; - } - - case '=': - { - int cond = GET_FIELD (insn, 27, 31); - - switch (cond) - { - case 0: fputs_filtered (" ", info); break; - case 1: fputs_filtered ("acc ", info); break; - case 2: fputs_filtered ("rej ", info); break; - case 5: fputs_filtered ("acc8 ", info); break; - case 6: fputs_filtered ("rej8 ", info); break; - case 9: fputs_filtered ("acc6 ", info); break; - case 13: fputs_filtered ("acc4 ", info); break; - case 17: fputs_filtered ("acc2 ", info); break; - default: break; - } - break; - } - - case 'X': - (*info->print_address_func) - (memaddr + 8 + extract_22 (insn), info); - break; - case 'L': - fputs_filtered (",rp", info); - break; - default: - (*info->fprintf_func) (info->stream, "%c", *s); - break; - } - } - return sizeof (insn); - } - } - (*info->fprintf_func) (info->stream, "#%8x", insn); - return sizeof (insn); -} diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 783565463fe..c0c9b5887c0 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -2329,8 +2329,8 @@ struct target_flock { struct target_flock64 { short l_type; short l_whence; -#if defined(TARGET_PPC) || defined(TARGET_X86_64) || defined(TARGET_MIPS) \ - || defined(TARGET_SPARC) || defined(TARGET_HPPA) \ +#if defined(TARGET_PPC) || defined(TARGET_X86_64) \ + || defined(TARGET_MIPS) || defined(TARGET_SPARC) \ || defined(TARGET_MICROBLAZE) || defined(TARGET_TILEGX) int __pad; #endif diff --git a/qemu-tech.texi b/qemu-tech.texi index bdb2285f4e7..1b048cb337b 100644 --- a/qemu-tech.texi +++ b/qemu-tech.texi @@ -89,8 +89,7 @@ QEMU generic features: @item Working on x86, x86_64 and PowerPC32/64 hosts. Being tested on ARM, -HPPA, Sparc32 and Sparc64. Previous versions had some support for -Alpha and S390 hosts, but TCG (see below) doesn't support those yet. +S390x, Sparc32 and Sparc64. @item Self-modifying code support. diff --git a/tcg/tci/README b/tcg/tci/README index 3786b0915b5..386c3c75075 100644 --- a/tcg/tci/README +++ b/tcg/tci/README @@ -9,7 +9,7 @@ code fragments ("basic blocks") from target code (any of the targets supported by QEMU) to a code representation which can be run on a host. -QEMU can create native code for some hosts (arm, hppa, i386, ia64, ppc, ppc64, +QEMU can create native code for some hosts (arm, i386, ia64, ppc, ppc64, s390, sparc, x86_64). For others, unofficial host support was written. By adding a code generator for a virtual machine and using an From 347519eb9d68303a6c23a7663c0fa6c20a225191 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 13 Sep 2016 15:45:39 +0200 Subject: [PATCH 016/723] tcg: Remove duplicate header includes host-utils.h and timer.h are included twice in tcg.c. One time should be enough. Signed-off-by: Thomas Huth Signed-off-by: Michael Tokarev --- tcg/tcg.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/tcg/tcg.c b/tcg/tcg.c index 42417bdc925..c450c6273be 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -40,8 +40,6 @@ #define NO_CPU_IO_DEFS #include "cpu.h" -#include "qemu/host-utils.h" -#include "qemu/timer.h" #include "exec/cpu-common.h" #include "exec/exec-all.h" From 344aa283b89bec2af976107e85c11963a1ad93d4 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 11 Aug 2016 09:21:00 +0200 Subject: [PATCH 017/723] ui/console: Fix non-working backspace key in monitor of gtk UI In the QEMU monitor pane of the gtk user interface, the backspace key is not working at all. This happens because of a missing mapping of the key in the qcode_to_keysym[] table. Thus let's add an entry there to get the backspace key working again. Buglink: https://bugs.launchpad.net/qemu/+bug/1611979 Signed-off-by: Thomas Huth Reviewed-by: Gerd Hoffmann Signed-off-by: Michael Tokarev --- ui/console.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/console.c b/ui/console.c index c24bfe422db..3940762851a 100644 --- a/ui/console.c +++ b/ui/console.c @@ -1142,6 +1142,7 @@ static const int qcode_to_keysym[Q_KEY_CODE__MAX] = { [Q_KEY_CODE_PGUP] = QEMU_KEY_PAGEUP, [Q_KEY_CODE_PGDN] = QEMU_KEY_PAGEDOWN, [Q_KEY_CODE_DELETE] = QEMU_KEY_DELETE, + [Q_KEY_CODE_BACKSPACE] = QEMU_KEY_BACKSPACE, }; bool kbd_put_qcode_console(QemuConsole *s, int qcode) From 47b98d5944ec773b665ae6f001b3abab61025a79 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 9 Sep 2016 23:16:03 +0200 Subject: [PATCH 018/723] MAINTAINERS: Add include/hw/unicore32/ to UniCore32 section get_maintainer.pl now properly recognizes that the file in include/hw/unicore32/ belongs to UniCore32. Signed-off-by: Thomas Huth Acked-by: Guan Xuetao Signed-off-by: Michael Tokarev --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 4db611ffb0f..303a395d376 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -202,6 +202,7 @@ M: Guan Xuetao S: Maintained F: target-unicore32/ F: hw/unicore32/ +F: include/hw/unicore32/ X86 M: Paolo Bonzini From d46d14e63150120aecbd2ddf76af9b4a3eea8cc8 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 9 Sep 2016 23:17:09 +0200 Subject: [PATCH 019/723] MAINTAINERS: Add include/hw/tricore/ to TriCore section get_maintainer.pl now properly recognizes that the file in include/hw/tricore/ belongs to TriCore. Signed-off-by: Thomas Huth Reviewed-by: Bastian Koppelmann Signed-off-by: Michael Tokarev --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 303a395d376..0edd7b3fdb7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -226,6 +226,7 @@ M: Bastian Koppelmann S: Maintained F: target-tricore/ F: hw/tricore/ +F: include/hw/tricore/ Guest CPU Cores (KVM): ---------------------- From 8a90f9008ba8d45de617ee5979a81e6d1e5026a8 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 9 Sep 2016 23:18:21 +0200 Subject: [PATCH 020/723] MAINTAINERS: Add include/hw/sh4/ to SH4 section get_maintainer.pl now properly recognizes that the files in include/hw/sh4/ belong to SH4. Signed-off-by: Thomas Huth Signed-off-by: Michael Tokarev --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 0edd7b3fdb7..9b10356bf0c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -187,6 +187,7 @@ S: Odd Fixes F: target-sh4/ F: hw/sh4/ F: disas/sh4.c +F: include/hw/sh4/ SPARC M: Mark Cave-Ayland From 460423d3a4e87eb45c18b94f5ec577c19e6851bc Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 9 Sep 2016 23:15:04 +0200 Subject: [PATCH 021/723] MAINTAINERS: Add include/sysemu/cpus.h This header seems to belong to the guest CPU section since it contains prototypes for cpus.c. Signed-off-by: Thomas Huth Signed-off-by: Michael Tokarev --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 9b10356bf0c..0605406ed2d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -83,6 +83,7 @@ F: include/exec/cpu*.h F: include/exec/exec-all.h F: include/exec/helper*.h F: include/exec/tb-hash.h +F: include/sysemu/cpus.h FPU emulation M: Aurelien Jarno From f586d5fc60aac64ad7b83cab3c80303cfae9390d Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 5 Sep 2016 14:28:52 +0200 Subject: [PATCH 022/723] MAINTAINERS: Fix up F: entry bit rot include/hw/xilinx.h is gone since commit d5001cf, drop. include/hw/*/xlnx*.c is a typo, change .c to .h. include/hw/acpi/piix.h is a typo, change piix.h to piix4.h. hw/i386/*dsl and scripts/acpi*py are gone since since commit 9fc6502, drop. hw/virtio/dataplane/* are gone since commit fee089e, drop. ICC Bus is gone since commit dfeb867, drop. block/raw-aio.h was moved to include/block/raw-aio.h in commit 0187f5c, update. Tracked down with for i in `grep "^[FX]: " MAINTAINERS | sed "s/^.: //"` do if [ ! -e "$i" ]; then echo "$i"; fi done Reported-by: Thomas Huth Signed-off-by: Markus Armbruster Reviewed-by: Thomas Huth Acked-by: Stefan Hajnoczi Signed-off-by: Michael Tokarev --- MAINTAINERS | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 0605406ed2d..7d430261620 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -460,7 +460,6 @@ S: Maintained F: hw/*/xilinx_* F: hw/*/cadence_* F: hw/misc/zynq_slcr.c -F: include/hw/xilinx.h X: hw/ssi/xilinx_* Xilinx ZynqMP @@ -469,7 +468,7 @@ M: Edgar E. Iglesias L: qemu-arm@nongnu.org S: Maintained F: hw/*/xlnx*.c -F: include/hw/*/xlnx*.c +F: include/hw/*/xlnx*.h ARM ACPI Subsystem M: Shannon Zhao @@ -699,7 +698,7 @@ F: hw/i2c/smbus_ich9.c F: hw/acpi/piix4.c F: hw/acpi/ich9.c F: include/hw/acpi/ich9.h -F: include/hw/acpi/piix.h +F: include/hw/acpi/piix4.h F: hw/misc/sga.c PC Chipset @@ -805,10 +804,8 @@ F: hw/mem/* F: hw/acpi/* F: hw/smbios/* F: hw/i386/acpi-build.[hc] -F: hw/i386/*dsl F: hw/arm/virt-acpi-build.c F: include/hw/arm/virt-acpi-build.h -F: scripts/acpi*py ppc4xx M: Alexander Graf @@ -910,7 +907,6 @@ L: qemu-block@nongnu.org S: Supported F: hw/block/virtio-blk.c F: hw/block/dataplane/* -F: hw/virtio/dataplane/* T: git git://github.com/stefanha/qemu.git block virtio-ccw @@ -1072,12 +1068,6 @@ S: Supported F: qom/cpu.c F: include/qom/cpu.h -ICC Bus -M: Igor Mammedov -S: Supported -F: include/hw/cpu/icc_bus.h -F: hw/cpu/icc_bus.c - Device Tree M: Peter Crosthwaite M: Alexander Graf @@ -1593,7 +1583,7 @@ M: Kevin Wolf L: qemu-block@nongnu.org S: Supported F: block/linux-aio.c -F: block/raw-aio.h +F: include/block/raw-aio.h F: block/raw-posix.c F: block/raw-win32.c F: block/raw_bsd.c From ace18d198af4eaaf10ea358f1444c75996e357b7 Mon Sep 17 00:00:00 2001 From: Reda Sallahi Date: Wed, 31 Aug 2016 18:31:04 +0200 Subject: [PATCH 023/723] sh4: fix broken link to documentation The page that was previously linked in the source code and the README file is no longer available so it now returns a 404 error message. This puts a previous snapshot from archive.org instead. Signed-off-by: Reda Sallahi Acked-by: Aurelien Jarno Signed-off-by: Michael Tokarev --- hw/sh4/shix.c | 2 +- target-sh4/README.sh4 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/sh4/shix.c b/hw/sh4/shix.c index ccc9e75894f..14d4007c1c4 100644 --- a/hw/sh4/shix.c +++ b/hw/sh4/shix.c @@ -23,7 +23,7 @@ */ /* Shix 2.0 board by Alexis Polti, described at - http://perso.enst.fr/~polti/realisations/shix20/ + https://web.archive.org/web/20070917001736/perso.enst.fr/~polti/realisations/shix20 More information in target-sh4/README.sh4 */ diff --git a/target-sh4/README.sh4 b/target-sh4/README.sh4 index e578830f79d..ece046442ab 100644 --- a/target-sh4/README.sh4 +++ b/target-sh4/README.sh4 @@ -25,7 +25,7 @@ Goals The primary model being worked on is the soft MMU target to be able to emulate the Shix 2.0 board by Alexis Polti, described at -http://perso.enst.fr/~polti/realisations/shix20/ +https://web.archive.org/web/20070917001736/http://perso.enst.fr/~polti/realisations/shix20/ Ultimately, qemu will be coupled with a system C or a verilog simulator to simulate the whole board functionalities. From d7d26226b839a2ad5fc356ce8f8d4db901cb29de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefano=20Dong=20=28=E8=91=A3=E5=85=B4=E6=B0=B4=29?= Date: Wed, 10 Aug 2016 06:38:34 +0800 Subject: [PATCH 024/723] ivshmem: Delete duplicate debug message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Duplicated in commit ca0b756. Delete it. Signed-off-by: Stefano Dong (董兴水) Reviewed-by: Marc-André Lureau Reviewed-by: Markus Armbruster Signed-off-by: Michael Tokarev --- hw/misc/ivshmem.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c index 40a2ebca20a..f803dfd5b33 100644 --- a/hw/misc/ivshmem.c +++ b/hw/misc/ivshmem.c @@ -628,7 +628,6 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size) s->msg_buffered_bytes = 0; fd = qemu_chr_fe_get_msgfd(s->server_chr); - IVSHMEM_DPRINTF("posn is %" PRId64 ", fd is %d\n", msg, fd); process_msg(s, msg, fd, &err); if (err) { From d4b84d564ee3eb7a58e4585d671fb3c220b6c3b9 Mon Sep 17 00:00:00 2001 From: Ladi Prosek Date: Mon, 13 Jun 2016 16:20:48 +0200 Subject: [PATCH 025/723] Remove unused function declarations Unused function declarations were found using a simple gcc plugin and manually verified by grepping the sources. Signed-off-by: Ladi Prosek Signed-off-by: Michael Tokarev --- block/qcow2.h | 1 - disas/sh4.c | 6 ------ hw/ppc/ppc405.h | 6 ------ hw/s390x/virtio-ccw.h | 1 - include/block/block.h | 6 ------ include/block/block_int.h | 9 --------- include/hw/arm/pxa.h | 1 - include/hw/bt.h | 2 -- include/hw/i386/pc.h | 2 -- include/hw/pci-host/spapr.h | 2 -- include/hw/pci/pci_bridge.h | 1 - include/hw/pci/pcie_port.h | 1 - include/hw/ppc/ppc4xx.h | 6 ------ include/hw/ppc/spapr.h | 3 --- include/hw/ppc/spapr_vio.h | 4 ---- include/hw/scsi/scsi.h | 1 - include/hw/virtio/virtio-bus.h | 3 --- include/migration/migration.h | 2 -- include/net/net.h | 2 -- include/qemu/bitmap.h | 4 ---- include/qemu/uri.h | 2 -- include/sysemu/kvm.h | 2 -- include/ui/console.h | 2 -- include/ui/input.h | 2 -- include/ui/spice-display.h | 2 -- target-alpha/cpu.h | 1 - target-m68k/cpu.h | 1 - target-ppc/cpu.h | 2 -- target-ppc/mmu-hash64.h | 1 - target-s390x/cpu.h | 2 -- tcg/tcg.h | 2 -- 31 files changed, 82 deletions(-) diff --git a/block/qcow2.h b/block/qcow2.h index b36a7bf8ad9..9ce5a37d3a1 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -530,7 +530,6 @@ int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order, int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size, bool exact_size); int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index); -void qcow2_l2_cache_reset(BlockDriverState *bs); int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset); int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num, uint8_t *out_buf, const uint8_t *in_buf, diff --git a/disas/sh4.c b/disas/sh4.c index 8b0415dfe9b..6b66176bedc 100644 --- a/disas/sh4.c +++ b/disas/sh4.c @@ -264,12 +264,6 @@ sh_dsp_reg_nums; be some confusion between DSP and FPU etc. */ #define SH_ARCH_UNKNOWN_ARCH 0xffffffff -/* These are defined in bfd/cpu-sh.c . */ -unsigned int sh_get_arch_from_bfd_mach (unsigned long mach); -unsigned int sh_get_arch_up_from_bfd_mach (unsigned long mach); -unsigned long sh_get_bfd_mach_from_arch_set (unsigned int arch_set); -/* bfd_boolean sh_merge_bfd_arch (bfd *ibfd, bfd *obfd); */ - /* Below are the 'architecture sets'. They describe the following inheritance graph: diff --git a/hw/ppc/ppc405.h b/hw/ppc/ppc405.h index c67febca2f0..a9ffc87f19f 100644 --- a/hw/ppc/ppc405.h +++ b/hw/ppc/ppc405.h @@ -71,11 +71,5 @@ CPUPPCState *ppc405ep_init(MemoryRegion *address_space_mem, hwaddr ram_sizes[2], uint32_t sysclk, qemu_irq **picp, int do_init); -/* IBM STBxxx microcontrollers */ -CPUPPCState *ppc_stb025_init (MemoryRegion ram_memories[2], - hwaddr ram_bases[2], - hwaddr ram_sizes[2], - uint32_t sysclk, qemu_irq **picp, - ram_addr_t *offsetp); #endif /* PPC405_H */ diff --git a/hw/s390x/virtio-ccw.h b/hw/s390x/virtio-ccw.h index 904e3575812..b58ab21d4ca 100644 --- a/hw/s390x/virtio-ccw.h +++ b/hw/s390x/virtio-ccw.h @@ -183,7 +183,6 @@ typedef struct VirtIORNGCcw { VirtIORNG vdev; } VirtIORNGCcw; -void virtio_ccw_device_update_status(SubchDev *sch); VirtIODevice *virtio_ccw_get_vdev(SubchDev *sch); #ifdef CONFIG_VIRTFS diff --git a/include/block/block.h b/include/block/block.h index 7edce5c35fe..ffecebfb3a7 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -185,11 +185,6 @@ typedef enum BlockOpType { BLOCK_OP_TYPE_MAX, } BlockOpType; -void bdrv_info_print(Monitor *mon, const QObject *data); -void bdrv_info(Monitor *mon, QObject **ret_data); -void bdrv_stats_print(Monitor *mon, const QObject *data); -void bdrv_info_stats(Monitor *mon, QObject **ret_data); - /* disk I/O throttling */ void bdrv_init(void); void bdrv_init_with_whitelist(void); @@ -393,7 +388,6 @@ bool bdrv_is_encrypted(BlockDriverState *bs); bool bdrv_key_required(BlockDriverState *bs); int bdrv_set_key(BlockDriverState *bs, const char *key); void bdrv_add_key(BlockDriverState *bs, const char *key, Error **errp); -int bdrv_query_missing_keys(void); void bdrv_iterate_format(void (*it)(void *opaque, const char *name), void *opaque); const char *bdrv_get_node_name(const BlockDriverState *bs); diff --git a/include/block/block_int.h b/include/block/block_int.h index 713cea60711..ef3c047cb37 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -562,15 +562,6 @@ extern BlockDriver bdrv_file; extern BlockDriver bdrv_raw; extern BlockDriver bdrv_qcow2; -/** - * bdrv_setup_io_funcs: - * - * Prepare a #BlockDriver for I/O request processing by populating - * unimplemented coroutine and AIO interfaces with generic wrapper functions - * that fall back to implemented interfaces. - */ -void bdrv_setup_io_funcs(BlockDriver *bdrv); - int coroutine_fn bdrv_co_preadv(BdrvChild *child, int64_t offset, unsigned int bytes, QEMUIOVector *qiov, BdrvRequestFlags flags); diff --git a/include/hw/arm/pxa.h b/include/hw/arm/pxa.h index dd1a48b0c13..191e0681841 100644 --- a/include/hw/arm/pxa.h +++ b/include/hw/arm/pxa.h @@ -83,7 +83,6 @@ typedef struct PXA2xxLCDState PXA2xxLCDState; PXA2xxLCDState *pxa2xx_lcdc_init(MemoryRegion *sysmem, hwaddr base, qemu_irq irq); void pxa2xx_lcd_vsync_notifier(PXA2xxLCDState *s, qemu_irq handler); -void pxa2xx_lcdc_oritentation(void *opaque, int angle); /* pxa2xx_mmci.c */ typedef struct PXA2xxMMCIState PXA2xxMMCIState; diff --git a/include/hw/bt.h b/include/hw/bt.h index 185e79df2bc..963f3301385 100644 --- a/include/hw/bt.h +++ b/include/hw/bt.h @@ -174,8 +174,6 @@ enum bt_l2cap_psm_predef { void bt_l2cap_sdp_init(struct bt_l2cap_device_s *dev); /* bt-hid.c */ -struct bt_device_s *bt_mouse_init(struct bt_scatternet_s *net); -struct bt_device_s *bt_tablet_init(struct bt_scatternet_s *net); struct bt_device_s *bt_keyboard_init(struct bt_scatternet_s *net); /* Link Management Protocol layer defines */ diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index ebba1510975..ab8e3195052 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -216,7 +216,6 @@ void vmmouse_set_data(const uint32_t *data); /* pckbd.c */ #define I8042_A20_LINE "a20" -void i8042_init(qemu_irq kbd_irq, qemu_irq mouse_irq, uint32_t io_base); void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq, MemoryRegion *region, ram_addr_t size, hwaddr mask); @@ -284,7 +283,6 @@ int cmos_get_fd_drive_type(FloppyDriveType fd0); I2CBus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base, qemu_irq sci_irq, qemu_irq smi_irq, int smm_enabled, DeviceState **piix4_pm); -void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr); /* hpet.c */ extern int no_hpet; diff --git a/include/hw/pci-host/spapr.h b/include/hw/pci-host/spapr.h index 5adc603d47a..1a2b11b322d 100644 --- a/include/hw/pci-host/spapr.h +++ b/include/hw/pci-host/spapr.h @@ -106,8 +106,6 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb, uint32_t xics_phandle, void *fdt); -void spapr_pci_msi_init(sPAPRMachineState *spapr, hwaddr addr); - void spapr_pci_rtas_init(void); sPAPRPHBState *spapr_pci_find_phb(sPAPRMachineState *spapr, uint64_t buid); diff --git a/include/hw/pci/pci_bridge.h b/include/hw/pci/pci_bridge.h index 847fd7db33e..d5891cd30ed 100644 --- a/include/hw/pci/pci_bridge.h +++ b/include/hw/pci/pci_bridge.h @@ -45,7 +45,6 @@ void pci_bridge_update_mappings(PCIBridge *br); void pci_bridge_write_config(PCIDevice *d, uint32_t address, uint32_t val, int len); void pci_bridge_disable_base_limit(PCIDevice *dev); -void pci_bridge_reset_reg(PCIDevice *dev); void pci_bridge_reset(DeviceState *qdev); void pci_bridge_initfn(PCIDevice *pci_dev, const char *typename); diff --git a/include/hw/pci/pcie_port.h b/include/hw/pci/pcie_port.h index e167bf7520b..f7b64db00cf 100644 --- a/include/hw/pci/pcie_port.h +++ b/include/hw/pci/pcie_port.h @@ -53,7 +53,6 @@ struct PCIESlot { }; void pcie_chassis_create(uint8_t chassis_number); -void pcie_main_chassis_create(void); PCIESlot *pcie_chassis_find_slot(uint8_t chassis, uint16_t slot); int pcie_chassis_add_slot(struct PCIESlot *slot); void pcie_chassis_del_slot(PCIESlot *s); diff --git a/include/hw/ppc/ppc4xx.h b/include/hw/ppc/ppc4xx.h index 3b01ae83141..66e57a5194b 100644 --- a/include/hw/ppc/ppc4xx.h +++ b/include/hw/ppc/ppc4xx.h @@ -55,10 +55,4 @@ void ppc4xx_sdram_init (CPUPPCState *env, qemu_irq irq, int nbanks, #define TYPE_PPC4xx_PCI_HOST_BRIDGE "ppc4xx-pcihost" -PCIBus *ppc4xx_pci_init(CPUPPCState *env, qemu_irq pci_irqs[4], - hwaddr config_space, - hwaddr int_ack, - hwaddr special_cycle, - hwaddr registers); - #endif /* PPC4XX_H */ diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index caf7be919f6..6289d50dbfb 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -368,9 +368,6 @@ void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn); target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode, target_ulong *args); -int spapr_allocate_irq(int hint, bool lsi); -int spapr_allocate_irq_block(int num, bool lsi, bool msi); - /* ibm,set-eeh-option */ #define RTAS_EEH_DISABLE 0 #define RTAS_EEH_ENABLE 1 diff --git a/include/hw/ppc/spapr_vio.h b/include/hw/ppc/spapr_vio.h index d4a1e2c8afa..40d0e5f6a39 100644 --- a/include/hw/ppc/spapr_vio.h +++ b/include/hw/ppc/spapr_vio.h @@ -85,8 +85,6 @@ extern VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg); extern int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt); extern int spapr_populate_chosen_stdout(void *fdt, VIOsPAPRBus *bus); -extern int spapr_vio_signal(VIOsPAPRDevice *dev, target_ulong mode); - static inline qemu_irq spapr_vio_qirq(VIOsPAPRDevice *dev) { sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); @@ -137,8 +135,6 @@ void spapr_vscsi_create(VIOsPAPRBus *bus); VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus); -void spapr_vio_quiesce(void); - extern const VMStateDescription vmstate_spapr_vio; #define VMSTATE_SPAPR_VIO(_f, _s) \ diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h index 94d78681058..9bad49e9179 100644 --- a/include/hw/scsi/scsi.h +++ b/include/hw/scsi/scsi.h @@ -243,7 +243,6 @@ extern const struct SCSISense sense_code_SPACE_ALLOC_FAILED; uint32_t scsi_data_cdb_xfer(uint8_t *buf); uint32_t scsi_cdb_xfer(uint8_t *buf); int scsi_cdb_length(uint8_t *buf); -int scsi_sense_valid(SCSISense sense); int scsi_build_sense(uint8_t *in_buf, int in_len, uint8_t *buf, int len, bool fixed); diff --git a/include/hw/virtio/virtio-bus.h b/include/hw/virtio/virtio-bus.h index f3e5ef3f5b1..c98aa526d15 100644 --- a/include/hw/virtio/virtio-bus.h +++ b/include/hw/virtio/virtio-bus.h @@ -111,9 +111,6 @@ void virtio_bus_device_unplugged(VirtIODevice *bus); uint16_t virtio_bus_get_vdev_id(VirtioBusState *bus); /* Get the config_len field of the plugged device. */ size_t virtio_bus_get_vdev_config_len(VirtioBusState *bus); -/* Get the features of the plugged device. */ -uint32_t virtio_bus_get_vdev_features(VirtioBusState *bus, - uint32_t requested_features); /* Get bad features of the plugged device. */ uint32_t virtio_bus_get_vdev_bad_features(VirtioBusState *bus); /* Get config of the plugged device. */ diff --git a/include/migration/migration.h b/include/migration/migration.h index 3c96623d3df..d4acc72b85d 100644 --- a/include/migration/migration.h +++ b/include/migration/migration.h @@ -229,8 +229,6 @@ void migrate_fd_error(MigrationState *s, const Error *error); void migrate_fd_connect(MigrationState *s); -int migrate_fd_close(MigrationState *s); - void add_migration_state_change_notifier(Notifier *notify); void remove_migration_state_change_notifier(Notifier *notify); MigrationState *migrate_init(const MigrationParams *params); diff --git a/include/net/net.h b/include/net/net.h index e8d9e9e4e9a..99b28d5b38e 100644 --- a/include/net/net.h +++ b/include/net/net.h @@ -138,8 +138,6 @@ NetClientState *qemu_get_queue(NICState *nic); NICState *qemu_get_nic(NetClientState *nc); void *qemu_get_nic_opaque(NetClientState *nc); void qemu_del_net_client(NetClientState *nc); -NetClientState *qemu_find_vlan_client_by_name(Monitor *mon, int vlan_id, - const char *client_str); typedef void (*qemu_nic_foreach)(NICState *nic, void *opaque); void qemu_foreach_nic(qemu_nic_foreach func, void *opaque); int qemu_can_send_packet(NetClientState *nc); diff --git a/include/qemu/bitmap.h b/include/qemu/bitmap.h index ec5146f84e2..7247f147889 100644 --- a/include/qemu/bitmap.h +++ b/include/qemu/bitmap.h @@ -75,10 +75,6 @@ int slow_bitmap_equal(const unsigned long *bitmap1, const unsigned long *bitmap2, long bits); void slow_bitmap_complement(unsigned long *dst, const unsigned long *src, long bits); -void slow_bitmap_shift_right(unsigned long *dst, - const unsigned long *src, int shift, long bits); -void slow_bitmap_shift_left(unsigned long *dst, - const unsigned long *src, int shift, long bits); int slow_bitmap_and(unsigned long *dst, const unsigned long *bitmap1, const unsigned long *bitmap2, long bits); void slow_bitmap_or(unsigned long *dst, const unsigned long *bitmap1, diff --git a/include/qemu/uri.h b/include/qemu/uri.h index de99b3bd4b8..d201c61260d 100644 --- a/include/qemu/uri.h +++ b/include/qemu/uri.h @@ -102,8 +102,6 @@ typedef struct QueryParams { } QueryParams; struct QueryParams *query_params_new (int init_alloc); -int query_param_append (QueryParams *ps, const char *name, const char *value); -extern char *query_param_to_string (const QueryParams *ps); extern QueryParams *query_params_parse (const char *query); extern void query_params_free (QueryParams *ps); diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index f2a7b3b8fe2..3e17ba76ce0 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -326,8 +326,6 @@ MemTxAttrs kvm_arch_post_run(CPUState *cpu, struct kvm_run *run); int kvm_arch_handle_exit(CPUState *cpu, struct kvm_run *run); -int kvm_arch_handle_ioapic_eoi(CPUState *cpu, struct kvm_run *run); - int kvm_arch_process_async_events(CPUState *cpu); int kvm_arch_get_registers(CPUState *cpu); diff --git a/include/ui/console.h b/include/ui/console.h index 2703a3aa5aa..d9c13d20b15 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -394,9 +394,7 @@ QemuUIInfo *qemu_console_get_ui_info(QemuConsole *con); int qemu_console_get_width(QemuConsole *con, int fallback); int qemu_console_get_height(QemuConsole *con, int fallback); -void text_consoles_set_display(DisplayState *ds); void console_select(unsigned int index); -void console_color_init(DisplayState *ds); void qemu_console_resize(QemuConsole *con, int width, int height); void qemu_console_copy(QemuConsole *con, int src_x, int src_y, int dst_x, int dst_y, int w, int h); diff --git a/include/ui/input.h b/include/ui/input.h index 102d8a3341f..d06a12dd4c4 100644 --- a/include/ui/input.h +++ b/include/ui/input.h @@ -65,6 +65,4 @@ void qemu_input_check_mode_change(void); void qemu_add_mouse_mode_change_notifier(Notifier *notify); void qemu_remove_mouse_mode_change_notifier(Notifier *notify); -int input_linux_init(void *opaque, QemuOpts *opts, Error **errp); - #endif /* INPUT_H */ diff --git a/include/ui/spice-display.h b/include/ui/spice-display.h index 568b64a0f65..42e0fdf775d 100644 --- a/include/ui/spice-display.h +++ b/include/ui/spice-display.h @@ -144,8 +144,6 @@ void qemu_spice_destroy_update(SimpleSpiceDisplay *sdpy, SimpleSpiceUpdate *upda void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd); void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd); void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd); -void qemu_spice_vm_change_state_handler(void *opaque, int running, - RunState state); void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd); void qemu_spice_display_update(SimpleSpiceDisplay *ssd, diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h index ac5e801fb43..dcdd0416bdd 100644 --- a/target-alpha/cpu.h +++ b/target-alpha/cpu.h @@ -474,7 +474,6 @@ int cpu_alpha_signal_handler(int host_signum, void *pinfo, void *puc); int alpha_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw, int mmu_idx); -void do_restore_state(CPUAlphaState *, uintptr_t retaddr); void QEMU_NORETURN dynamic_excp(CPUAlphaState *, uintptr_t, int, int); void QEMU_NORETURN arith_excp(CPUAlphaState *, uintptr_t, int, uint64_t); diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h index b2faa6b6056..c2d40cb1ccc 100644 --- a/target-m68k/cpu.h +++ b/target-m68k/cpu.h @@ -196,7 +196,6 @@ enum { #define MACSR_EV 0x001 void m68k_set_irq_level(M68kCPU *cpu, int level, uint8_t vector); -void m68k_set_macsr(CPUM68KState *env, uint32_t val); void m68k_switch_sp(CPUM68KState *env); #define M68K_FPCR_PREC (1 << 6) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 1e808c8884d..96174811969 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1184,8 +1184,6 @@ void ppc_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, int flags); void ppc_cpu_dump_statistics(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, int flags); -int ppc_cpu_get_monitor_def(CPUState *cs, const char *name, - uint64_t *pval); hwaddr ppc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); int ppc_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); int ppc_cpu_gdb_read_register_apple(CPUState *cpu, uint8_t *buf, int reg); diff --git a/target-ppc/mmu-hash64.h b/target-ppc/mmu-hash64.h index db265e30b2e..ab5d347a53e 100644 --- a/target-ppc/mmu-hash64.h +++ b/target-ppc/mmu-hash64.h @@ -4,7 +4,6 @@ #ifndef CONFIG_USER_ONLY #ifdef TARGET_PPC64 -void ppc_hash64_check_page_sizes(PowerPCCPU *cpu, Error **errp); void dump_slb(FILE *f, fprintf_function cpu_fprintf, PowerPCCPU *cpu); int ppc_store_slb(PowerPCCPU *cpu, target_ulong slot, target_ulong esid, target_ulong vsid); diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index ac75360eabb..5645e063af3 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -624,8 +624,6 @@ static inline unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu) return 0; } #endif -void cpu_lock(void); -void cpu_unlock(void); extern void subsystem_reset(void); diff --git a/tcg/tcg.h b/tcg/tcg.h index 1bcabcad9d5..9bf31bbc84b 100644 --- a/tcg/tcg.h +++ b/tcg/tcg.h @@ -723,7 +723,6 @@ static inline bool tcg_op_buf_full(void) void *tcg_malloc_internal(TCGContext *s, int size); void tcg_pool_reset(TCGContext *s); -void tcg_pool_delete(TCGContext *s); void tb_lock(void); void tb_unlock(void); @@ -907,7 +906,6 @@ void tcg_optimize(TCGContext *s); /* only used for debugging purposes */ void tcg_dump_ops(TCGContext *s); -void dump_ops(const uint16_t *opc_buf, const TCGArg *opparam_buf); TCGv_i32 tcg_const_i32(int32_t val); TCGv_i64 tcg_const_i64(int64_t val); TCGv_i32 tcg_const_local_i32(int32_t val); From a41c457881b5463b18901a849b4289459ab1d231 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Golembiovsk=C3=BD?= Date: Fri, 8 Jul 2016 13:18:09 +0200 Subject: [PATCH 026/723] curl: Operate on zero-length file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Another attempt to fix the bug 1596870. When creating new disk backed by remote file accessed via HTTPS and the backing file has zero length, qemu-img terminates with uniformative error message: qemu-img: disk.qcow2: CURL: Error opening file: While it may not make much sense to operate on empty file, other block backends (e.g. raw backend for regular files) seem to allow it. This patch fixes it for the curl backend and improves the reported error. Signed-off-by: Tomáš Golembiovský Signed-off-by: Michael Tokarev --- block/curl.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/block/curl.c b/block/curl.c index 426fb4d6748..571f24cac24 100644 --- a/block/curl.c +++ b/block/curl.c @@ -675,11 +675,28 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags, curl_easy_setopt(state->curl, CURLOPT_HEADERDATA, s); if (curl_easy_perform(state->curl)) goto out; - curl_easy_getinfo(state->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d); - if (d) - s->len = (size_t)d; - else if(!s->len) + if (curl_easy_getinfo(state->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d)) { goto out; + } + /* Prior CURL 7.19.4 return value of 0 could mean that the file size is not + * know or the size is zero. From 7.19.4 CURL returns -1 if size is not + * known and zero if it is realy zero-length file. */ +#if LIBCURL_VERSION_NUM >= 0x071304 + if (d < 0) { + pstrcpy(state->errmsg, CURL_ERROR_SIZE, + "Server didn't report file size."); + goto out; + } +#else + if (d <= 0) { + pstrcpy(state->errmsg, CURL_ERROR_SIZE, + "Unknown file size or zero-length file."); + goto out; + } +#endif + + s->len = (size_t)d; + if ((!strncasecmp(s->url, "http://", strlen("http://")) || !strncasecmp(s->url, "https://", strlen("https://"))) && !s->accept_range) { From ac4e29f100355bd2c5d93376ed9ae5b4b7e98bad Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Wed, 15 Jun 2016 18:14:31 +0200 Subject: [PATCH 027/723] coccinelle: add a script to remove useless casts Script from LKML. Signed-off-by: Laurent Vivier Signed-off-by: Michael Tokarev --- scripts/coccinelle/typecast.cocci | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 scripts/coccinelle/typecast.cocci diff --git a/scripts/coccinelle/typecast.cocci b/scripts/coccinelle/typecast.cocci new file mode 100644 index 00000000000..be2183ee4f5 --- /dev/null +++ b/scripts/coccinelle/typecast.cocci @@ -0,0 +1,7 @@ +// Remove useless casts +@@ +type T; +T v; +@@ +- (T *)&v ++ &v From c1bc91c35c28f40c53ebc64c9ce913ea9edeac99 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Wed, 15 Jun 2016 18:14:32 +0200 Subject: [PATCH 028/723] linux-user,s390x: remove useless cast This patch is the result of coccinelle script scripts/coccinelle/typecast.cocci CC: Riku Voipio CC: Alexander Graf Signed-off-by: Laurent Vivier Signed-off-by: Michael Tokarev --- linux-user/signal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index 9a4d894e3af..d3ac0e25652 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -4244,7 +4244,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, env->regs[5] = 0; // FIXME: no clue... current->thread.prot_addr; /* Place signal number on stack to allow backtrace from handler. */ - __put_user(env->regs[2], (int *) &frame->signo); + __put_user(env->regs[2], &frame->signo); unlock_user_struct(frame, frame_addr, 1); return; From 57ddd73e611bf547c4a28356df7b3c6ff43afb0c Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Wed, 15 Jun 2016 18:14:33 +0200 Subject: [PATCH 029/723] s390x: remove useless cast This patch is the result of coccinelle script scripts/coccinelle/typecast.cocci CC: Cornelia Huck Signed-off-by: Laurent Vivier Signed-off-by: Michael Tokarev --- hw/s390x/sclp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index 48e38b2bbe1..e741da11411 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -426,7 +426,7 @@ int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code) goto out; } - sclp_c->execute(sclp, (SCCB *)&work_sccb, code); + sclp_c->execute(sclp, &work_sccb, code); cpu_physical_memory_write(sccb, &work_sccb, be16_to_cpu(work_sccb.h.length)); From 416296a9d1167333f28f9a3fdad7a648e648f53f Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Wed, 15 Jun 2016 18:14:34 +0200 Subject: [PATCH 030/723] tricore: remove useless cast This patch is the result of coccinelle script scripts/coccinelle/typecast.cocci CC: Bastian Koppelmann Signed-off-by: Laurent Vivier Reviewed-by: Bastian Koppelmann Signed-off-by: Michael Tokarev --- hw/tricore/tricore_testboard.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/tricore/tricore_testboard.c b/hw/tricore/tricore_testboard.c index 8d3520f5be3..19dd5872077 100644 --- a/hw/tricore/tricore_testboard.c +++ b/hw/tricore/tricore_testboard.c @@ -46,7 +46,7 @@ static void tricore_load_kernel(CPUTriCoreState *env) long kernel_size; kernel_size = load_elf(tricoretb_binfo.kernel_filename, NULL, - NULL, (uint64_t *)&entry, NULL, + NULL, &entry, NULL, NULL, 0, EM_TRICORE, 1, 0); if (kernel_size <= 0) { From ec8193a001e86342d3d4e1ffda8c18fa27a722c2 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Wed, 15 Jun 2016 18:14:35 +0200 Subject: [PATCH 031/723] fw_cfg: remove useless casts This patch is the result of coccinelle script scripts/coccinelle/typecast.cocci CC: Laszlo Ersek Signed-off-by: Laurent Vivier Reviewed-by: Laszlo Ersek Signed-off-by: Michael Tokarev --- hw/nvram/fw_cfg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c index 6a68e594d5f..1776b1b3c46 100644 --- a/hw/nvram/fw_cfg.c +++ b/hw/nvram/fw_cfg.c @@ -180,7 +180,7 @@ static void fw_cfg_bootsplash(FWCfgState *s) temp = qemu_opt_get(opts, "splash-time"); if (temp != NULL) { p = (char *)temp; - boot_splash_time = strtol(p, (char **)&p, 10); + boot_splash_time = strtol(p, &p, 10); } } @@ -240,7 +240,7 @@ static void fw_cfg_reboot(FWCfgState *s) temp = qemu_opt_get(opts, "reboot-timeout"); if (temp != NULL) { p = (char *)temp; - reboot_timeout = strtol(p, (char **)&p, 10); + reboot_timeout = strtol(p, &p, 10); } } /* validate the input */ From 11d816a5bc3eedfdb079b158d62867bf78ff30fc Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Wed, 15 Jun 2016 18:14:37 +0200 Subject: [PATCH 032/723] sheepdog: remove useless casts This patch is the result of coccinelle script scripts/coccinelle/typecast.cocci CC: Hitoshi Mitake CC: qemu-block@nongnu.org Signed-off-by: Laurent Vivier Reviewed-by: Hitoshi Mitake Signed-off-by: Michael Tokarev --- block/sheepdog.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/block/sheepdog.c b/block/sheepdog.c index 66e1cb2b2dd..ccbf7e1fa68 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -1049,7 +1049,7 @@ static int parse_vdiname(BDRVSheepdogState *s, const char *filename, const char *host_spec, *vdi_spec; int nr_sep, ret; - strstart(filename, "sheepdog:", (const char **)&filename); + strstart(filename, "sheepdog:", &filename); p = q = g_strdup(filename); /* count the number of separators */ @@ -2652,7 +2652,7 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab) req.opcode = SD_OP_READ_VDIS; req.data_length = max; - ret = do_req(fd, s->aio_context, (SheepdogReq *)&req, + ret = do_req(fd, s->aio_context, &req, vdi_inuse, &wlen, &rlen); closesocket(fd); From 7ad9339e372fcd12d584684d7f52ac259604a4f4 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Tue, 14 Jun 2016 13:00:23 -0300 Subject: [PATCH 033/723] win32: don't run subprocess tests on Mingw32 platform On Tue, Jun 14, 2016 at 04:44:57PM +0100, Daniel P. Berrange wrote: > The g_test_trap_subprocess() method does not work on the > Mingw32 platform, causing the test-qdev-global-props > test case to abort > > (test-logging.exe:230): GLib-ERROR **: g_test_trap_subprocess() > failed: Failed to execute helper program (No such file or directory) > > This failure was introduced a while ago in > > commit 2177801a4899bf29108b3d471417a5b4d701ec29 > Author: Eduardo Habkost > Date: Fri Aug 8 16:03:27 2014 -0300 > > test-qdev-global-props: Run tests on subprocess > > Modify the configure time check to avoid enabling this feature > on Mingw, rather than trying to rewrite the test to avoid this > feature. I would do the following instead, just in case we have extra code looking at $glib_subprocess one day. Signed-off-by: Eduardo Habkost Signed-off-by: Michael Tokarev --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index 48593280a92..7d083bdd859 100755 --- a/configure +++ b/configure @@ -3014,7 +3014,7 @@ fi # g_test_trap_subprocess added in 2.38. Used by some tests. glib_subprocess=yes -if ! $pkg_config --atleast-version=2.38 glib-2.0; then +if test "$mingw32" = "yes" || ! $pkg_config --atleast-version=2.38 glib-2.0; then glib_subprocess=no fi From 38e826de00f019d6f833d39ebd72f9ab15f3da1c Mon Sep 17 00:00:00 2001 From: Md Haris Iqbal Date: Thu, 24 Mar 2016 00:02:03 +0530 Subject: [PATCH 034/723] linux-user/qemu.h: change malloc to g_malloc, free to g_free Signed-off-by: Md Haris Iqbal Reviewed-by: Stefan Hajnoczi Signed-off-by: Michael Tokarev --- linux-user/qemu.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-user/qemu.h b/linux-user/qemu.h index bef465de4d9..815447f5fc9 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -548,7 +548,7 @@ static inline void *lock_user(int type, abi_ulong guest_addr, long len, int copy #ifdef DEBUG_REMAP { void *addr; - addr = malloc(len); + addr = g_malloc(len); if (copy) memcpy(addr, g2h(guest_addr), len); else @@ -574,7 +574,7 @@ static inline void unlock_user(void *host_ptr, abi_ulong guest_addr, return; if (len > 0) memcpy(g2h(guest_addr), host_ptr, len); - free(host_ptr); + g_free(host_ptr); #endif } From afe4c95331cea4c78cab3240594055a72aa5c30c Mon Sep 17 00:00:00 2001 From: Cao jin Date: Mon, 20 Jun 2016 14:13:33 +0800 Subject: [PATCH 035/723] mptsas: change .realize function name All the other devices` .realize function name are xxx_realize, except this one. cc: Michael S. Tsirkin cc: Marcel Apfelbaum cc: Paolo Bonzini cc: Markus Armbruster Reviewed-by: Markus Armbruster Reviewed-by: Marcel Apfelbaum Signed-off-by: Cao jin Signed-off-by: Michael Tokarev --- hw/scsi/mptsas.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/scsi/mptsas.c b/hw/scsi/mptsas.c index 0e0a22f6968..8a3dee17fc5 100644 --- a/hw/scsi/mptsas.c +++ b/hw/scsi/mptsas.c @@ -1269,7 +1269,7 @@ static const struct SCSIBusInfo mptsas_scsi_info = { .load_request = mptsas_load_request, }; -static void mptsas_scsi_init(PCIDevice *dev, Error **errp) +static void mptsas_scsi_realize(PCIDevice *dev, Error **errp) { DeviceState *d = DEVICE(dev); MPTSASState *s = MPT_SAS(dev); @@ -1426,7 +1426,7 @@ static void mptsas1068_class_init(ObjectClass *oc, void *data) DeviceClass *dc = DEVICE_CLASS(oc); PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc); - pc->realize = mptsas_scsi_init; + pc->realize = mptsas_scsi_realize; pc->exit = mptsas_scsi_uninit; pc->romfile = 0; pc->vendor_id = PCI_VENDOR_ID_LSI_LOGIC; From 927d5a1d98ff9177ec29e883c5361e0d247291d8 Mon Sep 17 00:00:00 2001 From: Wanpeng Li Date: Thu, 15 Sep 2016 15:15:59 +0800 Subject: [PATCH 036/723] pc: apic: introduce APIC macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce a new APIC macro to replace APIC_COMMON macro in hw/intc/apic.c in order to capture access LAPIC in qemu even if LAPIC is emulated in kvm. Suggested-by: Paolo Bonzini Reviewed-by: Michael S. Tsirkin Cc: Paolo Bonzini Cc: Radim Krčmář Cc: Michael S. Tsirkin Cc: Eduardo Habkost Signed-off-by: Wanpeng Li Message-Id: <1473923759-13912-1-git-send-email-wanpeng.li@hotmail.com> Signed-off-by: Paolo Bonzini --- hw/intc/apic.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/hw/intc/apic.c b/hw/intc/apic.c index 45887d99c0e..7bd1d279c46 100644 --- a/hw/intc/apic.c +++ b/hw/intc/apic.c @@ -39,6 +39,10 @@ static APICCommonState *local_apics[MAX_APICS + 1]; +#define TYPE_APIC "apic" +#define APIC(obj) \ + OBJECT_CHECK(APICCommonState, (obj), TYPE_APIC) + static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode); static void apic_update_irq(APICCommonState *s); static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask, @@ -163,7 +167,7 @@ static void apic_local_deliver(APICCommonState *s, int vector) void apic_deliver_pic_intr(DeviceState *dev, int level) { - APICCommonState *s = APIC_COMMON(dev); + APICCommonState *s = APIC(dev); if (level) { apic_local_deliver(s, APIC_LVT_LINT0); @@ -373,7 +377,7 @@ static void apic_update_irq(APICCommonState *s) void apic_poll_irq(DeviceState *dev) { - APICCommonState *s = APIC_COMMON(dev); + APICCommonState *s = APIC(dev); apic_sync_vapic(s, SYNC_FROM_VAPIC); apic_update_irq(s); @@ -479,7 +483,7 @@ static void apic_startup(APICCommonState *s, int vector_num) void apic_sipi(DeviceState *dev) { - APICCommonState *s = APIC_COMMON(dev); + APICCommonState *s = APIC(dev); cpu_reset_interrupt(CPU(s->cpu), CPU_INTERRUPT_SIPI); @@ -493,7 +497,7 @@ static void apic_deliver(DeviceState *dev, uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode, uint8_t vector_num, uint8_t trigger_mode) { - APICCommonState *s = APIC_COMMON(dev); + APICCommonState *s = APIC(dev); uint32_t deliver_bitmask[MAX_APIC_WORDS]; int dest_shorthand = (s->icr[0] >> 18) & 3; APICCommonState *apic_iter; @@ -550,7 +554,7 @@ static bool apic_check_pic(APICCommonState *s) int apic_get_interrupt(DeviceState *dev) { - APICCommonState *s = APIC_COMMON(dev); + APICCommonState *s = APIC(dev); int intno; /* if the APIC is installed or enabled, we let the 8259 handle the @@ -584,7 +588,7 @@ int apic_get_interrupt(DeviceState *dev) int apic_accept_pic_intr(DeviceState *dev) { - APICCommonState *s = APIC_COMMON(dev); + APICCommonState *s = APIC(dev); uint32_t lvt0; if (!s) @@ -663,7 +667,7 @@ static uint32_t apic_mem_readl(void *opaque, hwaddr addr) if (!dev) { return 0; } - s = APIC_COMMON(dev); + s = APIC(dev); index = (addr >> 4) & 0xff; switch(index) { @@ -766,7 +770,7 @@ static void apic_mem_writel(void *opaque, hwaddr addr, uint32_t val) if (!dev) { return; } - s = APIC_COMMON(dev); + s = APIC(dev); trace_apic_mem_writel(addr, val); @@ -870,7 +874,7 @@ static const MemoryRegionOps apic_io_ops = { static void apic_realize(DeviceState *dev, Error **errp) { - APICCommonState *s = APIC_COMMON(dev); + APICCommonState *s = APIC(dev); if (s->id >= MAX_APICS) { error_setg(errp, "%s initialization failed. APIC ID %d is invalid", @@ -889,7 +893,7 @@ static void apic_realize(DeviceState *dev, Error **errp) static void apic_unrealize(DeviceState *dev, Error **errp) { - APICCommonState *s = APIC_COMMON(dev); + APICCommonState *s = APIC(dev); timer_del(s->timer); timer_free(s->timer); @@ -912,7 +916,7 @@ static void apic_class_init(ObjectClass *klass, void *data) } static const TypeInfo apic_info = { - .name = "apic", + .name = TYPE_APIC, .instance_size = sizeof(APICCommonState), .parent = TYPE_APIC_COMMON, .class_init = apic_class_init, From 46f5feaa0ac24c0dbe6e0d04d0b11ee1df7c3bfd Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Thu, 15 Sep 2016 12:01:28 +0300 Subject: [PATCH 037/723] kvmvapic: fix state change handler This patch fixes kvmvapic state change handler. It clears vmsentry field to allow recreating it at further vmstate loads. Signed-off-by: Pavel Dovgalyuk Message-Id: <20160915090127.6440.48793.stgit@PASHA-ISP> Signed-off-by: Paolo Bonzini --- hw/i386/kvmvapic.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/i386/kvmvapic.c b/hw/i386/kvmvapic.c index 3bf1ddd9761..a1cd9b5a292 100644 --- a/hw/i386/kvmvapic.c +++ b/hw/i386/kvmvapic.c @@ -768,6 +768,7 @@ static void kvmvapic_vm_state_change(void *opaque, int running, } qemu_del_vm_change_state_handler(s->vmsentry); + s->vmsentry = NULL; } static int vapic_post_load(void *opaque, int version_id) From 39c88f56977f9ad2451444d70dd21d8189d74f99 Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Thu, 15 Sep 2016 12:01:33 +0300 Subject: [PATCH 038/723] pcspk: adding vmstate for save/restore VMState added by this patch preserves correct loading of the PC speaker device state. Signed-off-by: Pavel Dovgalyuk Message-Id: <20160915090133.6440.65457.stgit@PASHA-ISP> Signed-off-by: Paolo Bonzini --- hw/audio/pcspk.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/hw/audio/pcspk.c b/hw/audio/pcspk.c index 42a6f4885a7..984534b2d18 100644 --- a/hw/audio/pcspk.c +++ b/hw/audio/pcspk.c @@ -52,8 +52,8 @@ typedef struct { unsigned int pit_count; unsigned int samples; unsigned int play_pos; - int data_on; - int dummy_refresh_clock; + uint8_t data_on; + uint8_t dummy_refresh_clock; } PCSpkState; static const char *s_spk = "pcspk"; @@ -187,6 +187,18 @@ static void pcspk_realizefn(DeviceState *dev, Error **errp) pcspk_state = s; } +static const VMStateDescription vmstate_spk = { + .name = "pcspk", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT8(data_on, PCSpkState), + VMSTATE_UINT8(dummy_refresh_clock, PCSpkState), + VMSTATE_END_OF_LIST() + } +}; + static Property pcspk_properties[] = { DEFINE_PROP_UINT32("iobase", PCSpkState, iobase, -1), DEFINE_PROP_END_OF_LIST(), @@ -198,6 +210,7 @@ static void pcspk_class_initfn(ObjectClass *klass, void *data) dc->realize = pcspk_realizefn; set_bit(DEVICE_CATEGORY_SOUND, dc->categories); + dc->vmsd = &vmstate_spk; dc->props = pcspk_properties; /* Reason: realize sets global pcspk_state */ dc->cannot_instantiate_with_device_add_yet = true; From d1b4259f1ab18af24e6a297edb6a8f71691f3256 Mon Sep 17 00:00:00 2001 From: Maxime Coquelin Date: Tue, 13 Sep 2016 15:30:30 +0200 Subject: [PATCH 039/723] virtio-bus: Plug devices after features are negotiated Currently, devices are plugged before features are negotiated. If the backend doesn't support VIRTIO_F_VERSION_1, the transport needs to rewind some settings. This is the case for CCW, for which a post_plugged callback had been introduced, where max_rev field is just updated if VIRTIO_F_VERSION_1 is not supported by the backend. For PCI, implementing post_plugged would be much more complicated, so it needs to know whether the backend supports VIRTIO_F_VERSION_1 at plug time. Currently, nothing is done for PCI. Modern capabilities get exposed to the guest even if VIRTIO_F_VERSION_1 is not supported by the backend, which confuses the guest. This patch replaces existing post_plugged solution with an approach that fits with both transports. Features negotiation is performed before ->device_plugged() call. A pre_plugged callback is introduced so that the transports can set their supported features. Cc: Michael S. Tsirkin Cc: qemu-stable@nongnu.org Tested-by: Cornelia Huck [ccw] Reviewed-by: Cornelia Huck Reviewed-by: Marcel Apfelbaum Signed-off-by: Maxime Coquelin --- hw/s390x/virtio-ccw.c | 30 ++++++++++++++-------------- hw/virtio/virtio-bus.c | 9 +++++---- hw/virtio/virtio-pci.c | 36 ++++++++++++++++++++++++++++++---- hw/virtio/virtio-pci.h | 5 +++++ include/hw/virtio/virtio-bus.h | 10 +++++----- 5 files changed, 62 insertions(+), 28 deletions(-) diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index 96789569a71..9f3f386964a 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -1261,6 +1261,16 @@ static int virtio_ccw_load_config(DeviceState *d, QEMUFile *f) return 0; } +static void virtio_ccw_pre_plugged(DeviceState *d, Error **errp) +{ + VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); + VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); + + if (dev->max_rev >= 1) { + virtio_add_feature(&vdev->host_features, VIRTIO_F_VERSION_1); + } +} + /* This is called by virtio-bus just after the device is plugged. */ static void virtio_ccw_device_plugged(DeviceState *d, Error **errp) { @@ -1270,6 +1280,10 @@ static void virtio_ccw_device_plugged(DeviceState *d, Error **errp) SubchDev *sch = ccw_dev->sch; int n = virtio_get_num_queues(vdev); + if (!virtio_has_feature(vdev->host_features, VIRTIO_F_VERSION_1)) { + dev->max_rev = 0; + } + if (virtio_get_num_queues(vdev) > VIRTIO_CCW_QUEUE_MAX) { error_setg(errp, "The number of virtqueues %d " "exceeds ccw limit %d", n, @@ -1283,25 +1297,11 @@ static void virtio_ccw_device_plugged(DeviceState *d, Error **errp) sch->id.cu_model = virtio_bus_get_vdev_id(&dev->bus); - if (dev->max_rev >= 1) { - virtio_add_feature(&vdev->host_features, VIRTIO_F_VERSION_1); - } css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid, d->hotplugged, 1); } -static void virtio_ccw_post_plugged(DeviceState *d, Error **errp) -{ - VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); - VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); - - if (!virtio_host_has_feature(vdev, VIRTIO_F_VERSION_1)) { - /* A backend didn't support modern virtio. */ - dev->max_rev = 0; - } -} - static void virtio_ccw_device_unplugged(DeviceState *d) { VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); @@ -1593,8 +1593,8 @@ static void virtio_ccw_bus_class_init(ObjectClass *klass, void *data) k->load_queue = virtio_ccw_load_queue; k->save_config = virtio_ccw_save_config; k->load_config = virtio_ccw_load_config; + k->pre_plugged = virtio_ccw_pre_plugged; k->device_plugged = virtio_ccw_device_plugged; - k->post_plugged = virtio_ccw_post_plugged; k->device_unplugged = virtio_ccw_device_unplugged; k->ioeventfd_started = virtio_ccw_ioeventfd_started; k->ioeventfd_set_started = virtio_ccw_ioeventfd_set_started; diff --git a/hw/virtio/virtio-bus.c b/hw/virtio/virtio-bus.c index 14927935aef..11f65bd2254 100644 --- a/hw/virtio/virtio-bus.c +++ b/hw/virtio/virtio-bus.c @@ -49,16 +49,17 @@ void virtio_bus_device_plugged(VirtIODevice *vdev, Error **errp) DPRINTF("%s: plug device.\n", qbus->name); - if (klass->device_plugged != NULL) { - klass->device_plugged(qbus->parent, errp); + if (klass->pre_plugged != NULL) { + klass->pre_plugged(qbus->parent, errp); } /* Get the features of the plugged device. */ assert(vdc->get_features != NULL); vdev->host_features = vdc->get_features(vdev, vdev->host_features, errp); - if (klass->post_plugged != NULL) { - klass->post_plugged(qbus->parent, errp); + + if (klass->device_plugged != NULL) { + klass->device_plugged(qbus->parent, errp); } } diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index dde71a59654..2d60a005b66 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1576,18 +1576,48 @@ static void virtio_pci_modern_io_region_unmap(VirtIOPCIProxy *proxy, ®ion->mr); } +static void virtio_pci_pre_plugged(DeviceState *d, Error **errp) +{ + VirtIOPCIProxy *proxy = VIRTIO_PCI(d); + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + + if (virtio_pci_modern(proxy)) { + virtio_add_feature(&vdev->host_features, VIRTIO_F_VERSION_1); + } + + virtio_add_feature(&vdev->host_features, VIRTIO_F_BAD_FEATURE); +} + /* This is called by virtio-bus just after the device is plugged. */ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) { VirtIOPCIProxy *proxy = VIRTIO_PCI(d); VirtioBusState *bus = &proxy->bus; bool legacy = virtio_pci_legacy(proxy); - bool modern = virtio_pci_modern(proxy); + bool modern; bool modern_pio = proxy->flags & VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY; uint8_t *config; uint32_t size; VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + /* + * Virtio capabilities present without + * VIRTIO_F_VERSION_1 confuses guests + */ + if (!virtio_has_feature(vdev->host_features, VIRTIO_F_VERSION_1)) { + virtio_pci_disable_modern(proxy); + + if (!legacy) { + error_setg(errp, "Device doesn't support modern mode, and legacy" + " mode is disabled"); + error_append_hint(errp, "Set disable-legacy to off\n"); + + return; + } + } + + modern = virtio_pci_modern(proxy); + config = proxy->pci_dev.config; if (proxy->class_code) { pci_config_set_class(config, proxy->class_code); @@ -1629,7 +1659,6 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) struct virtio_pci_cfg_cap *cfg_mask; - virtio_add_feature(&vdev->host_features, VIRTIO_F_VERSION_1); virtio_pci_modern_regions_init(proxy); virtio_pci_modern_mem_region_map(proxy, &proxy->common, &cap); @@ -1694,8 +1723,6 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) if (!kvm_has_many_ioeventfds()) { proxy->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD; } - - virtio_add_feature(&vdev->host_features, VIRTIO_F_BAD_FEATURE); } static void virtio_pci_device_unplugged(DeviceState *d) @@ -2508,6 +2535,7 @@ static void virtio_pci_bus_class_init(ObjectClass *klass, void *data) k->query_guest_notifiers = virtio_pci_query_guest_notifiers; k->set_guest_notifiers = virtio_pci_set_guest_notifiers; k->vmstate_change = virtio_pci_vmstate_change; + k->pre_plugged = virtio_pci_pre_plugged; k->device_plugged = virtio_pci_device_plugged; k->device_unplugged = virtio_pci_device_unplugged; k->query_nvectors = virtio_pci_query_nvectors; diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h index 0698157b32d..541cbdbc2bd 100644 --- a/hw/virtio/virtio-pci.h +++ b/hw/virtio/virtio-pci.h @@ -181,6 +181,11 @@ static inline void virtio_pci_force_virtio_1(VirtIOPCIProxy *proxy) proxy->disable_legacy = ON_OFF_AUTO_ON; } +static inline void virtio_pci_disable_modern(VirtIOPCIProxy *proxy) +{ + proxy->disable_modern = true; +} + /* * virtio-scsi-pci: This extends VirtioPCIProxy. */ diff --git a/include/hw/virtio/virtio-bus.h b/include/hw/virtio/virtio-bus.h index f3e5ef3f5b1..24caa0a6e55 100644 --- a/include/hw/virtio/virtio-bus.h +++ b/include/hw/virtio/virtio-bus.h @@ -53,16 +53,16 @@ typedef struct VirtioBusClass { bool (*query_guest_notifiers)(DeviceState *d); int (*set_guest_notifiers)(DeviceState *d, int nvqs, bool assign); void (*vmstate_change)(DeviceState *d, bool running); + /* + * Expose the features the transport layer supports before + * the negotiation takes place. + */ + void (*pre_plugged)(DeviceState *d, Error **errp); /* * transport independent init function. * This is called by virtio-bus just after the device is plugged. */ void (*device_plugged)(DeviceState *d, Error **errp); - /* - * Re-evaluate setup after feature bits have been validated - * by the device backend. - */ - void (*post_plugged)(DeviceState *d, Error **errp); /* * transport independent exit function. * This is called by virtio-bus just before the device is unplugged. From 6d17a018d09801a2b18133a4febd81433bb0cf85 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 15 Sep 2016 16:11:48 +1000 Subject: [PATCH 040/723] vfio/pci: Fix regression in MSI routing configuration d1f6af6 "kvm-irqchip: simplify kvm_irqchip_add_msi_route" was a cleanup of kvmchip routing configuration, that was mostly intended for x86. However, it also contains a subtle change in behaviour which breaks EEH[1] error recovery on certain VFIO passthrough devices on spapr guests. So far it's only been seen on a BCM5719 NIC on a POWER8 server, but there may be other hardware with the same problem. It's also possible there could be circumstances where it causes a bug on x86 as well, though I don't know of any obvious candidates. Prior to d1f6af6, both vfio_msix_vector_do_use() and vfio_add_kvm_msi_virq() used msg == NULL as a special flag to mark this as the "dummy" vector used to make the host hardware state sync with the guest expected hardware state in terms of MSI configuration. Specifically that flag caused vfio_add_kvm_msi_virq() to become a no-op, meaning the dummy irq would always be delivered via qemu. d1f6af6 changed vfio_add_kvm_msi_virq() so it takes a vector number instead of the msg parameter, and determines the correct message itself. The test for !msg was removed, and not replaced with anything there or in the caller. With an spapr guest which has a VFIO device, if an EEH error occurs on the host hardware, then the device will be isolated then reset. This is a combination of host and guest action, mediated by some EEH related hypercalls. I haven't fully traced the mechanics, but somehow installing the kvm irqchip route for the dummy irq on the BCM5719 means that after EEH reset and recovery, at least some irqs are no longer delivered to the guest. In particular, the guest never gets the link up event, and so the NIC is effectively dead. [1] EEH (Enhanced Error Handling) is an IBM POWER server specific PCI-* error reporting and recovery mechanism. The concept is somewhat similar to PCI-E AER, but the details are different. Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1373802 Cc: Alex Williamson Cc: Peter Xu Cc: Gavin Shan Signed-off-by: David Gibson Cc: qemu-stable@nongnu.org Fixes: d1f6af6a17a6 ("kvm-irqchip: simplify kvm_irqchip_add_msi_route") Signed-off-by: Alex Williamson --- hw/vfio/pci.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index 7bfa17ce38b..a5a620a0c4c 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -496,7 +496,9 @@ static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr, vfio_update_kvm_msi_virq(vector, *msg, pdev); } } else { - vfio_add_kvm_msi_virq(vdev, vector, nr, true); + if (msg) { + vfio_add_kvm_msi_virq(vdev, vector, nr, true); + } } /* From 799fe087e491e17ff02658d34e5fc696c79f6db5 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Fri, 16 Sep 2016 08:56:14 +0200 Subject: [PATCH 041/723] 9pfs: drop unused fmt strings in the proxy backend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The v9fs_request() function doesn't use its fmt argument: it passes literal format strings to proxy_marshal() for all commands. This patch simply drops the unused fmt argument and updates all callers accordingly. Signed-off-by: Greg Kurz Reviewed-by: Cédric Le Goater --- hw/9pfs/9p-proxy.c | 67 +++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 37 deletions(-) diff --git a/hw/9pfs/9p-proxy.c b/hw/9pfs/9p-proxy.c index f265501eac1..52bbf4f1b37 100644 --- a/hw/9pfs/9p-proxy.c +++ b/hw/9pfs/9p-proxy.c @@ -294,8 +294,7 @@ static int v9fs_receive_status(V9fsProxy *proxy, * This request read by proxy helper process * returns 0 on success and -errno on error */ -static int v9fs_request(V9fsProxy *proxy, int type, - void *response, const char *fmt, ...) +static int v9fs_request(V9fsProxy *proxy, int type, void *response, ...) { dev_t rdev; va_list ap; @@ -317,7 +316,7 @@ static int v9fs_request(V9fsProxy *proxy, int type, } iovec = &proxy->out_iovec; reply = &proxy->in_iovec; - va_start(ap, fmt); + va_start(ap, response); switch (type) { case T_OPEN: path = va_arg(ap, V9fsString *); @@ -605,7 +604,7 @@ static int v9fs_request(V9fsProxy *proxy, int type, static int proxy_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf) { int retval; - retval = v9fs_request(fs_ctx->private, T_LSTAT, stbuf, "s", fs_path); + retval = v9fs_request(fs_ctx->private, T_LSTAT, stbuf, fs_path); if (retval < 0) { errno = -retval; return -1; @@ -617,8 +616,7 @@ static ssize_t proxy_readlink(FsContext *fs_ctx, V9fsPath *fs_path, char *buf, size_t bufsz) { int retval; - retval = v9fs_request(fs_ctx->private, T_READLINK, buf, "sd", - fs_path, bufsz); + retval = v9fs_request(fs_ctx->private, T_READLINK, buf, fs_path, bufsz); if (retval < 0) { errno = -retval; return -1; @@ -639,7 +637,7 @@ static int proxy_closedir(FsContext *ctx, V9fsFidOpenState *fs) static int proxy_open(FsContext *ctx, V9fsPath *fs_path, int flags, V9fsFidOpenState *fs) { - fs->fd = v9fs_request(ctx->private, T_OPEN, NULL, "sd", fs_path, flags); + fs->fd = v9fs_request(ctx->private, T_OPEN, NULL, fs_path, flags); if (fs->fd < 0) { errno = -fs->fd; fs->fd = -1; @@ -653,7 +651,7 @@ static int proxy_opendir(FsContext *ctx, int serrno, fd; fs->dir.stream = NULL; - fd = v9fs_request(ctx->private, T_OPEN, NULL, "sd", fs_path, O_DIRECTORY); + fd = v9fs_request(ctx->private, T_OPEN, NULL, fs_path, O_DIRECTORY); if (fd < 0) { errno = -fd; return -1; @@ -735,8 +733,8 @@ static ssize_t proxy_pwritev(FsContext *ctx, V9fsFidOpenState *fs, static int proxy_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) { int retval; - retval = v9fs_request(fs_ctx->private, T_CHMOD, NULL, "sd", - fs_path, credp->fc_mode); + retval = v9fs_request(fs_ctx->private, T_CHMOD, NULL, fs_path, + credp->fc_mode); if (retval < 0) { errno = -retval; } @@ -752,8 +750,8 @@ static int proxy_mknod(FsContext *fs_ctx, V9fsPath *dir_path, v9fs_string_init(&fullname); v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); - retval = v9fs_request(fs_ctx->private, T_MKNOD, NULL, "sdqdd", - &fullname, credp->fc_mode, credp->fc_rdev, + retval = v9fs_request(fs_ctx->private, T_MKNOD, NULL, &fullname, + credp->fc_mode, credp->fc_rdev, credp->fc_uid, credp->fc_gid); v9fs_string_free(&fullname); if (retval < 0) { @@ -772,7 +770,7 @@ static int proxy_mkdir(FsContext *fs_ctx, V9fsPath *dir_path, v9fs_string_init(&fullname); v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); - retval = v9fs_request(fs_ctx->private, T_MKDIR, NULL, "sddd", &fullname, + retval = v9fs_request(fs_ctx->private, T_MKDIR, NULL, &fullname, credp->fc_mode, credp->fc_uid, credp->fc_gid); v9fs_string_free(&fullname); if (retval < 0) { @@ -804,9 +802,8 @@ static int proxy_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name, v9fs_string_init(&fullname); v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); - fs->fd = v9fs_request(fs_ctx->private, T_CREATE, NULL, "sdddd", - &fullname, flags, credp->fc_mode, - credp->fc_uid, credp->fc_gid); + fs->fd = v9fs_request(fs_ctx->private, T_CREATE, NULL, &fullname, flags, + credp->fc_mode, credp->fc_uid, credp->fc_gid); v9fs_string_free(&fullname); if (fs->fd < 0) { errno = -fs->fd; @@ -827,8 +824,8 @@ static int proxy_symlink(FsContext *fs_ctx, const char *oldpath, v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); v9fs_string_sprintf(&target, "%s", oldpath); - retval = v9fs_request(fs_ctx->private, T_SYMLINK, NULL, "ssdd", - &target, &fullname, credp->fc_uid, credp->fc_gid); + retval = v9fs_request(fs_ctx->private, T_SYMLINK, NULL, &target, &fullname, + credp->fc_uid, credp->fc_gid); v9fs_string_free(&fullname); v9fs_string_free(&target); if (retval < 0) { @@ -847,7 +844,7 @@ static int proxy_link(FsContext *ctx, V9fsPath *oldpath, v9fs_string_init(&newpath); v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name); - retval = v9fs_request(ctx->private, T_LINK, NULL, "ss", oldpath, &newpath); + retval = v9fs_request(ctx->private, T_LINK, NULL, oldpath, &newpath); v9fs_string_free(&newpath); if (retval < 0) { errno = -retval; @@ -860,7 +857,7 @@ static int proxy_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size) { int retval; - retval = v9fs_request(ctx->private, T_TRUNCATE, NULL, "sq", fs_path, size); + retval = v9fs_request(ctx->private, T_TRUNCATE, NULL, fs_path, size); if (retval < 0) { errno = -retval; return -1; @@ -879,8 +876,7 @@ static int proxy_rename(FsContext *ctx, const char *oldpath, v9fs_string_sprintf(&oldname, "%s", oldpath); v9fs_string_sprintf(&newname, "%s", newpath); - retval = v9fs_request(ctx->private, T_RENAME, NULL, "ss", - &oldname, &newname); + retval = v9fs_request(ctx->private, T_RENAME, NULL, &oldname, &newname); v9fs_string_free(&oldname); v9fs_string_free(&newname); if (retval < 0) { @@ -892,8 +888,8 @@ static int proxy_rename(FsContext *ctx, const char *oldpath, static int proxy_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) { int retval; - retval = v9fs_request(fs_ctx->private, T_CHOWN, NULL, "sdd", - fs_path, credp->fc_uid, credp->fc_gid); + retval = v9fs_request(fs_ctx->private, T_CHOWN, NULL, fs_path, + credp->fc_uid, credp->fc_gid); if (retval < 0) { errno = -retval; } @@ -904,8 +900,7 @@ static int proxy_utimensat(FsContext *s, V9fsPath *fs_path, const struct timespec *buf) { int retval; - retval = v9fs_request(s->private, T_UTIME, NULL, "sqqqq", - fs_path, + retval = v9fs_request(s->private, T_UTIME, NULL, fs_path, buf[0].tv_sec, buf[0].tv_nsec, buf[1].tv_sec, buf[1].tv_nsec); if (retval < 0) { @@ -920,7 +915,7 @@ static int proxy_remove(FsContext *ctx, const char *path) V9fsString name; v9fs_string_init(&name); v9fs_string_sprintf(&name, "%s", path); - retval = v9fs_request(ctx->private, T_REMOVE, NULL, "s", &name); + retval = v9fs_request(ctx->private, T_REMOVE, NULL, &name); v9fs_string_free(&name); if (retval < 0) { errno = -retval; @@ -949,7 +944,7 @@ static int proxy_fsync(FsContext *ctx, int fid_type, static int proxy_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf) { int retval; - retval = v9fs_request(s->private, T_STATFS, stbuf, "s", fs_path); + retval = v9fs_request(s->private, T_STATFS, stbuf, fs_path); if (retval < 0) { errno = -retval; return -1; @@ -965,8 +960,8 @@ static ssize_t proxy_lgetxattr(FsContext *ctx, V9fsPath *fs_path, v9fs_string_init(&xname); v9fs_string_sprintf(&xname, "%s", name); - retval = v9fs_request(ctx->private, T_LGETXATTR, value, "dss", size, - fs_path, &xname); + retval = v9fs_request(ctx->private, T_LGETXATTR, value, size, fs_path, + &xname); v9fs_string_free(&xname); if (retval < 0) { errno = -retval; @@ -978,8 +973,7 @@ static ssize_t proxy_llistxattr(FsContext *ctx, V9fsPath *fs_path, void *value, size_t size) { int retval; - retval = v9fs_request(ctx->private, T_LLISTXATTR, value, "ds", size, - fs_path); + retval = v9fs_request(ctx->private, T_LLISTXATTR, value, size, fs_path); if (retval < 0) { errno = -retval; } @@ -1000,8 +994,8 @@ static int proxy_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name, xvalue.data = g_malloc(size); memcpy(xvalue.data, value, size); - retval = v9fs_request(ctx->private, T_LSETXATTR, value, "sssdd", - fs_path, &xname, &xvalue, size, flags); + retval = v9fs_request(ctx->private, T_LSETXATTR, value, fs_path, &xname, + &xvalue, size, flags); v9fs_string_free(&xname); v9fs_string_free(&xvalue); if (retval < 0) { @@ -1018,8 +1012,7 @@ static int proxy_lremovexattr(FsContext *ctx, V9fsPath *fs_path, v9fs_string_init(&xname); v9fs_string_sprintf(&xname, "%s", name); - retval = v9fs_request(ctx->private, T_LREMOVEXATTR, NULL, "ss", - fs_path, &xname); + retval = v9fs_request(ctx->private, T_LREMOVEXATTR, NULL, fs_path, &xname); v9fs_string_free(&xname); if (retval < 0) { errno = -retval; @@ -1086,7 +1079,7 @@ static int proxy_ioc_getversion(FsContext *fs_ctx, V9fsPath *path, errno = ENOTTY; return -1; } - err = v9fs_request(fs_ctx->private, T_GETVERSION, st_gen, "s", path); + err = v9fs_request(fs_ctx->private, T_GETVERSION, st_gen, path); if (err < 0) { errno = -err; err = -1; From da4bc86c540991902e32e4e840c6ada573240254 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Fri, 16 Sep 2016 08:56:14 +0200 Subject: [PATCH 042/723] 9pfs: drop duplicate line in proxy backend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This double free did not cause harm because v9fs_string_free() sets str->data to NULL and g_free(NULL) is valid. Signed-off-by: Greg Kurz Reviewed-by: Cédric Le Goater --- hw/9pfs/9p-proxy.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/9pfs/9p-proxy.c b/hw/9pfs/9p-proxy.c index 52bbf4f1b37..d091564b6fd 100644 --- a/hw/9pfs/9p-proxy.c +++ b/hw/9pfs/9p-proxy.c @@ -777,7 +777,6 @@ static int proxy_mkdir(FsContext *fs_ctx, V9fsPath *dir_path, errno = -retval; retval = -1; } - v9fs_string_free(&fullname); return retval; } From abdf008640b7ff59ac4c08c85f76ed861290c60e Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Fri, 16 Sep 2016 08:56:15 +0200 Subject: [PATCH 043/723] 9pfs: drop useless v9fs_string_null() function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The v9fs_string_null() function just calls v9fs_string_free(). Also it only has 4 users, whereas v9fs_string_free() has 87. This patch converts users to call directly v9fs_string_free() and drops the useless function. Signed-off-by: Greg Kurz Reviewed-by: Cédric Le Goater --- fsdev/9p-marshal.c | 5 ----- fsdev/9p-marshal.h | 1 - hw/9pfs/9p.c | 8 ++++---- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/fsdev/9p-marshal.c b/fsdev/9p-marshal.c index 238dbf21b1d..a01bba6908a 100644 --- a/fsdev/9p-marshal.c +++ b/fsdev/9p-marshal.c @@ -25,11 +25,6 @@ void v9fs_string_free(V9fsString *str) str->size = 0; } -void v9fs_string_null(V9fsString *str) -{ - v9fs_string_free(str); -} - void GCC_FMT_ATTR(2, 3) v9fs_string_sprintf(V9fsString *str, const char *fmt, ...) { diff --git a/fsdev/9p-marshal.h b/fsdev/9p-marshal.h index 140db6d99f9..77f7fef326e 100644 --- a/fsdev/9p-marshal.h +++ b/fsdev/9p-marshal.h @@ -77,7 +77,6 @@ static inline void v9fs_string_init(V9fsString *str) str->size = 0; } extern void v9fs_string_free(V9fsString *str); -extern void v9fs_string_null(V9fsString *str); extern void v9fs_string_sprintf(V9fsString *str, const char *fmt, ...); extern void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs); diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index dfe293d11d1..d8f48ca76c4 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -810,15 +810,15 @@ static int stat_to_v9stat(V9fsPDU *pdu, V9fsPath *name, v9stat->mtime = stbuf->st_mtime; v9stat->length = stbuf->st_size; - v9fs_string_null(&v9stat->uid); - v9fs_string_null(&v9stat->gid); - v9fs_string_null(&v9stat->muid); + v9fs_string_free(&v9stat->uid); + v9fs_string_free(&v9stat->gid); + v9fs_string_free(&v9stat->muid); v9stat->n_uid = stbuf->st_uid; v9stat->n_gid = stbuf->st_gid; v9stat->n_muid = 0; - v9fs_string_null(&v9stat->extension); + v9fs_string_free(&v9stat->extension); if (v9stat->mode & P9_STAT_MODE_SYMLINK) { err = v9fs_co_readlink(pdu, name, &v9stat->extension); From e3e83f2e2130a3afbd41a2893d23397f03f6d9d0 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Fri, 16 Sep 2016 08:56:15 +0200 Subject: [PATCH 044/723] 9pfs: introduce v9fs_path_sprintf() helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This helper is similar to v9fs_string_sprintf(), but it includes the terminating NUL character in the size field. This is to avoid doing v9fs_string_sprintf((V9fsString *) &path) and then bumping the size. Affected users are changed to use this new helper. Signed-off-by: Greg Kurz Reviewed-by: Cédric Le Goater --- hw/9pfs/9p-local.c | 7 ++----- hw/9pfs/9p-proxy.c | 7 ++----- hw/9pfs/9p.c | 19 ++++++++++++++++--- hw/9pfs/9p.h | 1 + 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c index 3f271fcbd2c..845675e7a1b 100644 --- a/hw/9pfs/9p-local.c +++ b/hw/9pfs/9p-local.c @@ -1060,13 +1060,10 @@ static int local_name_to_path(FsContext *ctx, V9fsPath *dir_path, const char *name, V9fsPath *target) { if (dir_path) { - v9fs_string_sprintf((V9fsString *)target, "%s/%s", - dir_path->data, name); + v9fs_path_sprintf(target, "%s/%s", dir_path->data, name); } else { - v9fs_string_sprintf((V9fsString *)target, "%s", name); + v9fs_path_sprintf(target, "%s", name); } - /* Bump the size for including terminating NULL */ - target->size++; return 0; } diff --git a/hw/9pfs/9p-proxy.c b/hw/9pfs/9p-proxy.c index d091564b6fd..f2417b7fd73 100644 --- a/hw/9pfs/9p-proxy.c +++ b/hw/9pfs/9p-proxy.c @@ -1023,13 +1023,10 @@ static int proxy_name_to_path(FsContext *ctx, V9fsPath *dir_path, const char *name, V9fsPath *target) { if (dir_path) { - v9fs_string_sprintf((V9fsString *)target, "%s/%s", - dir_path->data, name); + v9fs_path_sprintf(target, "%s/%s", dir_path->data, name); } else { - v9fs_string_sprintf((V9fsString *)target, "%s", name); + v9fs_path_sprintf(target, "%s", name); } - /* Bump the size for including terminating NULL */ - target->size++; return 0; } diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index d8f48ca76c4..639f9393028 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -12,6 +12,7 @@ */ #include "qemu/osdep.h" +#include #include "hw/virtio/virtio.h" #include "qapi/error.h" #include "qemu/error-report.h" @@ -179,6 +180,20 @@ void v9fs_path_free(V9fsPath *path) path->size = 0; } + +void GCC_FMT_ATTR(2, 3) +v9fs_path_sprintf(V9fsPath *path, const char *fmt, ...) +{ + va_list ap; + + v9fs_path_free(path); + + va_start(ap, fmt); + /* Bump the size for including terminating NULL */ + path->size = g_vasprintf(&path->data, fmt, ap) + 1; + va_end(ap); +} + void v9fs_path_copy(V9fsPath *lhs, V9fsPath *rhs) { v9fs_path_free(lhs); @@ -917,10 +932,8 @@ static void v9fs_fix_path(V9fsPath *dst, V9fsPath *src, int len) V9fsPath str; v9fs_path_init(&str); v9fs_path_copy(&str, dst); - v9fs_string_sprintf((V9fsString *)dst, "%s%s", src->data, str.data+len); + v9fs_path_sprintf(dst, "%s%s", src->data, str.data + len); v9fs_path_free(&str); - /* +1 to include terminating NULL */ - dst->size++; } static inline bool is_ro_export(FsContext *ctx) diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h index a38603398ef..d539d2ebe9c 100644 --- a/hw/9pfs/9p.h +++ b/hw/9pfs/9p.h @@ -327,6 +327,7 @@ static inline uint8_t v9fs_request_cancelled(V9fsPDU *pdu) extern void v9fs_reclaim_fd(V9fsPDU *pdu); extern void v9fs_path_init(V9fsPath *path); extern void v9fs_path_free(V9fsPath *path); +extern void v9fs_path_sprintf(V9fsPath *path, const char *fmt, ...); extern void v9fs_path_copy(V9fsPath *lhs, V9fsPath *rhs); extern int v9fs_name_to_path(V9fsState *s, V9fsPath *dirpath, const char *name, V9fsPath *path); From 993f8054d1152439e81dc382ff73b4b52bf71673 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Fri, 16 Sep 2016 08:58:35 +0200 Subject: [PATCH 045/723] tests: virtio-9p: introduce start/stop functions First step to be able to run several functional steps. Signed-off-by: Greg Kurz Acked-by: Cornelia Huck --- tests/virtio-9p-test.c | 42 +++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/tests/virtio-9p-test.c b/tests/virtio-9p-test.c index 1e39335a794..45fc8041d7f 100644 --- a/tests/virtio-9p-test.c +++ b/tests/virtio-9p-test.c @@ -11,33 +11,41 @@ #include "libqtest.h" #include "qemu-common.h" -/* Tests only initialization so far. TODO: Replace with functional tests */ -static void pci_nop(void) -{ -} +static const char mount_tag[] = "qtest"; +static char *test_share; -static char test_share[] = "/tmp/qtest.XXXXXX"; - -int main(int argc, char **argv) +static void qvirtio_9p_start(void) { char *args; - int ret; - g_test_init(&argc, &argv, NULL); - qtest_add_func("/virtio/9p/pci/nop", pci_nop); - - g_assert(mkdtemp(test_share)); + test_share = g_strdup("/tmp/qtest.XXXXXX"); + g_assert_nonnull(mkdtemp(test_share)); args = g_strdup_printf("-fsdev local,id=fsdev0,security_model=none,path=%s " - "-device virtio-9p-pci,fsdev=fsdev0,mount_tag=qtest", - test_share); + "-device virtio-9p-pci,fsdev=fsdev0,mount_tag=%s", + test_share, mount_tag); + qtest_start(args); g_free(args); +} - ret = g_test_run(); - +static void qvirtio_9p_stop(void) +{ qtest_end(); rmdir(test_share); + g_free(test_share); +} + +static void pci_nop(void) +{ + qvirtio_9p_start(); + qvirtio_9p_stop(); +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + qtest_add_func("/virtio/9p/pci/nop", pci_nop); - return ret; + return g_test_run(); } From 557a4cc04a7cd092e8b5d6ef5a1e6799ed10b163 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Fri, 16 Sep 2016 08:58:35 +0200 Subject: [PATCH 046/723] tests: virtio-9p: add basic configuration test This adds PCI init code and a basic test that checks the device config matches what is passed on the command line. Signed-off-by: Greg Kurz Acked-by: Cornelia Huck --- tests/Makefile.include | 2 +- tests/virtio-9p-test.c | 77 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 1 deletion(-) diff --git a/tests/Makefile.include b/tests/Makefile.include index 2f11064699d..6052a3828f6 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -627,7 +627,7 @@ tests/virtio-blk-test$(EXESUF): tests/virtio-blk-test.o $(libqos-virtio-obj-y) tests/virtio-net-test$(EXESUF): tests/virtio-net-test.o $(libqos-pc-obj-y) $(libqos-virtio-obj-y) tests/virtio-rng-test$(EXESUF): tests/virtio-rng-test.o $(libqos-pc-obj-y) tests/virtio-scsi-test$(EXESUF): tests/virtio-scsi-test.o $(libqos-virtio-obj-y) -tests/virtio-9p-test$(EXESUF): tests/virtio-9p-test.o +tests/virtio-9p-test$(EXESUF): tests/virtio-9p-test.o $(libqos-virtio-obj-y) tests/virtio-serial-test$(EXESUF): tests/virtio-serial-test.o tests/virtio-console-test$(EXESUF): tests/virtio-console-test.o tests/tpci200-test$(EXESUF): tests/tpci200-test.o diff --git a/tests/virtio-9p-test.c b/tests/virtio-9p-test.c index 45fc8041d7f..b8fb6cd869a 100644 --- a/tests/virtio-9p-test.c +++ b/tests/virtio-9p-test.c @@ -10,6 +10,13 @@ #include "qemu/osdep.h" #include "libqtest.h" #include "qemu-common.h" +#include "libqos/pci-pc.h" +#include "libqos/virtio.h" +#include "libqos/virtio-pci.h" +#include "libqos/malloc.h" +#include "libqos/malloc-pc.h" +#include "standard-headers/linux/virtio_ids.h" +#include "standard-headers/linux/virtio_pci.h" static const char mount_tag[] = "qtest"; static char *test_share; @@ -42,10 +49,80 @@ static void pci_nop(void) qvirtio_9p_stop(); } +typedef struct { + QVirtioDevice *dev; + QGuestAllocator *alloc; + QPCIBus *bus; + QVirtQueue *vq; +} QVirtIO9P; + +static QVirtIO9P *qvirtio_9p_pci_init(void) +{ + QVirtIO9P *v9p; + QVirtioPCIDevice *dev; + + v9p = g_new0(QVirtIO9P, 1); + v9p->alloc = pc_alloc_init(); + v9p->bus = qpci_init_pc(); + + dev = qvirtio_pci_device_find(v9p->bus, VIRTIO_ID_9P); + g_assert_nonnull(dev); + g_assert_cmphex(dev->vdev.device_type, ==, VIRTIO_ID_9P); + v9p->dev = (QVirtioDevice *) dev; + + qvirtio_pci_device_enable(dev); + qvirtio_reset(&qvirtio_pci, v9p->dev); + qvirtio_set_acknowledge(&qvirtio_pci, v9p->dev); + qvirtio_set_driver(&qvirtio_pci, v9p->dev); + + v9p->vq = qvirtqueue_setup(&qvirtio_pci, v9p->dev, v9p->alloc, 0); + return v9p; +} + +static void qvirtio_9p_pci_free(QVirtIO9P *v9p) +{ + qvirtqueue_cleanup(&qvirtio_pci, v9p->vq, v9p->alloc); + pc_alloc_uninit(v9p->alloc); + qvirtio_pci_device_disable(container_of(v9p->dev, QVirtioPCIDevice, vdev)); + g_free(v9p->dev); + qpci_free_pc(v9p->bus); + g_free(v9p); +} + +static void pci_basic_config(void) +{ + QVirtIO9P *v9p; + void *addr; + size_t tag_len; + char *tag; + int i; + + qvirtio_9p_start(); + v9p = qvirtio_9p_pci_init(); + + addr = ((QVirtioPCIDevice *) v9p->dev)->addr + VIRTIO_PCI_CONFIG_OFF(false); + tag_len = qvirtio_config_readw(&qvirtio_pci, v9p->dev, + (uint64_t)(uintptr_t)addr); + g_assert_cmpint(tag_len, ==, strlen(mount_tag)); + addr += sizeof(uint16_t); + + tag = g_malloc(tag_len); + for (i = 0; i < tag_len; i++) { + tag[i] = qvirtio_config_readb(&qvirtio_pci, v9p->dev, + (uint64_t)(uintptr_t)addr + i); + } + g_assert_cmpmem(tag, tag_len, mount_tag, tag_len); + g_free(tag); + + qvirtio_9p_pci_free(v9p); + qvirtio_9p_stop(); +} + int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); qtest_add_func("/virtio/9p/pci/nop", pci_nop); + qtest_add_func("/virtio/9p/pci/basic/configuration", pci_basic_config); return g_test_run(); } From 85aa80813dd9f5c1f581c743e45678a3bee220f8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 14 Jul 2016 12:43:06 -0700 Subject: [PATCH 047/723] tcg: Support arbitrary size + alignment Previously we allowed fully unaligned operations, but not operations that are aligned but with less alignment than the operation size. In addition, arm32, ia64, mips, and sparc had been omitted from the previous overalignment patch, which would have led to that alignment being enforced. Signed-off-by: Richard Henderson --- softmmu_template.h | 16 +++++----- tcg/aarch64/tcg-target.inc.c | 13 ++++---- tcg/arm/tcg-target.inc.c | 19 +++++++----- tcg/i386/tcg-target.inc.c | 19 ++++++------ tcg/ia64/tcg-target.inc.c | 22 +++++++++----- tcg/mips/tcg-target.inc.c | 11 +++++-- tcg/ppc/tcg-target.inc.c | 58 +++++++++++++++++++----------------- tcg/s390/tcg-target.inc.c | 15 ++++------ tcg/sparc/tcg-target.inc.c | 16 ++++++---- tcg/tcg.h | 51 ++++++++++++------------------- 10 files changed, 128 insertions(+), 112 deletions(-) diff --git a/softmmu_template.h b/softmmu_template.h index 284ab2c7b29..5b2eacb411e 100644 --- a/softmmu_template.h +++ b/softmmu_template.h @@ -146,14 +146,14 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, unsigned mmu_idx = get_mmuidx(oi); int index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); target_ulong tlb_addr = env->tlb_table[mmu_idx][index].ADDR_READ; - int a_bits = get_alignment_bits(get_memop(oi)); + unsigned a_bits = get_alignment_bits(get_memop(oi)); uintptr_t haddr; DATA_TYPE res; /* Adjust the given return address. */ retaddr -= GETPC_ADJ; - if (a_bits > 0 && (addr & ((1 << a_bits) - 1)) != 0) { + if (addr & ((1 << a_bits) - 1)) { cpu_unaligned_access(ENV_GET_CPU(env), addr, READ_ACCESS_TYPE, mmu_idx, retaddr); } @@ -220,14 +220,14 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, unsigned mmu_idx = get_mmuidx(oi); int index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); target_ulong tlb_addr = env->tlb_table[mmu_idx][index].ADDR_READ; - int a_bits = get_alignment_bits(get_memop(oi)); + unsigned a_bits = get_alignment_bits(get_memop(oi)); uintptr_t haddr; DATA_TYPE res; /* Adjust the given return address. */ retaddr -= GETPC_ADJ; - if (a_bits > 0 && (addr & ((1 << a_bits) - 1)) != 0) { + if (addr & ((1 << a_bits) - 1)) { cpu_unaligned_access(ENV_GET_CPU(env), addr, READ_ACCESS_TYPE, mmu_idx, retaddr); } @@ -331,13 +331,13 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, unsigned mmu_idx = get_mmuidx(oi); int index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); target_ulong tlb_addr = env->tlb_table[mmu_idx][index].addr_write; - int a_bits = get_alignment_bits(get_memop(oi)); + unsigned a_bits = get_alignment_bits(get_memop(oi)); uintptr_t haddr; /* Adjust the given return address. */ retaddr -= GETPC_ADJ; - if (a_bits > 0 && (addr & ((1 << a_bits) - 1)) != 0) { + if (addr & ((1 << a_bits) - 1)) { cpu_unaligned_access(ENV_GET_CPU(env), addr, MMU_DATA_STORE, mmu_idx, retaddr); } @@ -414,13 +414,13 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, unsigned mmu_idx = get_mmuidx(oi); int index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); target_ulong tlb_addr = env->tlb_table[mmu_idx][index].addr_write; - int a_bits = get_alignment_bits(get_memop(oi)); + unsigned a_bits = get_alignment_bits(get_memop(oi)); uintptr_t haddr; /* Adjust the given return address. */ retaddr -= GETPC_ADJ; - if (a_bits > 0 && (addr & ((1 << a_bits) - 1)) != 0) { + if (addr & ((1 << a_bits) - 1)) { cpu_unaligned_access(ENV_GET_CPU(env), addr, MMU_DATA_STORE, mmu_idx, retaddr); } diff --git a/tcg/aarch64/tcg-target.inc.c b/tcg/aarch64/tcg-target.inc.c index 08b2d031aa3..c8374b864fb 100644 --- a/tcg/aarch64/tcg-target.inc.c +++ b/tcg/aarch64/tcg-target.inc.c @@ -1081,23 +1081,24 @@ static void tcg_out_tlb_read(TCGContext *s, TCGReg addr_reg, TCGMemOp opc, int tlb_offset = is_read ? offsetof(CPUArchState, tlb_table[mem_index][0].addr_read) : offsetof(CPUArchState, tlb_table[mem_index][0].addr_write); - int a_bits = get_alignment_bits(opc); + unsigned a_bits = get_alignment_bits(opc); + unsigned s_bits = opc & MO_SIZE; + unsigned a_mask = (1u << a_bits) - 1; + unsigned s_mask = (1u << s_bits) - 1; TCGReg base = TCG_AREG0, x3; uint64_t tlb_mask; /* For aligned accesses, we check the first byte and include the alignment bits within the address. For unaligned access, we check that we don't cross pages using the address of the last byte of the access. */ - if (a_bits >= 0) { - /* A byte access or an alignment check required */ - tlb_mask = TARGET_PAGE_MASK | ((1 << a_bits) - 1); + if (a_bits >= s_bits) { x3 = addr_reg; } else { tcg_out_insn(s, 3401, ADDI, TARGET_LONG_BITS == 64, - TCG_REG_X3, addr_reg, (1 << (opc & MO_SIZE)) - 1); - tlb_mask = TARGET_PAGE_MASK; + TCG_REG_X3, addr_reg, s_mask - a_mask); x3 = TCG_REG_X3; } + tlb_mask = (uint64_t)TARGET_PAGE_MASK | a_mask; /* Extract the TLB index from the address into X0. X0 = diff --git a/tcg/arm/tcg-target.inc.c b/tcg/arm/tcg-target.inc.c index 172febafdd7..094f3f804da 100644 --- a/tcg/arm/tcg-target.inc.c +++ b/tcg/arm/tcg-target.inc.c @@ -1168,7 +1168,7 @@ QEMU_BUILD_BUG_ON(offsetof(CPUArchState, tlb_table[NB_MMU_MODES - 1][1]) containing the addend of the tlb entry. Clobbers R0, R1, R2, TMP. */ static TCGReg tcg_out_tlb_read(TCGContext *s, TCGReg addrlo, TCGReg addrhi, - TCGMemOp s_bits, int mem_index, bool is_load) + TCGMemOp opc, int mem_index, bool is_load) { TCGReg base = TCG_AREG0; int cmp_off = @@ -1176,6 +1176,8 @@ static TCGReg tcg_out_tlb_read(TCGContext *s, TCGReg addrlo, TCGReg addrhi, ? offsetof(CPUArchState, tlb_table[mem_index][0].addr_read) : offsetof(CPUArchState, tlb_table[mem_index][0].addr_write)); int add_off = offsetof(CPUArchState, tlb_table[mem_index][0].addend); + unsigned s_bits = opc & MO_SIZE; + unsigned a_bits = get_alignment_bits(opc); /* Should generate something like the following: * shr tmp, addrlo, #TARGET_PAGE_BITS (1) @@ -1216,10 +1218,13 @@ static TCGReg tcg_out_tlb_read(TCGContext *s, TCGReg addrlo, TCGReg addrhi, } } - /* Check alignment. */ - if (s_bits) { - tcg_out_dat_imm(s, COND_AL, ARITH_TST, - 0, addrlo, (1 << s_bits) - 1); + /* Check alignment. We don't support inline unaligned acceses, + but we can easily support overalignment checks. */ + if (a_bits < s_bits) { + a_bits = s_bits; + } + if (a_bits) { + tcg_out_dat_imm(s, COND_AL, ARITH_TST, 0, addrlo, (1 << a_bits) - 1); } /* Load the tlb addend. */ @@ -1499,7 +1504,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is64) #ifdef CONFIG_SOFTMMU mem_index = get_mmuidx(oi); - addend = tcg_out_tlb_read(s, addrlo, addrhi, opc & MO_SIZE, mem_index, 1); + addend = tcg_out_tlb_read(s, addrlo, addrhi, opc, mem_index, 1); /* This a conditional BL only to load a pointer within this opcode into LR for the slow path. We will not be using the value for a tail call. */ @@ -1630,7 +1635,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is64) #ifdef CONFIG_SOFTMMU mem_index = get_mmuidx(oi); - addend = tcg_out_tlb_read(s, addrlo, addrhi, opc & MO_SIZE, mem_index, 0); + addend = tcg_out_tlb_read(s, addrlo, addrhi, opc, mem_index, 0); tcg_out_qemu_st_index(s, COND_EQ, opc, datalo, datahi, addrlo, addend); diff --git a/tcg/i386/tcg-target.inc.c b/tcg/i386/tcg-target.inc.c index 6f8cdca7566..e30a122f199 100644 --- a/tcg/i386/tcg-target.inc.c +++ b/tcg/i386/tcg-target.inc.c @@ -1202,7 +1202,10 @@ static inline void tcg_out_tlb_load(TCGContext *s, TCGReg addrlo, TCGReg addrhi, TCGType ttype = TCG_TYPE_I32; TCGType tlbtype = TCG_TYPE_I32; int trexw = 0, hrexw = 0, tlbrexw = 0; - int a_bits = get_alignment_bits(opc); + unsigned a_bits = get_alignment_bits(opc); + unsigned s_bits = opc & MO_SIZE; + unsigned a_mask = (1 << a_bits) - 1; + unsigned s_mask = (1 << s_bits) - 1; target_ulong tlb_mask; if (TCG_TARGET_REG_BITS == 64) { @@ -1220,17 +1223,15 @@ static inline void tcg_out_tlb_load(TCGContext *s, TCGReg addrlo, TCGReg addrhi, } tcg_out_mov(s, tlbtype, r0, addrlo); - if (a_bits >= 0) { - /* A byte access or an alignment check required */ + /* If the required alignment is at least as large as the access, simply + copy the address and mask. For lesser alignments, check that we don't + cross pages for the complete access. */ + if (a_bits >= s_bits) { tcg_out_mov(s, ttype, r1, addrlo); - tlb_mask = TARGET_PAGE_MASK | ((1 << a_bits) - 1); } else { - /* For unaligned access check that we don't cross pages using - the page address of the last byte. */ - tcg_out_modrm_offset(s, OPC_LEA + trexw, r1, addrlo, - (1 << (opc & MO_SIZE)) - 1); - tlb_mask = TARGET_PAGE_MASK; + tcg_out_modrm_offset(s, OPC_LEA + trexw, r1, addrlo, s_mask - a_mask); } + tlb_mask = TARGET_PAGE_MASK | a_mask; tcg_out_shifti(s, SHIFT_SHR + tlbrexw, r0, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); diff --git a/tcg/ia64/tcg-target.inc.c b/tcg/ia64/tcg-target.inc.c index c91f39281b9..7642390b4b8 100644 --- a/tcg/ia64/tcg-target.inc.c +++ b/tcg/ia64/tcg-target.inc.c @@ -1496,10 +1496,18 @@ QEMU_BUILD_BUG_ON(offsetof(CPUArchState, tlb_table[NB_MMU_MODES - 1][1]) R1, R3 are clobbered, leaving R56 free for... BSWAP_1, BSWAP_2 and I-slot insns for swapping data for store. */ static inline void tcg_out_qemu_tlb(TCGContext *s, TCGReg addr_reg, - TCGMemOp s_bits, int off_rw, int off_add, + TCGMemOp opc, int off_rw, int off_add, uint64_t bswap1, uint64_t bswap2) { - /* + unsigned s_bits = opc & MO_SIZE; + unsigned a_bits = get_alignment_bits(opc); + + /* We don't support unaligned accesses, but overalignment is easy. */ + if (a_bits < s_bits) { + a_bits = s_bits; + } + + /* .mii mov r2 = off_rw extr.u r3 = addr_reg, ... # extract tlb page @@ -1521,7 +1529,7 @@ static inline void tcg_out_qemu_tlb(TCGContext *s, TCGReg addr_reg, cmp.eq p6, p7 = r3, r58 nop ;; - */ + */ tcg_out_bundle(s, miI, tcg_opc_movi_a(TCG_REG_P0, TCG_REG_R2, off_rw), tcg_opc_i11(TCG_REG_P0, OPC_EXTR_U_I11, TCG_REG_R3, @@ -1536,8 +1544,8 @@ static inline void tcg_out_qemu_tlb(TCGContext *s, TCGReg addr_reg, TCG_REG_R3, 63 - CPU_TLB_ENTRY_BITS, 63 - CPU_TLB_ENTRY_BITS), tcg_opc_i14(TCG_REG_P0, OPC_DEP_I14, TCG_REG_R1, 0, - TCG_REG_R57, 63 - s_bits, - TARGET_PAGE_BITS - s_bits - 1)); + TCG_REG_R57, 63 - a_bits, + TARGET_PAGE_BITS - a_bits - 1)); tcg_out_bundle(s, MmI, tcg_opc_a1 (TCG_REG_P0, OPC_ADD_A1, TCG_REG_R2, TCG_REG_R2, TCG_REG_R3), @@ -1661,7 +1669,7 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args) s_bits = opc & MO_SIZE; /* Read the TLB entry */ - tcg_out_qemu_tlb(s, addr_reg, s_bits, + tcg_out_qemu_tlb(s, addr_reg, opc, offsetof(CPUArchState, tlb_table[mem_index][0].addr_read), offsetof(CPUArchState, tlb_table[mem_index][0].addend), INSN_NOP_I, INSN_NOP_I); @@ -1739,7 +1747,7 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args) pre1 = tcg_opc_ext_i(TCG_REG_P0, opc, TCG_REG_R58, data_reg); } - tcg_out_qemu_tlb(s, addr_reg, s_bits, + tcg_out_qemu_tlb(s, addr_reg, opc, offsetof(CPUArchState, tlb_table[mem_index][0].addr_write), offsetof(CPUArchState, tlb_table[mem_index][0].addend), pre1, pre2); diff --git a/tcg/mips/tcg-target.inc.c b/tcg/mips/tcg-target.inc.c index 2f9be481398..acb6ff06c6d 100644 --- a/tcg/mips/tcg-target.inc.c +++ b/tcg/mips/tcg-target.inc.c @@ -1040,7 +1040,9 @@ static void tcg_out_tlb_load(TCGContext *s, TCGReg base, TCGReg addrl, TCGReg addrh, TCGMemOpIdx oi, tcg_insn_unit *label_ptr[2], bool is_load) { - TCGMemOp s_bits = get_memop(oi) & MO_SIZE; + TCGMemOp opc = get_memop(oi); + unsigned s_bits = opc & MO_SIZE; + unsigned a_bits = get_alignment_bits(opc); int mem_index = get_mmuidx(oi); int cmp_off = (is_load @@ -1071,10 +1073,15 @@ static void tcg_out_tlb_load(TCGContext *s, TCGReg base, TCGReg addrl, tcg_out_opc_imm(s, OPC_LW, TCG_TMP0, TCG_REG_A0, cmp_off + (TARGET_LONG_BITS == 64 ? LO_OFF : 0)); + /* We don't currently support unaligned accesses. + We could do so with mips32r6. */ + if (a_bits < s_bits) { + a_bits = s_bits; + } /* Mask the page bits, keeping the alignment bits to compare against. In between on 32-bit targets, load the tlb addend for the fast path. */ tcg_out_movi(s, TCG_TYPE_I32, TCG_TMP1, - TARGET_PAGE_MASK | ((1 << s_bits) - 1)); + TARGET_PAGE_MASK | ((1 << a_bits) - 1)); if (TARGET_LONG_BITS == 32) { tcg_out_opc_imm(s, OPC_LW, TCG_REG_A0, TCG_REG_A0, add_off); } diff --git a/tcg/ppc/tcg-target.inc.c b/tcg/ppc/tcg-target.inc.c index eaf1bd9bfdb..d79969096f1 100644 --- a/tcg/ppc/tcg-target.inc.c +++ b/tcg/ppc/tcg-target.inc.c @@ -1404,8 +1404,8 @@ static TCGReg tcg_out_tlb_read(TCGContext *s, TCGMemOp opc, : offsetof(CPUArchState, tlb_table[mem_index][0].addr_write)); int add_off = offsetof(CPUArchState, tlb_table[mem_index][0].addend); TCGReg base = TCG_AREG0; - TCGMemOp s_bits = opc & MO_SIZE; - int a_bits = get_alignment_bits(opc); + unsigned s_bits = opc & MO_SIZE; + unsigned a_bits = get_alignment_bits(opc); /* Extract the page index, shifted into place for tlb index. */ if (TCG_TARGET_REG_BITS == 64) { @@ -1458,39 +1458,43 @@ static TCGReg tcg_out_tlb_read(TCGContext *s, TCGMemOp opc, tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_R3, TCG_REG_R3, add_off); /* Clear the non-page, non-alignment bits from the address */ - if (TCG_TARGET_REG_BITS == 32 || TARGET_LONG_BITS == 32) { - /* We don't support unaligned accesses on 32-bits, preserve - * the bottom bits and thus trigger a comparison failure on - * unaligned accesses + if (TCG_TARGET_REG_BITS == 32) { + /* We don't support unaligned accesses on 32-bits. + * Preserve the bottom bits and thus trigger a comparison + * failure on unaligned accesses. */ - if (a_bits < 0) { + if (a_bits < s_bits) { a_bits = s_bits; } tcg_out_rlw(s, RLWINM, TCG_REG_R0, addrlo, 0, (32 - a_bits) & 31, 31 - TARGET_PAGE_BITS); - } else if (a_bits) { - /* More than byte access, we need to handle alignment */ - if (a_bits > 0) { - /* Alignment required by the front-end, same as 32-bits */ - tcg_out_rld(s, RLDICL, TCG_REG_R0, addrlo, + } else { + TCGReg t = addrlo; + + /* If the access is unaligned, we need to make sure we fail if we + * cross a page boundary. The trick is to add the access size-1 + * to the address before masking the low bits. That will make the + * address overflow to the next page if we cross a page boundary, + * which will then force a mismatch of the TLB compare. + */ + if (a_bits < s_bits) { + unsigned a_mask = (1 << a_bits) - 1; + unsigned s_mask = (1 << s_bits) - 1; + tcg_out32(s, ADDI | TAI(TCG_REG_R0, t, s_mask - a_mask)); + t = TCG_REG_R0; + } + + /* Mask the address for the requested alignment. */ + if (TARGET_LONG_BITS == 32) { + tcg_out_rlw(s, RLWINM, TCG_REG_R0, t, 0, + (32 - a_bits) & 31, 31 - TARGET_PAGE_BITS); + } else if (a_bits == 0) { + tcg_out_rld(s, RLDICR, TCG_REG_R0, t, 0, 63 - TARGET_PAGE_BITS); + } else { + tcg_out_rld(s, RLDICL, TCG_REG_R0, t, 64 - TARGET_PAGE_BITS, TARGET_PAGE_BITS - a_bits); tcg_out_rld(s, RLDICL, TCG_REG_R0, TCG_REG_R0, TARGET_PAGE_BITS, 0); - } else { - /* We support unaligned accesses, we need to make sure we fail - * if we cross a page boundary. The trick is to add the - * access_size-1 to the address before masking the low bits. - * That will make the address overflow to the next page if we - * cross a page boundary which will then force a mismatch of - * the TLB compare since the next page cannot possibly be in - * the same TLB index. - */ - tcg_out32(s, ADDI | TAI(TCG_REG_R0, addrlo, (1 << s_bits) - 1)); - tcg_out_rld(s, RLDICR, TCG_REG_R0, TCG_REG_R0, - 0, 63 - TARGET_PAGE_BITS); } - } else { - /* Byte access, just chop off the bits below the page index */ - tcg_out_rld(s, RLDICR, TCG_REG_R0, addrlo, 0, 63 - TARGET_PAGE_BITS); } if (TCG_TARGET_REG_BITS < TARGET_LONG_BITS) { diff --git a/tcg/s390/tcg-target.inc.c b/tcg/s390/tcg-target.inc.c index 5a7495b0638..f0c88de6d3d 100644 --- a/tcg/s390/tcg-target.inc.c +++ b/tcg/s390/tcg-target.inc.c @@ -1505,21 +1505,18 @@ QEMU_BUILD_BUG_ON(offsetof(CPUArchState, tlb_table[NB_MMU_MODES - 1][1]) static TCGReg tcg_out_tlb_read(TCGContext* s, TCGReg addr_reg, TCGMemOp opc, int mem_index, bool is_ld) { - int a_bits = get_alignment_bits(opc); + unsigned s_bits = opc & MO_SIZE; + unsigned a_bits = get_alignment_bits(opc); + unsigned s_mask = (1 << s_bits) - 1; + unsigned a_mask = (1 << a_bits) - 1; int ofs, a_off; uint64_t tlb_mask; /* For aligned accesses, we check the first byte and include the alignment bits within the address. For unaligned access, we check that we don't cross pages using the address of the last byte of the access. */ - if (a_bits >= 0) { - /* A byte access or an alignment check required */ - a_off = 0; - tlb_mask = TARGET_PAGE_MASK | ((1 << a_bits) - 1); - } else { - a_off = (1 << (opc & MO_SIZE)) - 1; - tlb_mask = TARGET_PAGE_MASK; - } + a_off = (a_bits >= s_bits ? 0 : s_mask - a_mask); + tlb_mask = (uint64_t)TARGET_PAGE_MASK | a_mask; if (facilities & FACILITY_GEN_INST_EXT) { tcg_out_risbg(s, TCG_REG_R2, addr_reg, diff --git a/tcg/sparc/tcg-target.inc.c b/tcg/sparc/tcg-target.inc.c index 8e98172ca04..92f8818a9ed 100644 --- a/tcg/sparc/tcg-target.inc.c +++ b/tcg/sparc/tcg-target.inc.c @@ -996,19 +996,25 @@ static void tcg_target_qemu_prologue(TCGContext *s) is in the returned register, maybe %o0. The TLB addend is in %o1. */ static TCGReg tcg_out_tlb_load(TCGContext *s, TCGReg addr, int mem_index, - TCGMemOp s_bits, int which) + TCGMemOp opc, int which) { const TCGReg r0 = TCG_REG_O0; const TCGReg r1 = TCG_REG_O1; const TCGReg r2 = TCG_REG_O2; + unsigned s_bits = opc & MO_SIZE; + unsigned a_bits = get_alignment_bits(opc); int tlb_ofs; /* Shift the page number down. */ tcg_out_arithi(s, r1, addr, TARGET_PAGE_BITS, SHIFT_SRL); - /* Mask out the page offset, except for the required alignment. */ + /* Mask out the page offset, except for the required alignment. + We don't support unaligned accesses. */ + if (a_bits < s_bits) { + a_bits = s_bits; + } tcg_out_movi(s, TCG_TYPE_TL, TCG_REG_T1, - TARGET_PAGE_MASK | ((1 << s_bits) - 1)); + TARGET_PAGE_MASK | ((1 << a_bits) - 1)); /* Mask the tlb index. */ tcg_out_arithi(s, r1, r1, CPU_TLB_SIZE - 1, ARITH_AND); @@ -1087,7 +1093,7 @@ static void tcg_out_qemu_ld(TCGContext *s, TCGReg data, TCGReg addr, tcg_insn_unit *func; tcg_insn_unit *label_ptr; - addrz = tcg_out_tlb_load(s, addr, memi, memop & MO_SIZE, + addrz = tcg_out_tlb_load(s, addr, memi, memop, offsetof(CPUTLBEntry, addr_read)); /* The fast path is exactly one insn. Thus we can perform the @@ -1169,7 +1175,7 @@ static void tcg_out_qemu_st(TCGContext *s, TCGReg data, TCGReg addr, tcg_insn_unit *func; tcg_insn_unit *label_ptr; - addrz = tcg_out_tlb_load(s, addr, memi, memop & MO_SIZE, + addrz = tcg_out_tlb_load(s, addr, memi, memop, offsetof(CPUTLBEntry, addr_write)); /* The fast path is exactly one insn. Thus we can perform the entire diff --git a/tcg/tcg.h b/tcg/tcg.h index 9bf31bbc84b..0384d7adf03 100644 --- a/tcg/tcg.h +++ b/tcg/tcg.h @@ -287,20 +287,19 @@ typedef enum TCGMemOp { * MO_ALIGN accesses will result in a call to the CPU's * do_unaligned_access hook if the guest address is not aligned. * The default depends on whether the target CPU defines ALIGNED_ONLY. + * * Some architectures (e.g. ARMv8) need the address which is aligned * to a size more than the size of the memory access. - * To support such check it's enough the current costless alignment - * check implementation in QEMU, but we need to support - * an alignment size specifying. - * MO_ALIGN supposes a natural alignment - * (i.e. the alignment size is the size of a memory access). - * Note that an alignment size must be equal or greater - * than an access size. + * Some architectures (e.g. SPARCv9) need an address which is aligned, + * but less strictly than the natural alignment. + * + * MO_ALIGN supposes the alignment size is the size of a memory access. + * * There are three options: - * - an alignment to the size of an access (MO_ALIGN); - * - an alignment to the specified size that is equal or greater than - * an access size (MO_ALIGN_x where 'x' is a size in bytes); * - unaligned access permitted (MO_UNALN). + * - an alignment to the size of an access (MO_ALIGN); + * - an alignment to a specified size, which may be more or less than + * the access size (MO_ALIGN_x where 'x' is a size in bytes); */ MO_ASHIFT = 4, MO_AMASK = 7 << MO_ASHIFT, @@ -353,38 +352,26 @@ typedef enum TCGMemOp { * @memop: TCGMemOp value * * Extract the alignment size from the memop. - * - * Returns: 0 in case of byte access (which is always aligned); - * positive value - number of alignment bits; - * negative value if unaligned access enabled - * and this is not a byte access. */ -static inline int get_alignment_bits(TCGMemOp memop) +static inline unsigned get_alignment_bits(TCGMemOp memop) { - int a = memop & MO_AMASK; - int s = memop & MO_SIZE; - int r; + unsigned a = memop & MO_AMASK; if (a == MO_UNALN) { - /* Negative value if unaligned access enabled, - * or zero value in case of byte access. - */ - return -s; + /* No alignment required. */ + a = 0; } else if (a == MO_ALIGN) { - /* A natural alignment: return a number of access size bits */ - r = s; + /* A natural alignment requirement. */ + a = memop & MO_SIZE; } else { - /* Specific alignment size. It must be equal or greater - * than the access size. - */ - r = a >> MO_ASHIFT; - tcg_debug_assert(r >= s); + /* A specific alignment requirement. */ + a = a >> MO_ASHIFT; } #if defined(CONFIG_SOFTMMU) /* The requested alignment cannot overlap the TLB flags. */ - tcg_debug_assert((TLB_FLAGS_MASK & ((1 << r) - 1)) == 0); + tcg_debug_assert((TLB_FLAGS_MASK & ((1 << a) - 1)) == 0); #endif - return r; + return a; } typedef tcg_target_ulong TCGArg; From 01ecaf438b1eb46abe23392c8ce5b7628b0c8cf5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 26 Jul 2016 06:09:16 +0530 Subject: [PATCH 048/723] tcg: Merge GETPC and GETRA The return address argument to the softmmu template helpers was confused. In the legacy case, we wanted to indicate that there is no return address, and so passed in NULL. However, we then immediately subtracted GETPC_ADJ from NULL, resulting in a non-zero value, indicating the presence of an (invalid) return address. Push the GETPC_ADJ subtraction down to the only point it's required: immediately before use within cpu_restore_state_from_tb, after all NULL pointer checks have been completed. This makes GETPC and GETRA identical. Remove GETRA as the lesser used macro, replacing all uses with GETPC. Signed-off-by: Richard Henderson --- cputlb.c | 6 ++---- include/exec/exec-all.h | 9 +++------ softmmu_template.h | 32 ++++++-------------------------- target-arm/helper.c | 6 +++--- target-mips/op_helper.c | 18 +++++++++--------- translate-all.c | 2 ++ user-exec.c | 7 +++++-- 7 files changed, 30 insertions(+), 50 deletions(-) diff --git a/cputlb.c b/cputlb.c index d068ee597ef..3c99c34ac8b 100644 --- a/cputlb.c +++ b/cputlb.c @@ -543,10 +543,8 @@ static bool victim_tlb_hit(CPUArchState *env, size_t mmu_idx, size_t index, #undef MMUSUFFIX #define MMUSUFFIX _cmmu -#undef GETPC_ADJ -#define GETPC_ADJ 0 -#undef GETRA -#define GETRA() ((uintptr_t)0) +#undef GETPC +#define GETPC() ((uintptr_t)0) #define SOFTMMU_CODE_ACCESS #define SHIFT 0 diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index a0e87be88f9..008e09a3c14 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -349,13 +349,12 @@ static inline void tb_add_jump(TranslationBlock *tb, int n, tb_next->jmp_list_first = (uintptr_t)tb | n; } -/* GETRA is the true target of the return instruction that we'll execute, - defined here for simplicity of defining the follow-up macros. */ +/* GETPC is the true target of the return instruction that we'll execute. */ #if defined(CONFIG_TCG_INTERPRETER) extern uintptr_t tci_tb_ptr; -# define GETRA() tci_tb_ptr +# define GETPC() tci_tb_ptr #else -# define GETRA() \ +# define GETPC() \ ((uintptr_t)__builtin_extract_return_addr(__builtin_return_address(0))) #endif @@ -368,8 +367,6 @@ extern uintptr_t tci_tb_ptr; smaller than 4 bytes, so we don't worry about special-casing this. */ #define GETPC_ADJ 2 -#define GETPC() (GETRA() - GETPC_ADJ) - #if !defined(CONFIG_USER_ONLY) struct MemoryRegion *iotlb_to_region(CPUState *cpu, diff --git a/softmmu_template.h b/softmmu_template.h index 5b2eacb411e..27ed2694df2 100644 --- a/softmmu_template.h +++ b/softmmu_template.h @@ -150,9 +150,6 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, uintptr_t haddr; DATA_TYPE res; - /* Adjust the given return address. */ - retaddr -= GETPC_ADJ; - if (addr & ((1 << a_bits) - 1)) { cpu_unaligned_access(ENV_GET_CPU(env), addr, READ_ACCESS_TYPE, mmu_idx, retaddr); @@ -193,10 +190,8 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, do_unaligned_access: addr1 = addr & ~(DATA_SIZE - 1); addr2 = addr1 + DATA_SIZE; - /* Note the adjustment at the beginning of the function. - Undo that for the recursion. */ - res1 = helper_le_ld_name(env, addr1, oi, retaddr + GETPC_ADJ); - res2 = helper_le_ld_name(env, addr2, oi, retaddr + GETPC_ADJ); + res1 = helper_le_ld_name(env, addr1, oi, retaddr); + res2 = helper_le_ld_name(env, addr2, oi, retaddr); shift = (addr & (DATA_SIZE - 1)) * 8; /* Little-endian combine. */ @@ -224,9 +219,6 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, uintptr_t haddr; DATA_TYPE res; - /* Adjust the given return address. */ - retaddr -= GETPC_ADJ; - if (addr & ((1 << a_bits) - 1)) { cpu_unaligned_access(ENV_GET_CPU(env), addr, READ_ACCESS_TYPE, mmu_idx, retaddr); @@ -267,10 +259,8 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, do_unaligned_access: addr1 = addr & ~(DATA_SIZE - 1); addr2 = addr1 + DATA_SIZE; - /* Note the adjustment at the beginning of the function. - Undo that for the recursion. */ - res1 = helper_be_ld_name(env, addr1, oi, retaddr + GETPC_ADJ); - res2 = helper_be_ld_name(env, addr2, oi, retaddr + GETPC_ADJ); + res1 = helper_be_ld_name(env, addr1, oi, retaddr); + res2 = helper_be_ld_name(env, addr2, oi, retaddr); shift = (addr & (DATA_SIZE - 1)) * 8; /* Big-endian combine. */ @@ -334,9 +324,6 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, unsigned a_bits = get_alignment_bits(get_memop(oi)); uintptr_t haddr; - /* Adjust the given return address. */ - retaddr -= GETPC_ADJ; - if (addr & ((1 << a_bits) - 1)) { cpu_unaligned_access(ENV_GET_CPU(env), addr, MMU_DATA_STORE, mmu_idx, retaddr); @@ -391,10 +378,8 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, for (i = 0; i < DATA_SIZE; ++i) { /* Little-endian extract. */ uint8_t val8 = val >> (i * 8); - /* Note the adjustment at the beginning of the function. - Undo that for the recursion. */ glue(helper_ret_stb, MMUSUFFIX)(env, addr + i, val8, - oi, retaddr + GETPC_ADJ); + oi, retaddr); } return; } @@ -417,9 +402,6 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, unsigned a_bits = get_alignment_bits(get_memop(oi)); uintptr_t haddr; - /* Adjust the given return address. */ - retaddr -= GETPC_ADJ; - if (addr & ((1 << a_bits) - 1)) { cpu_unaligned_access(ENV_GET_CPU(env), addr, MMU_DATA_STORE, mmu_idx, retaddr); @@ -474,10 +456,8 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, for (i = 0; i < DATA_SIZE; ++i) { /* Big-endian extract. */ uint8_t val8 = val >> (((DATA_SIZE - 1) * 8) - (i * 8)); - /* Note the adjustment at the beginning of the function. - Undo that for the recursion. */ glue(helper_ret_stb, MMUSUFFIX)(env, addr + i, val8, - oi, retaddr + GETPC_ADJ); + oi, retaddr); } return; } diff --git a/target-arm/helper.c b/target-arm/helper.c index 5484c15d1af..25f612d4935 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -8310,12 +8310,12 @@ void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in) * this purpose use the actual register value passed to us * so that we get the fault address right. */ - helper_ret_stb_mmu(env, vaddr_in, 0, oi, GETRA()); + helper_ret_stb_mmu(env, vaddr_in, 0, oi, GETPC()); /* Now we can populate the other TLB entries, if any */ for (i = 0; i < maxidx; i++) { uint64_t va = vaddr + TARGET_PAGE_SIZE * i; if (va != (vaddr_in & TARGET_PAGE_MASK)) { - helper_ret_stb_mmu(env, va, 0, oi, GETRA()); + helper_ret_stb_mmu(env, va, 0, oi, GETPC()); } } } @@ -8332,7 +8332,7 @@ void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in) * bounce buffer was in use */ for (i = 0; i < blocklen; i++) { - helper_ret_stb_mmu(env, vaddr + i, 0, oi, GETRA()); + helper_ret_stb_mmu(env, vaddr + i, 0, oi, GETPC()); } } #else diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index ea2f2abe198..7af4c2f0847 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -4122,10 +4122,10 @@ void helper_msa_ld_ ## TYPE(CPUMIPSState *env, uint32_t wd, \ } #if !defined(CONFIG_USER_ONLY) -MSA_LD_DF(DF_BYTE, b, helper_ret_ldub_mmu, oi, GETRA()) -MSA_LD_DF(DF_HALF, h, helper_ret_lduw_mmu, oi, GETRA()) -MSA_LD_DF(DF_WORD, w, helper_ret_ldul_mmu, oi, GETRA()) -MSA_LD_DF(DF_DOUBLE, d, helper_ret_ldq_mmu, oi, GETRA()) +MSA_LD_DF(DF_BYTE, b, helper_ret_ldub_mmu, oi, GETPC()) +MSA_LD_DF(DF_HALF, h, helper_ret_lduw_mmu, oi, GETPC()) +MSA_LD_DF(DF_WORD, w, helper_ret_ldul_mmu, oi, GETPC()) +MSA_LD_DF(DF_DOUBLE, d, helper_ret_ldq_mmu, oi, GETPC()) #else MSA_LD_DF(DF_BYTE, b, cpu_ldub_data) MSA_LD_DF(DF_HALF, h, cpu_lduw_data) @@ -4161,17 +4161,17 @@ void helper_msa_st_ ## TYPE(CPUMIPSState *env, uint32_t wd, \ int mmu_idx = cpu_mmu_index(env, false); \ int i; \ MEMOP_IDX(DF) \ - ensure_writable_pages(env, addr, mmu_idx, GETRA()); \ + ensure_writable_pages(env, addr, mmu_idx, GETPC()); \ for (i = 0; i < DF_ELEMENTS(DF); i++) { \ ST_INSN(env, addr + (i << DF), pwd->TYPE[i], ##__VA_ARGS__); \ } \ } #if !defined(CONFIG_USER_ONLY) -MSA_ST_DF(DF_BYTE, b, helper_ret_stb_mmu, oi, GETRA()) -MSA_ST_DF(DF_HALF, h, helper_ret_stw_mmu, oi, GETRA()) -MSA_ST_DF(DF_WORD, w, helper_ret_stl_mmu, oi, GETRA()) -MSA_ST_DF(DF_DOUBLE, d, helper_ret_stq_mmu, oi, GETRA()) +MSA_ST_DF(DF_BYTE, b, helper_ret_stb_mmu, oi, GETPC()) +MSA_ST_DF(DF_HALF, h, helper_ret_stw_mmu, oi, GETPC()) +MSA_ST_DF(DF_WORD, w, helper_ret_stl_mmu, oi, GETPC()) +MSA_ST_DF(DF_DOUBLE, d, helper_ret_stq_mmu, oi, GETPC()) #else MSA_ST_DF(DF_BYTE, b, cpu_stb_data) MSA_ST_DF(DF_HALF, h, cpu_stw_data) diff --git a/translate-all.c b/translate-all.c index b6663dc91d6..e9bc90c6543 100644 --- a/translate-all.c +++ b/translate-all.c @@ -260,6 +260,8 @@ static int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb, int64_t ti = profile_getclock(); #endif + searched_pc -= GETPC_ADJ; + if (searched_pc < host_pc) { return -1; } diff --git a/user-exec.c b/user-exec.c index 95f9f97c5c8..6db075884d9 100644 --- a/user-exec.c +++ b/user-exec.c @@ -105,8 +105,11 @@ static inline int handle_cpu_signal(uintptr_t pc, unsigned long address, if (ret == 0) { return 1; /* the MMU fault was handled without causing real CPU fault */ } - /* now we have a real cpu fault */ - cpu_restore_state(cpu, pc); + + /* Now we have a real cpu fault. Since this is the exact location of + * the exception, we must undo the adjustment done by cpu_restore_state + * for handling call return addresses. */ + cpu_restore_state(cpu, pc + GETPC_ADJ); sigprocmask(SIG_SETMASK, old_set, NULL); cpu_loop_exit(cpu); From be2208e2a50f4b50980d92c26f2e12cb2bda4afc Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 12 Jul 2016 23:39:16 -0700 Subject: [PATCH 049/723] cpu-exec: Check -dfilter for -d cpu Signed-off-by: Richard Henderson --- cpu-exec.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cpu-exec.c b/cpu-exec.c index b240b9fa45a..9f4bd0b6dd8 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -147,7 +147,8 @@ static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, TranslationBlock *itb) itb->tc_ptr, itb->pc, lookup_symbol(itb->pc)); #if defined(DEBUG_DISAS) - if (qemu_loglevel_mask(CPU_LOG_TB_CPU)) { + if (qemu_loglevel_mask(CPU_LOG_TB_CPU) + && qemu_log_in_addr_range(itb->pc)) { #if defined(TARGET_I386) log_cpu_state(cpu, CPU_DUMP_CCOP); #elif defined(TARGET_M68K) From f65e19bc2c9e8358e634d309606144ac2a3c2936 Mon Sep 17 00:00:00 2001 From: Pranith Kumar Date: Thu, 14 Jul 2016 16:20:13 -0400 Subject: [PATCH 050/723] Introduce TCGOpcode for memory barrier This commit introduces the TCGOpcode for memory barrier instruction. This opcode takes an argument which is the type of memory barrier which should be generated. Signed-off-by: Pranith Kumar Message-Id: <20160714202026.9727-2-bobby.prani@gmail.com> Signed-off-by: Richard Henderson --- tcg/README | 17 +++++++++++++++++ tcg/tcg-op.c | 17 +++++++++++++++++ tcg/tcg-op.h | 2 ++ tcg/tcg-opc.h | 2 ++ tcg/tcg.h | 17 +++++++++++++++++ 5 files changed, 55 insertions(+) diff --git a/tcg/README b/tcg/README index ce8bebab372..1d48aa963f1 100644 --- a/tcg/README +++ b/tcg/README @@ -402,6 +402,23 @@ double-word product T0. The later is returned in two single-word outputs. Similar to mulu2, except the two inputs T1 and T2 are signed. +********* Memory Barrier support + +* mb <$arg> + +Generate a target memory barrier instruction to ensure memory ordering as being +enforced by a corresponding guest memory barrier instruction. The ordering +enforced by the backend may be stricter than the ordering required by the guest. +It cannot be weaker. This opcode takes a constant argument which is required to +generate the appropriate barrier instruction. The backend should take care to +emit the target barrier instruction only when necessary i.e., for SMP guests and +when MTTCG is enabled. + +The guest translators should generate this opcode for all guest instructions +which have ordering side effects. + +Please see docs/atomics.txt for more information on memory barriers. + ********* 64-bit guest on 32-bit host support The following opcodes are internal to TCG. Thus they are to be implemented by diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 0243c99094e..291d50bb7d5 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -148,6 +148,23 @@ void tcg_gen_op6(TCGContext *ctx, TCGOpcode opc, TCGArg a1, TCGArg a2, tcg_emit_op(ctx, opc, pi); } +void tcg_gen_mb(TCGBar mb_type) +{ + bool emit_barriers = true; + +#ifndef CONFIG_USER_ONLY + /* TODO: When MTTCG is available for system mode, we will check + * the following condition and enable emit_barriers + * (qemu_tcg_mttcg_enabled() && smp_cpus > 1) + */ + emit_barriers = false; +#endif + + if (emit_barriers) { + tcg_gen_op1(&tcg_ctx, INDEX_op_mb, mb_type); + } +} + /* 32 bit ops */ void tcg_gen_addi_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h index f217e807471..02cb3766819 100644 --- a/tcg/tcg-op.h +++ b/tcg/tcg-op.h @@ -261,6 +261,8 @@ static inline void tcg_gen_br(TCGLabel *l) tcg_gen_op1(&tcg_ctx, INDEX_op_br, label_arg(l)); } +void tcg_gen_mb(TCGBar); + /* Helper calls. */ /* 32 bit ops */ diff --git a/tcg/tcg-opc.h b/tcg/tcg-opc.h index 6d0410c4b9a..45528d2192e 100644 --- a/tcg/tcg-opc.h +++ b/tcg/tcg-opc.h @@ -42,6 +42,8 @@ DEF(br, 0, 0, 1, TCG_OPF_BB_END) # define IMPL64 TCG_OPF_64BIT #endif +DEF(mb, 0, 0, 1, 0) + DEF(mov_i32, 1, 1, 0, TCG_OPF_NOT_PRESENT) DEF(movi_i32, 1, 0, 1, TCG_OPF_NOT_PRESENT) DEF(setcond_i32, 1, 2, 1, 0) diff --git a/tcg/tcg.h b/tcg/tcg.h index 0384d7adf03..c9949aa79b6 100644 --- a/tcg/tcg.h +++ b/tcg/tcg.h @@ -465,6 +465,23 @@ static inline intptr_t QEMU_ARTIFICIAL GET_TCGV_PTR(TCGv_ptr t) #define TCG_CALL_DUMMY_TCGV MAKE_TCGV_I32(-1) #define TCG_CALL_DUMMY_ARG ((TCGArg)(-1)) +typedef enum { + /* Used to indicate the type of accesses on which ordering + is to be ensured. Modeled after SPARC barriers. */ + TCG_MO_LD_LD = 0x01, + TCG_MO_ST_LD = 0x02, + TCG_MO_LD_ST = 0x04, + TCG_MO_ST_ST = 0x08, + TCG_MO_ALL = 0x0F, /* OR of the above */ + + /* Used to indicate the kind of ordering which is to be ensured by the + instruction. These types are derived from x86/aarch64 instructions. + It should be noted that these are different from C11 semantics. */ + TCG_BAR_LDAQ = 0x10, /* Following ops will not come forward */ + TCG_BAR_STRL = 0x20, /* Previous ops will not be delayed */ + TCG_BAR_SC = 0x30, /* No ops cross barrier; OR of the above */ +} TCGBar; + /* Conditions. Note that these are laid out for easy manipulation by the functions below: bit 0 is used for inverting; From a7d00d4effb58889ac6df64f98ac50c9d1594149 Mon Sep 17 00:00:00 2001 From: Pranith Kumar Date: Thu, 14 Jul 2016 16:20:14 -0400 Subject: [PATCH 051/723] tcg/i386: Add support for fence Generate a 'lock orl $0,0(%esp)' instruction for ordering instead of mfence which has similar ordering semantics. Signed-off-by: Pranith Kumar Message-Id: <20160714202026.9727-3-bobby.prani@gmail.com> Signed-off-by: Richard Henderson --- tcg/i386/tcg-target.inc.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tcg/i386/tcg-target.inc.c b/tcg/i386/tcg-target.inc.c index e30a122f199..cf7536bd52b 100644 --- a/tcg/i386/tcg-target.inc.c +++ b/tcg/i386/tcg-target.inc.c @@ -686,6 +686,18 @@ static inline void tcg_out_pushi(TCGContext *s, tcg_target_long val) } } +static inline void tcg_out_mb(TCGContext *s, TCGArg a0) +{ + /* Given the strength of x86 memory ordering, we only need care for + store-load ordering. Experimentally, "lock orl $0,0(%esp)" is + faster than "mfence", so don't bother with the sse insn. */ + if (a0 & TCG_MO_ST_LD) { + tcg_out8(s, 0xf0); + tcg_out_modrm_offset(s, OPC_ARITH_EvIb, ARITH_OR, TCG_REG_ESP, 0); + tcg_out8(s, 0); + } +} + static inline void tcg_out_push(TCGContext *s, int reg) { tcg_out_opc(s, OPC_PUSH_r32 + LOWREGMASK(reg), 0, reg, 0); @@ -2131,6 +2143,9 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, } break; + case INDEX_op_mb: + tcg_out_mb(s, args[0]); + break; case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */ case INDEX_op_mov_i64: case INDEX_op_movi_i32: /* Always emitted via tcg_out_movi. */ @@ -2196,6 +2211,8 @@ static const TCGTargetOpDef x86_op_defs[] = { { INDEX_op_add2_i32, { "r", "r", "0", "1", "ri", "ri" } }, { INDEX_op_sub2_i32, { "r", "r", "0", "1", "ri", "ri" } }, + { INDEX_op_mb, { } }, + #if TCG_TARGET_REG_BITS == 32 { INDEX_op_brcond2_i32, { "r", "r", "ri", "ri" } }, { INDEX_op_setcond2_i32, { "r", "r", "r", "ri", "ri" } }, From c7a59c2a92592e556b9361437c9c4229917bd1e3 Mon Sep 17 00:00:00 2001 From: Pranith Kumar Date: Thu, 14 Jul 2016 16:20:15 -0400 Subject: [PATCH 052/723] tcg/aarch64: Add support for fence Cc: Claudio Fontana Signed-off-by: Pranith Kumar Message-Id: <20160714202026.9727-4-bobby.prani@gmail.com> Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.inc.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tcg/aarch64/tcg-target.inc.c b/tcg/aarch64/tcg-target.inc.c index c8374b864fb..1939d3528f2 100644 --- a/tcg/aarch64/tcg-target.inc.c +++ b/tcg/aarch64/tcg-target.inc.c @@ -372,6 +372,11 @@ typedef enum { I3510_EOR = 0x4a000000, I3510_EON = 0x4a200000, I3510_ANDS = 0x6a000000, + + /* System instructions. */ + DMB_ISH = 0xd50338bf, + DMB_LD = 0x00000100, + DMB_ST = 0x00000200, } AArch64Insn; static inline uint32_t tcg_in32(TCGContext *s) @@ -981,6 +986,18 @@ static inline void tcg_out_addsub2(TCGContext *s, int ext, TCGReg rl, tcg_out_mov(s, ext, orig_rl, rl); } +static inline void tcg_out_mb(TCGContext *s, TCGArg a0) +{ + static const uint32_t sync[] = { + [0 ... TCG_MO_ALL] = DMB_ISH | DMB_LD | DMB_ST, + [TCG_MO_ST_ST] = DMB_ISH | DMB_ST, + [TCG_MO_LD_LD] = DMB_ISH | DMB_LD, + [TCG_MO_LD_ST] = DMB_ISH | DMB_LD, + [TCG_MO_LD_ST | TCG_MO_LD_LD] = DMB_ISH | DMB_LD, + }; + tcg_out32(s, sync[a0 & TCG_MO_ALL]); +} + #ifdef CONFIG_SOFTMMU /* helper signature: helper_ret_ld_mmu(CPUState *env, target_ulong addr, * TCGMemOpIdx oi, uintptr_t ra) @@ -1649,6 +1666,10 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, tcg_out_insn(s, 3508, SMULH, TCG_TYPE_I64, a0, a1, a2); break; + case INDEX_op_mb: + tcg_out_mb(s, a0); + break; + case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */ case INDEX_op_mov_i64: case INDEX_op_movi_i32: /* Always emitted via tcg_out_movi. */ @@ -1773,6 +1794,7 @@ static const TCGTargetOpDef aarch64_op_defs[] = { { INDEX_op_muluh_i64, { "r", "r", "r" } }, { INDEX_op_mulsh_i64, { "r", "r", "r" } }, + { INDEX_op_mb, { } }, { -1 }, }; From 40f191ab8226fdada185efa49c44b60d8f494890 Mon Sep 17 00:00:00 2001 From: Pranith Kumar Date: Thu, 14 Jul 2016 16:20:16 -0400 Subject: [PATCH 053/723] tcg/arm: Add support for fence Cc: Andrzej Zaborowski Cc: Peter Maydell Signed-off-by: Pranith Kumar Message-Id: <20160714202026.9727-5-bobby.prani@gmail.com> Signed-off-by: Richard Henderson --- tcg/arm/tcg-target.inc.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tcg/arm/tcg-target.inc.c b/tcg/arm/tcg-target.inc.c index 094f3f804da..ffa0d40660a 100644 --- a/tcg/arm/tcg-target.inc.c +++ b/tcg/arm/tcg-target.inc.c @@ -313,6 +313,10 @@ typedef enum { INSN_LDRD_REG = 0x000000d0, INSN_STRD_IMM = 0x004000f0, INSN_STRD_REG = 0x000000f0, + + INSN_DMB_ISH = 0x5bf07ff5, + INSN_DMB_MCR = 0xba0f07ee, + } ARMInsn; #define SHIFT_IMM_LSL(im) (((im) << 7) | 0x00) @@ -1066,6 +1070,15 @@ static inline void tcg_out_goto_label(TCGContext *s, int cond, TCGLabel *l) } } +static inline void tcg_out_mb(TCGContext *s, TCGArg a0) +{ + if (use_armv7_instructions) { + tcg_out32(s, INSN_DMB_ISH); + } else if (use_armv6_instructions) { + tcg_out32(s, INSN_DMB_MCR); + } +} + #ifdef CONFIG_SOFTMMU /* helper signature: helper_ret_ld_mmu(CPUState *env, target_ulong addr, * int mmu_idx, uintptr_t ra) @@ -1928,6 +1941,10 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, tcg_out_udiv(s, COND_AL, args[0], args[1], args[2]); break; + case INDEX_op_mb: + tcg_out_mb(s, args[0]); + break; + case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */ case INDEX_op_movi_i32: /* Always emitted via tcg_out_movi. */ case INDEX_op_call: /* Always emitted via tcg_out_call. */ @@ -2002,6 +2019,7 @@ static const TCGTargetOpDef arm_op_defs[] = { { INDEX_op_div_i32, { "r", "r", "r" } }, { INDEX_op_divu_i32, { "r", "r", "r" } }, + { INDEX_op_mb, { } }, { -1 }, }; From 5bbadbdfd6d9fb8729901124233dfca9f1f9554d Mon Sep 17 00:00:00 2001 From: Pranith Kumar Date: Thu, 14 Jul 2016 16:20:17 -0400 Subject: [PATCH 054/723] tcg/ia64: Add support for fence Cc: Aurelien Jarno Signed-off-by: Pranith Kumar Message-Id: <20160714202026.9727-6-bobby.prani@gmail.com> Signed-off-by: Richard Henderson --- tcg/ia64/tcg-target.inc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tcg/ia64/tcg-target.inc.c b/tcg/ia64/tcg-target.inc.c index 7642390b4b8..b04d716c3da 100644 --- a/tcg/ia64/tcg-target.inc.c +++ b/tcg/ia64/tcg-target.inc.c @@ -247,6 +247,7 @@ enum { OPC_LD4_M3 = 0x0a080000000ull, OPC_LD8_M1 = 0x080c0000000ull, OPC_LD8_M3 = 0x0a0c0000000ull, + OPC_MF_M24 = 0x00110000000ull, OPC_MUX1_I3 = 0x0eca0000000ull, OPC_NOP_B9 = 0x04008000000ull, OPC_NOP_F16 = 0x00008000000ull, @@ -2231,6 +2232,9 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, tcg_out_qemu_st(s, args); break; + case INDEX_op_mb: + tcg_out_bundle(s, mmI, OPC_MF_M24, INSN_NOP_M, INSN_NOP_I); + break; case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */ case INDEX_op_mov_i64: case INDEX_op_movi_i32: /* Always emitted via tcg_out_movi. */ @@ -2344,6 +2348,7 @@ static const TCGTargetOpDef ia64_op_defs[] = { { INDEX_op_qemu_st_i32, { "SZ", "r" } }, { INDEX_op_qemu_st_i64, { "SZ", "r" } }, + { INDEX_op_mb, { } }, { -1 }, }; From 6f0b99104a396905870edc3049310ece29b6b8d6 Mon Sep 17 00:00:00 2001 From: Pranith Kumar Date: Thu, 14 Jul 2016 16:20:18 -0400 Subject: [PATCH 055/723] tcg/mips: Add support for fence Signed-off-by: Pranith Kumar Message-Id: <20160714202026.9727-7-bobby.prani@gmail.com> Signed-off-by: Richard Henderson --- tcg/mips/tcg-target.inc.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tcg/mips/tcg-target.inc.c b/tcg/mips/tcg-target.inc.c index acb6ff06c6d..abce6026f86 100644 --- a/tcg/mips/tcg-target.inc.c +++ b/tcg/mips/tcg-target.inc.c @@ -292,6 +292,7 @@ typedef enum { OPC_JALR = OPC_SPECIAL | 0x09, OPC_MOVZ = OPC_SPECIAL | 0x0A, OPC_MOVN = OPC_SPECIAL | 0x0B, + OPC_SYNC = OPC_SPECIAL | 0x0F, OPC_MFHI = OPC_SPECIAL | 0x10, OPC_MFLO = OPC_SPECIAL | 0x12, OPC_MULT = OPC_SPECIAL | 0x18, @@ -339,6 +340,14 @@ typedef enum { * backwards-compatible at the assembly level. */ OPC_MUL = use_mips32r6_instructions ? OPC_MUL_R6 : OPC_MUL_R5, + + /* MIPS r6 introduced names for weaker variants of SYNC. These are + backward compatible to previous architecture revisions. */ + OPC_SYNC_WMB = OPC_SYNC | 0x04 << 5, + OPC_SYNC_MB = OPC_SYNC | 0x10 << 5, + OPC_SYNC_ACQUIRE = OPC_SYNC | 0x11 << 5, + OPC_SYNC_RELEASE = OPC_SYNC | 0x12 << 5, + OPC_SYNC_RMB = OPC_SYNC | 0x13 << 5, } MIPSInsn; /* @@ -1384,6 +1393,22 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is_64) #endif } +static void tcg_out_mb(TCGContext *s, TCGArg a0) +{ + static const MIPSInsn sync[] = { + /* Note that SYNC_MB is a slightly weaker than SYNC 0, + as the former is an ordering barrier and the latter + is a completion barrier. */ + [0 ... TCG_MO_ALL] = OPC_SYNC_MB, + [TCG_MO_LD_LD] = OPC_SYNC_RMB, + [TCG_MO_ST_ST] = OPC_SYNC_WMB, + [TCG_MO_LD_ST] = OPC_SYNC_RELEASE, + [TCG_MO_LD_ST | TCG_MO_ST_ST] = OPC_SYNC_RELEASE, + [TCG_MO_LD_ST | TCG_MO_LD_LD] = OPC_SYNC_ACQUIRE, + }; + tcg_out32(s, sync[a0 & TCG_MO_ALL]); +} + static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, const int *const_args) { @@ -1653,6 +1678,9 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const_args[4], const_args[5], true); break; + case INDEX_op_mb: + tcg_out_mb(s, a0); + break; case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */ case INDEX_op_movi_i32: /* Always emitted via tcg_out_movi. */ case INDEX_op_call: /* Always emitted via tcg_out_call. */ @@ -1733,6 +1761,8 @@ static const TCGTargetOpDef mips_op_defs[] = { { INDEX_op_qemu_ld_i64, { "L", "L", "lZ", "lZ" } }, { INDEX_op_qemu_st_i64, { "SZ", "SZ", "SZ", "SZ" } }, #endif + + { INDEX_op_mb, { } }, { -1 }, }; From 7b4af5ee8a1336bc39714b6de47924ee71fba761 Mon Sep 17 00:00:00 2001 From: Pranith Kumar Date: Thu, 14 Jul 2016 16:20:19 -0400 Subject: [PATCH 056/723] tcg/ppc: Add support for fence Signed-off-by: Pranith Kumar Message-Id: <20160714202026.9727-8-bobby.prani@gmail.com> Signed-off-by: Richard Henderson --- tcg/ppc/tcg-target.inc.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tcg/ppc/tcg-target.inc.c b/tcg/ppc/tcg-target.inc.c index d79969096f1..a3262cfb0c5 100644 --- a/tcg/ppc/tcg-target.inc.c +++ b/tcg/ppc/tcg-target.inc.c @@ -469,6 +469,10 @@ static int tcg_target_const_match(tcg_target_long val, TCGType type, #define STHX XO31(407) #define STWX XO31(151) +#define EIEIO XO31(854) +#define HWSYNC XO31(598) +#define LWSYNC (HWSYNC | (1u << 21)) + #define SPR(a, b) ((((a)<<5)|(b))<<11) #define LR SPR(8, 0) #define CTR SPR(9, 0) @@ -1243,6 +1247,18 @@ static void tcg_out_brcond2 (TCGContext *s, const TCGArg *args, tcg_out_bc(s, BC | BI(7, CR_EQ) | BO_COND_TRUE, arg_label(args[5])); } +static void tcg_out_mb(TCGContext *s, TCGArg a0) +{ + uint32_t insn = HWSYNC; + a0 &= TCG_MO_ALL; + if (a0 == TCG_MO_LD_LD) { + insn = LWSYNC; + } else if (a0 == TCG_MO_ST_ST) { + insn = EIEIO; + } + tcg_out32(s, insn); +} + #ifdef __powerpc64__ void ppc_tb_set_jmp_target(uintptr_t jmp_addr, uintptr_t addr) { @@ -2453,6 +2469,10 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, tcg_out32(s, MULHD | TAB(args[0], args[1], args[2])); break; + case INDEX_op_mb: + tcg_out_mb(s, args[0]); + break; + case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */ case INDEX_op_mov_i64: case INDEX_op_movi_i32: /* Always emitted via tcg_out_movi. */ @@ -2600,6 +2620,7 @@ static const TCGTargetOpDef ppc_op_defs[] = { { INDEX_op_qemu_st_i64, { "S", "S", "S", "S" } }, #endif + { INDEX_op_mb, { } }, { -1 }, }; From c9314d610e0e5da4d2cd5a36f3563d102b3294e0 Mon Sep 17 00:00:00 2001 From: Pranith Kumar Date: Thu, 14 Jul 2016 16:20:20 -0400 Subject: [PATCH 057/723] tcg/s390: Add support for fence Cc: Alexander Graf Signed-off-by: Pranith Kumar Message-Id: <20160714202026.9727-9-bobby.prani@gmail.com> Signed-off-by: Richard Henderson --- tcg/s390/tcg-target.inc.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tcg/s390/tcg-target.inc.c b/tcg/s390/tcg-target.inc.c index f0c88de6d3d..253d4a0a0bc 100644 --- a/tcg/s390/tcg-target.inc.c +++ b/tcg/s390/tcg-target.inc.c @@ -343,6 +343,7 @@ static tcg_insn_unit *tb_ret_addr; #define FACILITY_EXT_IMM (1ULL << (63 - 21)) #define FACILITY_GEN_INST_EXT (1ULL << (63 - 34)) #define FACILITY_LOAD_ON_COND (1ULL << (63 - 45)) +#define FACILITY_FAST_BCR_SER FACILITY_LOAD_ON_COND static uint64_t facilities; @@ -2169,6 +2170,15 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, tgen_deposit(s, args[0], args[2], args[3], args[4]); break; + case INDEX_op_mb: + /* The host memory model is quite strong, we simply need to + serialize the instruction stream. */ + if (args[0] & TCG_MO_ST_LD) { + tcg_out_insn(s, RR, BCR, + facilities & FACILITY_FAST_BCR_SER ? 14 : 15, 0); + } + break; + case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */ case INDEX_op_mov_i64: case INDEX_op_movi_i32: /* Always emitted via tcg_out_movi. */ @@ -2290,6 +2300,7 @@ static const TCGTargetOpDef s390_op_defs[] = { { INDEX_op_movcond_i64, { "r", "r", "rC", "r", "0" } }, { INDEX_op_deposit_i64, { "r", "0", "r" } }, + { INDEX_op_mb, { } }, { -1 }, }; From f8f03b3707b49898052fb8cd75ee31d19c8161fc Mon Sep 17 00:00:00 2001 From: Pranith Kumar Date: Thu, 14 Jul 2016 16:20:21 -0400 Subject: [PATCH 058/723] tcg/sparc: Add support for fence Signed-off-by: Pranith Kumar Message-Id: <20160714202026.9727-10-bobby.prani@gmail.com> Signed-off-by: Richard Henderson --- tcg/sparc/tcg-target.inc.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tcg/sparc/tcg-target.inc.c b/tcg/sparc/tcg-target.inc.c index 92f8818a9ed..700c43487f4 100644 --- a/tcg/sparc/tcg-target.inc.c +++ b/tcg/sparc/tcg-target.inc.c @@ -249,6 +249,8 @@ static const int tcg_target_call_oarg_regs[] = { #define STWA (INSN_OP(3) | INSN_OP3(0x14)) #define STXA (INSN_OP(3) | INSN_OP3(0x1e)) +#define MEMBAR (INSN_OP(2) | INSN_OP3(0x28) | INSN_RS1(15) | (1 << 13)) + #ifndef ASI_PRIMARY_LITTLE #define ASI_PRIMARY_LITTLE 0x88 #endif @@ -835,6 +837,12 @@ static void tcg_out_call(TCGContext *s, tcg_insn_unit *dest) tcg_out_nop(s); } +static void tcg_out_mb(TCGContext *s, TCGArg a0) +{ + /* Note that the TCG memory order constants mirror the Sparc MEMBAR. */ + tcg_out32(s, MEMBAR | (a0 & TCG_MO_ALL)); +} + #ifdef CONFIG_SOFTMMU static tcg_insn_unit *qemu_ld_trampoline[16]; static tcg_insn_unit *qemu_st_trampoline[16]; @@ -1466,6 +1474,10 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, tcg_out_arithc(s, a0, TCG_REG_G0, a1, const_args[1], c); break; + case INDEX_op_mb: + tcg_out_mb(s, a0); + break; + case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */ case INDEX_op_mov_i64: case INDEX_op_movi_i32: /* Always emitted via tcg_out_movi. */ @@ -1567,6 +1579,7 @@ static const TCGTargetOpDef sparc_op_defs[] = { { INDEX_op_qemu_st_i32, { "sZ", "A" } }, { INDEX_op_qemu_st_i64, { "SZ", "A" } }, + { INDEX_op_mb, { } }, { -1 }, }; From a1e69e2f8112cd9406cd18a7d136d746f64db899 Mon Sep 17 00:00:00 2001 From: Pranith Kumar Date: Thu, 14 Jul 2016 16:20:22 -0400 Subject: [PATCH 059/723] tcg/tci: Add support for fence Cc: Stefan Weil Signed-off-by: Pranith Kumar Message-Id: <20160714202026.9727-11-bobby.prani@gmail.com> Signed-off-by: Richard Henderson --- tcg/tci/tcg-target.inc.c | 3 +++ tci.c | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/tcg/tci/tcg-target.inc.c b/tcg/tci/tcg-target.inc.c index 3c47ea7a9e1..9dbf4d55125 100644 --- a/tcg/tci/tcg-target.inc.c +++ b/tcg/tci/tcg-target.inc.c @@ -255,6 +255,7 @@ static const TCGTargetOpDef tcg_target_op_defs[] = { { INDEX_op_bswap32_i32, { R, R } }, #endif + { INDEX_op_mb, { } }, { -1 }, }; @@ -800,6 +801,8 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, } tcg_out_i(s, *args++); break; + case INDEX_op_mb: + break; case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */ case INDEX_op_mov_i64: case INDEX_op_movi_i32: /* Always emitted via tcg_out_movi. */ diff --git a/tci.c b/tci.c index b488c0d8e41..4bdc645f2a5 100644 --- a/tci.c +++ b/tci.c @@ -1236,6 +1236,10 @@ uintptr_t tcg_qemu_tb_exec(CPUArchState *env, uint8_t *tb_ptr) tcg_abort(); } break; + case INDEX_op_mb: + /* Ensure ordering for all kinds */ + smp_mb(); + break; default: TODO(); break; From ae2264d526ee60b57acad247292e2da4ee822eff Mon Sep 17 00:00:00 2001 From: Pranith Kumar Date: Thu, 14 Jul 2016 16:20:24 -0400 Subject: [PATCH 060/723] target-alpha: Generate fence op Signed-off-by: Pranith Kumar Message-Id: <20160714202026.9727-13-bobby.prani@gmail.com> Signed-off-by: Richard Henderson --- target-alpha/translate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-alpha/translate.c b/target-alpha/translate.c index 0ea0e6e1465..c27c7b9cc49 100644 --- a/target-alpha/translate.c +++ b/target-alpha/translate.c @@ -2338,11 +2338,11 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn) break; case 0x4000: /* MB */ - /* No-op */ + tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC); break; case 0x4400: /* WMB */ - /* No-op */ + tcg_gen_mb(TCG_MO_ST_ST | TCG_BAR_SC); break; case 0x8000: /* FETCH */ From 61e4c432ab26526bab0f3ef746c1861415b6da29 Mon Sep 17 00:00:00 2001 From: Pranith Kumar Date: Thu, 14 Jul 2016 16:20:23 -0400 Subject: [PATCH 061/723] target-arm: Generate fences in ARMv7 frontend Signed-off-by: Pranith Kumar Message-Id: <20160714202026.9727-12-bobby.prani@gmail.com> Signed-off-by: Richard Henderson --- target-arm/translate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index bd5d5cb5768..693d4bc6a24 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -8083,7 +8083,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) case 4: /* dsb */ case 5: /* dmb */ ARCH(7); - /* We don't emulate caches so these are a no-op. */ + tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC); return; case 6: /* isb */ /* We need to break the TB after this insn to execute @@ -10432,7 +10432,7 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw break; case 4: /* dsb */ case 5: /* dmb */ - /* These execute as NOPs. */ + tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC); break; case 6: /* isb */ /* We need to break the TB after this insn From ce1bd93f94e8d4b7117744e49652d2f907bed99f Mon Sep 17 00:00:00 2001 From: Pranith Kumar Date: Thu, 14 Jul 2016 16:20:25 -0400 Subject: [PATCH 062/723] target-aarch64: Generate fences for aarch64 Signed-off-by: Pranith Kumar Message-Id: <20160714202026.9727-14-bobby.prani@gmail.com> Signed-off-by: Richard Henderson --- target-arm/translate-a64.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c index f5e29d20a18..ddf52f5e796 100644 --- a/target-arm/translate-a64.c +++ b/target-arm/translate-a64.c @@ -1294,6 +1294,8 @@ static void gen_clrex(DisasContext *s, uint32_t insn) static void handle_sync(DisasContext *s, uint32_t insn, unsigned int op1, unsigned int op2, unsigned int crm) { + TCGBar bar; + if (op1 != 3) { unallocated_encoding(s); return; @@ -1305,7 +1307,18 @@ static void handle_sync(DisasContext *s, uint32_t insn, return; case 4: /* DSB */ case 5: /* DMB */ - /* We don't emulate caches so barriers are no-ops */ + switch (crm & 3) { + case 1: /* MBReqTypes_Reads */ + bar = TCG_BAR_SC | TCG_MO_LD_LD | TCG_MO_LD_ST; + break; + case 2: /* MBReqTypes_Writes */ + bar = TCG_BAR_SC | TCG_MO_ST_ST; + break; + default: /* MBReqTypes_All */ + bar = TCG_BAR_SC | TCG_MO_ALL; + break; + } + tcg_gen_mb(bar); return; case 6: /* ISB */ /* We need to break the TB after this insn to execute @@ -1934,7 +1947,13 @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn) if (!is_store) { s->is_ldex = true; gen_load_exclusive(s, rt, rt2, tcg_addr, size, is_pair); + if (is_lasr) { + tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ); + } } else { + if (is_lasr) { + tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL); + } gen_store_exclusive(s, rs, rt, rt2, tcg_addr, size, is_pair); } } else { @@ -1943,11 +1962,17 @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn) /* Generate ISS for non-exclusive accesses including LASR. */ if (is_store) { + if (is_lasr) { + tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL); + } do_gpr_st(s, tcg_rt, tcg_addr, size, true, rt, iss_sf, is_lasr); } else { do_gpr_ld(s, tcg_rt, tcg_addr, size, false, false, true, rt, iss_sf, is_lasr); + if (is_lasr) { + tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ); + } } } } From cc19e497a047193db5083425957d7292c8dd3226 Mon Sep 17 00:00:00 2001 From: Pranith Kumar Date: Thu, 14 Jul 2016 16:20:26 -0400 Subject: [PATCH 063/723] target-i386: Generate fences for x86 Signed-off-by: Pranith Kumar Message-Id: <20160714202026.9727-15-bobby.prani@gmail.com> Signed-off-by: Richard Henderson --- target-i386/translate.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/target-i386/translate.c b/target-i386/translate.c index fa2ac481731..94475579118 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -8012,13 +8012,21 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, || (prefixes & PREFIX_LOCK)) { goto illegal_op; } + tcg_gen_mb(TCG_MO_ST_ST | TCG_BAR_SC); break; case 0xe8 ... 0xef: /* lfence */ + if (!(s->cpuid_features & CPUID_SSE) + || (prefixes & PREFIX_LOCK)) { + goto illegal_op; + } + tcg_gen_mb(TCG_MO_LD_LD | TCG_BAR_SC); + break; case 0xf0 ... 0xf7: /* mfence */ if (!(s->cpuid_features & CPUID_SSE2) || (prefixes & PREFIX_LOCK)) { goto illegal_op; } + tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC); break; default: From 34f939218ce78163171addd63750e1e0300376ab Mon Sep 17 00:00:00 2001 From: Pranith Kumar Date: Tue, 23 Aug 2016 09:48:25 -0400 Subject: [PATCH 064/723] tcg: Optimize fence instructions This commit optimizes fence instructions. Two optimizations are currently implemented: (1) unnecessary duplicate fence instructions, and (2) merging weaker fences into a stronger fence. [rth: Merge tcg_optimize_mb back into tcg_optimize, so that we only loop over the opcode stream once. Merge "unrelated" weaker barriers into one stronger barrier.] Signed-off-by: Pranith Kumar Message-Id: <20160823134825.32578-1-bobby.prani@gmail.com> Signed-off-by: Richard Henderson --- tcg/optimize.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/tcg/optimize.c b/tcg/optimize.c index cffe89b5250..9998ac74138 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -542,6 +542,7 @@ static bool swap_commutative2(TCGArg *p1, TCGArg *p2) void tcg_optimize(TCGContext *s) { int oi, oi_next, nb_temps, nb_globals; + TCGArg *prev_mb_args = NULL; /* Array VALS has an element for each temp. If this temp holds a constant then its value is kept in VALS' element. @@ -1295,5 +1296,43 @@ void tcg_optimize(TCGContext *s) } break; } + + /* Eliminate duplicate and redundant fence instructions. */ + if (prev_mb_args) { + switch (opc) { + case INDEX_op_mb: + /* Merge two barriers of the same type into one, + * or a weaker barrier into a stronger one, + * or two weaker barriers into a stronger one. + * mb X; mb Y => mb X|Y + * mb; strl => mb; st + * ldaq; mb => ld; mb + * ldaq; strl => ld; mb; st + * Other combinations are also merged into a strong + * barrier. This is stricter than specified but for + * the purposes of TCG is better than not optimizing. + */ + prev_mb_args[0] |= args[0]; + tcg_op_remove(s, op); + break; + + default: + /* Opcodes that end the block stop the optimization. */ + if ((def->flags & TCG_OPF_BB_END) == 0) { + break; + } + /* fallthru */ + case INDEX_op_qemu_ld_i32: + case INDEX_op_qemu_ld_i64: + case INDEX_op_qemu_st_i32: + case INDEX_op_qemu_st_i64: + case INDEX_op_call: + /* Opcodes that touch guest memory stop the optimization. */ + prev_mb_args = NULL; + break; + } + } else if (opc == INDEX_op_mb) { + prev_mb_args = args; + } } } From 6bd7776cd0a9581cdb5e9dd40df8821a96e355d6 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Fri, 9 Sep 2016 10:31:20 +0200 Subject: [PATCH 065/723] MAINTAINERS: add virtio-* tests Except virtio-9p, all virtio-* tests are orphan. This patch tries to fix it, according to the following logic: - when the related subsystem has its own section in MAINTAINERS, the test is added there - otherwise it is added to the "parent" section (aka. SCSI, Network devices, virtio) Signed-off-by: Greg Kurz Reviewed-by: Amit Shah Reviewed-by: Stefan Hajnoczi Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 4db611ffb0f..0e0c326f553 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -830,6 +830,7 @@ Network devices M: Jason Wang S: Odd Fixes F: hw/net/ +F: tests/virtio-net-test.c T: git git://github.com/jasowang/qemu.git net SCSI @@ -837,6 +838,7 @@ M: Paolo Bonzini S: Supported F: include/hw/scsi/* F: hw/scsi/* +F: tests/virtio-scsi-test.c T: git git://github.com/bonzini/qemu.git scsi-next LSI53C895A @@ -889,6 +891,7 @@ S: Supported F: hw/*/virtio* F: net/vhost-user.c F: include/hw/virtio/ +F: tests/virtio-balloon-test.c virtio-9p M: Aneesh Kumar K.V @@ -907,6 +910,7 @@ S: Supported F: hw/block/virtio-blk.c F: hw/block/dataplane/* F: hw/virtio/dataplane/* +F: tests/virtio-blk-test.c T: git git://github.com/stefanha/qemu.git block virtio-ccw @@ -929,6 +933,8 @@ S: Supported F: hw/char/virtio-serial-bus.c F: hw/char/virtio-console.c F: include/hw/virtio/virtio-serial.h +F: tests/virtio-console-test.c +F: tests/virtio-serial-test.c virtio-rng M: Amit Shah @@ -937,6 +943,7 @@ F: hw/virtio/virtio-rng.c F: include/hw/virtio/virtio-rng.h F: include/sysemu/rng*.h F: backends/rng*.c +F: tests/virtio-rng-test.c nvme M: Keith Busch From e73316d594256cedb926cb76444e8ee00a5032b9 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Wed, 7 Sep 2016 12:50:40 +0200 Subject: [PATCH 066/723] s390x/kvm: disable cpu model for the 2.7 machine cpu model was merged with 2.8, it is wrong to abuse ri_allowed which was enabled with 2.7. Signed-off-by: Christian Borntraeger Signed-off-by: Cornelia Huck --- hw/s390x/s390-virtio-ccw.c | 17 +++++++++++++++++ include/hw/s390x/s390-virtio-ccw.h | 3 +++ target-s390x/kvm.c | 2 +- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index a63b4e8c617..e340eab36b7 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -193,6 +193,7 @@ static void ccw_machine_class_init(ObjectClass *oc, void *data) S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc); s390mc->ri_allowed = true; + s390mc->cpu_model_allowed = true; mc->init = ccw_init; mc->reset = s390_machine_reset; mc->hot_add_cpu = s390_hot_add_cpu; @@ -258,6 +259,19 @@ bool ri_allowed(void) return 0; } +bool cpu_model_allowed(void) +{ + MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine()); + if (object_class_dynamic_cast(OBJECT_CLASS(mc), + TYPE_S390_CCW_MACHINE)) { + S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc); + + return s390mc->cpu_model_allowed; + } + /* allow CPU model qmp queries with the "none" machine */ + return true; +} + static inline void s390_machine_initfn(Object *obj) { object_property_add_bool(obj, "aes-key-wrap", @@ -397,6 +411,9 @@ static void ccw_machine_2_7_instance_options(MachineState *machine) static void ccw_machine_2_7_class_options(MachineClass *mc) { + S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc); + + s390mc->cpu_model_allowed = false; ccw_machine_2_8_class_options(mc); SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_7); } diff --git a/include/hw/s390x/s390-virtio-ccw.h b/include/hw/s390x/s390-virtio-ccw.h index a0c1fc80839..6ecae003860 100644 --- a/include/hw/s390x/s390-virtio-ccw.h +++ b/include/hw/s390x/s390-virtio-ccw.h @@ -36,9 +36,12 @@ typedef struct S390CcwMachineClass { /*< public >*/ bool ri_allowed; + bool cpu_model_allowed; } S390CcwMachineClass; /* runtime-instrumentation allowed by the machine */ bool ri_allowed(void); +/* cpu model allowed by the machine */ +bool cpu_model_allowed(void); #endif diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index dfaf1ca8d17..4b847a3be48 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -2490,7 +2490,7 @@ static int configure_cpu_feat(const S390FeatBitmap features) bool kvm_s390_cpu_models_supported(void) { - if (!ri_allowed()) { + if (!cpu_model_allowed()) { /* compatibility machines interfere with the cpu model */ return false; } From 1e4738b2d4141e8045036ff7e03bed4f185649ff Mon Sep 17 00:00:00 2001 From: Sascha Silbe Date: Tue, 30 Aug 2016 14:02:16 +0200 Subject: [PATCH 067/723] MAINTAINERS: update s390 machine file patterns Some files used by s390 KVM code were missing in MAINTAINERS. Add them. Reported-by: Markus Armbruster Signed-off-by: Sascha Silbe Signed-off-by: Cornelia Huck --- MAINTAINERS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 7d430261620..7d2a33cb193 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -669,6 +669,9 @@ F: hw/s390x/ F: include/hw/s390x/ F: pc-bios/s390-ccw/ F: hw/watchdog/wdt_diag288.c +F: include/hw/watchdog/wdt_diag288.h +F: pc-bios/s390-ccw.img +F: default-configs/s390x-softmmu.mak T: git git://github.com/cohuck/qemu.git s390-next T: git git://github.com/borntraeger/qemu.git s390-next From e32652f7594e6c027737fa495974cb73754cb5d0 Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Wed, 7 Sep 2016 12:58:40 +0200 Subject: [PATCH 068/723] virtio-ccw: respond to READ_STATUS command This patch adds the response to the READ_STATUS CCW command. Signed-off-by: Pierre Morel Signed-off-by: Cornelia Huck --- hw/s390x/virtio-ccw.c | 20 ++++++++++++++++++++ hw/s390x/virtio-ccw.h | 1 + 2 files changed, 21 insertions(+) diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index 96789569a71..0a997e17b61 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -455,6 +455,26 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) } } break; + case CCW_CMD_READ_STATUS: + if (check_len) { + if (ccw.count != sizeof(status)) { + ret = -EINVAL; + break; + } + } else if (ccw.count < sizeof(status)) { + /* Can't execute command. */ + ret = -EINVAL; + break; + } + if (!ccw.cda) { + ret = -EFAULT; + } else { + address_space_stb(&address_space_memory, ccw.cda, vdev->status, + MEMTXATTRS_UNSPECIFIED, NULL); + sch->curr_status.scsw.count = ccw.count - sizeof(vdev->status);; + ret = 0; + } + break; case CCW_CMD_WRITE_STATUS: if (check_len) { if (ccw.count != sizeof(status)) { diff --git a/hw/s390x/virtio-ccw.h b/hw/s390x/virtio-ccw.h index b58ab21d4ca..6ef940a98c5 100644 --- a/hw/s390x/virtio-ccw.h +++ b/hw/s390x/virtio-ccw.h @@ -45,6 +45,7 @@ #define CCW_CMD_SET_IND 0x43 #define CCW_CMD_SET_CONF_IND 0x53 #define CCW_CMD_READ_VQ_CONF 0x32 +#define CCW_CMD_READ_STATUS 0x72 #define CCW_CMD_SET_IND_ADAPTER 0x73 #define CCW_CMD_SET_VIRTIO_REV 0x83 From 7aa2adc28335f4ac47f7e86e043fb8557eb3cbc3 Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Wed, 7 Sep 2016 13:04:46 +0200 Subject: [PATCH 069/723] virtio-ccw: set revision 2 as maximal revision number We have everything needed for virtio-ccw revision 2 wired up now. Bump the maximum supported revision reported on a device basis to the guest so they can make use of it. Signed-off-by: Pierre Morel Signed-off-by: Cornelia Huck --- hw/s390x/virtio-ccw.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/s390x/virtio-ccw.h b/hw/s390x/virtio-ccw.h index 6ef940a98c5..565094e4fb3 100644 --- a/hw/s390x/virtio-ccw.h +++ b/hw/s390x/virtio-ccw.h @@ -99,7 +99,7 @@ struct VirtioCcwDevice { }; /* The maximum virtio revision we support. */ -#define VIRTIO_CCW_MAX_REV 1 +#define VIRTIO_CCW_MAX_REV 2 static inline int virtio_ccw_rev_max(VirtioCcwDevice *dev) { return dev->max_rev; From 4d4ccabdd22153bd19e0c4bbb6fbfe8402a7b845 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Fri, 9 Sep 2016 14:35:27 +0200 Subject: [PATCH 070/723] QMP: fixup typos and whitespace damage Fixup some typos and whitespace damage introduced by the CPU model patches for s390. Reported-by: Eric Blake Signed-off-by: Christian Borntraeger Reviewed-by: Eric Blake Signed-off-by: Cornelia Huck --- qapi-schema.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/qapi-schema.json b/qapi-schema.json index c4f3674d08e..f1a79f5ed9a 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3163,7 +3163,7 @@ # @CpuModelCompareResult: # # An enumeration of CPU model comparation results. The result is usually -# calcualted using e.g. CPU features or CPU generations. +# calculated using e.g. CPU features or CPU generations. # # @incompatible: If model A is incompatible to model B, model A is not # guaranteed to run where model B runs and the other way around. @@ -3216,14 +3216,14 @@ # CPU model has to be created by baselining. # # Usually, a CPU model is compared against the maximum possible CPU model -# of a ceratin configuration (e.g. the "host" model for KVM). If that CPU +# of a certain configuration (e.g. the "host" model for KVM). If that CPU # model is identical or a subset, it will run in that configuration. # # The result returned by this command may be affected by: # # * QEMU version: CPU models may look different depending on the QEMU version. # (Except for CPU models reported as "static" in query-cpu-definitions.) -# * machine-type: CPU model may look different depending on the machine-type. +# * machine-type: CPU model may look different depending on the machine-type. # (Except for CPU models reported as "static" in query-cpu-definitions.) # * machine options (including accelerator): in some architectures, CPU models # may look different depending on machine and accelerator options. (Except for @@ -3274,7 +3274,7 @@ # # * QEMU version: CPU models may look different depending on the QEMU version. # (Except for CPU models reported as "static" in query-cpu-definitions.) -# * machine-type: CPU model may look different depending on the machine-type. +# * machine-type: CPU model may look different depending on the machine-type. # (Except for CPU models reported as "static" in query-cpu-definitions.) # * machine options (including accelerator): in some architectures, CPU models # may look different depending on machine and accelerator options. (Except for From 13fd08e631ec0c3ff5ad1bdcb6a4474c7d9a024f Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Fri, 16 Sep 2016 11:44:49 +0200 Subject: [PATCH 071/723] 9pfs: fix potential segfault during walk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the call to fid_to_qid() returns an error, we will call v9fs_path_free() on uninitialized paths. It is a regression introduced by the following commit: 56f101ecce0e 9pfs: handle walk of ".." in the root directory Let's fix this by initializing dpath and path before calling fid_to_qid(). Signed-off-by: Greg Kurz Reviewed-by: Cédric Le Goater [groug: updated the changelog to indicate this is regression and to provide the offending commit SHA1] Signed-off-by: Greg Kurz --- hw/9pfs/9p.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index 639f9393028..119ee584969 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -1333,13 +1333,14 @@ static void v9fs_walk(void *opaque) goto out_nofid; } + v9fs_path_init(&dpath); + v9fs_path_init(&path); + err = fid_to_qid(pdu, fidp, &qid); if (err < 0) { goto out; } - v9fs_path_init(&dpath); - v9fs_path_init(&path); /* * Both dpath and path initially poin to fidp. * Needed to handle request with nwnames == 0 From 59b060be184aff59cfa101c937c8139e66f452f2 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Mon, 12 Sep 2016 12:50:12 +0100 Subject: [PATCH 072/723] crypto: use uint64_t for pbkdf iteration count parameters The qcrypto_pbkdf_count_iters method uses a 64 bit int but then checks its value against INT32_MAX before returning it. This bounds check is premature, because the calling code may well scale the iteration count by some value. It is thus better to return a 64-bit integer and let the caller do range checking. For consistency the qcrypto_pbkdf method is also changed to accept a 64bit int, though this is somewhat academic since nettle is limited to taking an 'int' while gcrypt is limited to taking a 'long int'. Reviewed-by: Eric Blake Signed-off-by: Daniel P. Berrange --- crypto/block-luks.c | 52 +++++++++++++++++++++++++----------------- crypto/pbkdf-gcrypt.c | 9 +++++++- crypto/pbkdf-nettle.c | 8 ++++++- crypto/pbkdf-stub.c | 2 +- crypto/pbkdf.c | 16 ++++--------- include/crypto/pbkdf.h | 10 ++++---- 6 files changed, 57 insertions(+), 40 deletions(-) diff --git a/crypto/block-luks.c b/crypto/block-luks.c index aba4455646f..bc086acdab4 100644 --- a/crypto/block-luks.c +++ b/crypto/block-luks.c @@ -917,6 +917,7 @@ qcrypto_block_luks_create(QCryptoBlock *block, const char *hash_alg; char *cipher_mode_spec = NULL; QCryptoCipherAlgorithm ivcipheralg = 0; + uint64_t iters; memcpy(&luks_opts, &options->u.luks, sizeof(luks_opts)); if (!luks_opts.has_cipher_alg) { @@ -1064,12 +1065,11 @@ qcrypto_block_luks_create(QCryptoBlock *block, /* Determine how many iterations we need to hash the master * key, in order to have 1 second of compute time used */ - luks->header.master_key_iterations = - qcrypto_pbkdf2_count_iters(luks_opts.hash_alg, - masterkey, luks->header.key_bytes, - luks->header.master_key_salt, - QCRYPTO_BLOCK_LUKS_SALT_LEN, - &local_err); + iters = qcrypto_pbkdf2_count_iters(luks_opts.hash_alg, + masterkey, luks->header.key_bytes, + luks->header.master_key_salt, + QCRYPTO_BLOCK_LUKS_SALT_LEN, + &local_err); if (local_err) { error_propagate(errp, local_err); goto error; @@ -1079,11 +1079,15 @@ qcrypto_block_luks_create(QCryptoBlock *block, * explanation why they chose /= 8... Probably so that * if all 8 keyslots are active we only spend 1 second * in total time to check all keys */ - luks->header.master_key_iterations /= 8; - luks->header.master_key_iterations = MAX( - luks->header.master_key_iterations, - QCRYPTO_BLOCK_LUKS_MIN_MASTER_KEY_ITERS); - + iters /= 8; + if (iters > UINT32_MAX) { + error_setg_errno(errp, ERANGE, + "PBKDF iterations %llu larger than %u", + (unsigned long long)iters, UINT32_MAX); + goto error; + } + iters = MAX(iters, QCRYPTO_BLOCK_LUKS_MIN_MASTER_KEY_ITERS); + luks->header.master_key_iterations = iters; /* Hash the master key, saving the result in the LUKS * header. This hash is used when opening the encrypted @@ -1131,22 +1135,28 @@ qcrypto_block_luks_create(QCryptoBlock *block, /* Again we determine how many iterations are required to * hash the user password while consuming 1 second of compute * time */ - luks->header.key_slots[0].iterations = - qcrypto_pbkdf2_count_iters(luks_opts.hash_alg, - (uint8_t *)password, strlen(password), - luks->header.key_slots[0].salt, - QCRYPTO_BLOCK_LUKS_SALT_LEN, - &local_err); + iters = qcrypto_pbkdf2_count_iters(luks_opts.hash_alg, + (uint8_t *)password, strlen(password), + luks->header.key_slots[0].salt, + QCRYPTO_BLOCK_LUKS_SALT_LEN, + &local_err); if (local_err) { error_propagate(errp, local_err); goto error; } /* Why /= 2 ? That matches cryptsetup, but there's no * explanation why they chose /= 2... */ - luks->header.key_slots[0].iterations /= 2; - luks->header.key_slots[0].iterations = MAX( - luks->header.key_slots[0].iterations, - QCRYPTO_BLOCK_LUKS_MIN_SLOT_KEY_ITERS); + iters /= 2; + + if (iters > UINT32_MAX) { + error_setg_errno(errp, ERANGE, + "PBKDF iterations %llu larger than %u", + (unsigned long long)iters, UINT32_MAX); + goto error; + } + + luks->header.key_slots[0].iterations = + MAX(iters, QCRYPTO_BLOCK_LUKS_MIN_SLOT_KEY_ITERS); /* Generate a key that we'll use to encrypt the master diff --git a/crypto/pbkdf-gcrypt.c b/crypto/pbkdf-gcrypt.c index 34af3a97e9a..44cf31aff4a 100644 --- a/crypto/pbkdf-gcrypt.c +++ b/crypto/pbkdf-gcrypt.c @@ -38,7 +38,7 @@ bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash) int qcrypto_pbkdf2(QCryptoHashAlgorithm hash, const uint8_t *key, size_t nkey, const uint8_t *salt, size_t nsalt, - unsigned int iterations, + uint64_t iterations, uint8_t *out, size_t nout, Error **errp) { @@ -49,6 +49,13 @@ int qcrypto_pbkdf2(QCryptoHashAlgorithm hash, }; int ret; + if (iterations > ULONG_MAX) { + error_setg_errno(errp, ERANGE, + "PBKDF iterations %llu must be less than %lu", + (long long unsigned)iterations, ULONG_MAX); + return -1; + } + if (hash >= G_N_ELEMENTS(hash_map) || hash_map[hash] == GCRY_MD_NONE) { error_setg(errp, "Unexpected hash algorithm %d", hash); diff --git a/crypto/pbkdf-nettle.c b/crypto/pbkdf-nettle.c index d681a606f94..db81517adcc 100644 --- a/crypto/pbkdf-nettle.c +++ b/crypto/pbkdf-nettle.c @@ -38,10 +38,16 @@ bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash) int qcrypto_pbkdf2(QCryptoHashAlgorithm hash, const uint8_t *key, size_t nkey, const uint8_t *salt, size_t nsalt, - unsigned int iterations, + uint64_t iterations, uint8_t *out, size_t nout, Error **errp) { + if (iterations > UINT_MAX) { + error_setg_errno(errp, ERANGE, + "PBKDF iterations %llu must be less than %u", + (long long unsigned)iterations, UINT_MAX); + return -1; + } switch (hash) { case QCRYPTO_HASH_ALG_SHA1: pbkdf2_hmac_sha1(nkey, key, diff --git a/crypto/pbkdf-stub.c b/crypto/pbkdf-stub.c index 266a5051b7a..a15044da423 100644 --- a/crypto/pbkdf-stub.c +++ b/crypto/pbkdf-stub.c @@ -32,7 +32,7 @@ int qcrypto_pbkdf2(QCryptoHashAlgorithm hash G_GNUC_UNUSED, size_t nkey G_GNUC_UNUSED, const uint8_t *salt G_GNUC_UNUSED, size_t nsalt G_GNUC_UNUSED, - unsigned int iterations G_GNUC_UNUSED, + uint64_t iterations G_GNUC_UNUSED, uint8_t *out G_GNUC_UNUSED, size_t nout G_GNUC_UNUSED, Error **errp) diff --git a/crypto/pbkdf.c b/crypto/pbkdf.c index 695cc35df1b..929458b3122 100644 --- a/crypto/pbkdf.c +++ b/crypto/pbkdf.c @@ -62,13 +62,13 @@ static int qcrypto_pbkdf2_get_thread_cpu(unsigned long long *val_ms, #endif } -int qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash, - const uint8_t *key, size_t nkey, - const uint8_t *salt, size_t nsalt, - Error **errp) +uint64_t qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash, + const uint8_t *key, size_t nkey, + const uint8_t *salt, size_t nsalt, + Error **errp) { uint8_t out[32]; - long long int iterations = (1 << 15); + uint64_t iterations = (1 << 15); unsigned long long delta_ms, start_ms, end_ms; while (1) { @@ -100,11 +100,5 @@ int qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash, iterations = iterations * 1000 / delta_ms; - if (iterations > INT32_MAX) { - error_setg(errp, "Iterations %lld too large for a 32-bit int", - iterations); - return -1; - } - return iterations; } diff --git a/include/crypto/pbkdf.h b/include/crypto/pbkdf.h index e9e4ceca833..6f4ac85b5c0 100644 --- a/include/crypto/pbkdf.h +++ b/include/crypto/pbkdf.h @@ -122,7 +122,7 @@ bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash); int qcrypto_pbkdf2(QCryptoHashAlgorithm hash, const uint8_t *key, size_t nkey, const uint8_t *salt, size_t nsalt, - unsigned int iterations, + uint64_t iterations, uint8_t *out, size_t nout, Error **errp); @@ -144,9 +144,9 @@ int qcrypto_pbkdf2(QCryptoHashAlgorithm hash, * * Returns: number of iterations in 1 second, -1 on error */ -int qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash, - const uint8_t *key, size_t nkey, - const uint8_t *salt, size_t nsalt, - Error **errp); +uint64_t qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash, + const uint8_t *key, size_t nkey, + const uint8_t *salt, size_t nsalt, + Error **errp); #endif /* QCRYPTO_PBKDF_H */ From 3bd18890cab82735ae2565fa50aa122e1b4a0ef0 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Tue, 6 Sep 2016 18:43:00 +0100 Subject: [PATCH 073/723] crypto: make PBKDF iterations configurable for LUKS format As protection against bruteforcing passphrases, the PBKDF algorithm is tuned by counting the number of iterations needed to produce 1 second of running time. If the machine that the image will be used on is much faster than the machine where the image is created, it can be desirable to raise the number of iterations. This change adds a new 'iter-time' property that allows the user to choose the iteration wallclock time. Reviewed-by: Eric Blake Signed-off-by: Daniel P. Berrange --- block/crypto.c | 6 ++++++ crypto/block-luks.c | 24 ++++++++++++++++++++++++ qapi/crypto.json | 6 +++++- 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/block/crypto.c b/block/crypto.c index 7f61e126868..7aa7eb553e0 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -33,6 +33,7 @@ #define BLOCK_CRYPTO_OPT_LUKS_IVGEN_ALG "ivgen-alg" #define BLOCK_CRYPTO_OPT_LUKS_IVGEN_HASH_ALG "ivgen-hash-alg" #define BLOCK_CRYPTO_OPT_LUKS_HASH_ALG "hash-alg" +#define BLOCK_CRYPTO_OPT_LUKS_ITER_TIME "iter-time" typedef struct BlockCrypto BlockCrypto; @@ -183,6 +184,11 @@ static QemuOptsList block_crypto_create_opts_luks = { .type = QEMU_OPT_STRING, .help = "Name of encryption hash algorithm", }, + { + .name = BLOCK_CRYPTO_OPT_LUKS_ITER_TIME, + .type = QEMU_OPT_NUMBER, + .help = "Time to spend in PBKDF in milliseconds", + }, { /* end of list */ } }, }; diff --git a/crypto/block-luks.c b/crypto/block-luks.c index bc086acdab4..91a4172287c 100644 --- a/crypto/block-luks.c +++ b/crypto/block-luks.c @@ -920,6 +920,9 @@ qcrypto_block_luks_create(QCryptoBlock *block, uint64_t iters; memcpy(&luks_opts, &options->u.luks, sizeof(luks_opts)); + if (!luks_opts.has_iter_time) { + luks_opts.iter_time = 1000; + } if (!luks_opts.has_cipher_alg) { luks_opts.cipher_alg = QCRYPTO_CIPHER_ALG_AES_256; } @@ -1075,6 +1078,16 @@ qcrypto_block_luks_create(QCryptoBlock *block, goto error; } + if (iters > (ULLONG_MAX / luks_opts.iter_time)) { + error_setg_errno(errp, ERANGE, + "PBKDF iterations %llu too large to scale", + (unsigned long long)iters); + goto error; + } + + /* iter_time was in millis, but count_iters reported for secs */ + iters = iters * luks_opts.iter_time / 1000; + /* Why /= 8 ? That matches cryptsetup, but there's no * explanation why they chose /= 8... Probably so that * if all 8 keyslots are active we only spend 1 second @@ -1144,6 +1157,17 @@ qcrypto_block_luks_create(QCryptoBlock *block, error_propagate(errp, local_err); goto error; } + + if (iters > (ULLONG_MAX / luks_opts.iter_time)) { + error_setg_errno(errp, ERANGE, + "PBKDF iterations %llu too large to scale", + (unsigned long long)iters); + goto error; + } + + /* iter_time was in millis, but count_iters reported for secs */ + iters = iters * luks_opts.iter_time / 1000; + /* Why /= 2 ? That matches cryptsetup, but there's no * explanation why they chose /= 2... */ iters /= 2; diff --git a/qapi/crypto.json b/qapi/crypto.json index 34d2583154c..2b6118f660b 100644 --- a/qapi/crypto.json +++ b/qapi/crypto.json @@ -185,6 +185,9 @@ # Currently defaults to 'sha256' # @hash-alg: #optional the master key hash algorithm # Currently defaults to 'sha256' +# @iter-time: #optional number of milliseconds to spend in +# PBKDF passphrase processing. Currently defaults +# to 1000. (since 2.8) # Since: 2.6 ## { 'struct': 'QCryptoBlockCreateOptionsLUKS', @@ -193,7 +196,8 @@ '*cipher-mode': 'QCryptoCipherMode', '*ivgen-alg': 'QCryptoIVGenAlgorithm', '*ivgen-hash-alg': 'QCryptoHashAlgorithm', - '*hash-alg': 'QCryptoHashAlgorithm'}} + '*hash-alg': 'QCryptoHashAlgorithm', + '*iter-time': 'int'}} ## From 8813800b7d995d8b54ef0a1e16d41fc13d8b5f3a Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Wed, 7 Sep 2016 12:38:07 +0100 Subject: [PATCH 074/723] crypto: clear out buffer after timing pbkdf algorithm The 'out' buffer will hold a key derived from master password, so it is best practice to clear this buffer when no longer required. At this time, the code isn't worrying about locking buffers into RAM to prevent swapping sensitive data to disk. Reviewed-by: Eric Blake Signed-off-by: Daniel P. Berrange --- crypto/pbkdf.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/crypto/pbkdf.c b/crypto/pbkdf.c index 929458b3122..e3915058fbc 100644 --- a/crypto/pbkdf.c +++ b/crypto/pbkdf.c @@ -67,13 +67,14 @@ uint64_t qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash, const uint8_t *salt, size_t nsalt, Error **errp) { + uint64_t ret = -1; uint8_t out[32]; uint64_t iterations = (1 << 15); unsigned long long delta_ms, start_ms, end_ms; while (1) { if (qcrypto_pbkdf2_get_thread_cpu(&start_ms, errp) < 0) { - return -1; + goto cleanup; } if (qcrypto_pbkdf2(hash, key, nkey, @@ -81,10 +82,10 @@ uint64_t qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash, iterations, out, sizeof(out), errp) < 0) { - return -1; + goto cleanup; } if (qcrypto_pbkdf2_get_thread_cpu(&end_ms, errp) < 0) { - return -1; + goto cleanup; } delta_ms = end_ms - start_ms; @@ -100,5 +101,9 @@ uint64_t qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash, iterations = iterations * 1000 / delta_ms; - return iterations; + ret = iterations; + + cleanup: + memset(out, 0, sizeof(out)); + return ret; } From e74aabcffb74e6c15de05255480d43771ec63d8b Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Wed, 7 Sep 2016 12:43:29 +0100 Subject: [PATCH 075/723] crypto: use correct derived key size when timing pbkdf Currently when timing the pbkdf algorithm a fixed key size of 32 bytes is used. This results in inaccurate timings for certain hashes depending on their digest size. For example when using sha1 with aes-256, this causes us to measure time for the master key digest doing 2 sha1 operations per iteration, instead of 1. Instead we should pass in the desired key size to the timing routine that matches the key size that will be used for real later. Reviewed-by: Eric Blake Signed-off-by: Daniel P. Berrange --- crypto/block-luks.c | 2 ++ crypto/pbkdf.c | 10 +++++++--- include/crypto/pbkdf.h | 6 +++++- tests/test-crypto-pbkdf.c | 1 + 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/crypto/block-luks.c b/crypto/block-luks.c index 91a4172287c..9269aaf4883 100644 --- a/crypto/block-luks.c +++ b/crypto/block-luks.c @@ -1072,6 +1072,7 @@ qcrypto_block_luks_create(QCryptoBlock *block, masterkey, luks->header.key_bytes, luks->header.master_key_salt, QCRYPTO_BLOCK_LUKS_SALT_LEN, + QCRYPTO_BLOCK_LUKS_DIGEST_LEN, &local_err); if (local_err) { error_propagate(errp, local_err); @@ -1152,6 +1153,7 @@ qcrypto_block_luks_create(QCryptoBlock *block, (uint8_t *)password, strlen(password), luks->header.key_slots[0].salt, QCRYPTO_BLOCK_LUKS_SALT_LEN, + luks->header.key_bytes, &local_err); if (local_err) { error_propagate(errp, local_err); diff --git a/crypto/pbkdf.c b/crypto/pbkdf.c index e3915058fbc..f22e71d183e 100644 --- a/crypto/pbkdf.c +++ b/crypto/pbkdf.c @@ -65,13 +65,16 @@ static int qcrypto_pbkdf2_get_thread_cpu(unsigned long long *val_ms, uint64_t qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash, const uint8_t *key, size_t nkey, const uint8_t *salt, size_t nsalt, + size_t nout, Error **errp) { uint64_t ret = -1; - uint8_t out[32]; + uint8_t *out; uint64_t iterations = (1 << 15); unsigned long long delta_ms, start_ms, end_ms; + out = g_new(uint8_t, nout); + while (1) { if (qcrypto_pbkdf2_get_thread_cpu(&start_ms, errp) < 0) { goto cleanup; @@ -80,7 +83,7 @@ uint64_t qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash, key, nkey, salt, nsalt, iterations, - out, sizeof(out), + out, nout, errp) < 0) { goto cleanup; } @@ -104,6 +107,7 @@ uint64_t qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash, ret = iterations; cleanup: - memset(out, 0, sizeof(out)); + memset(out, 0, nout); + g_free(out); return ret; } diff --git a/include/crypto/pbkdf.h b/include/crypto/pbkdf.h index 6f4ac85b5c0..ef209b3e030 100644 --- a/include/crypto/pbkdf.h +++ b/include/crypto/pbkdf.h @@ -133,6 +133,7 @@ int qcrypto_pbkdf2(QCryptoHashAlgorithm hash, * @nkey: the length of @key in bytes * @salt: a random salt * @nsalt: length of @salt in bytes + * @nout: size of desired derived key * @errp: pointer to a NULL-initialized error object * * Time the PBKDF2 algorithm to determine how many @@ -140,13 +141,16 @@ int qcrypto_pbkdf2(QCryptoHashAlgorithm hash, * key from a user password provided in @key in 1 * second of compute time. The result of this can * be used as a the @iterations parameter of a later - * call to qcrypto_pbkdf2(). + * call to qcrypto_pbkdf2(). The value of @nout should + * match that value that will later be provided with + * a call to qcrypto_pbkdf2(). * * Returns: number of iterations in 1 second, -1 on error */ uint64_t qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash, const uint8_t *key, size_t nkey, const uint8_t *salt, size_t nsalt, + size_t nout, Error **errp); #endif /* QCRYPTO_PBKDF_H */ diff --git a/tests/test-crypto-pbkdf.c b/tests/test-crypto-pbkdf.c index 8ceceb18279..a651dc50a34 100644 --- a/tests/test-crypto-pbkdf.c +++ b/tests/test-crypto-pbkdf.c @@ -358,6 +358,7 @@ static void test_pbkdf_timing(void) iters = qcrypto_pbkdf2_count_iters(QCRYPTO_HASH_ALG_SHA256, key, sizeof(key), salt, sizeof(salt), + 32, &error_abort); g_assert(iters >= (1 << 15)); From acd0dfd0c252a06ec6f2146fea01b66b7bc68cfc Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Wed, 7 Sep 2016 13:17:07 +0100 Subject: [PATCH 076/723] crypto: remove bogus /= 2 for pbkdf iterations When calculating iterations for pbkdf of the key slot data, we had a /= 2, which was copied from identical code in cryptsetup. It was always unclear & undocumented why cryptsetup had this division and it was recently removed there, too. Reviewed-by: Eric Blake Signed-off-by: Daniel P. Berrange --- crypto/block-luks.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/crypto/block-luks.c b/crypto/block-luks.c index 9269aaf4883..3ab3250e3da 100644 --- a/crypto/block-luks.c +++ b/crypto/block-luks.c @@ -1170,10 +1170,6 @@ qcrypto_block_luks_create(QCryptoBlock *block, /* iter_time was in millis, but count_iters reported for secs */ iters = iters * luks_opts.iter_time / 1000; - /* Why /= 2 ? That matches cryptsetup, but there's no - * explanation why they chose /= 2... */ - iters /= 2; - if (iters > UINT32_MAX) { error_setg_errno(errp, ERANGE, "PBKDF iterations %llu larger than %u", From 2ab66cd577d6d0ec3c44b14cc823e76ea5a4397c Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Wed, 7 Sep 2016 12:48:32 +0100 Subject: [PATCH 077/723] crypto: increase default pbkdf2 time for luks to 2 seconds cryptsetup recently increased the default pbkdf2 time to 2 seconds to partially mitigate improvements in hardware performance wrt brute-forcing the pbkdf algorithm. This updates QEMU defaults to match. Reviewed-by: Eric Blake Signed-off-by: Daniel P. Berrange --- crypto/block-luks.c | 2 +- qapi/crypto.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crypto/block-luks.c b/crypto/block-luks.c index 3ab3250e3da..a848232034d 100644 --- a/crypto/block-luks.c +++ b/crypto/block-luks.c @@ -921,7 +921,7 @@ qcrypto_block_luks_create(QCryptoBlock *block, memcpy(&luks_opts, &options->u.luks, sizeof(luks_opts)); if (!luks_opts.has_iter_time) { - luks_opts.iter_time = 1000; + luks_opts.iter_time = 2000; } if (!luks_opts.has_cipher_alg) { luks_opts.cipher_alg = QCRYPTO_CIPHER_ALG_AES_256; diff --git a/qapi/crypto.json b/qapi/crypto.json index 2b6118f660b..6933b13bd01 100644 --- a/qapi/crypto.json +++ b/qapi/crypto.json @@ -187,7 +187,7 @@ # Currently defaults to 'sha256' # @iter-time: #optional number of milliseconds to spend in # PBKDF passphrase processing. Currently defaults -# to 1000. (since 2.8) +# to 2000. (since 2.8) # Since: 2.6 ## { 'struct': 'QCryptoBlockCreateOptionsLUKS', From 533008f4f382490f817a0c313f2d32f6173c08c7 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Wed, 7 Sep 2016 13:12:28 +0100 Subject: [PATCH 078/723] crypto: support more hash algorithms for pbkdf Currently pbkdf is only supported with SHA1 and SHA256. Expand this to support all algorithms known to QEMU. Reviewed-by: Eric Blake Signed-off-by: Daniel P. Berrange --- crypto/pbkdf-gcrypt.c | 12 +++++++- crypto/pbkdf-nettle.c | 63 +++++++++++++++++++++++++++++++++------ tests/test-crypto-pbkdf.c | 53 +++++++++++++++++++++++++++++++- 3 files changed, 117 insertions(+), 11 deletions(-) diff --git a/crypto/pbkdf-gcrypt.c b/crypto/pbkdf-gcrypt.c index 44cf31aff4a..40289858bf3 100644 --- a/crypto/pbkdf-gcrypt.c +++ b/crypto/pbkdf-gcrypt.c @@ -28,7 +28,11 @@ bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash) switch (hash) { case QCRYPTO_HASH_ALG_MD5: case QCRYPTO_HASH_ALG_SHA1: + case QCRYPTO_HASH_ALG_SHA224: case QCRYPTO_HASH_ALG_SHA256: + case QCRYPTO_HASH_ALG_SHA384: + case QCRYPTO_HASH_ALG_SHA512: + case QCRYPTO_HASH_ALG_RIPEMD160: return true; default: return false; @@ -45,7 +49,11 @@ int qcrypto_pbkdf2(QCryptoHashAlgorithm hash, static const int hash_map[QCRYPTO_HASH_ALG__MAX] = { [QCRYPTO_HASH_ALG_MD5] = GCRY_MD_MD5, [QCRYPTO_HASH_ALG_SHA1] = GCRY_MD_SHA1, + [QCRYPTO_HASH_ALG_SHA224] = GCRY_MD_SHA224, [QCRYPTO_HASH_ALG_SHA256] = GCRY_MD_SHA256, + [QCRYPTO_HASH_ALG_SHA384] = GCRY_MD_SHA384, + [QCRYPTO_HASH_ALG_SHA512] = GCRY_MD_SHA512, + [QCRYPTO_HASH_ALG_RIPEMD160] = GCRY_MD_RMD160, }; int ret; @@ -58,7 +66,9 @@ int qcrypto_pbkdf2(QCryptoHashAlgorithm hash, if (hash >= G_N_ELEMENTS(hash_map) || hash_map[hash] == GCRY_MD_NONE) { - error_setg(errp, "Unexpected hash algorithm %d", hash); + error_setg_errno(errp, ENOSYS, + "PBKDF does not support hash algorithm %s", + QCryptoHashAlgorithm_lookup[hash]); return -1; } diff --git a/crypto/pbkdf-nettle.c b/crypto/pbkdf-nettle.c index db81517adcc..6fb26716562 100644 --- a/crypto/pbkdf-nettle.c +++ b/crypto/pbkdf-nettle.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include +#include #include "qapi/error.h" #include "crypto/pbkdf.h" @@ -28,7 +29,11 @@ bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash) { switch (hash) { case QCRYPTO_HASH_ALG_SHA1: + case QCRYPTO_HASH_ALG_SHA224: case QCRYPTO_HASH_ALG_SHA256: + case QCRYPTO_HASH_ALG_SHA384: + case QCRYPTO_HASH_ALG_SHA512: + case QCRYPTO_HASH_ALG_RIPEMD160: return true; default: return false; @@ -42,30 +47,70 @@ int qcrypto_pbkdf2(QCryptoHashAlgorithm hash, uint8_t *out, size_t nout, Error **errp) { + union { + struct hmac_md5_ctx md5; + struct hmac_sha1_ctx sha1; + struct hmac_sha224_ctx sha224; + struct hmac_sha256_ctx sha256; + struct hmac_sha384_ctx sha384; + struct hmac_sha512_ctx sha512; + struct hmac_ripemd160_ctx ripemd160; + } ctx; + if (iterations > UINT_MAX) { error_setg_errno(errp, ERANGE, "PBKDF iterations %llu must be less than %u", (long long unsigned)iterations, UINT_MAX); return -1; } + switch (hash) { + case QCRYPTO_HASH_ALG_MD5: + hmac_md5_set_key(&ctx.md5, nkey, key); + PBKDF2(&ctx.md5, hmac_md5_update, hmac_md5_digest, + MD5_DIGEST_SIZE, iterations, nsalt, salt, nout, out); + break; + case QCRYPTO_HASH_ALG_SHA1: - pbkdf2_hmac_sha1(nkey, key, - iterations, - nsalt, salt, - nout, out); + hmac_sha1_set_key(&ctx.sha1, nkey, key); + PBKDF2(&ctx.sha1, hmac_sha1_update, hmac_sha1_digest, + SHA1_DIGEST_SIZE, iterations, nsalt, salt, nout, out); + break; + + case QCRYPTO_HASH_ALG_SHA224: + hmac_sha224_set_key(&ctx.sha224, nkey, key); + PBKDF2(&ctx.sha224, hmac_sha224_update, hmac_sha224_digest, + SHA224_DIGEST_SIZE, iterations, nsalt, salt, nout, out); break; case QCRYPTO_HASH_ALG_SHA256: - pbkdf2_hmac_sha256(nkey, key, - iterations, - nsalt, salt, - nout, out); + hmac_sha256_set_key(&ctx.sha256, nkey, key); + PBKDF2(&ctx.sha256, hmac_sha256_update, hmac_sha256_digest, + SHA256_DIGEST_SIZE, iterations, nsalt, salt, nout, out); + break; + + case QCRYPTO_HASH_ALG_SHA384: + hmac_sha384_set_key(&ctx.sha384, nkey, key); + PBKDF2(&ctx.sha384, hmac_sha384_update, hmac_sha384_digest, + SHA384_DIGEST_SIZE, iterations, nsalt, salt, nout, out); + break; + + case QCRYPTO_HASH_ALG_SHA512: + hmac_sha512_set_key(&ctx.sha512, nkey, key); + PBKDF2(&ctx.sha512, hmac_sha512_update, hmac_sha512_digest, + SHA512_DIGEST_SIZE, iterations, nsalt, salt, nout, out); + break; + + case QCRYPTO_HASH_ALG_RIPEMD160: + hmac_ripemd160_set_key(&ctx.ripemd160, nkey, key); + PBKDF2(&ctx.ripemd160, hmac_ripemd160_update, hmac_ripemd160_digest, + RIPEMD160_DIGEST_SIZE, iterations, nsalt, salt, nout, out); break; default: error_setg_errno(errp, ENOSYS, - "PBKDF does not support hash algorithm %d", hash); + "PBKDF does not support hash algorithm %s", + QCryptoHashAlgorithm_lookup[hash]); return -1; } return 0; diff --git a/tests/test-crypto-pbkdf.c b/tests/test-crypto-pbkdf.c index a651dc50a34..d937aff6b2e 100644 --- a/tests/test-crypto-pbkdf.c +++ b/tests/test-crypto-pbkdf.c @@ -261,7 +261,6 @@ static QCryptoPbkdfTestData test_data[] = { "\xcc\x4a\x5e\x6d\xca\x04\xec\x58", .nout = 32 }, -#if 0 { .path = "/crypto/pbkdf/nonrfc/sha512/iter1200", .hash = QCRYPTO_HASH_ALG_SHA512, @@ -279,6 +278,58 @@ static QCryptoPbkdfTestData test_data[] = { "\x76\x14\x80\xf3\xe3\x7a\x22\xb9", .nout = 32 }, + { + .path = "/crypto/pbkdf/nonrfc/sha224/iter1200", + .hash = QCRYPTO_HASH_ALG_SHA224, + .iterations = 1200, + .key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + .nkey = 129, + .salt = "pass phrase exceeds block size", + .nsalt = 30, + .out = "\x13\x3b\x88\x0c\x0e\x52\xa2\x41" + "\x49\x33\x35\xa6\xc3\x83\xae\x23" + "\xf6\x77\x43\x9e\x5b\x30\x92\x3e" + "\x4a\x3a\xaa\x24\x69\x3c\xed\x20", + .nout = 32 + }, + { + .path = "/crypto/pbkdf/nonrfc/sha384/iter1200", + .hash = QCRYPTO_HASH_ALG_SHA384, + .iterations = 1200, + .key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + .nkey = 129, + .salt = "pass phrase exceeds block size", + .nsalt = 30, + .out = "\xfe\xe3\xe1\x84\xc9\x25\x3e\x10" + "\x47\xc8\x7d\x53\xc6\xa5\xe3\x77" + "\x29\x41\x76\xbd\x4b\xe3\x9b\xac" + "\x05\x6c\x11\xdd\x17\xc5\x93\x80", + .nout = 32 + }, + { + .path = "/crypto/pbkdf/nonrfc/ripemd160/iter1200", + .hash = QCRYPTO_HASH_ALG_RIPEMD160, + .iterations = 1200, + .key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + .nkey = 129, + .salt = "pass phrase exceeds block size", + .nsalt = 30, + .out = "\xd6\xcb\xd8\xa7\xdb\x0c\xa2\x2a" + "\x23\x5e\x47\xaf\xdb\xda\xa8\xef" + "\xe4\x01\x0d\x6f\xb5\x33\xc8\xbd" + "\xce\xbf\x91\x14\x8b\x5c\x48\x41", + .nout = 32 + }, +#if 0 { .path = "/crypto/pbkdf/nonrfc/whirlpool/iter1200", .hash = QCRYPTO_HASH_ALG_WHIRLPOOL, From b57482d7a0fe669aeb6f0c3c3503d143b9db89dd Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Wed, 14 Sep 2016 10:18:09 +0100 Subject: [PATCH 079/723] crypto: add trace points for TLS cert verification It is very useful to know about TLS cert verification status when debugging, so add a trace point for it. Signed-off-by: Daniel P. Berrange --- crypto/tlssession.c | 10 ++++++++-- crypto/trace-events | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/crypto/tlssession.c b/crypto/tlssession.c index 2de42c61cb4..96a02deb695 100644 --- a/crypto/tlssession.c +++ b/crypto/tlssession.c @@ -351,16 +351,22 @@ qcrypto_tls_session_check_credentials(QCryptoTLSSession *session, { if (object_dynamic_cast(OBJECT(session->creds), TYPE_QCRYPTO_TLS_CREDS_ANON)) { + trace_qcrypto_tls_session_check_creds(session, "nop"); return 0; } else if (object_dynamic_cast(OBJECT(session->creds), TYPE_QCRYPTO_TLS_CREDS_X509)) { if (session->creds->verifyPeer) { - return qcrypto_tls_session_check_certificate(session, - errp); + int ret = qcrypto_tls_session_check_certificate(session, + errp); + trace_qcrypto_tls_session_check_creds(session, + ret == 0 ? "pass" : "fail"); + return ret; } else { + trace_qcrypto_tls_session_check_creds(session, "skip"); return 0; } } else { + trace_qcrypto_tls_session_check_creds(session, "error"); error_setg(errp, "Unexpected credential type %s", object_get_typename(OBJECT(session->creds))); return -1; diff --git a/crypto/trace-events b/crypto/trace-events index 81818437237..dc6ddd30d65 100644 --- a/crypto/trace-events +++ b/crypto/trace-events @@ -17,3 +17,4 @@ qcrypto_tls_creds_x509_load_cert_list(void *creds, const char *file) "TLS creds # crypto/tlssession.c qcrypto_tls_session_new(void *session, void *creds, const char *hostname, const char *aclname, int endpoint) "TLS session new session=%p creds=%p hostname=%s aclname=%s endpoint=%d" +qcrypto_tls_session_check_creds(void *session, const char *status) "TLS session check creds session=%p status=%s" From 3688d8c717927e7ecaa8c260bc9cc706e3dbef7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 12 Sep 2016 13:18:56 +0400 Subject: [PATCH 080/723] build-sys: define QEMU_VERSION_{MAJOR, MINOR, MICRO} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are better chances to find what went wrong at build time than a later assert in qmp_query_version Signed-off-by: Marc-André Lureau Message-Id: <20160912091913.15831-2-marcandre.lureau@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- qmp.c | 16 +++------------- scripts/create_config | 6 ++++++ 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/qmp.c b/qmp.c index dea8f81345b..6733463fa23 100644 --- a/qmp.c +++ b/qmp.c @@ -51,21 +51,11 @@ NameInfo *qmp_query_name(Error **errp) VersionInfo *qmp_query_version(Error **errp) { VersionInfo *info = g_new0(VersionInfo, 1); - const char *version = QEMU_VERSION; - const char *tmp; - int err; info->qemu = g_new0(VersionTriple, 1); - err = qemu_strtoll(version, &tmp, 10, &info->qemu->major); - assert(err == 0); - tmp++; - - err = qemu_strtoll(tmp, &tmp, 10, &info->qemu->minor); - assert(err == 0); - tmp++; - - err = qemu_strtoll(tmp, &tmp, 10, &info->qemu->micro); - assert(err == 0); + info->qemu->major = QEMU_VERSION_MAJOR; + info->qemu->minor = QEMU_VERSION_MINOR; + info->qemu->micro = QEMU_VERSION_MICRO; info->package = g_strdup(QEMU_PKGVERSION); return info; diff --git a/scripts/create_config b/scripts/create_config index 1dd6a354f53..e6929dd61ef 100755 --- a/scripts/create_config +++ b/scripts/create_config @@ -7,7 +7,13 @@ while read line; do case $line in VERSION=*) # configuration version=${line#*=} + major=$(echo "$version" | cut -d. -f1) + minor=$(echo "$version" | cut -d. -f2) + micro=$(echo "$version" | cut -d. -f3) echo "#define QEMU_VERSION \"$version\"" + echo "#define QEMU_VERSION_MAJOR $major" + echo "#define QEMU_VERSION_MINOR $minor" + echo "#define QEMU_VERSION_MICRO $micro" ;; qemu_*dir=*) # qemu-specific directory configuration name=${line%=*} From 119ebac1feb26181cbadd13a8a795a199d0bbaa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 12 Sep 2016 13:18:57 +0400 Subject: [PATCH 081/723] qapi-schema: use generated marshaller for 'qmp_capabilities' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit qapi'fy the 'qmp_capabilities' command, makes the command visible in query-qmp-schema. Signed-off-by: Marc-André Lureau Reviewed-by: Eric Blake Reviewed-by: Markus Armbruster Message-Id: <20160912091913.15831-3-marcandre.lureau@redhat.com> Signed-off-by: Markus Armbruster --- monitor.c | 4 ++-- qapi-schema.json | 21 +++++++++++++++++++++ qmp-commands.hx | 2 +- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/monitor.c b/monitor.c index 5c003731e28..991eaf7e0c1 100644 --- a/monitor.c +++ b/monitor.c @@ -617,7 +617,7 @@ static void monitor_qapi_event_init(void) qmp_event_set_func_emit(monitor_qapi_event_queue); } -static void qmp_capabilities(QDict *params, QObject **ret_data, Error **errp) +void qmp_qmp_capabilities(Error **errp) { cur_mon->qmp.in_command_mode = true; } @@ -3656,7 +3656,7 @@ static int monitor_can_read(void *opaque) static bool invalid_qmp_mode(const Monitor *mon, const mon_cmd_t *cmd, Error **errp) { - bool is_cap = cmd->mhandler.cmd_new == qmp_capabilities; + bool is_cap = cmd->mhandler.cmd_new == qmp_marshal_qmp_capabilities; if (is_cap && mon->qmp.in_command_mode) { error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND, diff --git a/qapi-schema.json b/qapi-schema.json index c4f3674d08e..5e15d284689 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -20,6 +20,27 @@ # QAPI introspection { 'include': 'qapi/introspect.json' } +## +# @qmp_capabilities: +# +# Enable QMP capabilities. +# +# Arguments: None. +# +# Example: +# +# -> { "execute": "qmp_capabilities" } +# <- { "return": {} } +# +# Notes: This command is valid exactly when first connecting: it must be +# issued before any other command will be accepted, and will fail once the +# monitor is accepting other commands. (see qemu docs/qmp-spec.txt) +# +# Since: 0.13 +# +## +{ 'command': 'qmp_capabilities' } + ## # @LostTickPolicy: # diff --git a/qmp-commands.hx b/qmp-commands.hx index e6c91936003..8a135506dcc 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -2219,7 +2219,7 @@ EQMP .args_type = "", .params = "", .help = "enable QMP capabilities", - .mhandler.cmd_new = qmp_capabilities, + .mhandler.cmd_new = qmp_marshal_qmp_capabilities, }, SQMP From 94cfd07f26ef240499f3a4a7a14a4bcc17b8f003 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 12 Sep 2016 13:18:58 +0400 Subject: [PATCH 082/723] qapi-schema: add 'device_add' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Even though device_add is not fully qapi'fied, we may add it to the json schema with 'gen': false, so registration and documentation can be generated. Signed-off-by: Marc-André Lureau Reviewed-by: Eric Blake Message-Id: <20160912091913.15831-4-marcandre.lureau@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- qapi-schema.json | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/qapi-schema.json b/qapi-schema.json index 5e15d284689..55f825dd067 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -2200,6 +2200,46 @@ ## { 'command': 'xen-set-global-dirty-log', 'data': { 'enable': 'bool' } } +## +# @device_add: +# +# @driver: the name of the new device's driver +# +# @bus: #optional the device's parent bus (device tree path) +# +# @id: the device's ID, must be unique +# +# Additional arguments depend on the type. +# +# Add a device. +# +# Notes: +# 1. For detailed information about this command, please refer to the +# 'docs/qdev-device-use.txt' file. +# +# 2. It's possible to list device properties by running QEMU with the +# "-device DEVICE,help" command-line argument, where DEVICE is the +# device's name +# +# Example: +# +# -> { "execute": "device_add", +# "arguments": { "driver": "e1000", "id": "net1", +# "bus": "pci.0", +# "mac": "52:54:00:12:34:56" } } +# <- { "return": {} } +# +# TODO This command effectively bypasses QAPI completely due to its +# "additional arguments" business. It shouldn't have been added to +# the schema in this form. It should be qapified properly, or +# replaced by a properly qapified command. +# +# Since: 0.13 +## +{ 'command': 'device_add', + 'data': {'driver': 'str', 'id': 'str'}, + 'gen': false } # so we can get the additional arguments + ## # @device_del: # From d79bedfa404a02a4652cc8d964fa6dc9b7ec62f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 12 Sep 2016 13:18:59 +0400 Subject: [PATCH 083/723] monitor: simplify invalid_qmp_mode() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit handle_qmp_command() will switch to use qmp_dispatch(). It won't have a pointer to the marshaller function anymore, but only the name of the command to invoke. Simplify invalid_qmp_mode() so it can just be called with the command name. Signed-off-by: Marc-André Lureau Reviewed-by: Eric Blake Message-Id: <20160912091913.15831-5-marcandre.lureau@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- monitor.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/monitor.c b/monitor.c index 991eaf7e0c1..e156026ffab 100644 --- a/monitor.c +++ b/monitor.c @@ -3653,21 +3653,21 @@ static int monitor_can_read(void *opaque) return (mon->suspend_cnt == 0) ? 1 : 0; } -static bool invalid_qmp_mode(const Monitor *mon, const mon_cmd_t *cmd, +static bool invalid_qmp_mode(const Monitor *mon, const char *cmd, Error **errp) { - bool is_cap = cmd->mhandler.cmd_new == qmp_marshal_qmp_capabilities; + bool is_cap = g_str_equal(cmd, "qmp_capabilities"); if (is_cap && mon->qmp.in_command_mode) { error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND, "Capabilities negotiation is already complete, command " - "'%s' ignored", cmd->name); + "'%s' ignored", cmd); return true; } if (!is_cap && !mon->qmp.in_command_mode) { error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND, "Expecting capabilities negotiation with " - "'qmp_capabilities' before command '%s'", cmd->name); + "'qmp_capabilities' before command '%s'", cmd); return true; } return false; @@ -3958,7 +3958,7 @@ static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens) "The command %s has not been found", cmd_name); goto err_out; } - if (invalid_qmp_mode(mon, cmd, &local_err)) { + if (invalid_qmp_mode(mon, cmd_name, &local_err)) { goto err_out; } From edcfaefe07e242f204d476a8f2290895593eb09f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 12 Sep 2016 13:19:00 +0400 Subject: [PATCH 084/723] monitor: register gen:false commands manually MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since a few commands are using 'gen': false, they are not registered automatically by the generator. Register manually instead. This is in preparation for removal of qapi 'middle' mode generation. Note that qmp_init_marshal() function isn't run yet, so the commands aren't actually registered, until module_call_init(MODULE_INIT_QAPI) is added in a later patch. Signed-off-by: Marc-André Lureau Reviewed-by: Eric Blake Message-Id: <20160912091913.15831-6-marcandre.lureau@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- monitor.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/monitor.c b/monitor.c index e156026ffab..b7ae5528a10 100644 --- a/monitor.c +++ b/monitor.c @@ -79,6 +79,7 @@ #include "sysemu/block-backend.h" #include "sysemu/qtest.h" #include "qemu/cutils.h" +#include "qapi/qmp/dispatch.h" /* for hmp_info_irq/pic */ #if defined(TARGET_SPARC) @@ -1007,6 +1008,18 @@ static void qmp_query_qmp_schema(QDict *qdict, QObject **ret_data, *ret_data = qobject_from_json(qmp_schema_json); } +static void qmp_init_marshal(void) +{ + qmp_register_command("query-qmp-schema", qmp_query_qmp_schema, + QCO_NO_OPTIONS); + qmp_register_command("device_add", qmp_device_add, + QCO_NO_OPTIONS); + qmp_register_command("netdev_add", qmp_netdev_add, + QCO_NO_OPTIONS); +} + +qapi_init(qmp_init_marshal); + /* set the current CPU defined by the user */ int monitor_set_cpu(int cpu_index) { From 60b03e4e6ac6eee3acac3c3173180f43adc6ddd5 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 12 Sep 2016 13:19:01 +0400 Subject: [PATCH 085/723] qapi: Support unregistering QMP commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Markus Armbruster Reviewed-by: Marc-André Lureau Message-Id: <20160912091913.15831-7-marcandre.lureau@redhat.com> --- include/qapi/qmp/dispatch.h | 1 + qapi/qmp-registry.c | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h index 48c11b66d1f..57651ea955d 100644 --- a/include/qapi/qmp/dispatch.h +++ b/include/qapi/qmp/dispatch.h @@ -36,6 +36,7 @@ typedef struct QmpCommand void qmp_register_command(const char *name, QmpCommandFunc *fn, QmpCommandOptions options); +void qmp_unregister_command(const char *name); QmpCommand *qmp_find_command(const char *name); QObject *qmp_dispatch(QObject *request); void qmp_disable_command(const char *name); diff --git a/qapi/qmp-registry.c b/qapi/qmp-registry.c index 68b24c98b0e..e8053686f3f 100644 --- a/qapi/qmp-registry.c +++ b/qapi/qmp-registry.c @@ -30,6 +30,14 @@ void qmp_register_command(const char *name, QmpCommandFunc *fn, QTAILQ_INSERT_TAIL(&qmp_commands, cmd, node); } +void qmp_unregister_command(const char *name) +{ + QmpCommand *cmd = qmp_find_command(name); + + QTAILQ_REMOVE(&qmp_commands, cmd, node); + g_free(cmd); +} + QmpCommand *qmp_find_command(const char *name) { QmpCommand *cmd; From 5032a16d1d44cc805ea0240903dc8dc98294da1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 12 Sep 2016 13:19:02 +0400 Subject: [PATCH 086/723] qmp: Hack to keep commands configuration-specific MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We currently define QMP commands in two places: the QAPI schema and qmp-commands.hx. The latter is preprocessed, the former is not. We use the preprocessor to suppress configuration-specific commands. For instance, query-spice is only available #ifdef CONFIG_SPICE. QMP command dispatch and query-commands use the qmp-commands.hx definition, and thus obey the #ifdeffery there. Good, because it lets QMP clients probe for available features more easily. query-qmp-schema uses the QAPI schema, and thus lists the configuration-specific commands even when they're unavailable. Not so good. We're about to flip command dispatch and query-commands to the non-middle-mode command registry, which uses the QAPI schema, so we can ditch qmp-commands.hx. To avoid regressing query-commands, arrange for commands that are suppressed with the preprocessor now to be unregistered with that registry. This will keep them unavailable and out of query-commands when we flip command dispatch and query-commands to that registry, exactly as before. This is a hack. The proper solution is to support configuration-specific commands in the QAPI schema. Mark it FIXME. Signed-off-by: Marc-André Lureau Signed-off-by: Markus Armbruster Message-Id: <20160912091913.15831-8-marcandre.lureau@redhat.com> --- monitor.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/monitor.c b/monitor.c index b7ae5528a10..18d37f7f136 100644 --- a/monitor.c +++ b/monitor.c @@ -1008,6 +1008,38 @@ static void qmp_query_qmp_schema(QDict *qdict, QObject **ret_data, *ret_data = qobject_from_json(qmp_schema_json); } +/* + * Note: right now, this function is never called. It will be called + * shortly when we stop using QAPI 'middle mode'. The rest of this + * comment is written as if that was the case already. + * + * We used to define commands in qmp-commands.hx in addition to the + * QAPI schema. This permitted defining some of them only in certain + * configurations. query-commands has always reflected that (good, + * because it lets QMP clients figure out what's actually available), + * while query-qmp-schema never did (not so good). This function is a + * hack to keep the configuration-specific commands defined exactly as + * before, even though qmp-commands.hx is gone. + * + * FIXME Educate the QAPI schema on configuration-specific commands, + * and drop this hack. + */ +static void qmp_unregister_commands_hack(void) +{ +#ifndef CONFIG_SPICE + qmp_unregister_command("query-spice"); +#endif +#ifndef TARGET_I386 + qmp_unregister_command("rtc-reset-reinjection"); +#endif +#ifndef TARGET_S390X + qmp_unregister_command("dump-skeys"); +#endif +#ifndef TARGET_ARM + qmp_unregister_command("query-gic-capabilities"); +#endif +} + static void qmp_init_marshal(void) { qmp_register_command("query-qmp-schema", qmp_query_qmp_schema, @@ -1016,6 +1048,9 @@ static void qmp_init_marshal(void) QCO_NO_OPTIONS); qmp_register_command("netdev_add", qmp_netdev_add, QCO_NO_OPTIONS); + + /* call it after the rest of qapi_init() */ + register_module_init(qmp_unregister_commands_hack, MODULE_INIT_QAPI); } qapi_init(qmp_init_marshal); From b804dc3bcddce6d0cd58e3c66cb0ee5b282b9e14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 12 Sep 2016 13:19:03 +0400 Subject: [PATCH 087/723] qapi: export the marshallers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make it possible to call marshallers manually, without going through qmp_dispatch(). (this is currently only possible in middle-mode, but it's also useful in general) Signed-off-by: Marc-André Lureau Message-Id: <20160912091913.15831-9-marcandre.lureau@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- scripts/qapi-commands.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py index a06a2c4f9b1..b150db97922 100644 --- a/scripts/qapi-commands.py +++ b/scripts/qapi-commands.py @@ -84,10 +84,7 @@ def gen_marshal_output(ret_type): def gen_marshal_proto(name): - ret = 'void qmp_marshal_%s(QDict *args, QObject **ret, Error **errp)' % c_name(name) - if not middle_mode: - ret = 'static ' + ret - return ret + return 'void qmp_marshal_%s(QDict *args, QObject **ret, Error **errp)' % c_name(name) def gen_marshal_decl(name): @@ -222,8 +219,7 @@ def visit_command(self, name, info, arg_type, ret_type, if ret_type and ret_type not in self._visited_ret_types: self._visited_ret_types.add(ret_type) self.defn += gen_marshal_output(ret_type) - if middle_mode: - self.decl += gen_marshal_decl(name) + self.decl += gen_marshal_decl(name) self.defn += gen_marshal(name, arg_type, boxed, ret_type) if not middle_mode: self._regy += gen_register_command(name, success_response) From c823501ea9bf7b13ca32226e1c628480edb034d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 12 Sep 2016 13:19:04 +0400 Subject: [PATCH 088/723] monitor: use qmp_find_command() (using generated qapi code) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stop using the so-called 'middle' mode. Instead, use qmp_find_command() from generated qapi commands registry. Update and fix the documentation too. Signed-off-by: Marc-André Lureau Message-Id: <20160912091913.15831-10-marcandre.lureau@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- Makefile | 2 +- docs/writing-qmp-commands.txt | 8 +- monitor.c | 14 ++-- qmp-commands.hx | 146 ---------------------------------- vl.c | 1 + 5 files changed, 11 insertions(+), 160 deletions(-) diff --git a/Makefile b/Makefile index 1fad5b78e57..1c9f062f915 100644 --- a/Makefile +++ b/Makefile @@ -312,7 +312,7 @@ $(qapi-modules) $(SRC_PATH)/scripts/qapi-event.py $(qapi-py) qmp-commands.h qmp-marshal.c :\ $(qapi-modules) $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py \ - $(gen-out-type) -o "." -m $<, \ + $(gen-out-type) -o "." $<, \ " GEN $@") qmp-introspect.h qmp-introspect.c :\ $(qapi-modules) $(SRC_PATH)/scripts/qapi-introspect.py $(qapi-py) diff --git a/docs/writing-qmp-commands.txt b/docs/writing-qmp-commands.txt index 59aa77ae254..0a66e0ebb8d 100644 --- a/docs/writing-qmp-commands.txt +++ b/docs/writing-qmp-commands.txt @@ -127,7 +127,6 @@ following at the bottom: { .name = "hello-world", .args_type = "", - .mhandler.cmd_new = qmp_marshal_hello_world, }, You're done. Now build qemu, run it as suggested in the "Testing" section, @@ -179,7 +178,6 @@ The last step is to update the qmp-commands.hx file: { .name = "hello-world", .args_type = "message:s?", - .mhandler.cmd_new = qmp_marshal_hello_world, }, Notice that the "args_type" member got our "message" argument. The character @@ -454,12 +452,11 @@ There are a number of things to be noticed: 6. You have to include the "qmp-commands.h" header file in qemu-timer.c, otherwise qemu won't build -The last step is to add the correspoding entry in the qmp-commands.hx file: +The last step is to add the corresponding entry in the qmp-commands.hx file: { .name = "query-alarm-clock", .args_type = "", - .mhandler.cmd_new = qmp_marshal_query_alarm_clock, }, Time to test the new command. Build qemu, run it as described in the "Testing" @@ -518,7 +515,7 @@ in the monitor.c file. The entry for the "info alarmclock" follows: .args_type = "", .params = "", .help = "show information about the alarm clock", - .mhandler.info = hmp_info_alarm_clock, + .mhandler.cmd = hmp_info_alarm_clock, }, To test this, run qemu and type "info alarmclock" in the user monitor. @@ -605,7 +602,6 @@ To test this you have to add the corresponding qmp-commands.hx entry: { .name = "query-alarm-methods", .args_type = "", - .mhandler.cmd_new = qmp_marshal_query_alarm_methods, }, Now Build qemu, run it as explained in the "Testing" section and try our new diff --git a/monitor.c b/monitor.c index 18d37f7f136..6e0ae814542 100644 --- a/monitor.c +++ b/monitor.c @@ -1009,10 +1009,6 @@ static void qmp_query_qmp_schema(QDict *qdict, QObject **ret_data, } /* - * Note: right now, this function is never called. It will be called - * shortly when we stop using QAPI 'middle mode'. The rest of this - * comment is written as if that was the case already. - * * We used to define commands in qmp-commands.hx in addition to the * QAPI schema. This permitted defining some of them only in certain * configurations. query-commands has always reflected that (good, @@ -3976,6 +3972,7 @@ static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens) QObject *obj, *data; QDict *input, *args; const mon_cmd_t *cmd; + QmpCommand *qcmd; const char *cmd_name; Monitor *mon = cur_mon; @@ -4001,7 +3998,8 @@ static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens) cmd_name = qdict_get_str(input, "execute"); trace_handle_qmp_command(mon, cmd_name); cmd = qmp_find_cmd(cmd_name); - if (!cmd) { + qcmd = qmp_find_command(cmd_name); + if (!qcmd || !cmd) { error_set(&local_err, ERROR_CLASS_COMMAND_NOT_FOUND, "The command %s has not been found", cmd_name); goto err_out; @@ -4023,7 +4021,7 @@ static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens) goto err_out; } - cmd->mhandler.cmd_new(args, &data, &local_err); + qcmd->fn(args, &data, &local_err); err_out: monitor_protocol_emitter(mon, data, local_err); @@ -4095,7 +4093,9 @@ static QObject *get_qmp_greeting(void) QObject *ver = NULL; qmp_marshal_query_version(NULL, &ver, NULL); - return qobject_from_jsonf("{'QMP':{'version': %p,'capabilities': []}}",ver); + + return qobject_from_jsonf("{'QMP': {'version': %p, 'capabilities': []}}", + ver); } static void monitor_qmp_event(void *opaque, int event) diff --git a/qmp-commands.hx b/qmp-commands.hx index 8a135506dcc..734f3d73422 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -63,7 +63,6 @@ EQMP { .name = "quit", .args_type = "", - .mhandler.cmd_new = qmp_marshal_quit, }, SQMP @@ -84,7 +83,6 @@ EQMP { .name = "eject", .args_type = "force:-f,device:B", - .mhandler.cmd_new = qmp_marshal_eject, }, SQMP @@ -110,7 +108,6 @@ EQMP { .name = "change", .args_type = "device:B,target:F,arg:s?", - .mhandler.cmd_new = qmp_marshal_change, }, SQMP @@ -146,7 +143,6 @@ EQMP { .name = "screendump", .args_type = "filename:F", - .mhandler.cmd_new = qmp_marshal_screendump, }, SQMP @@ -169,7 +165,6 @@ EQMP { .name = "stop", .args_type = "", - .mhandler.cmd_new = qmp_marshal_stop, }, SQMP @@ -190,7 +185,6 @@ EQMP { .name = "cont", .args_type = "", - .mhandler.cmd_new = qmp_marshal_cont, }, SQMP @@ -211,7 +205,6 @@ EQMP { .name = "system_wakeup", .args_type = "", - .mhandler.cmd_new = qmp_marshal_system_wakeup, }, SQMP @@ -232,7 +225,6 @@ EQMP { .name = "system_reset", .args_type = "", - .mhandler.cmd_new = qmp_marshal_system_reset, }, SQMP @@ -253,7 +245,6 @@ EQMP { .name = "system_powerdown", .args_type = "", - .mhandler.cmd_new = qmp_marshal_system_powerdown, }, SQMP @@ -276,7 +267,6 @@ EQMP .args_type = "device:O", .params = "driver[,prop=value][,...]", .help = "add device, like -device on the command line", - .mhandler.cmd_new = qmp_device_add, }, SQMP @@ -310,7 +300,6 @@ EQMP { .name = "device_del", .args_type = "id:s", - .mhandler.cmd_new = qmp_marshal_device_del, }, SQMP @@ -338,7 +327,6 @@ EQMP { .name = "send-key", .args_type = "keys:q,hold-time:i?", - .mhandler.cmd_new = qmp_marshal_send_key, }, SQMP @@ -369,7 +357,6 @@ EQMP { .name = "cpu", .args_type = "index:i", - .mhandler.cmd_new = qmp_marshal_cpu, }, SQMP @@ -394,7 +381,6 @@ EQMP { .name = "cpu-add", .args_type = "id:i", - .mhandler.cmd_new = qmp_marshal_cpu_add, }, SQMP @@ -417,7 +403,6 @@ EQMP { .name = "memsave", .args_type = "val:l,size:i,filename:s,cpu:i?", - .mhandler.cmd_new = qmp_marshal_memsave, }, SQMP @@ -446,7 +431,6 @@ EQMP { .name = "pmemsave", .args_type = "val:l,size:i,filename:s", - .mhandler.cmd_new = qmp_marshal_pmemsave, }, SQMP @@ -474,7 +458,6 @@ EQMP { .name = "inject-nmi", .args_type = "", - .mhandler.cmd_new = qmp_marshal_inject_nmi, }, SQMP @@ -497,7 +480,6 @@ EQMP { .name = "ringbuf-write", .args_type = "device:s,data:s,format:s?", - .mhandler.cmd_new = qmp_marshal_ringbuf_write, }, SQMP @@ -526,7 +508,6 @@ EQMP { .name = "ringbuf-read", .args_type = "device:s,size:i,format:s?", - .mhandler.cmd_new = qmp_marshal_ringbuf_read, }, SQMP @@ -562,7 +543,6 @@ EQMP { .name = "xen-save-devices-state", .args_type = "filename:F", - .mhandler.cmd_new = qmp_marshal_xen_save_devices_state, }, SQMP @@ -589,7 +569,6 @@ EQMP { .name = "xen-load-devices-state", .args_type = "filename:F", - .mhandler.cmd_new = qmp_marshal_xen_load_devices_state, }, SQMP @@ -616,7 +595,6 @@ EQMP { .name = "xen-set-global-dirty-log", .args_type = "enable:b", - .mhandler.cmd_new = qmp_marshal_xen_set_global_dirty_log, }, SQMP @@ -640,7 +618,6 @@ EQMP { .name = "migrate", .args_type = "detach:-d,blk:-b,inc:-i,uri:s", - .mhandler.cmd_new = qmp_marshal_migrate, }, SQMP @@ -673,7 +650,6 @@ EQMP { .name = "migrate_cancel", .args_type = "", - .mhandler.cmd_new = qmp_marshal_migrate_cancel, }, SQMP @@ -694,7 +670,6 @@ EQMP { .name = "migrate-incoming", .args_type = "uri:s", - .mhandler.cmd_new = qmp_marshal_migrate_incoming, }, SQMP @@ -722,7 +697,6 @@ EQMP { .name = "migrate-set-cache-size", .args_type = "value:o", - .mhandler.cmd_new = qmp_marshal_migrate_set_cache_size, }, SQMP @@ -745,7 +719,6 @@ EQMP { .name = "migrate-start-postcopy", .args_type = "", - .mhandler.cmd_new = qmp_marshal_migrate_start_postcopy, }, SQMP @@ -764,7 +737,6 @@ EQMP { .name = "query-migrate-cache-size", .args_type = "", - .mhandler.cmd_new = qmp_marshal_query_migrate_cache_size, }, SQMP @@ -786,7 +758,6 @@ EQMP { .name = "migrate_set_speed", .args_type = "value:o", - .mhandler.cmd_new = qmp_marshal_migrate_set_speed, }, SQMP @@ -809,7 +780,6 @@ EQMP { .name = "migrate_set_downtime", .args_type = "value:T", - .mhandler.cmd_new = qmp_marshal_migrate_set_downtime, }, SQMP @@ -834,7 +804,6 @@ EQMP .args_type = "protocol:s,hostname:s,port:i?,tls-port:i?,cert-subject:s?", .params = "protocol hostname port tls-port cert-subject", .help = "set migration information for remote display", - .mhandler.cmd_new = qmp_marshal_client_migrate_info, }, SQMP @@ -868,7 +837,6 @@ EQMP .args_type = "paging:b,protocol:s,detach:b?,begin:i?,end:i?,format:s?", .params = "-p protocol [-d] [begin] [length] [format]", .help = "dump guest memory to file", - .mhandler.cmd_new = qmp_marshal_dump_guest_memory, }, SQMP @@ -907,7 +875,6 @@ EQMP { .name = "query-dump-guest-memory-capability", .args_type = "", - .mhandler.cmd_new = qmp_marshal_query_dump_guest_memory_capability, }, SQMP @@ -929,7 +896,6 @@ EQMP .args_type = "", .params = "", .help = "query background dump status", - .mhandler.cmd_new = qmp_marshal_query_dump, }, SQMP @@ -952,7 +918,6 @@ EQMP { .name = "dump-skeys", .args_type = "filename:F", - .mhandler.cmd_new = qmp_marshal_dump_skeys, }, #endif @@ -976,7 +941,6 @@ EQMP { .name = "netdev_add", .args_type = "netdev:O", - .mhandler.cmd_new = qmp_netdev_add, }, SQMP @@ -1007,7 +971,6 @@ EQMP { .name = "netdev_del", .args_type = "id:s", - .mhandler.cmd_new = qmp_marshal_netdev_del, }, SQMP @@ -1031,7 +994,6 @@ EQMP { .name = "object-add", .args_type = "qom-type:s,id:s,props:q?", - .mhandler.cmd_new = qmp_marshal_object_add, }, SQMP @@ -1057,7 +1019,6 @@ EQMP { .name = "object-del", .args_type = "id:s", - .mhandler.cmd_new = qmp_marshal_object_del, }, SQMP @@ -1082,7 +1043,6 @@ EQMP { .name = "block_resize", .args_type = "device:s?,node-name:s?,size:o", - .mhandler.cmd_new = qmp_marshal_block_resize, }, SQMP @@ -1107,7 +1067,6 @@ EQMP { .name = "block-stream", .args_type = "job-id:s?,device:B,base:s?,speed:o?,backing-file:s?,on-error:s?", - .mhandler.cmd_new = qmp_marshal_block_stream, }, SQMP @@ -1152,7 +1111,6 @@ EQMP { .name = "block-commit", .args_type = "job-id:s?,device:B,base:s?,top:s?,backing-file:s?,speed:o?", - .mhandler.cmd_new = qmp_marshal_block_commit, }, SQMP @@ -1219,7 +1177,6 @@ EQMP .args_type = "job-id:s?,sync:s,device:B,target:s,speed:i?,mode:s?," "format:s?,bitmap:s?,compress:b?," "on-source-error:s?,on-target-error:s?", - .mhandler.cmd_new = qmp_marshal_drive_backup, }, SQMP @@ -1277,7 +1234,6 @@ EQMP .name = "blockdev-backup", .args_type = "job-id:s?,sync:s,device:B,target:B,speed:i?,compress:b?," "on-source-error:s?,on-target-error:s?", - .mhandler.cmd_new = qmp_marshal_blockdev_backup, }, SQMP @@ -1321,33 +1277,27 @@ EQMP { .name = "block-job-set-speed", .args_type = "device:B,speed:o", - .mhandler.cmd_new = qmp_marshal_block_job_set_speed, }, { .name = "block-job-cancel", .args_type = "device:B,force:b?", - .mhandler.cmd_new = qmp_marshal_block_job_cancel, }, { .name = "block-job-pause", .args_type = "device:B", - .mhandler.cmd_new = qmp_marshal_block_job_pause, }, { .name = "block-job-resume", .args_type = "device:B", - .mhandler.cmd_new = qmp_marshal_block_job_resume, }, { .name = "block-job-complete", .args_type = "device:B", - .mhandler.cmd_new = qmp_marshal_block_job_complete, }, { .name = "transaction", .args_type = "actions:q,properties:q?", - .mhandler.cmd_new = qmp_marshal_transaction, }, SQMP @@ -1442,7 +1392,6 @@ EQMP { .name = "block-dirty-bitmap-add", .args_type = "node:B,name:s,granularity:i?", - .mhandler.cmd_new = qmp_marshal_block_dirty_bitmap_add, }, SQMP @@ -1470,7 +1419,6 @@ EQMP { .name = "block-dirty-bitmap-remove", .args_type = "node:B,name:s", - .mhandler.cmd_new = qmp_marshal_block_dirty_bitmap_remove, }, SQMP @@ -1498,7 +1446,6 @@ EQMP { .name = "block-dirty-bitmap-clear", .args_type = "node:B,name:s", - .mhandler.cmd_new = qmp_marshal_block_dirty_bitmap_clear, }, SQMP @@ -1527,7 +1474,6 @@ EQMP { .name = "blockdev-snapshot-sync", .args_type = "device:s?,node-name:s?,snapshot-file:s,snapshot-node-name:s?,format:s?,mode:s?", - .mhandler.cmd_new = qmp_marshal_blockdev_snapshot_sync, }, SQMP @@ -1563,7 +1509,6 @@ EQMP { .name = "blockdev-snapshot", .args_type = "node:s,overlay:s", - .mhandler.cmd_new = qmp_marshal_blockdev_snapshot, }, SQMP @@ -1601,7 +1546,6 @@ EQMP { .name = "blockdev-snapshot-internal-sync", .args_type = "device:B,name:s", - .mhandler.cmd_new = qmp_marshal_blockdev_snapshot_internal_sync, }, SQMP @@ -1631,8 +1575,6 @@ EQMP { .name = "blockdev-snapshot-delete-internal-sync", .args_type = "device:B,id:s?,name:s?", - .mhandler.cmd_new = - qmp_marshal_blockdev_snapshot_delete_internal_sync, }, SQMP @@ -1676,7 +1618,6 @@ EQMP "on-source-error:s?,on-target-error:s?," "unmap:b?," "granularity:i?,buf-size:i?", - .mhandler.cmd_new = qmp_marshal_drive_mirror, }, SQMP @@ -1741,7 +1682,6 @@ EQMP .args_type = "job-id:s?,sync:s,device:B,target:B,replaces:s?,speed:i?," "on-source-error:s?,on-target-error:s?," "granularity:i?,buf-size:i?", - .mhandler.cmd_new = qmp_marshal_blockdev_mirror, }, SQMP @@ -1790,7 +1730,6 @@ EQMP { .name = "change-backing-file", .args_type = "device:s,image-node-name:s,backing-file:s", - .mhandler.cmd_new = qmp_marshal_change_backing_file, }, SQMP @@ -1830,7 +1769,6 @@ EQMP { .name = "balloon", .args_type = "value:M", - .mhandler.cmd_new = qmp_marshal_balloon, }, SQMP @@ -1853,7 +1791,6 @@ EQMP { .name = "set_link", .args_type = "name:s,up:b", - .mhandler.cmd_new = qmp_marshal_set_link, }, SQMP @@ -1879,7 +1816,6 @@ EQMP .args_type = "fdname:s", .params = "getfd name", .help = "receive a file descriptor via SCM rights and assign it a name", - .mhandler.cmd_new = qmp_marshal_getfd, }, SQMP @@ -1912,7 +1848,6 @@ EQMP .args_type = "fdname:s", .params = "closefd name", .help = "close a file descriptor previously passed via SCM rights", - .mhandler.cmd_new = qmp_marshal_closefd, }, SQMP @@ -1937,7 +1872,6 @@ EQMP .args_type = "fdset-id:i?,opaque:s?", .params = "add-fd fdset-id opaque", .help = "Add a file descriptor, that was passed via SCM rights, to an fd set", - .mhandler.cmd_new = qmp_marshal_add_fd, }, SQMP @@ -1976,7 +1910,6 @@ EQMP .args_type = "fdset-id:i,fd:i?", .params = "remove-fd fdset-id fd", .help = "Remove a file descriptor from an fd set", - .mhandler.cmd_new = qmp_marshal_remove_fd, }, SQMP @@ -2008,7 +1941,6 @@ EQMP .name = "query-fdsets", .args_type = "", .help = "Return information describing all fd sets", - .mhandler.cmd_new = qmp_marshal_query_fdsets, }, SQMP @@ -2057,7 +1989,6 @@ EQMP { .name = "block_passwd", .args_type = "device:s?,node-name:s?,password:s", - .mhandler.cmd_new = qmp_marshal_block_passwd, }, SQMP @@ -2083,7 +2014,6 @@ EQMP { .name = "block_set_io_throttle", .args_type = "device:B,bps:l,bps_rd:l,bps_wr:l,iops:l,iops_rd:l,iops_wr:l,bps_max:l?,bps_rd_max:l?,bps_wr_max:l?,iops_max:l?,iops_rd_max:l?,iops_wr_max:l?,bps_max_length:l?,bps_rd_max_length:l?,bps_wr_max_length:l?,iops_max_length:l?,iops_rd_max_length:l?,iops_wr_max_length:l?,iops_size:l?,group:s?", - .mhandler.cmd_new = qmp_marshal_block_set_io_throttle, }, SQMP @@ -2140,7 +2070,6 @@ EQMP { .name = "set_password", .args_type = "protocol:s,password:s,connected:s?", - .mhandler.cmd_new = qmp_marshal_set_password, }, SQMP @@ -2166,7 +2095,6 @@ EQMP { .name = "expire_password", .args_type = "protocol:s,time:s", - .mhandler.cmd_new = qmp_marshal_expire_password, }, SQMP @@ -2191,7 +2119,6 @@ EQMP { .name = "add_client", .args_type = "protocol:s,fdname:s,skipauth:b?,tls:b?", - .mhandler.cmd_new = qmp_marshal_add_client, }, SQMP @@ -2219,7 +2146,6 @@ EQMP .args_type = "", .params = "", .help = "enable QMP capabilities", - .mhandler.cmd_new = qmp_marshal_qmp_capabilities, }, SQMP @@ -2242,7 +2168,6 @@ EQMP { .name = "human-monitor-command", .args_type = "command-line:s,cpu-index:i?", - .mhandler.cmd_new = qmp_marshal_human_monitor_command, }, SQMP @@ -2321,7 +2246,6 @@ EQMP { .name = "query-version", .args_type = "", - .mhandler.cmd_new = qmp_marshal_query_version, }, SQMP @@ -2358,7 +2282,6 @@ EQMP { .name = "query-commands", .args_type = "", - .mhandler.cmd_new = qmp_marshal_query_commands, }, SQMP @@ -2395,7 +2318,6 @@ EQMP { .name = "query-events", .args_type = "", - .mhandler.cmd_new = qmp_marshal_query_events, }, SQMP @@ -2412,7 +2334,6 @@ EQMP { .name = "query-qmp-schema", .args_type = "", - .mhandler.cmd_new = qmp_query_qmp_schema, }, SQMP @@ -2457,7 +2378,6 @@ EQMP { .name = "query-chardev", .args_type = "", - .mhandler.cmd_new = qmp_marshal_query_chardev, }, SQMP @@ -2498,7 +2418,6 @@ EQMP { .name = "query-chardev-backends", .args_type = "", - .mhandler.cmd_new = qmp_marshal_query_chardev_backends, }, SQMP @@ -2682,7 +2601,6 @@ EQMP { .name = "query-block", .args_type = "", - .mhandler.cmd_new = qmp_marshal_query_block, }, SQMP @@ -2879,7 +2797,6 @@ EQMP { .name = "query-blockstats", .args_type = "query-nodes:b?", - .mhandler.cmd_new = qmp_marshal_query_blockstats, }, SQMP @@ -2934,7 +2851,6 @@ EQMP { .name = "query-cpus", .args_type = "", - .mhandler.cmd_new = qmp_marshal_query_cpus, }, SQMP @@ -2973,7 +2889,6 @@ EQMP { .name = "query-iothreads", .args_type = "", - .mhandler.cmd_new = qmp_marshal_query_iothreads, }, SQMP @@ -3190,7 +3105,6 @@ EQMP { .name = "query-pci", .args_type = "", - .mhandler.cmd_new = qmp_marshal_query_pci, }, SQMP @@ -3214,7 +3128,6 @@ EQMP { .name = "query-kvm", .args_type = "", - .mhandler.cmd_new = qmp_marshal_query_kvm, }, SQMP @@ -3254,7 +3167,6 @@ EQMP { .name = "query-status", .args_type = "", - .mhandler.cmd_new = qmp_marshal_query_status, }, SQMP @@ -3298,7 +3210,6 @@ EQMP { .name = "query-mice", .args_type = "", - .mhandler.cmd_new = qmp_marshal_query_mice, }, SQMP @@ -3361,12 +3272,10 @@ EQMP { .name = "query-vnc", .args_type = "", - .mhandler.cmd_new = qmp_marshal_query_vnc, }, { .name = "query-vnc-servers", .args_type = "", - .mhandler.cmd_new = qmp_marshal_query_vnc_servers, }, SQMP @@ -3443,7 +3352,6 @@ EQMP { .name = "query-spice", .args_type = "", - .mhandler.cmd_new = qmp_marshal_query_spice, }, #endif @@ -3467,7 +3375,6 @@ EQMP { .name = "query-name", .args_type = "", - .mhandler.cmd_new = qmp_marshal_query_name, }, SQMP @@ -3490,7 +3397,6 @@ EQMP { .name = "query-uuid", .args_type = "", - .mhandler.cmd_new = qmp_marshal_query_uuid, }, SQMP @@ -3539,7 +3445,6 @@ EQMP { .name = "query-command-line-options", .args_type = "option:s?", - .mhandler.cmd_new = qmp_marshal_query_command_line_options, }, SQMP @@ -3717,7 +3622,6 @@ EQMP { .name = "query-migrate", .args_type = "", - .mhandler.cmd_new = qmp_marshal_query_migrate, }, SQMP @@ -3747,7 +3651,6 @@ EQMP .name = "migrate-set-capabilities", .args_type = "capabilities:q", .params = "capability:s,state:b", - .mhandler.cmd_new = qmp_marshal_migrate_set_capabilities, }, SQMP query-migrate-capabilities @@ -3784,7 +3687,6 @@ EQMP { .name = "query-migrate-capabilities", .args_type = "", - .mhandler.cmd_new = qmp_marshal_query_migrate_capabilities, }, SQMP @@ -3814,7 +3716,6 @@ EQMP .name = "migrate-set-parameters", .args_type = "compress-level:i?,compress-threads:i?,decompress-threads:i?,cpu-throttle-initial:i?,cpu-throttle-increment:i?", - .mhandler.cmd_new = qmp_marshal_migrate_set_parameters, }, SQMP query-migrate-parameters @@ -3851,7 +3752,6 @@ EQMP { .name = "query-migrate-parameters", .args_type = "", - .mhandler.cmd_new = qmp_marshal_query_migrate_parameters, }, SQMP @@ -3879,106 +3779,88 @@ EQMP { .name = "query-balloon", .args_type = "", - .mhandler.cmd_new = qmp_marshal_query_balloon, }, { .name = "query-block-jobs", .args_type = "", - .mhandler.cmd_new = qmp_marshal_query_block_jobs, }, { .name = "qom-list", .args_type = "path:s", - .mhandler.cmd_new = qmp_marshal_qom_list, }, { .name = "qom-set", .args_type = "path:s,property:s,value:q", - .mhandler.cmd_new = qmp_marshal_qom_set, }, { .name = "qom-get", .args_type = "path:s,property:s", - .mhandler.cmd_new = qmp_marshal_qom_get, }, { .name = "nbd-server-start", .args_type = "addr:q,tls-creds:s?", - .mhandler.cmd_new = qmp_marshal_nbd_server_start, }, { .name = "nbd-server-add", .args_type = "device:B,writable:b?", - .mhandler.cmd_new = qmp_marshal_nbd_server_add, }, { .name = "nbd-server-stop", .args_type = "", - .mhandler.cmd_new = qmp_marshal_nbd_server_stop, }, { .name = "change-vnc-password", .args_type = "password:s", - .mhandler.cmd_new = qmp_marshal_change_vnc_password, }, { .name = "qom-list-types", .args_type = "implements:s?,abstract:b?", - .mhandler.cmd_new = qmp_marshal_qom_list_types, }, { .name = "device-list-properties", .args_type = "typename:s", - .mhandler.cmd_new = qmp_marshal_device_list_properties, }, { .name = "query-machines", .args_type = "", - .mhandler.cmd_new = qmp_marshal_query_machines, }, { .name = "query-cpu-definitions", .args_type = "", - .mhandler.cmd_new = qmp_marshal_query_cpu_definitions, }, { .name = "query-cpu-model-expansion", .args_type = "type:s,model:q", - .mhandler.cmd_new = qmp_marshal_query_cpu_model_expansion, }, { .name = "query-cpu-model-comparison", .args_type = "modela:q,modelb:q", - .mhandler.cmd_new = qmp_marshal_query_cpu_model_comparison, }, { .name = "query-cpu-model-baseline", .args_type = "modela:q,modelb:q", - .mhandler.cmd_new = qmp_marshal_query_cpu_model_baseline, }, { .name = "query-target", .args_type = "", - .mhandler.cmd_new = qmp_marshal_query_target, }, { .name = "query-tpm", .args_type = "", - .mhandler.cmd_new = qmp_marshal_query_tpm, }, SQMP @@ -4012,7 +3894,6 @@ EQMP { .name = "query-tpm-models", .args_type = "", - .mhandler.cmd_new = qmp_marshal_query_tpm_models, }, SQMP @@ -4033,7 +3914,6 @@ EQMP { .name = "query-tpm-types", .args_type = "", - .mhandler.cmd_new = qmp_marshal_query_tpm_types, }, SQMP @@ -4054,7 +3934,6 @@ EQMP { .name = "chardev-add", .args_type = "id:s,backend:q", - .mhandler.cmd_new = qmp_marshal_chardev_add, }, SQMP @@ -4091,7 +3970,6 @@ EQMP { .name = "chardev-remove", .args_type = "id:s", - .mhandler.cmd_new = qmp_marshal_chardev_remove, }, @@ -4114,7 +3992,6 @@ EQMP { .name = "query-rx-filter", .args_type = "name:s?", - .mhandler.cmd_new = qmp_marshal_query_rx_filter, }, SQMP @@ -4180,7 +4057,6 @@ EQMP { .name = "blockdev-add", .args_type = "options:q", - .mhandler.cmd_new = qmp_marshal_blockdev_add, }, SQMP @@ -4239,7 +4115,6 @@ EQMP { .name = "x-blockdev-del", .args_type = "id:s?,node-name:s?", - .mhandler.cmd_new = qmp_marshal_x_blockdev_del, }, SQMP @@ -4296,7 +4171,6 @@ EQMP { .name = "blockdev-open-tray", .args_type = "device:s,force:b?", - .mhandler.cmd_new = qmp_marshal_blockdev_open_tray, }, SQMP @@ -4344,7 +4218,6 @@ EQMP { .name = "blockdev-close-tray", .args_type = "device:s", - .mhandler.cmd_new = qmp_marshal_blockdev_close_tray, }, SQMP @@ -4379,7 +4252,6 @@ EQMP { .name = "x-blockdev-remove-medium", .args_type = "device:s", - .mhandler.cmd_new = qmp_marshal_x_blockdev_remove_medium, }, SQMP @@ -4427,7 +4299,6 @@ EQMP { .name = "x-blockdev-insert-medium", .args_type = "device:s,node-name:s", - .mhandler.cmd_new = qmp_marshal_x_blockdev_insert_medium, }, SQMP @@ -4467,7 +4338,6 @@ EQMP { .name = "x-blockdev-change", .args_type = "parent:B,child:B?,node:B?", - .mhandler.cmd_new = qmp_marshal_x_blockdev_change, }, SQMP @@ -4520,7 +4390,6 @@ EQMP { .name = "query-named-block-nodes", .args_type = "", - .mhandler.cmd_new = qmp_marshal_query_named_block_nodes, }, SQMP @@ -4582,7 +4451,6 @@ EQMP { .name = "blockdev-change-medium", .args_type = "device:B,filename:F,format:s?,read-only-mode:s?", - .mhandler.cmd_new = qmp_marshal_blockdev_change_medium, }, SQMP @@ -4635,7 +4503,6 @@ EQMP { .name = "query-memdev", .args_type = "", - .mhandler.cmd_new = qmp_marshal_query_memdev, }, SQMP @@ -4673,7 +4540,6 @@ EQMP { .name = "query-memory-devices", .args_type = "", - .mhandler.cmd_new = qmp_marshal_query_memory_devices, }, SQMP @@ -4700,7 +4566,6 @@ EQMP { .name = "query-acpi-ospm-status", .args_type = "", - .mhandler.cmd_new = qmp_marshal_query_acpi_ospm_status, }, SQMP @@ -4723,7 +4588,6 @@ EQMP { .name = "rtc-reset-reinjection", .args_type = "", - .mhandler.cmd_new = qmp_marshal_rtc_reset_reinjection, }, #endif @@ -4744,7 +4608,6 @@ EQMP { .name = "trace-event-get-state", .args_type = "name:s,vcpu:i?", - .mhandler.cmd_new = qmp_marshal_trace_event_get_state, }, SQMP @@ -4776,7 +4639,6 @@ EQMP { .name = "trace-event-set-state", .args_type = "name:s,enable:b,ignore-unavailable:b?,vcpu:i?", - .mhandler.cmd_new = qmp_marshal_trace_event_set_state, }, SQMP @@ -4811,7 +4673,6 @@ EQMP { .name = "input-send-event", .args_type = "console:i?,events:q", - .mhandler.cmd_new = qmp_marshal_input_send_event, }, SQMP @@ -4875,7 +4736,6 @@ EQMP { .name = "block-set-write-threshold", .args_type = "node-name:s,write-threshold:l", - .mhandler.cmd_new = qmp_marshal_block_set_write_threshold, }, SQMP @@ -4903,7 +4763,6 @@ EQMP { .name = "query-rocker", .args_type = "name:s", - .mhandler.cmd_new = qmp_marshal_query_rocker, }, SQMP @@ -4924,7 +4783,6 @@ EQMP { .name = "query-rocker-ports", .args_type = "name:s", - .mhandler.cmd_new = qmp_marshal_query_rocker_ports, }, SQMP @@ -4949,7 +4807,6 @@ EQMP { .name = "query-rocker-of-dpa-flows", .args_type = "name:s,tbl-id:i?", - .mhandler.cmd_new = qmp_marshal_query_rocker_of_dpa_flows, }, SQMP @@ -4978,7 +4835,6 @@ EQMP { .name = "query-rocker-of-dpa-groups", .args_type = "name:s,type:i?", - .mhandler.cmd_new = qmp_marshal_query_rocker_of_dpa_groups, }, SQMP @@ -5009,7 +4865,6 @@ EQMP { .name = "query-gic-capabilities", .args_type = "", - .mhandler.cmd_new = qmp_marshal_query_gic_capabilities, }, #endif @@ -5033,7 +4888,6 @@ EQMP { .name = "query-hotpluggable-cpus", .args_type = "", - .mhandler.cmd_new = qmp_marshal_query_hotpluggable_cpus, }, SQMP diff --git a/vl.c b/vl.c index ad2664bbc4f..fca04871675 100644 --- a/vl.c +++ b/vl.c @@ -2987,6 +2987,7 @@ int main(int argc, char **argv, char **envp) qemu_init_exec_dir(argv[0]); module_call_init(MODULE_INIT_QOM); + module_call_init(MODULE_INIT_QAPI); qemu_add_opts(&qemu_drive_opts); qemu_add_drive_opts(&qemu_legacy_drive_opts); From 9e812b6adc6d9efe640fabeb9f5edee8248fdac9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 12 Sep 2016 13:19:05 +0400 Subject: [PATCH 089/723] monitor: implement 'qmp_query_commands' without qmp_cmds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit One step towards getting rid of the static qmp_cmds table. Signed-off-by: Marc-André Lureau Reviewed-by: Eric Blake Message-Id: <20160912091913.15831-11-marcandre.lureau@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- monitor.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/monitor.c b/monitor.c index 6e0ae814542..f50aa6e5d02 100644 --- a/monitor.c +++ b/monitor.c @@ -957,21 +957,28 @@ static void hmp_info_help(Monitor *mon, const QDict *qdict) help_cmd(mon, "info"); } -CommandInfoList *qmp_query_commands(Error **errp) +static void query_commands_cb(QmpCommand *cmd, void *opaque) { - CommandInfoList *info, *cmd_list = NULL; - const mon_cmd_t *cmd; - - for (cmd = qmp_cmds; cmd->name != NULL; cmd++) { - info = g_malloc0(sizeof(*info)); - info->value = g_malloc0(sizeof(*info->value)); - info->value->name = g_strdup(cmd->name); + CommandInfoList *info, **list = opaque; - info->next = cmd_list; - cmd_list = info; + if (!cmd->enabled) { + return; } - return cmd_list; + info = g_malloc0(sizeof(*info)); + info->value = g_malloc0(sizeof(*info->value)); + info->value->name = g_strdup(cmd->name); + info->next = *list; + *list = info; +} + +CommandInfoList *qmp_query_commands(Error **errp) +{ + CommandInfoList *list = NULL; + + qmp_for_each_command(query_commands_cb, &list); + + return list; } EventInfoList *qmp_query_events(Error **errp) From 2b9e35760a8ff5548f6789d048c6e6e3c22c70ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 12 Sep 2016 13:19:06 +0400 Subject: [PATCH 090/723] monitor: remove mhandler.cmd_new MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is no longer necessary now that we aren't using middle mode anymore. Signed-off-by: Marc-André Lureau Reviewed-by: Eric Blake Message-Id: <20160912091913.15831-12-marcandre.lureau@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- docs/writing-qmp-commands.txt | 4 +- hmp-commands-info.hx | 118 +++++++++---------- hmp-commands.hx | 208 +++++++++++++++++----------------- monitor.c | 13 +-- 4 files changed, 170 insertions(+), 173 deletions(-) diff --git a/docs/writing-qmp-commands.txt b/docs/writing-qmp-commands.txt index 0a66e0ebb8d..c425393092e 100644 --- a/docs/writing-qmp-commands.txt +++ b/docs/writing-qmp-commands.txt @@ -335,7 +335,7 @@ we should add it to the hmp-commands.hx file: .args_type = "message:s?", .params = "hello-world [message]", .help = "Print message to the standard output", - .mhandler.cmd = hmp_hello_world, + .cmd = hmp_hello_world, }, STEXI @@ -515,7 +515,7 @@ in the monitor.c file. The entry for the "info alarmclock" follows: .args_type = "", .params = "", .help = "show information about the alarm clock", - .mhandler.cmd = hmp_info_alarm_clock, + .cmd = hmp_info_alarm_clock, }, To test this, run qemu and type "info alarmclock" in the user monitor. diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx index 74446c669e8..19729e55aea 100644 --- a/hmp-commands-info.hx +++ b/hmp-commands-info.hx @@ -18,7 +18,7 @@ ETEXI .args_type = "", .params = "", .help = "show the version of QEMU", - .mhandler.cmd = hmp_info_version, + .cmd = hmp_info_version, }, STEXI @@ -32,7 +32,7 @@ ETEXI .args_type = "", .params = "", .help = "show the network state", - .mhandler.cmd = hmp_info_network, + .cmd = hmp_info_network, }, STEXI @@ -46,7 +46,7 @@ ETEXI .args_type = "", .params = "", .help = "show the character devices", - .mhandler.cmd = hmp_info_chardev, + .cmd = hmp_info_chardev, }, STEXI @@ -61,7 +61,7 @@ ETEXI .params = "[-n] [-v] [device]", .help = "show info of one block device or all block devices " "(-n: show named nodes; -v: show details)", - .mhandler.cmd = hmp_info_block, + .cmd = hmp_info_block, }, STEXI @@ -75,7 +75,7 @@ ETEXI .args_type = "", .params = "", .help = "show block device statistics", - .mhandler.cmd = hmp_info_blockstats, + .cmd = hmp_info_blockstats, }, STEXI @@ -89,7 +89,7 @@ ETEXI .args_type = "", .params = "", .help = "show progress of ongoing block device operations", - .mhandler.cmd = hmp_info_block_jobs, + .cmd = hmp_info_block_jobs, }, STEXI @@ -103,7 +103,7 @@ ETEXI .args_type = "", .params = "", .help = "show the cpu registers", - .mhandler.cmd = hmp_info_registers, + .cmd = hmp_info_registers, }, STEXI @@ -118,7 +118,7 @@ ETEXI .args_type = "", .params = "", .help = "show local apic state", - .mhandler.cmd = hmp_info_local_apic, + .cmd = hmp_info_local_apic, }, #endif @@ -134,7 +134,7 @@ ETEXI .args_type = "", .params = "", .help = "show io apic state", - .mhandler.cmd = hmp_info_io_apic, + .cmd = hmp_info_io_apic, }, #endif @@ -149,7 +149,7 @@ ETEXI .args_type = "", .params = "", .help = "show infos for each CPU", - .mhandler.cmd = hmp_info_cpus, + .cmd = hmp_info_cpus, }, STEXI @@ -163,7 +163,7 @@ ETEXI .args_type = "", .params = "", .help = "show the command line history", - .mhandler.cmd = hmp_info_history, + .cmd = hmp_info_history, }, STEXI @@ -180,11 +180,11 @@ ETEXI .params = "", .help = "show the interrupts statistics (if available)", #ifdef TARGET_SPARC - .mhandler.cmd = sun4m_hmp_info_irq, + .cmd = sun4m_hmp_info_irq, #elif defined(TARGET_LM32) - .mhandler.cmd = lm32_hmp_info_irq, + .cmd = lm32_hmp_info_irq, #else - .mhandler.cmd = hmp_info_irq, + .cmd = hmp_info_irq, #endif }, @@ -200,11 +200,11 @@ ETEXI .params = "", .help = "show i8259 (PIC) state", #ifdef TARGET_SPARC - .mhandler.cmd = sun4m_hmp_info_pic, + .cmd = sun4m_hmp_info_pic, #elif defined(TARGET_LM32) - .mhandler.cmd = lm32_hmp_info_pic, + .cmd = lm32_hmp_info_pic, #else - .mhandler.cmd = hmp_info_pic, + .cmd = hmp_info_pic, #endif }, #endif @@ -220,7 +220,7 @@ ETEXI .args_type = "", .params = "", .help = "show PCI info", - .mhandler.cmd = hmp_info_pci, + .cmd = hmp_info_pci, }, STEXI @@ -236,7 +236,7 @@ ETEXI .args_type = "", .params = "", .help = "show virtual to physical memory mappings", - .mhandler.cmd = hmp_info_tlb, + .cmd = hmp_info_tlb, }, #endif @@ -252,7 +252,7 @@ ETEXI .args_type = "", .params = "", .help = "show the active virtual memory mappings", - .mhandler.cmd = hmp_info_mem, + .cmd = hmp_info_mem, }, #endif @@ -267,7 +267,7 @@ ETEXI .args_type = "", .params = "", .help = "show memory tree", - .mhandler.cmd = hmp_info_mtree, + .cmd = hmp_info_mtree, }, STEXI @@ -281,7 +281,7 @@ ETEXI .args_type = "", .params = "", .help = "show dynamic compiler info", - .mhandler.cmd = hmp_info_jit, + .cmd = hmp_info_jit, }, STEXI @@ -295,7 +295,7 @@ ETEXI .args_type = "", .params = "", .help = "show dynamic compiler opcode counters", - .mhandler.cmd = hmp_info_opcount, + .cmd = hmp_info_opcount, }, STEXI @@ -309,7 +309,7 @@ ETEXI .args_type = "", .params = "", .help = "show KVM information", - .mhandler.cmd = hmp_info_kvm, + .cmd = hmp_info_kvm, }, STEXI @@ -323,7 +323,7 @@ ETEXI .args_type = "", .params = "", .help = "show NUMA information", - .mhandler.cmd = hmp_info_numa, + .cmd = hmp_info_numa, }, STEXI @@ -337,7 +337,7 @@ ETEXI .args_type = "", .params = "", .help = "show guest USB devices", - .mhandler.cmd = hmp_info_usb, + .cmd = hmp_info_usb, }, STEXI @@ -351,7 +351,7 @@ ETEXI .args_type = "", .params = "", .help = "show host USB devices", - .mhandler.cmd = hmp_info_usbhost, + .cmd = hmp_info_usbhost, }, STEXI @@ -365,7 +365,7 @@ ETEXI .args_type = "", .params = "", .help = "show profiling information", - .mhandler.cmd = hmp_info_profile, + .cmd = hmp_info_profile, }, STEXI @@ -379,7 +379,7 @@ ETEXI .args_type = "", .params = "", .help = "show capture information", - .mhandler.cmd = hmp_info_capture, + .cmd = hmp_info_capture, }, STEXI @@ -393,7 +393,7 @@ ETEXI .args_type = "", .params = "", .help = "show the currently saved VM snapshots", - .mhandler.cmd = hmp_info_snapshots, + .cmd = hmp_info_snapshots, }, STEXI @@ -407,7 +407,7 @@ ETEXI .args_type = "", .params = "", .help = "show the current VM status (running|paused)", - .mhandler.cmd = hmp_info_status, + .cmd = hmp_info_status, }, STEXI @@ -421,7 +421,7 @@ ETEXI .args_type = "", .params = "", .help = "show which guest mouse is receiving events", - .mhandler.cmd = hmp_info_mice, + .cmd = hmp_info_mice, }, STEXI @@ -435,7 +435,7 @@ ETEXI .args_type = "", .params = "", .help = "show the vnc server status", - .mhandler.cmd = hmp_info_vnc, + .cmd = hmp_info_vnc, }, STEXI @@ -450,7 +450,7 @@ ETEXI .args_type = "", .params = "", .help = "show the spice server status", - .mhandler.cmd = hmp_info_spice, + .cmd = hmp_info_spice, }, #endif @@ -465,7 +465,7 @@ ETEXI .args_type = "", .params = "", .help = "show the current VM name", - .mhandler.cmd = hmp_info_name, + .cmd = hmp_info_name, }, STEXI @@ -479,7 +479,7 @@ ETEXI .args_type = "", .params = "", .help = "show the current VM UUID", - .mhandler.cmd = hmp_info_uuid, + .cmd = hmp_info_uuid, }, STEXI @@ -493,7 +493,7 @@ ETEXI .args_type = "", .params = "", .help = "show CPU statistics", - .mhandler.cmd = hmp_info_cpustats, + .cmd = hmp_info_cpustats, }, STEXI @@ -508,7 +508,7 @@ ETEXI .args_type = "", .params = "", .help = "show user network stack connection states", - .mhandler.cmd = hmp_info_usernet, + .cmd = hmp_info_usernet, }, #endif @@ -523,7 +523,7 @@ ETEXI .args_type = "", .params = "", .help = "show migration status", - .mhandler.cmd = hmp_info_migrate, + .cmd = hmp_info_migrate, }, STEXI @@ -537,7 +537,7 @@ ETEXI .args_type = "", .params = "", .help = "show current migration capabilities", - .mhandler.cmd = hmp_info_migrate_capabilities, + .cmd = hmp_info_migrate_capabilities, }, STEXI @@ -551,7 +551,7 @@ ETEXI .args_type = "", .params = "", .help = "show current migration parameters", - .mhandler.cmd = hmp_info_migrate_parameters, + .cmd = hmp_info_migrate_parameters, }, STEXI @@ -565,7 +565,7 @@ ETEXI .args_type = "", .params = "", .help = "show current migration xbzrle cache size", - .mhandler.cmd = hmp_info_migrate_cache_size, + .cmd = hmp_info_migrate_cache_size, }, STEXI @@ -579,7 +579,7 @@ ETEXI .args_type = "", .params = "", .help = "show balloon information", - .mhandler.cmd = hmp_info_balloon, + .cmd = hmp_info_balloon, }, STEXI @@ -593,7 +593,7 @@ ETEXI .args_type = "", .params = "", .help = "show device tree", - .mhandler.cmd = hmp_info_qtree, + .cmd = hmp_info_qtree, }, STEXI @@ -607,7 +607,7 @@ ETEXI .args_type = "", .params = "", .help = "show qdev device model list", - .mhandler.cmd = hmp_info_qdm, + .cmd = hmp_info_qdm, }, STEXI @@ -621,7 +621,7 @@ ETEXI .args_type = "path:s?", .params = "[path]", .help = "show QOM composition tree", - .mhandler.cmd = hmp_info_qom_tree, + .cmd = hmp_info_qom_tree, }, STEXI @@ -635,7 +635,7 @@ ETEXI .args_type = "", .params = "", .help = "show roms", - .mhandler.cmd = hmp_info_roms, + .cmd = hmp_info_roms, }, STEXI @@ -650,7 +650,7 @@ ETEXI .params = "[name] [vcpu]", .help = "show available trace-events & their state " "(name: event name pattern; vcpu: vCPU to query, default is any)", - .mhandler.cmd = hmp_info_trace_events, + .cmd = hmp_info_trace_events, .command_completion = info_trace_events_completion, }, @@ -665,7 +665,7 @@ ETEXI .args_type = "", .params = "", .help = "show the TPM device", - .mhandler.cmd = hmp_info_tpm, + .cmd = hmp_info_tpm, }, STEXI @@ -679,7 +679,7 @@ ETEXI .args_type = "", .params = "", .help = "show memory backends", - .mhandler.cmd = hmp_info_memdev, + .cmd = hmp_info_memdev, }, STEXI @@ -693,7 +693,7 @@ ETEXI .args_type = "", .params = "", .help = "show memory devices", - .mhandler.cmd = hmp_info_memory_devices, + .cmd = hmp_info_memory_devices, }, STEXI @@ -707,7 +707,7 @@ ETEXI .args_type = "", .params = "", .help = "show iothreads", - .mhandler.cmd = hmp_info_iothreads, + .cmd = hmp_info_iothreads, }, STEXI @@ -721,7 +721,7 @@ ETEXI .args_type = "name:s", .params = "name", .help = "Show rocker switch", - .mhandler.cmd = hmp_rocker, + .cmd = hmp_rocker, }, STEXI @@ -735,7 +735,7 @@ ETEXI .args_type = "name:s", .params = "name", .help = "Show rocker ports", - .mhandler.cmd = hmp_rocker_ports, + .cmd = hmp_rocker_ports, }, STEXI @@ -749,7 +749,7 @@ ETEXI .args_type = "name:s,tbl_id:i?", .params = "name [tbl_id]", .help = "Show rocker OF-DPA flow tables", - .mhandler.cmd = hmp_rocker_of_dpa_flows, + .cmd = hmp_rocker_of_dpa_flows, }, STEXI @@ -763,7 +763,7 @@ ETEXI .args_type = "name:s,type:i?", .params = "name [type]", .help = "Show rocker OF-DPA groups", - .mhandler.cmd = hmp_rocker_of_dpa_groups, + .cmd = hmp_rocker_of_dpa_groups, }, STEXI @@ -778,7 +778,7 @@ ETEXI .args_type = "addr:l", .params = "address", .help = "Display the value of a storage key", - .mhandler.cmd = hmp_info_skeys, + .cmd = hmp_info_skeys, }, #endif @@ -793,7 +793,7 @@ ETEXI .args_type = "", .params = "", .help = "Display the latest dump status", - .mhandler.cmd = hmp_info_dump, + .cmd = hmp_info_dump, }, STEXI @@ -807,7 +807,7 @@ ETEXI .args_type = "", .params = "", .help = "Show information about hotpluggable CPUs", - .mhandler.cmd = hmp_hotpluggable_cpus, + .cmd = hmp_hotpluggable_cpus, }, STEXI diff --git a/hmp-commands.hx b/hmp-commands.hx index 74f32e515cd..06bef470b99 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -14,7 +14,7 @@ ETEXI .args_type = "name:S?", .params = "[cmd]", .help = "show the help", - .mhandler.cmd = do_help_cmd, + .cmd = do_help_cmd, }, STEXI @@ -28,7 +28,7 @@ ETEXI .args_type = "device:B", .params = "device|all", .help = "commit changes to the disk images (if -snapshot is used) or backing files", - .mhandler.cmd = hmp_commit, + .cmd = hmp_commit, }, STEXI @@ -47,7 +47,7 @@ ETEXI .args_type = "", .params = "", .help = "quit the emulator", - .mhandler.cmd = hmp_quit, + .cmd = hmp_quit, }, STEXI @@ -61,7 +61,7 @@ ETEXI .args_type = "device:B,size:o", .params = "device size", .help = "resize a block image", - .mhandler.cmd = hmp_block_resize, + .cmd = hmp_block_resize, }, STEXI @@ -78,7 +78,7 @@ ETEXI .args_type = "device:B,speed:o?,base:s?", .params = "device [speed [base]]", .help = "copy data from a backing file into a block device", - .mhandler.cmd = hmp_block_stream, + .cmd = hmp_block_stream, }, STEXI @@ -92,7 +92,7 @@ ETEXI .args_type = "device:B,speed:o", .params = "device speed", .help = "set maximum speed for a background block operation", - .mhandler.cmd = hmp_block_job_set_speed, + .cmd = hmp_block_job_set_speed, }, STEXI @@ -107,7 +107,7 @@ ETEXI .params = "[-f] device", .help = "stop an active background block operation (use -f" "\n\t\t\t if the operation is currently paused)", - .mhandler.cmd = hmp_block_job_cancel, + .cmd = hmp_block_job_cancel, }, STEXI @@ -121,7 +121,7 @@ ETEXI .args_type = "device:B", .params = "device", .help = "stop an active background block operation", - .mhandler.cmd = hmp_block_job_complete, + .cmd = hmp_block_job_complete, }, STEXI @@ -136,7 +136,7 @@ ETEXI .args_type = "device:B", .params = "device", .help = "pause an active background block operation", - .mhandler.cmd = hmp_block_job_pause, + .cmd = hmp_block_job_pause, }, STEXI @@ -150,7 +150,7 @@ ETEXI .args_type = "device:B", .params = "device", .help = "resume a paused background block operation", - .mhandler.cmd = hmp_block_job_resume, + .cmd = hmp_block_job_resume, }, STEXI @@ -164,7 +164,7 @@ ETEXI .args_type = "force:-f,device:B", .params = "[-f] device", .help = "eject a removable medium (use -f to force it)", - .mhandler.cmd = hmp_eject, + .cmd = hmp_eject, }, STEXI @@ -178,7 +178,7 @@ ETEXI .args_type = "id:B", .params = "device", .help = "remove host block device", - .mhandler.cmd = hmp_drive_del, + .cmd = hmp_drive_del, }, STEXI @@ -197,7 +197,7 @@ ETEXI .args_type = "device:B,target:F,arg:s?,read-only-mode:s?", .params = "device filename [format [read-only-mode]]", .help = "change a removable medium, optional format", - .mhandler.cmd = hmp_change, + .cmd = hmp_change, }, STEXI @@ -256,7 +256,7 @@ ETEXI .args_type = "filename:F", .params = "filename", .help = "save screen into PPM image 'filename'", - .mhandler.cmd = hmp_screendump, + .cmd = hmp_screendump, }, STEXI @@ -270,7 +270,7 @@ ETEXI .args_type = "filename:F", .params = "filename", .help = "output logs to 'filename'", - .mhandler.cmd = hmp_logfile, + .cmd = hmp_logfile, }, STEXI @@ -285,7 +285,7 @@ ETEXI .params = "name on|off [vcpu]", .help = "changes status of a specific trace event " "(vcpu: vCPU to set, default is all)", - .mhandler.cmd = hmp_trace_event, + .cmd = hmp_trace_event, .command_completion = trace_event_completion, }, @@ -301,7 +301,7 @@ ETEXI .args_type = "op:s?,arg:F?", .params = "on|off|flush|set [arg]", .help = "open, close, or flush trace file, or set a new file name", - .mhandler.cmd = hmp_trace_file, + .cmd = hmp_trace_file, }, STEXI @@ -316,7 +316,7 @@ ETEXI .args_type = "items:s", .params = "item1[,...]", .help = "activate logging of the specified items", - .mhandler.cmd = hmp_log, + .cmd = hmp_log, }, STEXI @@ -330,7 +330,7 @@ ETEXI .args_type = "name:s?", .params = "[tag|id]", .help = "save a VM snapshot. If no tag or id are provided, a new snapshot is created", - .mhandler.cmd = hmp_savevm, + .cmd = hmp_savevm, }, STEXI @@ -347,7 +347,7 @@ ETEXI .args_type = "name:s", .params = "tag|id", .help = "restore a VM snapshot from its tag or id", - .mhandler.cmd = hmp_loadvm, + .cmd = hmp_loadvm, .command_completion = loadvm_completion, }, @@ -363,7 +363,7 @@ ETEXI .args_type = "name:s", .params = "tag|id", .help = "delete a VM snapshot from its tag or id", - .mhandler.cmd = hmp_delvm, + .cmd = hmp_delvm, .command_completion = delvm_completion, }, @@ -378,7 +378,7 @@ ETEXI .args_type = "option:s?", .params = "[on|off]", .help = "run emulation in singlestep mode or switch to normal mode", - .mhandler.cmd = hmp_singlestep, + .cmd = hmp_singlestep, }, STEXI @@ -393,7 +393,7 @@ ETEXI .args_type = "", .params = "", .help = "stop emulation", - .mhandler.cmd = hmp_stop, + .cmd = hmp_stop, }, STEXI @@ -407,7 +407,7 @@ ETEXI .args_type = "", .params = "", .help = "resume emulation", - .mhandler.cmd = hmp_cont, + .cmd = hmp_cont, }, STEXI @@ -421,7 +421,7 @@ ETEXI .args_type = "", .params = "", .help = "wakeup guest from suspend", - .mhandler.cmd = hmp_system_wakeup, + .cmd = hmp_system_wakeup, }, STEXI @@ -435,7 +435,7 @@ ETEXI .args_type = "device:s?", .params = "[device]", .help = "start gdbserver on given device (default 'tcp::1234'), stop with 'none'", - .mhandler.cmd = hmp_gdbserver, + .cmd = hmp_gdbserver, }, STEXI @@ -449,7 +449,7 @@ ETEXI .args_type = "fmt:/,addr:l", .params = "/fmt addr", .help = "virtual memory dump starting at 'addr'", - .mhandler.cmd = hmp_memory_dump, + .cmd = hmp_memory_dump, }, STEXI @@ -463,7 +463,7 @@ ETEXI .args_type = "fmt:/,addr:l", .params = "/fmt addr", .help = "physical memory dump starting at 'addr'", - .mhandler.cmd = hmp_physical_memory_dump, + .cmd = hmp_physical_memory_dump, }, STEXI @@ -530,7 +530,7 @@ ETEXI .args_type = "fmt:/,val:l", .params = "/fmt expr", .help = "print expression value (use $reg for CPU register access)", - .mhandler.cmd = do_print, + .cmd = do_print, }, STEXI @@ -545,7 +545,7 @@ ETEXI .args_type = "fmt:/,addr:i,index:i.", .params = "/fmt addr", .help = "I/O port read", - .mhandler.cmd = hmp_ioport_read, + .cmd = hmp_ioport_read, }, STEXI @@ -559,7 +559,7 @@ ETEXI .args_type = "fmt:/,addr:i,val:i", .params = "/fmt addr value", .help = "I/O port write", - .mhandler.cmd = hmp_ioport_write, + .cmd = hmp_ioport_write, }, STEXI @@ -573,7 +573,7 @@ ETEXI .args_type = "keys:s,hold-time:i?", .params = "keys [hold_ms]", .help = "send keys to the VM (e.g. 'sendkey ctrl-alt-f1', default hold time=100 ms)", - .mhandler.cmd = hmp_sendkey, + .cmd = hmp_sendkey, .command_completion = sendkey_completion, }, @@ -596,7 +596,7 @@ ETEXI .args_type = "", .params = "", .help = "reset the system", - .mhandler.cmd = hmp_system_reset, + .cmd = hmp_system_reset, }, STEXI @@ -610,7 +610,7 @@ ETEXI .args_type = "", .params = "", .help = "send system power down event", - .mhandler.cmd = hmp_system_powerdown, + .cmd = hmp_system_powerdown, }, STEXI @@ -624,7 +624,7 @@ ETEXI .args_type = "start:i,size:i", .params = "addr size", .help = "compute the checksum of a memory region", - .mhandler.cmd = hmp_sum, + .cmd = hmp_sum, }, STEXI @@ -638,7 +638,7 @@ ETEXI .args_type = "devname:s", .params = "device", .help = "add USB device (e.g. 'host:bus.addr' or 'host:vendor_id:product_id')", - .mhandler.cmd = hmp_usb_add, + .cmd = hmp_usb_add, }, STEXI @@ -653,7 +653,7 @@ ETEXI .args_type = "devname:s", .params = "device", .help = "remove USB device 'bus.addr'", - .mhandler.cmd = hmp_usb_del, + .cmd = hmp_usb_del, }, STEXI @@ -669,7 +669,7 @@ ETEXI .args_type = "device:O", .params = "driver[,prop=value][,...]", .help = "add device, like -device on the command line", - .mhandler.cmd = hmp_device_add, + .cmd = hmp_device_add, .command_completion = device_add_completion, }, @@ -684,7 +684,7 @@ ETEXI .args_type = "id:s", .params = "device", .help = "remove device", - .mhandler.cmd = hmp_device_del, + .cmd = hmp_device_del, .command_completion = device_del_completion, }, @@ -700,7 +700,7 @@ ETEXI .args_type = "index:i", .params = "index", .help = "set the default CPU", - .mhandler.cmd = hmp_cpu, + .cmd = hmp_cpu, }, STEXI @@ -714,7 +714,7 @@ ETEXI .args_type = "dx_str:s,dy_str:s,dz_str:s?", .params = "dx dy [dz]", .help = "send mouse move events", - .mhandler.cmd = hmp_mouse_move, + .cmd = hmp_mouse_move, }, STEXI @@ -729,7 +729,7 @@ ETEXI .args_type = "button_state:i", .params = "state", .help = "change mouse button state (1=L, 2=M, 4=R)", - .mhandler.cmd = hmp_mouse_button, + .cmd = hmp_mouse_button, }, STEXI @@ -743,7 +743,7 @@ ETEXI .args_type = "index:i", .params = "index", .help = "set which mouse device receives events", - .mhandler.cmd = hmp_mouse_set, + .cmd = hmp_mouse_set, }, STEXI @@ -761,7 +761,7 @@ ETEXI .args_type = "path:F,freq:i?,bits:i?,nchannels:i?", .params = "path [frequency [bits [channels]]]", .help = "capture audio to a wave file (default frequency=44100 bits=16 channels=2)", - .mhandler.cmd = hmp_wavcapture, + .cmd = hmp_wavcapture, }, STEXI @item wavcapture @var{filename} [@var{frequency} [@var{bits} [@var{channels}]]] @@ -782,7 +782,7 @@ ETEXI .args_type = "n:i", .params = "capture index", .help = "stop capture", - .mhandler.cmd = hmp_stopcapture, + .cmd = hmp_stopcapture, }, STEXI @item stopcapture @var{index} @@ -798,7 +798,7 @@ ETEXI .args_type = "val:l,size:i,filename:s", .params = "addr size file", .help = "save to disk virtual memory dump starting at 'addr' of size 'size'", - .mhandler.cmd = hmp_memsave, + .cmd = hmp_memsave, }, STEXI @@ -812,7 +812,7 @@ ETEXI .args_type = "val:l,size:i,filename:s", .params = "addr size file", .help = "save to disk physical memory dump starting at 'addr' of size 'size'", - .mhandler.cmd = hmp_pmemsave, + .cmd = hmp_pmemsave, }, STEXI @@ -826,7 +826,7 @@ ETEXI .args_type = "bootdevice:s", .params = "bootdevice", .help = "define new values for the boot device list", - .mhandler.cmd = hmp_boot_set, + .cmd = hmp_boot_set, }, STEXI @@ -844,7 +844,7 @@ ETEXI .args_type = "", .params = "", .help = "inject an NMI", - .mhandler.cmd = hmp_nmi, + .cmd = hmp_nmi, }, STEXI @item nmi @var{cpu} @@ -858,7 +858,7 @@ ETEXI .args_type = "device:s,data:s", .params = "device data", .help = "Write to a ring buffer character device", - .mhandler.cmd = hmp_ringbuf_write, + .cmd = hmp_ringbuf_write, .command_completion = ringbuf_write_completion, }, @@ -875,7 +875,7 @@ ETEXI .args_type = "device:s,size:i", .params = "device size", .help = "Read from a ring buffer character device", - .mhandler.cmd = hmp_ringbuf_read, + .cmd = hmp_ringbuf_read, .command_completion = ringbuf_write_completion, }, @@ -901,7 +901,7 @@ ETEXI " full copy of disk\n\t\t\t -i for migration without " "shared storage with incremental copy of disk " "(base image shared between src and destination)", - .mhandler.cmd = hmp_migrate, + .cmd = hmp_migrate, }, @@ -918,7 +918,7 @@ ETEXI .args_type = "", .params = "", .help = "cancel the current VM migration", - .mhandler.cmd = hmp_migrate_cancel, + .cmd = hmp_migrate_cancel, }, STEXI @@ -933,7 +933,7 @@ ETEXI .args_type = "uri:s", .params = "uri", .help = "Continue an incoming migration from an -incoming defer", - .mhandler.cmd = hmp_migrate_incoming, + .cmd = hmp_migrate_incoming, }, STEXI @@ -954,7 +954,7 @@ ETEXI "The cache size affects the number of cache misses." "In case of a high cache miss ratio you need to increase" " the cache size", - .mhandler.cmd = hmp_migrate_set_cache_size, + .cmd = hmp_migrate_set_cache_size, }, STEXI @@ -969,7 +969,7 @@ ETEXI .params = "value", .help = "set maximum speed (in bytes) for migrations. " "Defaults to MB if no size suffix is specified, ie. B/K/M/G/T", - .mhandler.cmd = hmp_migrate_set_speed, + .cmd = hmp_migrate_set_speed, }, STEXI @@ -983,7 +983,7 @@ ETEXI .args_type = "value:T", .params = "value", .help = "set maximum tolerated downtime (in seconds) for migrations", - .mhandler.cmd = hmp_migrate_set_downtime, + .cmd = hmp_migrate_set_downtime, }, STEXI @@ -997,7 +997,7 @@ ETEXI .args_type = "capability:s,state:b", .params = "capability state", .help = "Enable/Disable the usage of a capability for migration", - .mhandler.cmd = hmp_migrate_set_capability, + .cmd = hmp_migrate_set_capability, .command_completion = migrate_set_capability_completion, }, @@ -1012,7 +1012,7 @@ ETEXI .args_type = "parameter:s,value:s", .params = "parameter value", .help = "Set the parameter for migration", - .mhandler.cmd = hmp_migrate_set_parameter, + .cmd = hmp_migrate_set_parameter, .command_completion = migrate_set_parameter_completion, }, @@ -1029,7 +1029,7 @@ ETEXI .help = "Followup to a migration command to switch the migration" " to postcopy mode. The postcopy-ram capability must " "be set before the original migration command.", - .mhandler.cmd = hmp_migrate_start_postcopy, + .cmd = hmp_migrate_start_postcopy, }, STEXI @@ -1044,7 +1044,7 @@ ETEXI .args_type = "protocol:s,hostname:s,port:i?,tls-port:i?,cert-subject:s?", .params = "protocol hostname port tls-port cert-subject", .help = "set migration information for remote display", - .mhandler.cmd = hmp_client_migrate_info, + .cmd = hmp_client_migrate_info, }, STEXI @@ -1067,7 +1067,7 @@ ETEXI "-s: dump in kdump-compressed format, with snappy compression.\n\t\t\t" "begin: the starting physical address.\n\t\t\t" "length: the memory size, in bytes.", - .mhandler.cmd = hmp_dump_guest_memory, + .cmd = hmp_dump_guest_memory, }, @@ -1094,7 +1094,7 @@ ETEXI .args_type = "filename:F", .params = "", .help = "Save guest storage keys into file 'filename'.\n", - .mhandler.cmd = hmp_dump_skeys, + .cmd = hmp_dump_skeys, }, #endif @@ -1116,7 +1116,7 @@ ETEXI "The default format is qcow2. The -n flag requests QEMU\n\t\t\t" "to reuse the image found in new-image-file, instead of\n\t\t\t" "recreating it from scratch.", - .mhandler.cmd = hmp_snapshot_blkdev, + .cmd = hmp_snapshot_blkdev, }, STEXI @@ -1132,7 +1132,7 @@ ETEXI .help = "take an internal snapshot of device.\n\t\t\t" "The format of the image used by device must\n\t\t\t" "support it, such as qcow2.\n\t\t\t", - .mhandler.cmd = hmp_snapshot_blkdev_internal, + .cmd = hmp_snapshot_blkdev_internal, }, STEXI @@ -1150,7 +1150,7 @@ ETEXI "the snapshot matching both id and name.\n\t\t\t" "The format of the image used by device must\n\t\t\t" "support it, such as qcow2.\n\t\t\t", - .mhandler.cmd = hmp_snapshot_delete_blkdev_internal, + .cmd = hmp_snapshot_delete_blkdev_internal, }, STEXI @@ -1171,7 +1171,7 @@ ETEXI "in new-image-file, instead of recreating it from scratch.\n\t\t\t" "The -f flag requests QEMU to copy the whole disk,\n\t\t\t" "so that the result does not need a backing file.\n\t\t\t", - .mhandler.cmd = hmp_drive_mirror, + .cmd = hmp_drive_mirror, }, STEXI @item drive_mirror @@ -1194,7 +1194,7 @@ ETEXI "so that the result does not need a backing file.\n\t\t\t" "The -c flag requests QEMU to compress backup data\n\t\t\t" "(if the target format supports it).\n\t\t\t", - .mhandler.cmd = hmp_drive_backup, + .cmd = hmp_drive_backup, }, STEXI @item drive_backup @@ -1212,7 +1212,7 @@ ETEXI "[,snapshot=on|off][,cache=on|off]\n" "[,readonly=on|off][,copy-on-read=on|off]", .help = "add drive to PCI storage controller", - .mhandler.cmd = hmp_drive_add, + .cmd = hmp_drive_add, }, STEXI @@ -1236,7 +1236,7 @@ ETEXI " = error string or 32bit\n\t\t\t" " = 32bit x 4\n\t\t\t" " = 32bit x 4", - .mhandler.cmd = hmp_pcie_aer_inject_error, + .cmd = hmp_pcie_aer_inject_error, }, STEXI @@ -1250,7 +1250,7 @@ ETEXI .args_type = "device:s,opts:s?", .params = "tap|user|socket|vde|netmap|bridge|vhost-user|dump [options]", .help = "add host VLAN client", - .mhandler.cmd = hmp_host_net_add, + .cmd = hmp_host_net_add, .command_completion = host_net_add_completion, }, @@ -1265,7 +1265,7 @@ ETEXI .args_type = "vlan_id:i,device:s", .params = "vlan_id name", .help = "remove host VLAN client", - .mhandler.cmd = hmp_host_net_remove, + .cmd = hmp_host_net_remove, .command_completion = host_net_remove_completion, }, @@ -1280,7 +1280,7 @@ ETEXI .args_type = "netdev:O", .params = "[user|tap|socket|vde|bridge|hubport|netmap|vhost-user],id=str[,prop=value][,...]", .help = "add host network device", - .mhandler.cmd = hmp_netdev_add, + .cmd = hmp_netdev_add, .command_completion = netdev_add_completion, }, @@ -1295,7 +1295,7 @@ ETEXI .args_type = "id:s", .params = "id", .help = "remove host network device", - .mhandler.cmd = hmp_netdev_del, + .cmd = hmp_netdev_del, .command_completion = netdev_del_completion, }, @@ -1310,7 +1310,7 @@ ETEXI .args_type = "object:O", .params = "[qom-type=]type,id=str[,prop=value][,...]", .help = "create QOM object", - .mhandler.cmd = hmp_object_add, + .cmd = hmp_object_add, .command_completion = object_add_completion, }, @@ -1325,7 +1325,7 @@ ETEXI .args_type = "id:s", .params = "id", .help = "destroy QOM object", - .mhandler.cmd = hmp_object_del, + .cmd = hmp_object_del, .command_completion = object_del_completion, }, @@ -1341,7 +1341,7 @@ ETEXI .args_type = "arg1:s,arg2:s?,arg3:s?", .params = "[vlan_id name] [tcp|udp]:[hostaddr]:hostport-[guestaddr]:guestport", .help = "redirect TCP or UDP connections from host to guest (requires -net user)", - .mhandler.cmd = hmp_hostfwd_add, + .cmd = hmp_hostfwd_add, }, #endif STEXI @@ -1356,7 +1356,7 @@ ETEXI .args_type = "arg1:s,arg2:s?,arg3:s?", .params = "[vlan_id name] [tcp|udp]:[hostaddr]:hostport", .help = "remove host-to-guest TCP or UDP redirection", - .mhandler.cmd = hmp_hostfwd_remove, + .cmd = hmp_hostfwd_remove, }, #endif @@ -1371,7 +1371,7 @@ ETEXI .args_type = "value:M", .params = "target", .help = "request VM to change its memory allocation (in MB)", - .mhandler.cmd = hmp_balloon, + .cmd = hmp_balloon, }, STEXI @@ -1385,7 +1385,7 @@ ETEXI .args_type = "name:s,up:b", .params = "name on|off", .help = "change the link status of a network adapter", - .mhandler.cmd = hmp_set_link, + .cmd = hmp_set_link, .command_completion = set_link_completion, }, @@ -1400,7 +1400,7 @@ ETEXI .args_type = "action:s", .params = "[reset|shutdown|poweroff|pause|debug|none]", .help = "change watchdog action", - .mhandler.cmd = hmp_watchdog_action, + .cmd = hmp_watchdog_action, .command_completion = watchdog_action_completion, }, @@ -1415,7 +1415,7 @@ ETEXI .args_type = "aclname:s", .params = "aclname", .help = "list rules in the access control list", - .mhandler.cmd = hmp_acl_show, + .cmd = hmp_acl_show, }, STEXI @@ -1432,7 +1432,7 @@ ETEXI .args_type = "aclname:s,policy:s", .params = "aclname allow|deny", .help = "set default access control list policy", - .mhandler.cmd = hmp_acl_policy, + .cmd = hmp_acl_policy, }, STEXI @@ -1448,7 +1448,7 @@ ETEXI .args_type = "aclname:s,match:s,policy:s,index:i?", .params = "aclname match allow|deny [index]", .help = "add a match rule to the access control list", - .mhandler.cmd = hmp_acl_add, + .cmd = hmp_acl_add, }, STEXI @@ -1467,7 +1467,7 @@ ETEXI .args_type = "aclname:s,match:s", .params = "aclname match", .help = "remove a match rule from the access control list", - .mhandler.cmd = hmp_acl_remove, + .cmd = hmp_acl_remove, }, STEXI @@ -1481,7 +1481,7 @@ ETEXI .args_type = "aclname:s", .params = "aclname", .help = "reset the access control list", - .mhandler.cmd = hmp_acl_reset, + .cmd = hmp_acl_reset, }, STEXI @@ -1496,7 +1496,7 @@ ETEXI .args_type = "all:-a,writable:-w,uri:s", .params = "nbd_server_start [-a] [-w] host:port", .help = "serve block devices on the given host and port", - .mhandler.cmd = hmp_nbd_server_start, + .cmd = hmp_nbd_server_start, }, STEXI @item nbd_server_start @var{host}:@var{port} @@ -1512,7 +1512,7 @@ ETEXI .args_type = "writable:-w,device:B", .params = "nbd_server_add [-w] device", .help = "export a block device via NBD", - .mhandler.cmd = hmp_nbd_server_add, + .cmd = hmp_nbd_server_add, }, STEXI @item nbd_server_add @var{device} @@ -1527,7 +1527,7 @@ ETEXI .args_type = "", .params = "nbd_server_stop", .help = "stop serving block devices using the NBD protocol", - .mhandler.cmd = hmp_nbd_server_stop, + .cmd = hmp_nbd_server_stop, }, STEXI @item nbd_server_stop @@ -1543,7 +1543,7 @@ ETEXI .args_type = "broadcast:-b,cpu_index:i,bank:i,status:l,mcg_status:l,addr:l,misc:l", .params = "[-b] cpu bank status mcgstatus addr misc", .help = "inject a MCE on the given CPU [and broadcast to other CPUs with -b option]", - .mhandler.cmd = hmp_mce, + .cmd = hmp_mce, }, #endif @@ -1558,7 +1558,7 @@ ETEXI .args_type = "fdname:s", .params = "getfd name", .help = "receive a file descriptor via SCM rights and assign it a name", - .mhandler.cmd = hmp_getfd, + .cmd = hmp_getfd, }, STEXI @@ -1574,7 +1574,7 @@ ETEXI .args_type = "fdname:s", .params = "closefd name", .help = "close a file descriptor previously passed via SCM rights", - .mhandler.cmd = hmp_closefd, + .cmd = hmp_closefd, }, STEXI @@ -1590,7 +1590,7 @@ ETEXI .args_type = "device:B,password:s", .params = "block_passwd device password", .help = "set the password of encrypted block devices", - .mhandler.cmd = hmp_block_passwd, + .cmd = hmp_block_passwd, }, STEXI @@ -1604,7 +1604,7 @@ ETEXI .args_type = "device:B,bps:l,bps_rd:l,bps_wr:l,iops:l,iops_rd:l,iops_wr:l", .params = "device bps bps_rd bps_wr iops iops_rd iops_wr", .help = "change I/O throttle limits for a block drive", - .mhandler.cmd = hmp_block_set_io_throttle, + .cmd = hmp_block_set_io_throttle, }, STEXI @@ -1618,7 +1618,7 @@ ETEXI .args_type = "protocol:s,password:s,connected:s?", .params = "protocol password action-if-connected", .help = "set spice/vnc password", - .mhandler.cmd = hmp_set_password, + .cmd = hmp_set_password, }, STEXI @@ -1637,7 +1637,7 @@ ETEXI .args_type = "protocol:s,time:s", .params = "protocol time", .help = "set spice/vnc password expire-time", - .mhandler.cmd = hmp_expire_password, + .cmd = hmp_expire_password, }, STEXI @@ -1668,7 +1668,7 @@ ETEXI .args_type = "args:s", .params = "args", .help = "add chardev", - .mhandler.cmd = hmp_chardev_add, + .cmd = hmp_chardev_add, .command_completion = chardev_add_completion, }, @@ -1684,7 +1684,7 @@ ETEXI .args_type = "id:s", .params = "id", .help = "remove chardev", - .mhandler.cmd = hmp_chardev_remove, + .cmd = hmp_chardev_remove, .command_completion = chardev_remove_completion, }, @@ -1700,7 +1700,7 @@ ETEXI .args_type = "device:B,command:s", .params = "[device] \"[command]\"", .help = "run a qemu-io command on a block device", - .mhandler.cmd = hmp_qemu_io, + .cmd = hmp_qemu_io, }, STEXI @@ -1715,7 +1715,7 @@ ETEXI .args_type = "id:i", .params = "id", .help = "add cpu", - .mhandler.cmd = hmp_cpu_add, + .cmd = hmp_cpu_add, }, STEXI @@ -1729,7 +1729,7 @@ ETEXI .args_type = "path:s?", .params = "path", .help = "list QOM properties", - .mhandler.cmd = hmp_qom_list, + .cmd = hmp_qom_list, }, STEXI @@ -1742,7 +1742,7 @@ ETEXI .args_type = "path:s,property:s,value:s", .params = "path property value", .help = "set QOM property", - .mhandler.cmd = hmp_qom_set, + .cmd = hmp_qom_set, }, STEXI @@ -1755,8 +1755,8 @@ ETEXI .args_type = "item:s?", .params = "[subcommand]", .help = "show various information about the system state", - .mhandler.cmd = hmp_info_help, - .sub_table = info_cmds, + .cmd = hmp_info_help, + .sub_table = info_cmds, }, STEXI diff --git a/monitor.c b/monitor.c index f50aa6e5d02..d5d6e95e9db 100644 --- a/monitor.c +++ b/monitor.c @@ -130,13 +130,10 @@ typedef struct mon_cmd_t { const char *args_type; const char *params; const char *help; - union { - void (*cmd)(Monitor *mon, const QDict *qdict); - void (*cmd_new)(QDict *params, QObject **ret_data, Error **errp); - } mhandler; - /* @sub_table is a list of 2nd level of commands. If it do not exist, - * mhandler should be used. If it exist, sub_table[?].mhandler should be - * used, and mhandler of 1st level plays the role of help function. + void (*cmd)(Monitor *mon, const QDict *qdict); + /* @sub_table is a list of 2nd level of commands. If it does not exist, + * cmd should be used. If it exists, sub_table[?].cmd should be + * used, and cmd of 1st level plays the role of help function. */ struct mon_cmd_t *sub_table; void (*command_completion)(ReadLineState *rs, int nb_args, const char *str); @@ -3005,7 +3002,7 @@ static void handle_hmp_command(Monitor *mon, const char *cmdline) return; } - cmd->mhandler.cmd(mon, qdict); + cmd->cmd(mon, qdict); QDECREF(qdict); } From 077b009ebb98c45ac1a88332e2ddb99a88cc09cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 12 Sep 2016 13:19:07 +0400 Subject: [PATCH 091/723] qapi: remove the "middle" mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that the register function is always generated, we can remove the so-called "middle" mode from the generator script. Signed-off-by: Marc-André Lureau Message-Id: <20160912091913.15831-13-marcandre.lureau@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- scripts/qapi-commands.py | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py index b150db97922..eac64cedc57 100644 --- a/scripts/qapi-commands.py +++ b/scripts/qapi-commands.py @@ -206,8 +206,7 @@ def visit_begin(self, schema): self._visited_ret_types = set() def visit_end(self): - if not middle_mode: - self.defn += gen_registry(self._regy) + self.defn += gen_registry(self._regy) self._regy = None self._visited_ret_types = None @@ -221,18 +220,10 @@ def visit_command(self, name, info, arg_type, ret_type, self.defn += gen_marshal_output(ret_type) self.decl += gen_marshal_decl(name) self.defn += gen_marshal(name, arg_type, boxed, ret_type) - if not middle_mode: - self._regy += gen_register_command(name, success_response) + self._regy += gen_register_command(name, success_response) -middle_mode = False - -(input_file, output_dir, do_c, do_h, prefix, opts) = \ - parse_command_line("m", ["middle"]) - -for o, a in opts: - if o in ("-m", "--middle"): - middle_mode = True +(input_file, output_dir, do_c, do_h, prefix, opts) = parse_command_line() c_comment = ''' /* From a0067da1577e3eb0c60758384282568f4b2328fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 12 Sep 2016 13:19:08 +0400 Subject: [PATCH 092/723] qapi: check invalid arguments on no-args commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The generated marshal functions do not visit arguments from commands that take no arguments. Thus they fail to catch invalid members. Visit the arguments, if provided, to throw an error in case of invalid members. Currently, qmp_check_client_args() checks for invalid arguments and correctly catches this case. When switching to qmp_dispatch() we want to keep that behaviour. The commands using 'O' may have arbitrary arguments, and must have 'gen': false in the qapi schema to skip the generated checks. Old/new diff: void qmp_marshal_stop(QDict *args, QObject **ret, Error **errp) { Error *err = NULL; + Visitor *v = NULL; - (void)args; + if (args) { + v = qmp_input_visitor_new(QOBJECT(args), true); + visit_start_struct(v, NULL, NULL, 0, &err); + if (err) { + goto out; + } + + if (!err) { + visit_check_struct(v, &err); + } + visit_end_struct(v, NULL); + if (err) { + goto out; + } + } qmp_stop(&err); + +out: error_propagate(errp, err); + visit_free(v); + if (args) { + v = qapi_dealloc_visitor_new(); + visit_start_struct(v, NULL, NULL, 0, NULL); + + visit_end_struct(v, NULL); + visit_free(v); + } } The new code closely resembles code for a command with arguments. Differences: - the visit of the argument and its cleanup struct don't visit any members (because there are none). - the visit of the argument struct and its cleanup are conditional. Signed-off-by: Marc-André Lureau Message-Id: <20160912091913.15831-14-marcandre.lureau@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- scripts/qapi-commands.py | 58 +++++++++++++++++++++++++++++---------- tests/test-qmp-commands.c | 15 ++++++++++ 2 files changed, 58 insertions(+), 15 deletions(-) diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py index eac64cedc57..2f603b0c0ed 100644 --- a/scripts/qapi-commands.py +++ b/scripts/qapi-commands.py @@ -95,6 +95,8 @@ def gen_marshal_decl(name): def gen_marshal(name, arg_type, boxed, ret_type): + have_args = arg_type and not arg_type.is_empty() + ret = mcgen(''' %(proto)s @@ -109,17 +111,31 @@ def gen_marshal(name, arg_type, boxed, ret_type): ''', c_type=ret_type.c_type()) - if arg_type and not arg_type.is_empty(): + if have_args: + visit_members = ('visit_type_%s_members(v, &arg, &err);' + % arg_type.c_name()) ret += mcgen(''' Visitor *v; %(c_name)s arg = {0}; +''', + c_name=arg_type.c_name()) + else: + visit_members = '' + ret += mcgen(''' + Visitor *v = NULL; + + if (args) { +''') + push_indent() + + ret += mcgen(''' v = qmp_input_visitor_new(QOBJECT(args), true); visit_start_struct(v, NULL, NULL, 0, &err); if (err) { goto out; } - visit_type_%(c_name)s_members(v, &arg, &err); + %(visit_members)s if (!err) { visit_check_struct(v, &err); } @@ -128,35 +144,47 @@ def gen_marshal(name, arg_type, boxed, ret_type): goto out; } ''', - c_name=arg_type.c_name()) + visit_members=visit_members) - else: + if not have_args: + pop_indent() ret += mcgen(''' - - (void)args; + } ''') ret += gen_call(name, arg_type, boxed, ret_type) - # 'goto out' produced above for arg_type, and by gen_call() for ret_type - if (arg_type and not arg_type.is_empty()) or ret_type: - ret += mcgen(''' + ret += mcgen(''' out: -''') - ret += mcgen(''' error_propagate(errp, err); + visit_free(v); ''') - if arg_type and not arg_type.is_empty(): + + if have_args: + visit_members = ('visit_type_%s_members(v, &arg, NULL);' + % arg_type.c_name()) + else: + visit_members = '' ret += mcgen(''' - visit_free(v); + if (args) { +''') + push_indent() + + ret += mcgen(''' v = qapi_dealloc_visitor_new(); visit_start_struct(v, NULL, NULL, 0, NULL); - visit_type_%(c_name)s_members(v, &arg, NULL); + %(visit_members)s visit_end_struct(v, NULL); visit_free(v); ''', - c_name=arg_type.c_name()) + visit_members=visit_members) + + if not have_args: + pop_indent() + ret += mcgen(''' + } +''') ret += mcgen(''' } diff --git a/tests/test-qmp-commands.c b/tests/test-qmp-commands.c index 261fd9e3130..81cbe545c49 100644 --- a/tests/test-qmp-commands.c +++ b/tests/test-qmp-commands.c @@ -106,6 +106,7 @@ static void test_dispatch_cmd(void) static void test_dispatch_cmd_failure(void) { QDict *req = qdict_new(); + QDict *args = qdict_new(); QObject *resp; qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd2"))); @@ -116,6 +117,20 @@ static void test_dispatch_cmd_failure(void) qobject_decref(resp); QDECREF(req); + + /* check that with extra arguments it throws an error */ + req = qdict_new(); + qdict_put(args, "a", qint_from_int(66)); + qdict_put(req, "arguments", args); + + qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd"))); + + resp = qmp_dispatch(QOBJECT(req)); + assert(resp != NULL); + assert(qdict_haskey(qobject_to_qdict(resp), "error")); + + qobject_decref(resp); + QDECREF(req); } static QObject *test_qmp_dispatch(QDict *req) From 4bdadd86718c901fc1a512a7e3e0cbe7518cf277 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 12 Sep 2016 13:19:09 +0400 Subject: [PATCH 093/723] tests: add a test to check invalid args MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check that invalid args on commands without arguments returns an error. Signed-off-by: Marc-André Lureau Message-Id: <20160912091913.15831-15-marcandre.lureau@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- tests/test-qga.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/test-qga.c b/tests/test-qga.c index 21f44f89156..40af64987a3 100644 --- a/tests/test-qga.c +++ b/tests/test-qga.c @@ -198,6 +198,26 @@ static void test_qga_ping(gconstpointer fix) QDECREF(ret); } +static void test_qga_invalid_args(gconstpointer fix) +{ + const TestFixture *fixture = fix; + QDict *ret, *error; + const gchar *class, *desc; + + ret = qmp_fd(fixture->fd, "{'execute': 'guest-ping', " + "'arguments': {'foo': 42 }}"); + g_assert_nonnull(ret); + + error = qdict_get_qdict(ret, "error"); + class = qdict_get_try_str(error, "class"); + desc = qdict_get_try_str(error, "desc"); + + g_assert_cmpstr(class, ==, "GenericError"); + g_assert_cmpstr(desc, ==, "QMP input object member 'foo' is unexpected"); + + QDECREF(ret); +} + static void test_qga_invalid_cmd(gconstpointer fix) { const TestFixture *fixture = fix; @@ -911,6 +931,7 @@ int main(int argc, char **argv) g_test_add_data_func("/qga/file-write-read", &fix, test_qga_file_write_read); g_test_add_data_func("/qga/get-time", &fix, test_qga_get_time); g_test_add_data_func("/qga/invalid-cmd", &fix, test_qga_invalid_cmd); + g_test_add_data_func("/qga/invalid-args", &fix, test_qga_invalid_args); g_test_add_data_func("/qga/fsfreeze-status", &fix, test_qga_fsfreeze_status); From 5c678ee8d9406b9baeec788530965483575db555 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 12 Sep 2016 13:19:10 +0400 Subject: [PATCH 094/723] monitor: use qmp_dispatch() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the old manual dispatch and validation code by the generic one provided by qapi common code. Note that it is now possible to call the following commands that used to be disabled by compile-time conditionals: - dump-skeys - query-spice - rtc-reset-reinjection - query-gic-capabilities Their fallback functions return an appropriate "feature disabled" error. Signed-off-by: Marc-André Lureau Message-Id: <20160912091913.15831-16-marcandre.lureau@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- monitor.c | 326 ++++++--------------------------------------------- trace-events | 1 - 2 files changed, 34 insertions(+), 293 deletions(-) diff --git a/monitor.c b/monitor.c index d5d6e95e9db..8bb8bbfd151 100644 --- a/monitor.c +++ b/monitor.c @@ -166,7 +166,6 @@ struct MonFdset { }; typedef struct { - QObject *id; JSONMessageParser parser; /* * When a client connects, we're in capabilities negotiation mode. @@ -229,8 +228,6 @@ static int mon_refcount; static mon_cmd_t mon_cmds[]; static mon_cmd_t info_cmds[]; -static const mon_cmd_t qmp_cmds[]; - Monitor *cur_mon; static QEMUClockType event_clock_type = QEMU_CLOCK_REALTIME; @@ -401,49 +398,6 @@ static void monitor_json_emitter(Monitor *mon, const QObject *data) QDECREF(json); } -static QDict *build_qmp_error_dict(Error *err) -{ - QObject *obj; - - obj = qobject_from_jsonf("{ 'error': { 'class': %s, 'desc': %s } }", - QapiErrorClass_lookup[error_get_class(err)], - error_get_pretty(err)); - - return qobject_to_qdict(obj); -} - -static void monitor_protocol_emitter(Monitor *mon, QObject *data, - Error *err) -{ - QDict *qmp; - - trace_monitor_protocol_emitter(mon); - - if (!err) { - /* success response */ - qmp = qdict_new(); - if (data) { - qobject_incref(data); - qdict_put_obj(qmp, "return", data); - } else { - /* return an empty QDict by default */ - qdict_put(qmp, "return", qdict_new()); - } - } else { - /* error response */ - qmp = build_qmp_error_dict(err); - } - - if (mon->qmp.id) { - qdict_put_obj(qmp, "id", mon->qmp.id); - mon->qmp.id = NULL; - } - - monitor_json_emitter(mon, QOBJECT(qmp)); - QDECREF(qmp); -} - - static MonitorQAPIEventConf monitor_qapi_event_conf[QAPI_EVENT__MAX] = { /* Limit guest-triggerable events to 1 per second */ [QAPI_EVENT_RTC_CHANGE] = { 1000 * SCALE_MS }, @@ -2211,11 +2165,6 @@ static mon_cmd_t mon_cmds[] = { { NULL, NULL, }, }; -static const mon_cmd_t qmp_cmds[] = { -#include "qmp-commands-old.h" - { /* NULL */ }, -}; - /*******************************************************************/ static const char *pch; @@ -2566,11 +2515,6 @@ static const mon_cmd_t *search_dispatch_table(const mon_cmd_t *disp_table, return NULL; } -static const mon_cmd_t *qmp_find_cmd(const char *cmdname) -{ - return search_dispatch_table(qmp_cmds, cmdname); -} - /* * Parse command name from @cmdp according to command table @table. * If blank, return NULL. @@ -3721,199 +3665,6 @@ static bool invalid_qmp_mode(const Monitor *mon, const char *cmd, return false; } -/* - * Argument validation rules: - * - * 1. The argument must exist in cmd_args qdict - * 2. The argument type must be the expected one - * - * Special case: If the argument doesn't exist in cmd_args and - * the QMP_ACCEPT_UNKNOWNS flag is set, then the - * checking is skipped for it. - */ -static void check_client_args_type(const QDict *client_args, - const QDict *cmd_args, int flags, - Error **errp) -{ - const QDictEntry *ent; - - for (ent = qdict_first(client_args); ent;ent = qdict_next(client_args,ent)){ - QObject *obj; - QString *arg_type; - const QObject *client_arg = qdict_entry_value(ent); - const char *client_arg_name = qdict_entry_key(ent); - - obj = qdict_get(cmd_args, client_arg_name); - if (!obj) { - if (flags & QMP_ACCEPT_UNKNOWNS) { - /* handler accepts unknowns */ - continue; - } - /* client arg doesn't exist */ - error_setg(errp, QERR_INVALID_PARAMETER, client_arg_name); - return; - } - - arg_type = qobject_to_qstring(obj); - assert(arg_type != NULL); - - /* check if argument's type is correct */ - switch (qstring_get_str(arg_type)[0]) { - case 'F': - case 'B': - case 's': - if (qobject_type(client_arg) != QTYPE_QSTRING) { - error_setg(errp, QERR_INVALID_PARAMETER_TYPE, - client_arg_name, "string"); - return; - } - break; - case 'i': - case 'l': - case 'M': - case 'o': - if (qobject_type(client_arg) != QTYPE_QINT) { - error_setg(errp, QERR_INVALID_PARAMETER_TYPE, - client_arg_name, "int"); - return; - } - break; - case 'T': - if (qobject_type(client_arg) != QTYPE_QINT && - qobject_type(client_arg) != QTYPE_QFLOAT) { - error_setg(errp, QERR_INVALID_PARAMETER_TYPE, - client_arg_name, "number"); - return; - } - break; - case 'b': - case '-': - if (qobject_type(client_arg) != QTYPE_QBOOL) { - error_setg(errp, QERR_INVALID_PARAMETER_TYPE, - client_arg_name, "bool"); - return; - } - break; - case 'O': - assert(flags & QMP_ACCEPT_UNKNOWNS); - break; - case 'q': - /* Any QObject can be passed. */ - break; - case '/': - case '.': - /* - * These types are not supported by QMP and thus are not - * handled here. Fall through. - */ - default: - abort(); - } - } -} - -/* - * - Check if the client has passed all mandatory args - * - Set special flags for argument validation - */ -static void check_mandatory_args(const QDict *cmd_args, - const QDict *client_args, int *flags, - Error **errp) -{ - const QDictEntry *ent; - - for (ent = qdict_first(cmd_args); ent; ent = qdict_next(cmd_args, ent)) { - const char *cmd_arg_name = qdict_entry_key(ent); - QString *type = qobject_to_qstring(qdict_entry_value(ent)); - assert(type != NULL); - - if (qstring_get_str(type)[0] == 'O') { - assert((*flags & QMP_ACCEPT_UNKNOWNS) == 0); - *flags |= QMP_ACCEPT_UNKNOWNS; - } else if (qstring_get_str(type)[0] != '-' && - qstring_get_str(type)[1] != '?' && - !qdict_haskey(client_args, cmd_arg_name)) { - error_setg(errp, QERR_MISSING_PARAMETER, cmd_arg_name); - return; - } - } -} - -static QDict *qdict_from_args_type(const char *args_type) -{ - int i; - QDict *qdict; - QString *key, *type, *cur_qs; - - assert(args_type != NULL); - - qdict = qdict_new(); - - if (args_type == NULL || args_type[0] == '\0') { - /* no args, empty qdict */ - goto out; - } - - key = qstring_new(); - type = qstring_new(); - - cur_qs = key; - - for (i = 0;; i++) { - switch (args_type[i]) { - case ',': - case '\0': - qdict_put(qdict, qstring_get_str(key), type); - QDECREF(key); - if (args_type[i] == '\0') { - goto out; - } - type = qstring_new(); /* qdict has ref */ - cur_qs = key = qstring_new(); - break; - case ':': - cur_qs = type; - break; - default: - qstring_append_chr(cur_qs, args_type[i]); - break; - } - } - -out: - return qdict; -} - -/* - * Client argument checking rules: - * - * 1. Client must provide all mandatory arguments - * 2. Each argument provided by the client must be expected - * 3. Each argument provided by the client must have the type expected - * by the command - */ -static void qmp_check_client_args(const mon_cmd_t *cmd, QDict *client_args, - Error **errp) -{ - Error *err = NULL; - int flags; - QDict *cmd_args; - - cmd_args = qdict_from_args_type(cmd->args_type); - - flags = 0; - check_mandatory_args(cmd_args, client_args, &flags, &err); - if (err) { - goto out; - } - - check_client_args_type(client_args, cmd_args, flags, &err); - -out: - error_propagate(errp, err); - QDECREF(cmd_args); -} - /* * Input object checking rules * @@ -3972,67 +3723,58 @@ static QDict *qmp_check_input_obj(QObject *input_obj, Error **errp) static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens) { - Error *local_err = NULL; - QObject *obj, *data; - QDict *input, *args; - const mon_cmd_t *cmd; - QmpCommand *qcmd; + QObject *req, *rsp = NULL, *id = NULL; + QDict *qdict = NULL; const char *cmd_name; Monitor *mon = cur_mon; + Error *err = NULL; - args = input = NULL; - data = NULL; - - obj = json_parser_parse(tokens, NULL); - if (!obj) { - // FIXME: should be triggered in json_parser_parse() - error_setg(&local_err, QERR_JSON_PARSING); + req = json_parser_parse_err(tokens, NULL, &err); + if (err || !req || qobject_type(req) != QTYPE_QDICT) { + if (!err) { + error_setg(&err, QERR_JSON_PARSING); + } goto err_out; } - input = qmp_check_input_obj(obj, &local_err); - if (!input) { - qobject_decref(obj); + qdict = qmp_check_input_obj(req, &err); + if (!qdict) { goto err_out; } - mon->qmp.id = qdict_get(input, "id"); - qobject_incref(mon->qmp.id); + id = qdict_get(qdict, "id"); + qobject_incref(id); + qdict_del(qdict, "id"); - cmd_name = qdict_get_str(input, "execute"); + cmd_name = qdict_get_str(qdict, "execute"); trace_handle_qmp_command(mon, cmd_name); - cmd = qmp_find_cmd(cmd_name); - qcmd = qmp_find_command(cmd_name); - if (!qcmd || !cmd) { - error_set(&local_err, ERROR_CLASS_COMMAND_NOT_FOUND, - "The command %s has not been found", cmd_name); - goto err_out; - } - if (invalid_qmp_mode(mon, cmd_name, &local_err)) { + + if (invalid_qmp_mode(mon, cmd_name, &err)) { goto err_out; } - obj = qdict_get(input, "arguments"); - if (!obj) { - args = qdict_new(); - } else { - args = qobject_to_qdict(obj); - QINCREF(args); - } + rsp = qmp_dispatch(req); - qmp_check_client_args(cmd, args, &local_err); - if (local_err) { - goto err_out; +err_out: + if (err) { + qdict = qdict_new(); + qdict_put_obj(qdict, "error", qmp_build_error_object(err)); + error_free(err); + rsp = QOBJECT(qdict); } - qcmd->fn(args, &data, &local_err); + if (rsp) { + if (id) { + qdict_put_obj(qobject_to_qdict(rsp), "id", id); + id = NULL; + } -err_out: - monitor_protocol_emitter(mon, data, local_err); - qobject_decref(data); - error_free(local_err); - QDECREF(input); - QDECREF(args); + monitor_json_emitter(mon, rsp); + } + + qobject_decref(id); + qobject_decref(rsp); + qobject_decref(req); } static void monitor_qmp_read(void *opaque, const uint8_t *buf, int size) diff --git a/trace-events b/trace-events index 616cc523780..8d59631ae83 100644 --- a/trace-events +++ b/trace-events @@ -98,7 +98,6 @@ qemu_co_mutex_unlock_return(void *mutex, void *self) "mutex %p self %p" # monitor.c handle_qmp_command(void *mon, const char *cmd_name) "mon %p cmd_name \"%s\"" -monitor_protocol_emitter(void *mon) "mon %p" monitor_protocol_event_handler(uint32_t event, void *qdict) "event=%d data=%p" monitor_protocol_event_emit(uint32_t event, void *data) "event=%d data=%p" monitor_protocol_event_queue(uint32_t event, void *qdict, uint64_t rate) "event=%d data=%p rate=%" PRId64 From 842894994e089d3d8fc2cedd4679f1367b761212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 12 Sep 2016 13:19:11 +0400 Subject: [PATCH 095/723] build-sys: remove qmp-commands-old.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marc-André Lureau Reviewed-by: Eric Blake Message-Id: <20160912091913.15831-17-marcandre.lureau@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- Makefile.target | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Makefile.target b/Makefile.target index 8c7a072f08a..19cc49c0d7c 100644 --- a/Makefile.target +++ b/Makefile.target @@ -156,7 +156,7 @@ else obj-y += hw/$(TARGET_BASE_ARCH)/ endif -GENERATED_HEADERS += hmp-commands.h hmp-commands-info.h qmp-commands-old.h +GENERATED_HEADERS += hmp-commands.h hmp-commands-info.h endif # CONFIG_SOFTMMU @@ -209,13 +209,10 @@ hmp-commands.h: $(SRC_PATH)/hmp-commands.hx $(SRC_PATH)/scripts/hxtool hmp-commands-info.h: $(SRC_PATH)/hmp-commands-info.hx $(SRC_PATH)/scripts/hxtool $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@," GEN $(TARGET_DIR)$@") -qmp-commands-old.h: $(SRC_PATH)/qmp-commands.hx $(SRC_PATH)/scripts/hxtool - $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@," GEN $(TARGET_DIR)$@") - clean: clean-target rm -f *.a *~ $(PROGS) rm -f $(shell find . -name '*.[od]') - rm -f hmp-commands.h qmp-commands-old.h gdbstub-xml.c + rm -f hmp-commands.h gdbstub-xml.c ifdef CONFIG_TRACE_SYSTEMTAP rm -f *.stp endif From bdf05133233faa11899738d5c90c7b78d145682b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 12 Sep 2016 13:19:12 +0400 Subject: [PATCH 096/723] qmp-commands.hx: fix some styling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add some missing lines, remove superflous @ in command name, remove trailing spaces. Signed-off-by: Marc-André Lureau Message-Id: <20160912091913.15831-18-marcandre.lureau@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- qmp-commands.hx | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/qmp-commands.hx b/qmp-commands.hx index 734f3d73422..b38772cdd22 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -91,7 +91,7 @@ eject Eject a removable medium. -Arguments: +Arguments: - force: force ejection (json-bool, optional) - device: device name (json-string) @@ -1395,7 +1395,6 @@ EQMP }, SQMP - block-dirty-bitmap-add ---------------------- Since 2.4 @@ -1422,7 +1421,6 @@ EQMP }, SQMP - block-dirty-bitmap-remove ------------------------- Since 2.4 @@ -1449,7 +1447,6 @@ EQMP }, SQMP - block-dirty-bitmap-clear ------------------------ Since 2.4 @@ -2176,7 +2173,7 @@ human-monitor-command Execute a Human Monitor command. -Arguments: +Arguments: - command-line: the command name and its arguments, just like the Human Monitor's shell (json-string) @@ -2988,7 +2985,7 @@ Example: }, "function":0, "regions":[ - + ] }, { @@ -3005,7 +3002,7 @@ Example: }, "function":0, "regions":[ - + ] }, { @@ -3467,8 +3464,8 @@ The main json-object contains the following: - "setup-time" amount of setup time in milliseconds _before_ the iterations begin but _after_ the QMP command is issued. This is designed to provide an accounting of any activities - (such as RDMA pinning) which may be expensive, but do not - actually occur during the iterative migration rounds + (such as RDMA pinning) which may be expensive, but do not + actually occur during the iterative migration rounds themselves. (json-int) - "downtime": only present when migration has finished correctly total amount in ms for downtime that happened (json-int) @@ -4393,8 +4390,8 @@ EQMP }, SQMP -@query-named-block-nodes ------------------------- +query-named-block-nodes +----------------------- Return a list of BlockDeviceInfo for all the named block driver nodes @@ -4543,7 +4540,7 @@ EQMP }, SQMP -@query-memory-devices +query-memory-devices -------------------- Return a list of memory devices. @@ -4561,6 +4558,7 @@ Example: "slot": 0}, "type": "dimm" } ] } + EQMP { @@ -4569,8 +4567,8 @@ EQMP }, SQMP -@query-acpi-ospm-status --------------------- +query-acpi-ospm-status +---------------------- Return list of ACPIOSTInfo for devices that support status reporting via ACPI _OST method. @@ -4582,6 +4580,7 @@ Example: { "slot": "2", "slot-type": "DIMM", "source": 0, "status": 0}, { "slot": "3", "slot-type": "DIMM", "source": 0, "status": 0} ]} + EQMP #if defined TARGET_I386 @@ -4603,6 +4602,7 @@ Example: -> { "execute": "rtc-reset-reinjection" } <- { "return": {} } + EQMP { @@ -4634,6 +4634,7 @@ Example: -> { "execute": "trace-event-get-state", "arguments": { "name": "qemu_memalign" } } <- { "return": [ { "name": "qemu_memalign", "state": "disabled" } ] } + EQMP { @@ -4668,6 +4669,7 @@ Example: -> { "execute": "trace-event-set-state", "arguments": { "name": "qemu_memalign", "enable": "true" } } <- { "return": {} } + EQMP { @@ -4676,8 +4678,8 @@ EQMP }, SQMP -@input-send-event ------------------ +input-send-event +---------------- Send input event to guest. From bd6092e407a5d682fbfddcbc510038b84bc1a1aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 12 Sep 2016 13:19:13 +0400 Subject: [PATCH 097/723] Replace qmp-commands.hx by docs/qmp-commands.txt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The only remaining function of qmp-commands.hx is to let us generate qmp-commands.txt from it. Replace qmp-commands.hx by qmp-commands.txt. We intend to move the documentation into the QAPI schema and generate qapi-commands.txt from it, but not right now. Signed-off-by: Marc-André Lureau Message-Id: <20160912091913.15831-19-marcandre.lureau@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- .gitignore | 1 - MAINTAINERS | 1 - Makefile | 6 +- docs/qapi-code-gen.txt | 6 +- qmp-commands.hx => docs/qmp-commands.txt | 1127 ---------------------- docs/writing-qmp-commands.txt | 38 - 6 files changed, 4 insertions(+), 1175 deletions(-) rename qmp-commands.hx => docs/qmp-commands.txt (87%) diff --git a/.gitignore b/.gitignore index 5ffc84ba9ff..c91d018c78c 100644 --- a/.gitignore +++ b/.gitignore @@ -55,7 +55,6 @@ /qemu-monitor-info.texi /qemu-version.h /qemu-version.h.tmp -/qmp-commands.txt /vscclient /fsdev/virtfs-proxy-helper *.[1-9] diff --git a/MAINTAINERS b/MAINTAINERS index 7d430261620..d4ee9495b05 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1235,7 +1235,6 @@ M: Markus Armbruster S: Supported F: qmp.c F: monitor.c -F: qmp-commands.hx F: docs/*qmp-* F: scripts/qmp/ T: git git://repo.or.cz/qemu/armbru.git qapi-next diff --git a/Makefile b/Makefile index 1c9f062f915..81ca388a75c 100644 --- a/Makefile +++ b/Makefile @@ -92,7 +92,6 @@ HELPERS-$(CONFIG_LINUX) = qemu-bridge-helper$(EXESUF) ifdef BUILD_DOCS DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1 qemu-nbd.8 qemu-ga.8 -DOCS+=qmp-commands.txt ifdef CONFIG_VIRTFS DOCS+=fsdev/virtfs-proxy-helper.1 endif @@ -432,7 +431,7 @@ endif install-doc: $(DOCS) $(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)" $(INSTALL_DATA) qemu-doc.html qemu-tech.html "$(DESTDIR)$(qemu_docdir)" - $(INSTALL_DATA) qmp-commands.txt "$(DESTDIR)$(qemu_docdir)" + $(INSTALL_DATA) docs/qmp-commands.txt "$(DESTDIR)$(qemu_docdir)" ifdef CONFIG_POSIX $(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1" $(INSTALL_DATA) qemu.1 "$(DESTDIR)$(mandir)/man1" @@ -555,9 +554,6 @@ qemu-monitor.texi: $(SRC_PATH)/hmp-commands.hx $(SRC_PATH)/scripts/hxtool qemu-monitor-info.texi: $(SRC_PATH)/hmp-commands-info.hx $(SRC_PATH)/scripts/hxtool $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@," GEN $@") -qmp-commands.txt: $(SRC_PATH)/qmp-commands.hx $(SRC_PATH)/scripts/hxtool - $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -q < $< > $@," GEN $@") - qemu-img-cmds.texi: $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/scripts/hxtool $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@," GEN $@") diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt index de298dcaecf..5d4c2cdd7e7 100644 --- a/docs/qapi-code-gen.txt +++ b/docs/qapi-code-gen.txt @@ -964,9 +964,9 @@ Example: Used to generate the marshaling/dispatch functions for the commands defined in the schema. The generated code implements -qmp_marshal_COMMAND() (mentioned in qmp-commands.hx, and registered -automatically), and declares qmp_COMMAND() that the user must -implement. The following files are generated: +qmp_marshal_COMMAND() (registered automatically), and declares +qmp_COMMAND() that the user must implement. The following files are +generated: $(prefix)qmp-marshal.c: command marshal/dispatch functions for each QMP command defined in the schema. Functions diff --git a/qmp-commands.hx b/docs/qmp-commands.txt similarity index 87% rename from qmp-commands.hx rename to docs/qmp-commands.txt index b38772cdd22..acebeb3954a 100644 --- a/qmp-commands.hx +++ b/docs/qmp-commands.txt @@ -1,8 +1,3 @@ -HXCOMM QMP dispatch table and documentation -HXCOMM Text between SQMP and EQMP is copied to the QMP documentation file and -HXCOMM does not show up in the other formats. - -SQMP QMP Supported Commands ---------------------- @@ -58,14 +53,6 @@ If you're planning to adopt QMP, please observe the following: Server's responses in the examples below are always a success response, please refer to the QMP specification for more details on error responses. -EQMP - - { - .name = "quit", - .args_type = "", - }, - -SQMP quit ---- @@ -78,14 +65,6 @@ Example: -> { "execute": "quit" } <- { "return": {} } -EQMP - - { - .name = "eject", - .args_type = "force:-f,device:B", - }, - -SQMP eject ----- @@ -103,14 +82,6 @@ Example: Note: The "force" argument defaults to false. -EQMP - - { - .name = "change", - .args_type = "device:B,target:F,arg:s?", - }, - -SQMP change ------ @@ -138,14 +109,6 @@ Examples: "arg": "foobar1" } } <- { "return": {} } -EQMP - - { - .name = "screendump", - .args_type = "filename:F", - }, - -SQMP screendump ---------- @@ -160,14 +123,6 @@ Example: -> { "execute": "screendump", "arguments": { "filename": "/tmp/image" } } <- { "return": {} } -EQMP - - { - .name = "stop", - .args_type = "", - }, - -SQMP stop ---- @@ -180,14 +135,6 @@ Example: -> { "execute": "stop" } <- { "return": {} } -EQMP - - { - .name = "cont", - .args_type = "", - }, - -SQMP cont ---- @@ -200,14 +147,6 @@ Example: -> { "execute": "cont" } <- { "return": {} } -EQMP - - { - .name = "system_wakeup", - .args_type = "", - }, - -SQMP system_wakeup ------------- @@ -220,14 +159,6 @@ Example: -> { "execute": "system_wakeup" } <- { "return": {} } -EQMP - - { - .name = "system_reset", - .args_type = "", - }, - -SQMP system_reset ------------ @@ -240,14 +171,6 @@ Example: -> { "execute": "system_reset" } <- { "return": {} } -EQMP - - { - .name = "system_powerdown", - .args_type = "", - }, - -SQMP system_powerdown ---------------- @@ -260,16 +183,6 @@ Example: -> { "execute": "system_powerdown" } <- { "return": {} } -EQMP - - { - .name = "device_add", - .args_type = "device:O", - .params = "driver[,prop=value][,...]", - .help = "add device, like -device on the command line", - }, - -SQMP device_add ---------- @@ -295,14 +208,6 @@ Notes: (2) It's possible to list device properties by running QEMU with the "-device DEVICE,\?" command-line argument, where DEVICE is the device's name -EQMP - - { - .name = "device_del", - .args_type = "id:s", - }, - -SQMP device_del ---------- @@ -322,14 +227,6 @@ Example: -> { "execute": "device_del", "arguments": { "id": "/machine/peripheral-anon/device[0]" } } <- { "return": {} } -EQMP - - { - .name = "send-key", - .args_type = "keys:q,hold-time:i?", - }, - -SQMP send-key ---------- @@ -352,14 +249,6 @@ Example: { "type": "qcode", "data": "delete" } ] } } <- { "return": {} } -EQMP - - { - .name = "cpu", - .args_type = "index:i", - }, - -SQMP cpu --- @@ -376,14 +265,6 @@ Example: Note: CPUs' indexes are obtained with the 'query-cpus' command. -EQMP - - { - .name = "cpu-add", - .args_type = "id:i", - }, - -SQMP cpu-add ------- @@ -398,14 +279,6 @@ Example: -> { "execute": "cpu-add", "arguments": { "id": 2 } } <- { "return": {} } -EQMP - - { - .name = "memsave", - .args_type = "val:l,size:i,filename:s,cpu:i?", - }, - -SQMP memsave ------- @@ -426,14 +299,6 @@ Example: "filename": "/tmp/virtual-mem-dump" } } <- { "return": {} } -EQMP - - { - .name = "pmemsave", - .args_type = "val:l,size:i,filename:s", - }, - -SQMP pmemsave -------- @@ -453,14 +318,6 @@ Example: "filename": "/tmp/physical-mem-dump" } } <- { "return": {} } -EQMP - - { - .name = "inject-nmi", - .args_type = "", - }, - -SQMP inject-nmi ---------- @@ -475,14 +332,6 @@ Example: Note: inject-nmi fails when the guest doesn't support injecting. -EQMP - - { - .name = "ringbuf-write", - .args_type = "device:s,data:s,format:s?", - }, - -SQMP ringbuf-write ------------- @@ -503,14 +352,6 @@ Example: "format": "utf8" } } <- { "return": {} } -EQMP - - { - .name = "ringbuf-read", - .args_type = "device:s,size:i,format:s?", - }, - -SQMP ringbuf-read ------------- @@ -538,14 +379,6 @@ Example: "format": "utf8" } } <- {"return": "abcdefgh"} -EQMP - - { - .name = "xen-save-devices-state", - .args_type = "filename:F", - }, - -SQMP xen-save-devices-state ------- @@ -564,14 +397,6 @@ Example: "arguments": { "filename": "/tmp/save" } } <- { "return": {} } -EQMP - - { - .name = "xen-load-devices-state", - .args_type = "filename:F", - }, - -SQMP xen-load-devices-state ---------------------- @@ -590,14 +415,6 @@ Example: "arguments": { "filename": "/tmp/resume" } } <- { "return": {} } -EQMP - - { - .name = "xen-set-global-dirty-log", - .args_type = "enable:b", - }, - -SQMP xen-set-global-dirty-log ------- @@ -613,14 +430,6 @@ Example: "arguments": { "enable": true } } <- { "return": {} } -EQMP - - { - .name = "migrate", - .args_type = "detach:-d,blk:-b,inc:-i,uri:s", - }, - -SQMP migrate ------- @@ -645,14 +454,6 @@ Notes: (3) The user Monitor's "detach" argument is invalid in QMP and should not be used -EQMP - - { - .name = "migrate_cancel", - .args_type = "", - }, - -SQMP migrate_cancel -------------- @@ -665,14 +466,6 @@ Example: -> { "execute": "migrate_cancel" } <- { "return": {} } -EQMP - - { - .name = "migrate-incoming", - .args_type = "uri:s", - }, - -SQMP migrate-incoming ---------------- @@ -693,13 +486,6 @@ Notes: be used (2) The uri format is the same as for -incoming -EQMP - { - .name = "migrate-set-cache-size", - .args_type = "value:o", - }, - -SQMP migrate-set-cache-size ---------------------- @@ -715,13 +501,6 @@ Example: -> { "execute": "migrate-set-cache-size", "arguments": { "value": 536870912 } } <- { "return": {} } -EQMP - { - .name = "migrate-start-postcopy", - .args_type = "", - }, - -SQMP migrate-start-postcopy ---------------------- @@ -732,14 +511,6 @@ Example: -> { "execute": "migrate-start-postcopy" } <- { "return": {} } -EQMP - - { - .name = "query-migrate-cache-size", - .args_type = "", - }, - -SQMP query-migrate-cache-size ------------------------ @@ -753,14 +524,6 @@ Example: -> { "execute": "query-migrate-cache-size" } <- { "return": 67108864 } -EQMP - - { - .name = "migrate_set_speed", - .args_type = "value:o", - }, - -SQMP migrate_set_speed ----------------- @@ -775,14 +538,6 @@ Example: -> { "execute": "migrate_set_speed", "arguments": { "value": 1024 } } <- { "return": {} } -EQMP - - { - .name = "migrate_set_downtime", - .args_type = "value:T", - }, - -SQMP migrate_set_downtime -------------------- @@ -797,16 +552,6 @@ Example: -> { "execute": "migrate_set_downtime", "arguments": { "value": 0.1 } } <- { "return": {} } -EQMP - - { - .name = "client_migrate_info", - .args_type = "protocol:s,hostname:s,port:i?,tls-port:i?,cert-subject:s?", - .params = "protocol hostname port tls-port cert-subject", - .help = "set migration information for remote display", - }, - -SQMP client_migrate_info ------------------- @@ -830,16 +575,6 @@ Example: "port": 1234 } } <- { "return": {} } -EQMP - - { - .name = "dump-guest-memory", - .args_type = "paging:b,protocol:s,detach:b?,begin:i?,end:i?,format:s?", - .params = "-p protocol [-d] [begin] [length] [format]", - .help = "dump guest memory to file", - }, - -SQMP dump @@ -870,14 +605,6 @@ Notes: (1) All boolean arguments default to false -EQMP - - { - .name = "query-dump-guest-memory-capability", - .args_type = "", - }, - -SQMP query-dump-guest-memory-capability ---------- @@ -889,16 +616,6 @@ Example: <- { "return": { "formats": ["elf", "kdump-zlib", "kdump-lzo", "kdump-snappy"] } -EQMP - - { - .name = "query-dump", - .args_type = "", - .params = "", - .help = "query background dump status", - }, - -SQMP query-dump ---------- @@ -912,16 +629,6 @@ Example: <- { "return": { "status": "active", "completed": 1024000, "total": 2048000 } } -EQMP - -#if defined TARGET_S390X - { - .name = "dump-skeys", - .args_type = "filename:F", - }, -#endif - -SQMP dump-skeys ---------- @@ -936,14 +643,6 @@ Example: -> { "execute": "dump-skeys", "arguments": { "filename": "/tmp/skeys" } } <- { "return": {} } -EQMP - - { - .name = "netdev_add", - .args_type = "netdev:O", - }, - -SQMP netdev_add ---------- @@ -966,14 +665,6 @@ Note: The supported device options are the same ones supported by the '-netdev' command-line argument, which are listed in the '-help' output or QEMU's manual -EQMP - - { - .name = "netdev_del", - .args_type = "id:s", - }, - -SQMP netdev_del ---------- @@ -989,14 +680,6 @@ Example: <- { "return": {} } -EQMP - - { - .name = "object-add", - .args_type = "qom-type:s,id:s,props:q?", - }, - -SQMP object-add ---------- @@ -1014,14 +697,6 @@ Example: "props": { "filename": "/dev/hwrng" } } } <- { "return": {} } -EQMP - - { - .name = "object-del", - .args_type = "id:s", - }, - -SQMP object-del ---------- @@ -1037,15 +712,6 @@ Example: <- { "return": {} } -EQMP - - - { - .name = "block_resize", - .args_type = "device:s?,node-name:s?,size:o", - }, - -SQMP block_resize ------------ @@ -1062,14 +728,6 @@ Example: -> { "execute": "block_resize", "arguments": { "device": "scratch", "size": 1073741824 } } <- { "return": {} } -EQMP - - { - .name = "block-stream", - .args_type = "job-id:s?,device:B,base:s?,speed:o?,backing-file:s?,on-error:s?", - }, - -SQMP block-stream ------------ @@ -1106,14 +764,6 @@ Example: "base": "/tmp/master.qcow2" } } <- { "return": {} } -EQMP - - { - .name = "block-commit", - .args_type = "job-id:s?,device:B,base:s?,top:s?,backing-file:s?,speed:o?", - }, - -SQMP block-commit ------------ @@ -1170,16 +820,6 @@ Example: "top": "/tmp/snap1.qcow2" } } <- { "return": {} } -EQMP - - { - .name = "drive-backup", - .args_type = "job-id:s?,sync:s,device:B,target:s,speed:i?,mode:s?," - "format:s?,bitmap:s?,compress:b?," - "on-source-error:s?,on-target-error:s?", - }, - -SQMP drive-backup ------------ @@ -1228,15 +868,6 @@ Example: "target": "backup.img" } } <- { "return": {} } -EQMP - - { - .name = "blockdev-backup", - .args_type = "job-id:s?,sync:s,device:B,target:B,speed:i?,compress:b?," - "on-source-error:s?,on-target-error:s?", - }, - -SQMP blockdev-backup --------------- @@ -1272,35 +903,6 @@ Example: "target": "tgt-id" } } <- { "return": {} } -EQMP - - { - .name = "block-job-set-speed", - .args_type = "device:B,speed:o", - }, - - { - .name = "block-job-cancel", - .args_type = "device:B,force:b?", - }, - { - .name = "block-job-pause", - .args_type = "device:B", - }, - { - .name = "block-job-resume", - .args_type = "device:B", - }, - { - .name = "block-job-complete", - .args_type = "device:B", - }, - { - .name = "transaction", - .args_type = "actions:q,properties:q?", - }, - -SQMP transaction ----------- @@ -1387,14 +989,6 @@ Example: "name": "snapshot0" } } ] } } <- { "return": {} } -EQMP - - { - .name = "block-dirty-bitmap-add", - .args_type = "node:B,name:s,granularity:i?", - }, - -SQMP block-dirty-bitmap-add ---------------------- Since 2.4 @@ -1413,14 +1007,6 @@ Example: "name": "bitmap0" } } <- { "return": {} } -EQMP - - { - .name = "block-dirty-bitmap-remove", - .args_type = "node:B,name:s", - }, - -SQMP block-dirty-bitmap-remove ------------------------- Since 2.4 @@ -1439,14 +1025,6 @@ Example: "name": "bitmap0" } } <- { "return": {} } -EQMP - - { - .name = "block-dirty-bitmap-clear", - .args_type = "node:B,name:s", - }, - -SQMP block-dirty-bitmap-clear ------------------------ Since 2.4 @@ -1466,14 +1044,6 @@ Example: "name": "bitmap0" } } <- { "return": {} } -EQMP - - { - .name = "blockdev-snapshot-sync", - .args_type = "device:s?,node-name:s?,snapshot-file:s,snapshot-node-name:s?,format:s?,mode:s?", - }, - -SQMP blockdev-snapshot-sync ---------------------- @@ -1501,14 +1071,6 @@ Example: "format": "qcow2" } } <- { "return": {} } -EQMP - - { - .name = "blockdev-snapshot", - .args_type = "node:s,overlay:s", - }, - -SQMP blockdev-snapshot ----------------- Since 2.5 @@ -1538,14 +1100,6 @@ Example: "overlay": "node1534" } } <- { "return": {} } -EQMP - - { - .name = "blockdev-snapshot-internal-sync", - .args_type = "device:B,name:s", - }, - -SQMP blockdev-snapshot-internal-sync ------------------------------- @@ -1567,14 +1121,6 @@ Example: } <- { "return": {} } -EQMP - - { - .name = "blockdev-snapshot-delete-internal-sync", - .args_type = "device:B,id:s?,name:s?", - }, - -SQMP blockdev-snapshot-delete-internal-sync -------------------------------------- @@ -1606,18 +1152,6 @@ Example: } } -EQMP - - { - .name = "drive-mirror", - .args_type = "job-id:s?,sync:s,device:B,target:s,speed:i?,mode:s?," - "format:s?,node-name:s?,replaces:s?," - "on-source-error:s?,on-target-error:s?," - "unmap:b?," - "granularity:i?,buf-size:i?", - }, - -SQMP drive-mirror ------------ @@ -1672,16 +1206,6 @@ Example: "format": "qcow2" } } <- { "return": {} } -EQMP - - { - .name = "blockdev-mirror", - .args_type = "job-id:s?,sync:s,device:B,target:B,replaces:s?,speed:i?," - "on-source-error:s?,on-target-error:s?," - "granularity:i?,buf-size:i?", - }, - -SQMP blockdev-mirror ------------ @@ -1723,13 +1247,6 @@ Example: "sync": "full" } } <- { "return": {} } -EQMP - { - .name = "change-backing-file", - .args_type = "device:s,image-node-name:s,backing-file:s", - }, - -SQMP change-backing-file ------------------- Since: 2.1 @@ -1761,14 +1278,6 @@ Arguments: Returns: Nothing on success If "device" does not exist or cannot be determined, DeviceNotFound -EQMP - - { - .name = "balloon", - .args_type = "value:M", - }, - -SQMP balloon ------- @@ -1783,14 +1292,6 @@ Example: -> { "execute": "balloon", "arguments": { "value": 536870912 } } <- { "return": {} } -EQMP - - { - .name = "set_link", - .args_type = "name:s,up:b", - }, - -SQMP set_link -------- @@ -1806,16 +1307,6 @@ Example: -> { "execute": "set_link", "arguments": { "name": "e1000.0", "up": false } } <- { "return": {} } -EQMP - - { - .name = "getfd", - .args_type = "fdname:s", - .params = "getfd name", - .help = "receive a file descriptor via SCM rights and assign it a name", - }, - -SQMP getfd ----- @@ -1838,16 +1329,6 @@ Notes: (2) The 'closefd' command can be used to explicitly close the file descriptor when it is no longer needed. -EQMP - - { - .name = "closefd", - .args_type = "fdname:s", - .params = "closefd name", - .help = "close a file descriptor previously passed via SCM rights", - }, - -SQMP closefd ------- @@ -1862,16 +1343,6 @@ Example: -> { "execute": "closefd", "arguments": { "fdname": "fd1" } } <- { "return": {} } -EQMP - - { - .name = "add-fd", - .args_type = "fdset-id:i?,opaque:s?", - .params = "add-fd fdset-id opaque", - .help = "Add a file descriptor, that was passed via SCM rights, to an fd set", - }, - -SQMP add-fd ------- @@ -1900,16 +1371,6 @@ Notes: (1) The list of fd sets is shared by all monitor connections. (2) If "fdset-id" is not specified, a new fd set will be created. -EQMP - - { - .name = "remove-fd", - .args_type = "fdset-id:i,fd:i?", - .params = "remove-fd fdset-id fd", - .help = "Remove a file descriptor from an fd set", - }, - -SQMP remove-fd --------- @@ -1932,15 +1393,6 @@ Notes: (2) If "fd" is not specified, all file descriptors in "fdset-id" will be removed. -EQMP - - { - .name = "query-fdsets", - .args_type = "", - .help = "Return information describing all fd sets", - }, - -SQMP query-fdsets ------------- @@ -1981,14 +1433,6 @@ Example: Note: The list of fd sets is shared by all monitor connections. -EQMP - - { - .name = "block_passwd", - .args_type = "device:s?,node-name:s?,password:s", - }, - -SQMP block_passwd ------------ @@ -2006,14 +1450,6 @@ Example: "password": "12345" } } <- { "return": {} } -EQMP - - { - .name = "block_set_io_throttle", - .args_type = "device:B,bps:l,bps_rd:l,bps_wr:l,iops:l,iops_rd:l,iops_wr:l,bps_max:l?,bps_rd_max:l?,bps_wr_max:l?,iops_max:l?,iops_rd_max:l?,iops_wr_max:l?,bps_max_length:l?,bps_rd_max_length:l?,bps_wr_max_length:l?,iops_max_length:l?,iops_rd_max_length:l?,iops_wr_max_length:l?,iops_size:l?,group:s?", - }, - -SQMP block_set_io_throttle ------------ @@ -2062,14 +1498,6 @@ Example: "iops_size": 0 } } <- { "return": {} } -EQMP - - { - .name = "set_password", - .args_type = "protocol:s,password:s,connected:s?", - }, - -SQMP set_password ------------ @@ -2087,14 +1515,6 @@ Example: "password": "secret" } } <- { "return": {} } -EQMP - - { - .name = "expire_password", - .args_type = "protocol:s,time:s", - }, - -SQMP expire_password --------------- @@ -2111,14 +1531,6 @@ Example: "time": "+60" } } <- { "return": {} } -EQMP - - { - .name = "add_client", - .args_type = "protocol:s,fdname:s,skipauth:b?,tls:b?", - }, - -SQMP add_client ---------- @@ -2137,15 +1549,6 @@ Example: "fdname": "myclient" } } <- { "return": {} } -EQMP - { - .name = "qmp_capabilities", - .args_type = "", - .params = "", - .help = "enable QMP capabilities", - }, - -SQMP qmp_capabilities ---------------- @@ -2160,14 +1563,6 @@ Example: Note: This command must be issued before issuing any other command. -EQMP - - { - .name = "human-monitor-command", - .args_type = "command-line:s,cpu-index:i?", - }, - -SQMP human-monitor-command --------------------- @@ -2204,13 +1599,7 @@ Notes: 3. Query Commands ================= -HXCOMM Each query command below is inside a SQMP/EQMP section, do NOT change -HXCOMM this! We will possibly move query commands definitions inside those -HXCOMM sections, just like regular commands. - -EQMP -SQMP query-version ------------- @@ -2238,14 +1627,6 @@ Example: } } -EQMP - - { - .name = "query-version", - .args_type = "", - }, - -SQMP query-commands -------------- @@ -2274,14 +1655,6 @@ Example: Note: This example has been shortened as the real response is too long. -EQMP - - { - .name = "query-commands", - .args_type = "", - }, - -SQMP query-events -------------- @@ -2310,14 +1683,6 @@ Example: Note: This example has been shortened as the real response is too long. -EQMP - - { - .name = "query-events", - .args_type = "", - }, - -SQMP query-qmp-schema ---------------- @@ -2326,14 +1691,6 @@ named schema entities. Entities are commands, events and various types. See docs/qapi-code-gen.txt for information on their structure and intended use. -EQMP - - { - .name = "query-qmp-schema", - .args_type = "", - }, - -SQMP query-chardev ------------- @@ -2370,14 +1727,6 @@ Example: ] } -EQMP - - { - .name = "query-chardev", - .args_type = "", - }, - -SQMP query-chardev-backends ------------- @@ -2410,14 +1759,6 @@ Example: ] } -EQMP - - { - .name = "query-chardev-backends", - .args_type = "", - }, - -SQMP query-block ----------- @@ -2593,14 +1934,6 @@ Example: ] } -EQMP - - { - .name = "query-block", - .args_type = "", - }, - -SQMP query-blockstats ---------------- @@ -2789,14 +2122,6 @@ Example: ] } -EQMP - - { - .name = "query-blockstats", - .args_type = "query-nodes:b?", - }, - -SQMP query-cpus ---------- @@ -2843,14 +2168,6 @@ Example: ] } -EQMP - - { - .name = "query-cpus", - .args_type = "", - }, - -SQMP query-iothreads --------------- @@ -2881,14 +2198,6 @@ Example: ] } -EQMP - - { - .name = "query-iothreads", - .args_type = "", - }, - -SQMP query-pci --------- @@ -3097,14 +2406,6 @@ Example: Note: This example has been shortened as the real response is too long. -EQMP - - { - .name = "query-pci", - .args_type = "", - }, - -SQMP query-kvm --------- @@ -3120,14 +2421,6 @@ Example: -> { "execute": "query-kvm" } <- { "return": { "enabled": true, "present": true } } -EQMP - - { - .name = "query-kvm", - .args_type = "", - }, - -SQMP query-status ------------ @@ -3159,14 +2452,6 @@ Example: -> { "execute": "query-status" } <- { "return": { "running": true, "singlestep": false, "status": "running" } } -EQMP - - { - .name = "query-status", - .args_type = "", - }, - -SQMP query-mice ---------- @@ -3202,14 +2487,6 @@ Example: ] } -EQMP - - { - .name = "query-mice", - .args_type = "", - }, - -SQMP query-vnc --------- @@ -3264,18 +2541,6 @@ Example: } } -EQMP - - { - .name = "query-vnc", - .args_type = "", - }, - { - .name = "query-vnc-servers", - .args_type = "", - }, - -SQMP query-spice ----------- @@ -3343,16 +2608,6 @@ Example: } } -EQMP - -#if defined(CONFIG_SPICE) - { - .name = "query-spice", - .args_type = "", - }, -#endif - -SQMP query-name ---------- @@ -3367,14 +2622,6 @@ Example: -> { "execute": "query-name" } <- { "return": { "name": "qemu-name" } } -EQMP - - { - .name = "query-name", - .args_type = "", - }, - -SQMP query-uuid ---------- @@ -3389,14 +2636,6 @@ Example: -> { "execute": "query-uuid" } <- { "return": { "UUID": "550e8400-e29b-41d4-a716-446655440000" } } -EQMP - - { - .name = "query-uuid", - .args_type = "", - }, - -SQMP query-command-line-options -------------------------- @@ -3437,14 +2676,6 @@ Example: ] } -EQMP - - { - .name = "query-command-line-options", - .args_type = "option:s?", - }, - -SQMP query-migrate ------------- @@ -3614,14 +2845,6 @@ Examples: } } -EQMP - - { - .name = "query-migrate", - .args_type = "", - }, - -SQMP migrate-set-capabilities ------------------------ @@ -3642,14 +2865,6 @@ Example: -> { "execute": "migrate-set-capabilities" , "arguments": { "capabilities": [ { "capability": "xbzrle", "state": true } ] } } -EQMP - - { - .name = "migrate-set-capabilities", - .args_type = "capabilities:q", - .params = "capability:s,state:b", - }, -SQMP query-migrate-capabilities -------------------------- @@ -3679,14 +2894,6 @@ Example: {"state": false, "capability": "postcopy-ram"} ]} -EQMP - - { - .name = "query-migrate-capabilities", - .args_type = "", - }, - -SQMP migrate-set-parameters ---------------------- @@ -3707,14 +2914,6 @@ Example: -> { "execute": "migrate-set-parameters" , "arguments": { "compress-level": 1 } } -EQMP - - { - .name = "migrate-set-parameters", - .args_type = - "compress-level:i?,compress-threads:i?,decompress-threads:i?,cpu-throttle-initial:i?,cpu-throttle-increment:i?", - }, -SQMP query-migrate-parameters ------------------------ @@ -3744,14 +2943,6 @@ Example: } } -EQMP - - { - .name = "query-migrate-parameters", - .args_type = "", - }, - -SQMP query-balloon ------------- @@ -3771,96 +2962,6 @@ Example: } } -EQMP - - { - .name = "query-balloon", - .args_type = "", - }, - - { - .name = "query-block-jobs", - .args_type = "", - }, - - { - .name = "qom-list", - .args_type = "path:s", - }, - - { - .name = "qom-set", - .args_type = "path:s,property:s,value:q", - }, - - { - .name = "qom-get", - .args_type = "path:s,property:s", - }, - - { - .name = "nbd-server-start", - .args_type = "addr:q,tls-creds:s?", - }, - { - .name = "nbd-server-add", - .args_type = "device:B,writable:b?", - }, - { - .name = "nbd-server-stop", - .args_type = "", - }, - - { - .name = "change-vnc-password", - .args_type = "password:s", - }, - { - .name = "qom-list-types", - .args_type = "implements:s?,abstract:b?", - }, - - { - .name = "device-list-properties", - .args_type = "typename:s", - }, - - { - .name = "query-machines", - .args_type = "", - }, - - { - .name = "query-cpu-definitions", - .args_type = "", - }, - - { - .name = "query-cpu-model-expansion", - .args_type = "type:s,model:q", - }, - - { - .name = "query-cpu-model-comparison", - .args_type = "modela:q,modelb:q", - }, - - { - .name = "query-cpu-model-baseline", - .args_type = "modela:q,modelb:q", - }, - - { - .name = "query-target", - .args_type = "", - }, - - { - .name = "query-tpm", - .args_type = "", - }, - -SQMP query-tpm --------- @@ -3886,14 +2987,6 @@ Example: ] } -EQMP - - { - .name = "query-tpm-models", - .args_type = "", - }, - -SQMP query-tpm-models ---------------- @@ -3906,14 +2999,6 @@ Example: -> { "execute": "query-tpm-models" } <- { "return": [ "tpm-tis" ] } -EQMP - - { - .name = "query-tpm-types", - .args_type = "", - }, - -SQMP query-tpm-types --------------- @@ -3926,14 +3011,6 @@ Example: -> { "execute": "query-tpm-types" } <- { "return": [ "passthrough" ] } -EQMP - - { - .name = "chardev-add", - .args_type = "id:s,backend:q", - }, - -SQMP chardev-add ---------------- @@ -3962,15 +3039,6 @@ Examples: "backend" : { "type" : "pty", "data" : {} } } } <- { "return": { "pty" : "/dev/pty/42" } } -EQMP - - { - .name = "chardev-remove", - .args_type = "id:s", - }, - - -SQMP chardev-remove -------------- @@ -3985,13 +3053,6 @@ Example: -> { "execute": "chardev-remove", "arguments": { "id" : "foo" } } <- { "return": {} } -EQMP - { - .name = "query-rx-filter", - .args_type = "name:s?", - }, - -SQMP query-rx-filter --------------- @@ -4049,14 +3110,6 @@ Example: ] } -EQMP - - { - .name = "blockdev-add", - .args_type = "options:q", - }, - -SQMP blockdev-add ------------ @@ -4107,14 +3160,6 @@ Example (2): <- { "return": {} } -EQMP - - { - .name = "x-blockdev-del", - .args_type = "id:s?,node-name:s?", - }, - -SQMP x-blockdev-del ------------ Since 2.5 @@ -4163,14 +3208,6 @@ Example: } <- { "return": {} } -EQMP - - { - .name = "blockdev-open-tray", - .args_type = "device:s,force:b?", - }, - -SQMP blockdev-open-tray ------------------ @@ -4210,14 +3247,6 @@ Example: <- { "return": {} } -EQMP - - { - .name = "blockdev-close-tray", - .args_type = "device:s", - }, - -SQMP blockdev-close-tray ------------------- @@ -4244,14 +3273,6 @@ Example: <- { "return": {} } -EQMP - - { - .name = "x-blockdev-remove-medium", - .args_type = "device:s", - }, - -SQMP x-blockdev-remove-medium ------------------------ @@ -4291,14 +3312,6 @@ Example: <- { "return": {} } -EQMP - - { - .name = "x-blockdev-insert-medium", - .args_type = "device:s,node-name:s", - }, - -SQMP x-blockdev-insert-medium ------------------------ @@ -4330,14 +3343,6 @@ Example: <- { "return": {} } -EQMP - - { - .name = "x-blockdev-change", - .args_type = "parent:B,child:B?,node:B?", - }, - -SQMP x-blockdev-change ----------------- @@ -4382,14 +3387,6 @@ Delete a quorum's node "child": "children.1" } } <- { "return": {} } -EQMP - - { - .name = "query-named-block-nodes", - .args_type = "", - }, - -SQMP query-named-block-nodes ----------------------- @@ -4443,14 +3440,6 @@ Example: } } } ] } -EQMP - - { - .name = "blockdev-change-medium", - .args_type = "device:B,filename:F,format:s?,read-only-mode:s?", - }, - -SQMP blockdev-change-medium ---------------------- @@ -4495,14 +3484,6 @@ Examples: <- { "return": {} } -EQMP - - { - .name = "query-memdev", - .args_type = "", - }, - -SQMP query-memdev ------------ @@ -4532,14 +3513,6 @@ Example (1): ] } -EQMP - - { - .name = "query-memory-devices", - .args_type = "", - }, - -SQMP query-memory-devices -------------------- @@ -4559,14 +3532,6 @@ Example: "type": "dimm" } ] } -EQMP - - { - .name = "query-acpi-ospm-status", - .args_type = "", - }, - -SQMP query-acpi-ospm-status ---------------------- @@ -4581,16 +3546,6 @@ Example: { "slot": "3", "slot-type": "DIMM", "source": 0, "status": 0} ]} -EQMP - -#if defined TARGET_I386 - { - .name = "rtc-reset-reinjection", - .args_type = "", - }, -#endif - -SQMP rtc-reset-reinjection --------------------- @@ -4603,14 +3558,6 @@ Example: -> { "execute": "rtc-reset-reinjection" } <- { "return": {} } -EQMP - - { - .name = "trace-event-get-state", - .args_type = "name:s,vcpu:i?", - }, - -SQMP trace-event-get-state --------------------- @@ -4635,14 +3582,6 @@ Example: -> { "execute": "trace-event-get-state", "arguments": { "name": "qemu_memalign" } } <- { "return": [ { "name": "qemu_memalign", "state": "disabled" } ] } -EQMP - - { - .name = "trace-event-set-state", - .args_type = "name:s,enable:b,ignore-unavailable:b?,vcpu:i?", - }, - -SQMP trace-event-set-state --------------------- @@ -4670,14 +3609,6 @@ Example: -> { "execute": "trace-event-set-state", "arguments": { "name": "qemu_memalign", "enable": "true" } } <- { "return": {} } -EQMP - - { - .name = "input-send-event", - .args_type = "console:i?,events:q", - }, - -SQMP input-send-event ---------------- @@ -4733,14 +3664,6 @@ Move mouse pointer to absolute coordinates (20000, 400). { "type": "abs", "data" : { "axis": "y", "value" : 400 } } ] } } <- { "return": {} } -EQMP - - { - .name = "block-set-write-threshold", - .args_type = "node-name:s,write-threshold:l", - }, - -SQMP block-set-write-threshold ------------ @@ -4760,14 +3683,6 @@ Example: "write-threshold": 17179869184 } } <- { "return": {} } -EQMP - - { - .name = "query-rocker", - .args_type = "name:s", - }, - -SQMP Show rocker switch ------------------ @@ -4780,14 +3695,6 @@ Example: -> { "execute": "query-rocker", "arguments": { "name": "sw1" } } <- { "return": {"name": "sw1", "ports": 2, "id": 1327446905938}} -EQMP - - { - .name = "query-rocker-ports", - .args_type = "name:s", - }, - -SQMP Show rocker switch ports ------------------------ @@ -4804,14 +3711,6 @@ Example: "autoneg": "off", "link-up": true, "speed": 10000} ]} -EQMP - - { - .name = "query-rocker-of-dpa-flows", - .args_type = "name:s,tbl-id:i?", - }, - -SQMP Show rocker switch OF-DPA flow tables ------------------------------------- @@ -4832,14 +3731,6 @@ Example: {...more...}, ]} -EQMP - - { - .name = "query-rocker-of-dpa-groups", - .args_type = "name:s,type:i?", - }, - -SQMP Show rocker OF-DPA group tables ------------------------------- @@ -4861,16 +3752,6 @@ Example: "pop-vlan": 1, "id": 251658240} ]} -EQMP - -#if defined TARGET_ARM - { - .name = "query-gic-capabilities", - .args_type = "", - }, -#endif - -SQMP query-gic-capabilities --------------- @@ -4885,14 +3766,6 @@ Example: <- { "return": [{ "version": 2, "emulated": true, "kernel": false }, { "version": 3, "emulated": false, "kernel": true } ] } -EQMP - - { - .name = "query-hotpluggable-cpus", - .args_type = "", - }, - -SQMP Show existing/possible CPUs --------------------------- diff --git a/docs/writing-qmp-commands.txt b/docs/writing-qmp-commands.txt index c425393092e..cfa6fe7c0df 100644 --- a/docs/writing-qmp-commands.txt +++ b/docs/writing-qmp-commands.txt @@ -119,16 +119,6 @@ There are a few things to be noticed: 5. Printing to the terminal is discouraged for QMP commands, we do it here because it's the easiest way to demonstrate a QMP command -Now a little hack is needed. As we're still using the old QMP server we need -to add the new command to its internal dispatch table. This step won't be -required in the near future. Open the qmp-commands.hx file and add the -following at the bottom: - - { - .name = "hello-world", - .args_type = "", - }, - You're done. Now build qemu, run it as suggested in the "Testing" section, and then type the following QMP command: @@ -173,20 +163,6 @@ There are two important details to be noticed: 2. The C implementation signature must follow the schema's argument ordering, which is defined by the "data" member -The last step is to update the qmp-commands.hx file: - - { - .name = "hello-world", - .args_type = "message:s?", - }, - -Notice that the "args_type" member got our "message" argument. The character -"s" stands for "string" and "?" means it's optional. This too must be ordered -according to the C implementation and schema file. You can look for more -examples in the qmp-commands.hx file if you need to define more arguments. - -Again, this step won't be required in the future. - Time to test our new version of the "hello-world" command. Build qemu, run it as described in the "Testing" section and then send two commands: @@ -452,13 +428,6 @@ There are a number of things to be noticed: 6. You have to include the "qmp-commands.h" header file in qemu-timer.c, otherwise qemu won't build -The last step is to add the corresponding entry in the qmp-commands.hx file: - - { - .name = "query-alarm-clock", - .args_type = "", - }, - Time to test the new command. Build qemu, run it as described in the "Testing" section and try this: @@ -597,13 +566,6 @@ iteration of the loop. That's because the alarm timer method in use is the first element of the alarm_timers array. Also notice that QAPI lists are handled by hand and we return the head of the list. -To test this you have to add the corresponding qmp-commands.hx entry: - - { - .name = "query-alarm-methods", - .args_type = "", - }, - Now Build qemu, run it as explained in the "Testing" section and try our new command: From 3f32bd21df655e62eb271182a5c63280d631c7b3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 6 Jul 2016 13:35:00 -0700 Subject: [PATCH 098/723] target-i386: Use struct X86XSaveArea in fpu_helper.c This avoids a double hand-full of magic numbers in the xsave and xrstor helper functions. Signed-off-by: Richard Henderson Signed-off-by: Eduardo Habkost --- target-i386/cpu.c | 7 ++- target-i386/cpu.h | 10 +--- target-i386/fpu_helper.c | 108 +++++++++++++++++++++------------------ 3 files changed, 67 insertions(+), 58 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 5a5299ad3ca..db12728abf8 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -538,7 +538,12 @@ static const X86RegisterInfo32 x86_reg_info_32[CPU_NB_REGS32] = { }; #undef REGISTER -const ExtSaveArea x86_ext_save_areas[] = { +typedef struct ExtSaveArea { + uint32_t feature, bits; + uint32_t offset, size; +} ExtSaveArea; + +static const ExtSaveArea x86_ext_save_areas[] = { [XSTATE_YMM_BIT] = { .feature = FEAT_1_ECX, .bits = CPUID_EXT_AVX, .offset = offsetof(X86XSaveArea, avx_state), diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 58e43b6f4b5..27af9c3f9ab 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -877,7 +877,8 @@ typedef union X86LegacyXSaveArea { typedef struct X86XSaveHeader { uint64_t xstate_bv; uint64_t xcomp_bv; - uint8_t reserved[48]; + uint64_t reserve0; + uint8_t reserved[40]; } X86XSaveHeader; /* Ext. save area 2: AVX State */ @@ -1392,13 +1393,6 @@ int cpu_x86_signal_handler(int host_signum, void *pinfo, void *puc); /* cpu.c */ -typedef struct ExtSaveArea { - uint32_t feature, bits; - uint32_t offset, size; -} ExtSaveArea; - -extern const ExtSaveArea x86_ext_save_areas[]; - void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx); diff --git a/target-i386/fpu_helper.c b/target-i386/fpu_helper.c index 929489bfc81..2049a8c01df 100644 --- a/target-i386/fpu_helper.c +++ b/target-i386/fpu_helper.c @@ -1110,6 +1110,8 @@ void cpu_x86_frstor(CPUX86State *env, target_ulong ptr, int data32) } #endif +#define XO(X) offsetof(X86XSaveArea, X) + static void do_xsave_fpu(CPUX86State *env, target_ulong ptr, uintptr_t ra) { int fpus, fptag, i; @@ -1120,17 +1122,18 @@ static void do_xsave_fpu(CPUX86State *env, target_ulong ptr, uintptr_t ra) for (i = 0; i < 8; i++) { fptag |= (env->fptags[i] << i); } - cpu_stw_data_ra(env, ptr, env->fpuc, ra); - cpu_stw_data_ra(env, ptr + 2, fpus, ra); - cpu_stw_data_ra(env, ptr + 4, fptag ^ 0xff, ra); + + cpu_stw_data_ra(env, ptr + XO(legacy.fcw), env->fpuc, ra); + cpu_stw_data_ra(env, ptr + XO(legacy.fsw), fpus, ra); + cpu_stw_data_ra(env, ptr + XO(legacy.ftw), fptag ^ 0xff, ra); /* In 32-bit mode this is eip, sel, dp, sel. In 64-bit mode this is rip, rdp. But in either case we don't write actual data, just zeros. */ - cpu_stq_data_ra(env, ptr + 0x08, 0, ra); /* eip+sel; rip */ - cpu_stq_data_ra(env, ptr + 0x10, 0, ra); /* edp+sel; rdp */ + cpu_stq_data_ra(env, ptr + XO(legacy.fpip), 0, ra); /* eip+sel; rip */ + cpu_stq_data_ra(env, ptr + XO(legacy.fpdp), 0, ra); /* edp+sel; rdp */ - addr = ptr + 0x20; + addr = ptr + XO(legacy.fpregs); for (i = 0; i < 8; i++) { floatx80 tmp = ST(i); helper_fstt(env, tmp, addr, ra); @@ -1140,8 +1143,8 @@ static void do_xsave_fpu(CPUX86State *env, target_ulong ptr, uintptr_t ra) static void do_xsave_mxcsr(CPUX86State *env, target_ulong ptr, uintptr_t ra) { - cpu_stl_data_ra(env, ptr + 0x18, env->mxcsr, ra); /* mxcsr */ - cpu_stl_data_ra(env, ptr + 0x1c, 0x0000ffff, ra); /* mxcsr_mask */ + cpu_stl_data_ra(env, ptr + XO(legacy.mxcsr), env->mxcsr, ra); + cpu_stl_data_ra(env, ptr + XO(legacy.mxcsr_mask), 0x0000ffff, ra); } static void do_xsave_sse(CPUX86State *env, target_ulong ptr, uintptr_t ra) @@ -1155,7 +1158,7 @@ static void do_xsave_sse(CPUX86State *env, target_ulong ptr, uintptr_t ra) nb_xmm_regs = 8; } - addr = ptr + 0xa0; + addr = ptr + XO(legacy.xmm_regs); for (i = 0; i < nb_xmm_regs; i++) { cpu_stq_data_ra(env, addr, env->xmm_regs[i].ZMM_Q(0), ra); cpu_stq_data_ra(env, addr + 8, env->xmm_regs[i].ZMM_Q(1), ra); @@ -1163,8 +1166,9 @@ static void do_xsave_sse(CPUX86State *env, target_ulong ptr, uintptr_t ra) } } -static void do_xsave_bndregs(CPUX86State *env, target_ulong addr, uintptr_t ra) +static void do_xsave_bndregs(CPUX86State *env, target_ulong ptr, uintptr_t ra) { + target_ulong addr = ptr + offsetof(XSaveBNDREG, bnd_regs); int i; for (i = 0; i < 4; i++, addr += 16) { @@ -1173,15 +1177,17 @@ static void do_xsave_bndregs(CPUX86State *env, target_ulong addr, uintptr_t ra) } } -static void do_xsave_bndcsr(CPUX86State *env, target_ulong addr, uintptr_t ra) +static void do_xsave_bndcsr(CPUX86State *env, target_ulong ptr, uintptr_t ra) { - cpu_stq_data_ra(env, addr, env->bndcs_regs.cfgu, ra); - cpu_stq_data_ra(env, addr + 8, env->bndcs_regs.sts, ra); + cpu_stq_data_ra(env, ptr + offsetof(XSaveBNDCSR, bndcsr.cfgu), + env->bndcs_regs.cfgu, ra); + cpu_stq_data_ra(env, ptr + offsetof(XSaveBNDCSR, bndcsr.sts), + env->bndcs_regs.sts, ra); } -static void do_xsave_pkru(CPUX86State *env, target_ulong addr, uintptr_t ra) +static void do_xsave_pkru(CPUX86State *env, target_ulong ptr, uintptr_t ra) { - cpu_stq_data_ra(env, addr, env->pkru, ra); + cpu_stq_data_ra(env, ptr, env->pkru, ra); } void helper_fxsave(CPUX86State *env, target_ulong ptr) @@ -1250,22 +1256,19 @@ static void do_xsave(CPUX86State *env, target_ulong ptr, uint64_t rfbm, do_xsave_sse(env, ptr, ra); } if (opt & XSTATE_BNDREGS_MASK) { - target_ulong off = x86_ext_save_areas[XSTATE_BNDREGS_BIT].offset; - do_xsave_bndregs(env, ptr + off, ra); + do_xsave_bndregs(env, ptr + XO(bndreg_state), ra); } if (opt & XSTATE_BNDCSR_MASK) { - target_ulong off = x86_ext_save_areas[XSTATE_BNDCSR_BIT].offset; - do_xsave_bndcsr(env, ptr + off, ra); + do_xsave_bndcsr(env, ptr + XO(bndcsr_state), ra); } if (opt & XSTATE_PKRU_MASK) { - target_ulong off = x86_ext_save_areas[XSTATE_PKRU_BIT].offset; - do_xsave_pkru(env, ptr + off, ra); + do_xsave_pkru(env, ptr + XO(pkru_state), ra); } /* Update the XSTATE_BV field. */ - old_bv = cpu_ldq_data_ra(env, ptr + 512, ra); + old_bv = cpu_ldq_data_ra(env, ptr + XO(header.xstate_bv), ra); new_bv = (old_bv & ~rfbm) | (inuse & rfbm); - cpu_stq_data_ra(env, ptr + 512, new_bv, ra); + cpu_stq_data_ra(env, ptr + XO(header.xstate_bv), new_bv, ra); } void helper_xsave(CPUX86State *env, target_ulong ptr, uint64_t rfbm) @@ -1281,12 +1284,13 @@ void helper_xsaveopt(CPUX86State *env, target_ulong ptr, uint64_t rfbm) static void do_xrstor_fpu(CPUX86State *env, target_ulong ptr, uintptr_t ra) { - int i, fpus, fptag; + int i, fpuc, fpus, fptag; target_ulong addr; - cpu_set_fpuc(env, cpu_lduw_data_ra(env, ptr, ra)); - fpus = cpu_lduw_data_ra(env, ptr + 2, ra); - fptag = cpu_lduw_data_ra(env, ptr + 4, ra); + fpuc = cpu_lduw_data_ra(env, ptr + XO(legacy.fcw), ra); + fpus = cpu_lduw_data_ra(env, ptr + XO(legacy.fsw), ra); + fptag = cpu_lduw_data_ra(env, ptr + XO(legacy.ftw), ra); + cpu_set_fpuc(env, fpuc); env->fpstt = (fpus >> 11) & 7; env->fpus = fpus & ~0x3800; fptag ^= 0xff; @@ -1294,7 +1298,7 @@ static void do_xrstor_fpu(CPUX86State *env, target_ulong ptr, uintptr_t ra) env->fptags[i] = ((fptag >> i) & 1); } - addr = ptr + 0x20; + addr = ptr + XO(legacy.fpregs); for (i = 0; i < 8; i++) { floatx80 tmp = helper_fldt(env, addr, ra); ST(i) = tmp; @@ -1304,7 +1308,7 @@ static void do_xrstor_fpu(CPUX86State *env, target_ulong ptr, uintptr_t ra) static void do_xrstor_mxcsr(CPUX86State *env, target_ulong ptr, uintptr_t ra) { - cpu_set_mxcsr(env, cpu_ldl_data_ra(env, ptr + 0x18, ra)); + cpu_set_mxcsr(env, cpu_ldl_data_ra(env, ptr + XO(legacy.mxcsr), ra)); } static void do_xrstor_sse(CPUX86State *env, target_ulong ptr, uintptr_t ra) @@ -1318,7 +1322,7 @@ static void do_xrstor_sse(CPUX86State *env, target_ulong ptr, uintptr_t ra) nb_xmm_regs = 8; } - addr = ptr + 0xa0; + addr = ptr + XO(legacy.xmm_regs); for (i = 0; i < nb_xmm_regs; i++) { env->xmm_regs[i].ZMM_Q(0) = cpu_ldq_data_ra(env, addr, ra); env->xmm_regs[i].ZMM_Q(1) = cpu_ldq_data_ra(env, addr + 8, ra); @@ -1326,8 +1330,9 @@ static void do_xrstor_sse(CPUX86State *env, target_ulong ptr, uintptr_t ra) } } -static void do_xrstor_bndregs(CPUX86State *env, target_ulong addr, uintptr_t ra) +static void do_xrstor_bndregs(CPUX86State *env, target_ulong ptr, uintptr_t ra) { + target_ulong addr = ptr + offsetof(XSaveBNDREG, bnd_regs); int i; for (i = 0; i < 4; i++, addr += 16) { @@ -1336,16 +1341,18 @@ static void do_xrstor_bndregs(CPUX86State *env, target_ulong addr, uintptr_t ra) } } -static void do_xrstor_bndcsr(CPUX86State *env, target_ulong addr, uintptr_t ra) +static void do_xrstor_bndcsr(CPUX86State *env, target_ulong ptr, uintptr_t ra) { /* FIXME: Extend highest implemented bit of linear address. */ - env->bndcs_regs.cfgu = cpu_ldq_data_ra(env, addr, ra); - env->bndcs_regs.sts = cpu_ldq_data_ra(env, addr + 8, ra); + env->bndcs_regs.cfgu + = cpu_ldq_data_ra(env, ptr + offsetof(XSaveBNDCSR, bndcsr.cfgu), ra); + env->bndcs_regs.sts + = cpu_ldq_data_ra(env, ptr + offsetof(XSaveBNDCSR, bndcsr.sts), ra); } -static void do_xrstor_pkru(CPUX86State *env, target_ulong addr, uintptr_t ra) +static void do_xrstor_pkru(CPUX86State *env, target_ulong ptr, uintptr_t ra) { - env->pkru = cpu_ldq_data_ra(env, addr, ra); + env->pkru = cpu_ldq_data_ra(env, ptr, ra); } void helper_fxrstor(CPUX86State *env, target_ulong ptr) @@ -1373,7 +1380,7 @@ void helper_fxrstor(CPUX86State *env, target_ulong ptr) void helper_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm) { uintptr_t ra = GETPC(); - uint64_t xstate_bv, xcomp_bv0, xcomp_bv1; + uint64_t xstate_bv, xcomp_bv, reserve0; rfbm &= env->xcr0; @@ -1387,7 +1394,7 @@ void helper_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm) raise_exception_ra(env, EXCP0D_GPF, ra); } - xstate_bv = cpu_ldq_data_ra(env, ptr + 512, ra); + xstate_bv = cpu_ldq_data_ra(env, ptr + XO(header.xstate_bv), ra); if ((int64_t)xstate_bv < 0) { /* FIXME: Compact form. */ @@ -1396,15 +1403,19 @@ void helper_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm) /* Standard form. */ - /* The XSTATE field must not set bits not present in XCR0. */ + /* The XSTATE_BV field must not set bits not present in XCR0. */ if (xstate_bv & ~env->xcr0) { raise_exception_ra(env, EXCP0D_GPF, ra); } - /* The XCOMP field must be zero. */ - xcomp_bv0 = cpu_ldq_data_ra(env, ptr + 520, ra); - xcomp_bv1 = cpu_ldq_data_ra(env, ptr + 528, ra); - if (xcomp_bv0 || xcomp_bv1) { + /* The XCOMP_BV field must be zero. Note that, as of the April 2016 + revision, the description of the XSAVE Header (Vol 1, Sec 13.4.2) + describes only XCOMP_BV, but the description of the standard form + of XRSTOR (Vol 1, Sec 13.8.1) checks bytes 23:8 for zero, which + includes the next 64-bit field. */ + xcomp_bv = cpu_ldq_data_ra(env, ptr + XO(header.xcomp_bv), ra); + reserve0 = cpu_ldq_data_ra(env, ptr + XO(header.reserve0), ra); + if (xcomp_bv || reserve0) { raise_exception_ra(env, EXCP0D_GPF, ra); } @@ -1430,8 +1441,7 @@ void helper_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm) } if (rfbm & XSTATE_BNDREGS_MASK) { if (xstate_bv & XSTATE_BNDREGS_MASK) { - target_ulong off = x86_ext_save_areas[XSTATE_BNDREGS_BIT].offset; - do_xrstor_bndregs(env, ptr + off, ra); + do_xrstor_bndregs(env, ptr + XO(bndreg_state), ra); env->hflags |= HF_MPX_IU_MASK; } else { memset(env->bnd_regs, 0, sizeof(env->bnd_regs)); @@ -1440,8 +1450,7 @@ void helper_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm) } if (rfbm & XSTATE_BNDCSR_MASK) { if (xstate_bv & XSTATE_BNDCSR_MASK) { - target_ulong off = x86_ext_save_areas[XSTATE_BNDCSR_BIT].offset; - do_xrstor_bndcsr(env, ptr + off, ra); + do_xrstor_bndcsr(env, ptr + XO(bndcsr_state), ra); } else { memset(&env->bndcs_regs, 0, sizeof(env->bndcs_regs)); } @@ -1450,8 +1459,7 @@ void helper_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm) if (rfbm & XSTATE_PKRU_MASK) { uint64_t old_pkru = env->pkru; if (xstate_bv & XSTATE_PKRU_MASK) { - target_ulong off = x86_ext_save_areas[XSTATE_PKRU_BIT].offset; - do_xrstor_pkru(env, ptr + off, ra); + do_xrstor_pkru(env, ptr + XO(pkru_state), ra); } else { env->pkru = 0; } @@ -1462,6 +1470,8 @@ void helper_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm) } } +#undef XO + uint64_t helper_xgetbv(CPUX86State *env, uint32_t ecx) { /* The OS must have enabled XSAVE. */ From 1560fcfa96594f62cb2062f88e6785dda663529c Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 15 Sep 2016 18:05:51 +0300 Subject: [PATCH 099/723] kvm/apic: drop debugging commit 78d6a05d2f69cbfa6e95f0a4a24a2c934969913b ("x86/lapic: Load LAPIC state at post_load") has some debugging leftovers. Drop them. Cc: Dr. David Alan Gilbert Signed-off-by: Michael S. Tsirkin Signed-off-by: Eduardo Habkost --- hw/i386/kvm/apic.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/i386/kvm/apic.c b/hw/i386/kvm/apic.c index 5d140b93411..feb00024f20 100644 --- a/hw/i386/kvm/apic.c +++ b/hw/i386/kvm/apic.c @@ -141,7 +141,6 @@ static void kvm_apic_put(void *data) static void kvm_apic_post_load(APICCommonState *s) { - fprintf(stderr, "%s: Yeh\n", __func__); run_on_cpu(CPU(s->cpu), kvm_apic_put, s); } From fa5376dd8adb5ad104e5773f09c15af2e8a76738 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Fri, 16 Sep 2016 19:50:23 +0400 Subject: [PATCH 100/723] linux-user-i386: Fix crash on cpuid MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Running cpuid instructions with a simple run like: i386-linux-user/qemu-i386 tests/tcg/sha1-i386 Results in the following assert: #0 0x00007ffff64246f5 in raise () from /lib64/libc.so.6 #1 0x00007ffff64262fa in abort () from /lib64/libc.so.6 #2 0x00007ffff7937ec5 in g_assertion_message () from /lib64/libglib-2.0.so.0 #3 0x00007ffff7937f5a in g_assertion_message_expr () from /lib64/libglib-2.0.so.0 #4 0x000055555561b54c in apicid_bitwidth_for_count (count=0) at /home/elmarco/src/qemu/include/hw/i386/topology.h:58 #5 0x000055555561b58a in apicid_smt_width (nr_cores=0, nr_threads=0) at /home/elmarco/src/qemu/include/hw/i386/topology.h:67 #6 0x000055555561b5c3 in apicid_core_offset (nr_cores=0, nr_threads=0) at /home/elmarco/src/qemu/include/hw/i386/topology.h:82 #7 0x000055555561b5e3 in apicid_pkg_offset (nr_cores=0, nr_threads=0) at /home/elmarco/src/qemu/include/hw/i386/topology.h:89 #8 0x000055555561dd86 in cpu_x86_cpuid (env=0x555557999550, index=4, count=3, eax=0x7fffffffcae8, ebx=0x7fffffffcaec, ecx=0x7fffffffcaf0, edx=0x7fffffffcaf4) at /home/elmarco/src/qemu/target-i386/cpu.c:2405 #9 0x0000555555638e8e in helper_cpuid (env=0x555557999550) at /home/elmarco/src/qemu/target-i386/misc_helper.c:106 #10 0x000055555599dc5e in static_code_gen_buffer () #11 0x00005555555952f8 in cpu_tb_exec (cpu=0x5555579912d0, itb=0x7ffff4371ab0) at /home/elmarco/src/qemu/cpu-exec.c:166 #12 0x0000555555595c8e in cpu_loop_exec_tb (cpu=0x5555579912d0, tb=0x7ffff4371ab0, last_tb=0x7fffffffd088, tb_exit=0x7fffffffd084, sc=0x7fffffffd0a0) at /home/elmarco/src/qemu/cpu-exec.c:517 #13 0x0000555555595e50 in cpu_exec (cpu=0x5555579912d0) at /home/elmarco/src/qemu/cpu-exec.c:612 #14 0x00005555555c065b in cpu_loop (env=0x555557999550) at /home/elmarco/src/qemu/linux-user/main.c:297 #15 0x00005555555c25b2 in main (argc=2, argv=0x7fffffffd848, envp=0x7fffffffd860) at /home/elmarco/src/qemu/linux-user/main.c:4803 The fields are set in qemu_init_vcpu() with softmmu, but it's a stub with linux-user. Signed-off-by: Marc-André Lureau Reviewed-by: Eduardo Habkost Signed-off-by: Eduardo Habkost --- qom/cpu.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/qom/cpu.c b/qom/cpu.c index 25532479072..f783b5a6bd6 100644 --- a/qom/cpu.c +++ b/qom/cpu.c @@ -342,6 +342,11 @@ static void cpu_common_initfn(Object *obj) cpu->cpu_index = UNASSIGNED_CPU_INDEX; cpu->gdb_num_regs = cpu->gdb_num_g_regs = cc->gdb_num_core_regs; + /* *-user doesn't have configurable SMP topology */ + /* the default value is changed by qemu_init_vcpu() for softmmu */ + cpu->nr_cores = 1; + cpu->nr_threads = 1; + qemu_mutex_init(&cpu->work_mutex); QTAILQ_INIT(&cpu->breakpoints); QTAILQ_INIT(&cpu->watchpoints); From a008535b9fa396226ff9cf78b8ac5f3584bda58e Mon Sep 17 00:00:00 2001 From: Riku Voipio Date: Tue, 20 Sep 2016 12:01:34 +0300 Subject: [PATCH 101/723] build-sys: fix make install regression MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since bd6092e Replace qmp-commands.hx by docs/qmp-commands.txt make install fails if building out of source-tree. Cc: Marc-André Lureau Cc: Markus Armbruster Signed-off-by: Riku Voipio Reviewed-by: Marc-André Lureau Reviewed-by: Markus Armbruster Message-id: 1474362094-2293-1-git-send-email-riku.voipio@linaro.org Signed-off-by: Peter Maydell --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 81ca388a75c..444ae37bd30 100644 --- a/Makefile +++ b/Makefile @@ -431,7 +431,7 @@ endif install-doc: $(DOCS) $(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)" $(INSTALL_DATA) qemu-doc.html qemu-tech.html "$(DESTDIR)$(qemu_docdir)" - $(INSTALL_DATA) docs/qmp-commands.txt "$(DESTDIR)$(qemu_docdir)" + $(INSTALL_DATA) $(SRC_PATH)/docs/qmp-commands.txt "$(DESTDIR)$(qemu_docdir)" ifdef CONFIG_POSIX $(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1" $(INSTALL_DATA) qemu.1 "$(DESTDIR)$(mandir)/man1" From ebb90a005da67147245cd38fb04a965a87a961b7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 20 Sep 2016 11:45:30 -0700 Subject: [PATCH 102/723] tcg/i386: Extend TARGET_PAGE_MASK to the proper type TARGET_PAGE_MASK, as defined, has type "int". We need to extend that to the proper target width before oring in an "unsigned". Signed-off-by: Richard Henderson --- tcg/i386/tcg-target.inc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tcg/i386/tcg-target.inc.c b/tcg/i386/tcg-target.inc.c index cf7536bd52b..eeb1777bbb5 100644 --- a/tcg/i386/tcg-target.inc.c +++ b/tcg/i386/tcg-target.inc.c @@ -1243,7 +1243,7 @@ static inline void tcg_out_tlb_load(TCGContext *s, TCGReg addrlo, TCGReg addrhi, } else { tcg_out_modrm_offset(s, OPC_LEA + trexw, r1, addrlo, s_mask - a_mask); } - tlb_mask = TARGET_PAGE_MASK | a_mask; + tlb_mask = (target_ulong)TARGET_PAGE_MASK | a_mask; tcg_out_shifti(s, SHIFT_SHR + tlbrexw, r0, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); From 86ce1f6e2b73b33c4a52818e245378bf52d27200 Mon Sep 17 00:00:00 2001 From: Reda Sallahi Date: Wed, 10 Aug 2016 04:43:12 +0200 Subject: [PATCH 103/723] qemu-img: add the 'dd' subcommand This patch adds a basic dd subcommand analogous to dd(1) to qemu-img. For the start, this implements the bs, if, of and count options and requires both if and of to be specified (no stdin/stdout if not specified) and doesn't support tty, pipes, etc. The image format must be specified with -O for the output if the raw format is not the intended one. Two tests are added to test qemu-img dd. Signed-off-by: Reda Sallahi Message-id: 20160810024312.14544-1-fullmanet@gmail.com Reviewed-by: Stefan Hajnoczi [mreitz: Moved test 158 to 170] Signed-off-by: Max Reitz --- qemu-img-cmds.hx | 6 + qemu-img.c | 303 ++++++++++++++++++++++++++++++- qemu-img.texi | 25 +++ tests/qemu-iotests/159 | 70 +++++++ tests/qemu-iotests/159.out | 87 +++++++++ tests/qemu-iotests/170 | 67 +++++++ tests/qemu-iotests/170.out | 15 ++ tests/qemu-iotests/common.filter | 9 + tests/qemu-iotests/common.rc | 5 +- tests/qemu-iotests/group | 2 + 10 files changed, 584 insertions(+), 5 deletions(-) create mode 100755 tests/qemu-iotests/159 create mode 100644 tests/qemu-iotests/159.out create mode 100755 tests/qemu-iotests/170 create mode 100644 tests/qemu-iotests/170.out diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx index 7e95b2da791..03bdd7ad7bf 100644 --- a/qemu-img-cmds.hx +++ b/qemu-img-cmds.hx @@ -45,6 +45,12 @@ STEXI @item convert [--object @var{objectdef}] [--image-opts] [-c] [-p] [-q] [-n] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_id_or_name}] [-l @var{snapshot_param}] [-S @var{sparse_size}] @var{filename} [@var{filename2} [...]] @var{output_filename} ETEXI +DEF("dd", img_dd, + "dd [--image-opts] [-f fmt] [-O output_fmt] [bs=block_size] [count=blocks] if=input of=output") +STEXI +@item dd [--image-opts] [-f @var{fmt}] [-O @var{output_fmt}] [bs=@var{block_size}] [count=@var{blocks}] if=@var{input} of=@var{output} +ETEXI + DEF("info", img_info, "info [--object objectdef] [--image-opts] [-f fmt] [--output=ofmt] [--backing-chain] filename") STEXI diff --git a/qemu-img.c b/qemu-img.c index ea52486e814..5bdac8ddb7f 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -166,7 +166,14 @@ static void QEMU_NORETURN help(void) "Parameters to compare subcommand:\n" " '-f' first image format\n" " '-F' second image format\n" - " '-s' run in Strict mode - fail on different image size or sector allocation\n"; + " '-s' run in Strict mode - fail on different image size or sector allocation\n" + "\n" + "Parameters to dd subcommand:\n" + " 'bs=BYTES' read and write up to BYTES bytes at a time " + "(default: 512)\n" + " 'count=N' copy only N input blocks\n" + " 'if=FILE' read from FILE\n" + " 'of=FILE' write to FILE\n"; printf("%s\nSupported formats:", help_msg); bdrv_iterate_format(format_print, NULL); @@ -3796,6 +3803,300 @@ static int img_bench(int argc, char **argv) return 0; } +#define C_BS 01 +#define C_COUNT 02 +#define C_IF 04 +#define C_OF 010 + +struct DdInfo { + unsigned int flags; + int64_t count; +}; + +struct DdIo { + int bsz; /* Block size */ + char *filename; + uint8_t *buf; +}; + +struct DdOpts { + const char *name; + int (*f)(const char *, struct DdIo *, struct DdIo *, struct DdInfo *); + unsigned int flag; +}; + +static int img_dd_bs(const char *arg, + struct DdIo *in, struct DdIo *out, + struct DdInfo *dd) +{ + char *end; + int64_t res; + + res = qemu_strtosz_suffix(arg, &end, QEMU_STRTOSZ_DEFSUFFIX_B); + + if (res <= 0 || res > INT_MAX || *end) { + error_report("invalid number: '%s'", arg); + return 1; + } + in->bsz = out->bsz = res; + + return 0; +} + +static int img_dd_count(const char *arg, + struct DdIo *in, struct DdIo *out, + struct DdInfo *dd) +{ + char *end; + + dd->count = qemu_strtosz_suffix(arg, &end, QEMU_STRTOSZ_DEFSUFFIX_B); + + if (dd->count < 0 || *end) { + error_report("invalid number: '%s'", arg); + return 1; + } + + return 0; +} + +static int img_dd_if(const char *arg, + struct DdIo *in, struct DdIo *out, + struct DdInfo *dd) +{ + in->filename = g_strdup(arg); + + return 0; +} + +static int img_dd_of(const char *arg, + struct DdIo *in, struct DdIo *out, + struct DdInfo *dd) +{ + out->filename = g_strdup(arg); + + return 0; +} + +static int img_dd(int argc, char **argv) +{ + int ret = 0; + char *arg = NULL; + char *tmp; + BlockDriver *drv = NULL, *proto_drv = NULL; + BlockBackend *blk1 = NULL, *blk2 = NULL; + QemuOpts *opts = NULL; + QemuOptsList *create_opts = NULL; + Error *local_err = NULL; + bool image_opts = false; + int c, i; + const char *out_fmt = "raw"; + const char *fmt = NULL; + int64_t size = 0; + int64_t block_count = 0, out_pos, in_pos; + struct DdInfo dd = { + .flags = 0, + .count = 0, + }; + struct DdIo in = { + .bsz = 512, /* Block size is by default 512 bytes */ + .filename = NULL, + .buf = NULL + }; + struct DdIo out = { + .bsz = 512, + .filename = NULL, + .buf = NULL + }; + + const struct DdOpts options[] = { + { "bs", img_dd_bs, C_BS }, + { "count", img_dd_count, C_COUNT }, + { "if", img_dd_if, C_IF }, + { "of", img_dd_of, C_OF }, + { NULL, NULL, 0 } + }; + const struct option long_options[] = { + { "help", no_argument, 0, 'h'}, + { "image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, + { 0, 0, 0, 0 } + }; + + while ((c = getopt_long(argc, argv, "hf:O:", long_options, NULL))) { + if (c == EOF) { + break; + } + switch (c) { + case 'O': + out_fmt = optarg; + break; + case 'f': + fmt = optarg; + break; + case '?': + error_report("Try 'qemu-img --help' for more information."); + ret = -1; + goto out; + case 'h': + help(); + break; + case OPTION_IMAGE_OPTS: + image_opts = true; + break; + } + } + + for (i = optind; i < argc; i++) { + int j; + arg = g_strdup(argv[i]); + + tmp = strchr(arg, '='); + if (tmp == NULL) { + error_report("unrecognized operand %s", arg); + ret = -1; + goto out; + } + + *tmp++ = '\0'; + + for (j = 0; options[j].name != NULL; j++) { + if (!strcmp(arg, options[j].name)) { + break; + } + } + if (options[j].name == NULL) { + error_report("unrecognized operand %s", arg); + ret = -1; + goto out; + } + + if (options[j].f(tmp, &in, &out, &dd) != 0) { + ret = -1; + goto out; + } + dd.flags |= options[j].flag; + g_free(arg); + arg = NULL; + } + + if (!(dd.flags & C_IF && dd.flags & C_OF)) { + error_report("Must specify both input and output files"); + ret = -1; + goto out; + } + blk1 = img_open(image_opts, in.filename, fmt, 0, false, false); + + if (!blk1) { + ret = -1; + goto out; + } + + drv = bdrv_find_format(out_fmt); + if (!drv) { + error_report("Unknown file format"); + ret = -1; + goto out; + } + proto_drv = bdrv_find_protocol(out.filename, true, &local_err); + + if (!proto_drv) { + error_report_err(local_err); + ret = -1; + goto out; + } + if (!drv->create_opts) { + error_report("Format driver '%s' does not support image creation", + drv->format_name); + ret = -1; + goto out; + } + if (!proto_drv->create_opts) { + error_report("Protocol driver '%s' does not support image creation", + proto_drv->format_name); + ret = -1; + goto out; + } + create_opts = qemu_opts_append(create_opts, drv->create_opts); + create_opts = qemu_opts_append(create_opts, proto_drv->create_opts); + + opts = qemu_opts_create(create_opts, NULL, 0, &error_abort); + + size = blk_getlength(blk1); + if (size < 0) { + error_report("Failed to get size for '%s'", in.filename); + ret = -1; + goto out; + } + + if (dd.flags & C_COUNT && dd.count <= INT64_MAX / in.bsz && + dd.count * in.bsz < size) { + size = dd.count * in.bsz; + } + + qemu_opt_set_number(opts, BLOCK_OPT_SIZE, size, &error_abort); + + ret = bdrv_create(drv, out.filename, opts, &local_err); + if (ret < 0) { + error_reportf_err(local_err, + "%s: error while creating output image: ", + out.filename); + ret = -1; + goto out; + } + + blk2 = img_open(image_opts, out.filename, out_fmt, BDRV_O_RDWR, + false, false); + + if (!blk2) { + ret = -1; + goto out; + } + + in.buf = g_new(uint8_t, in.bsz); + + for (in_pos = 0, out_pos = 0; in_pos < size; block_count++) { + int in_ret, out_ret; + + if (in_pos + in.bsz > size) { + in_ret = blk_pread(blk1, in_pos, in.buf, size - in_pos); + } else { + in_ret = blk_pread(blk1, in_pos, in.buf, in.bsz); + } + if (in_ret < 0) { + error_report("error while reading from input image file: %s", + strerror(-in_ret)); + ret = -1; + goto out; + } + in_pos += in_ret; + + out_ret = blk_pwrite(blk2, out_pos, in.buf, in_ret, 0); + + if (out_ret < 0) { + error_report("error while writing to output image file: %s", + strerror(-out_ret)); + ret = -1; + goto out; + } + out_pos += out_ret; + } + +out: + g_free(arg); + qemu_opts_del(opts); + qemu_opts_free(create_opts); + blk_unref(blk1); + blk_unref(blk2); + g_free(in.filename); + g_free(out.filename); + g_free(in.buf); + g_free(out.buf); + + if (ret) { + return 1; + } + return 0; +} + static const img_cmd_t img_cmds[] = { #define DEF(option, callback, arg_string) \ diff --git a/qemu-img.texi b/qemu-img.texi index 449a19c7104..880293aefa5 100644 --- a/qemu-img.texi +++ b/qemu-img.texi @@ -139,6 +139,20 @@ Parameters to convert subcommand: Skip the creation of the target volume @end table +Parameters to dd subcommand: + +@table @option + +@item bs=@var{block_size} +defines the block size +@item count=@var{blocks} +sets the number of input blocks to copy +@item if=@var{input} +sets the input file +@item of=@var{output} +sets the output file +@end table + Command description: @table @option @@ -310,6 +324,17 @@ skipped. This is useful for formats such as @code{rbd} if the target volume has already been created with site specific options that cannot be supplied through qemu-img. +@item dd [-f @var{fmt}] [-O @var{output_fmt}] [bs=@var{block_size}] [count=@var{blocks}] if=@var{input} of=@var{output} + +Dd copies from @var{input} file to @var{output} file converting it from +@var{fmt} format to @var{output_fmt} format. + +The data is by default read and written using blocks of 512 bytes but can be +modified by specifying @var{block_size}. If count=@var{blocks} is specified +dd will stop reading input after reading @var{blocks} input blocks. + +The size syntax is similar to dd(1)'s size syntax. + @item info [-f @var{fmt}] [--output=@var{ofmt}] [--backing-chain] @var{filename} Give information about the disk image @var{filename}. Use it in diff --git a/tests/qemu-iotests/159 b/tests/qemu-iotests/159 new file mode 100755 index 00000000000..825f05fab8b --- /dev/null +++ b/tests/qemu-iotests/159 @@ -0,0 +1,70 @@ +#! /bin/bash +# +# qemu-img dd test with different block sizes +# +# Copyright (C) 2016 Reda Sallahi +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +owner=fullmanet@gmail.com + +seq="$(basename $0)" +echo "QA output created by $seq" + +here="$PWD" +status=1 + +_cleanup() +{ + _cleanup_test_img + rm -f "$TEST_IMG.out" +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +. ./common.rc +. ./common.filter +. ./common.pattern + +_supported_fmt generic +_supported_proto file +_supported_os Linux + +TEST_SIZES="5 512 1024 1999 1K 64K 1M" + +for bs in $TEST_SIZES; do + echo + echo "== Creating image ==" + + size=1M + _make_test_img $size + _check_test_img + $QEMU_IO -c "write -P 0xa 0 $size" "$TEST_IMG" | _filter_qemu_io + + echo + echo "== Converting the image with dd with a block size of $bs ==" + + $QEMU_IMG dd if="$TEST_IMG" of="$TEST_IMG.out" bs=$bs -O "$IMGFMT" + TEST_IMG="$TEST_IMG.out" _check_test_img + + echo + echo "== Compare the images with qemu-img compare ==" + + $QEMU_IMG compare "$TEST_IMG" "$TEST_IMG.out" +done + +echo +echo "*** done" +rm -f "$seq.full" +status=0 diff --git a/tests/qemu-iotests/159.out b/tests/qemu-iotests/159.out new file mode 100644 index 00000000000..b86b63abe68 --- /dev/null +++ b/tests/qemu-iotests/159.out @@ -0,0 +1,87 @@ +QA output created by 159 + +== Creating image == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 +No errors were found on the image. +wrote 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== Converting the image with dd with a block size of 5 == +No errors were found on the image. + +== Compare the images with qemu-img compare == +Images are identical. + +== Creating image == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 +No errors were found on the image. +wrote 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== Converting the image with dd with a block size of 512 == +No errors were found on the image. + +== Compare the images with qemu-img compare == +Images are identical. + +== Creating image == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 +No errors were found on the image. +wrote 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== Converting the image with dd with a block size of 1024 == +No errors were found on the image. + +== Compare the images with qemu-img compare == +Images are identical. + +== Creating image == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 +No errors were found on the image. +wrote 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== Converting the image with dd with a block size of 1999 == +No errors were found on the image. + +== Compare the images with qemu-img compare == +Images are identical. + +== Creating image == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 +No errors were found on the image. +wrote 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== Converting the image with dd with a block size of 1K == +No errors were found on the image. + +== Compare the images with qemu-img compare == +Images are identical. + +== Creating image == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 +No errors were found on the image. +wrote 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== Converting the image with dd with a block size of 64K == +No errors were found on the image. + +== Compare the images with qemu-img compare == +Images are identical. + +== Creating image == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 +No errors were found on the image. +wrote 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== Converting the image with dd with a block size of 1M == +No errors were found on the image. + +== Compare the images with qemu-img compare == +Images are identical. + +*** done diff --git a/tests/qemu-iotests/170 b/tests/qemu-iotests/170 new file mode 100755 index 00000000000..5b335dbc3e9 --- /dev/null +++ b/tests/qemu-iotests/170 @@ -0,0 +1,67 @@ +#! /bin/bash +# +# qemu-img dd test +# +# Copyright (C) 2016 Reda Sallahi +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +owner=fullmanet@gmail.com + +seq="$(basename $0)" +echo "QA output created by $seq" + +here="$PWD" +status=1 + +_cleanup() +{ + _cleanup_test_img + rm -f "$TEST_IMG.out" +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +. ./common.rc +. ./common.filter +. ./common.pattern + +_supported_fmt generic +_supported_proto file +_supported_os Linux + +echo +echo "== Creating image ==" + +size=1M +_make_test_img $size +_check_test_img + +$QEMU_IO -c "write -P 0xa 0 $size" "$TEST_IMG" | _filter_qemu_io + +echo +echo "== Converting the image with dd ==" + +$QEMU_IMG dd if="$TEST_IMG" of="$TEST_IMG.out" -O "$IMGFMT" +TEST_IMG="$TEST_IMG.out" _check_test_img + +echo +echo "== Compare the images with qemu-img compare ==" + +$QEMU_IMG compare "$TEST_IMG" "$TEST_IMG.out" + +echo +echo "*** done" +rm -f "$seq.full" +status=0 diff --git a/tests/qemu-iotests/170.out b/tests/qemu-iotests/170.out new file mode 100644 index 00000000000..a83fb82fa7c --- /dev/null +++ b/tests/qemu-iotests/170.out @@ -0,0 +1,15 @@ +QA output created by 170 + +== Creating image == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 +No errors were found on the image. +wrote 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== Converting the image with dd == +No errors were found on the image. + +== Compare the images with qemu-img compare == +Images are identical. + +*** done diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter index 3ab6e4d764c..240ed0697a1 100644 --- a/tests/qemu-iotests/common.filter +++ b/tests/qemu-iotests/common.filter @@ -44,6 +44,15 @@ _filter_imgfmt() sed -e "s#$IMGFMT#IMGFMT#g" } +# Replace error message when the format is not supported and delete +# the output lines after the first one +_filter_qemu_img_check() +{ + sed -e '/allocated.*fragmented.*compressed clusters/d' \ + -e 's/qemu-img: This image format does not support checks/No errors were found on the image./' \ + -e '/Image end offset: [0-9]\+/d' +} + # Removes \r from messages _filter_win32() { diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc index 306b00c210f..126bd67043e 100644 --- a/tests/qemu-iotests/common.rc +++ b/tests/qemu-iotests/common.rc @@ -234,10 +234,7 @@ _check_test_img() else $QEMU_IMG check "$@" -f $IMGFMT "$TEST_IMG" 2>&1 fi - ) | _filter_testdir | \ - sed -e '/allocated.*fragmented.*compressed clusters/d' \ - -e 's/qemu-img: This image format does not support checks/No errors were found on the image./' \ - -e '/Image end offset: [0-9]\+/d' + ) | _filter_testdir | _filter_qemu_img_check } _img_info() diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index 50ddeed80a0..c46beb1b0dd 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -157,4 +157,6 @@ 155 rw auto 156 rw auto quick 157 auto +159 rw auto quick 162 auto quick +170 rw auto quick From f7c1553388c98efcdcc70371e655417cf1ed7df6 Mon Sep 17 00:00:00 2001 From: Reda Sallahi Date: Wed, 10 Aug 2016 16:16:09 +0200 Subject: [PATCH 104/723] qemu-img: add skip option to dd This adds the skip option which allows qemu-img dd to skip a number of blocks before copying the input. A test case was added to test the skip option. Signed-off-by: Reda Sallahi Message-id: 20160810141609.32727-1-fullmanet@gmail.com Signed-off-by: Max Reitz --- qemu-img-cmds.hx | 4 +-- qemu-img.c | 50 +++++++++++++++++++++++--- qemu-img.texi | 4 ++- tests/qemu-iotests/160 | 72 ++++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/160.out | 51 +++++++++++++++++++++++++++ tests/qemu-iotests/group | 1 + 6 files changed, 174 insertions(+), 8 deletions(-) create mode 100755 tests/qemu-iotests/160 create mode 100644 tests/qemu-iotests/160.out diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx index 03bdd7ad7bf..f054599a912 100644 --- a/qemu-img-cmds.hx +++ b/qemu-img-cmds.hx @@ -46,9 +46,9 @@ STEXI ETEXI DEF("dd", img_dd, - "dd [--image-opts] [-f fmt] [-O output_fmt] [bs=block_size] [count=blocks] if=input of=output") + "dd [--image-opts] [-f fmt] [-O output_fmt] [bs=block_size] [count=blocks] [skip=blocks] if=input of=output") STEXI -@item dd [--image-opts] [-f @var{fmt}] [-O @var{output_fmt}] [bs=@var{block_size}] [count=@var{blocks}] if=@var{input} of=@var{output} +@item dd [--image-opts] [-f @var{fmt}] [-O @var{output_fmt}] [bs=@var{block_size}] [count=@var{blocks}] [skip=@var{blocks}] if=@var{input} of=@var{output} ETEXI DEF("info", img_info, diff --git a/qemu-img.c b/qemu-img.c index 5bdac8ddb7f..ceffefeacb6 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -173,7 +173,8 @@ static void QEMU_NORETURN help(void) "(default: 512)\n" " 'count=N' copy only N input blocks\n" " 'if=FILE' read from FILE\n" - " 'of=FILE' write to FILE\n"; + " 'of=FILE' write to FILE\n" + " 'skip=N' skip N bs-sized blocks at the start of input\n"; printf("%s\nSupported formats:", help_msg); bdrv_iterate_format(format_print, NULL); @@ -3807,6 +3808,7 @@ static int img_bench(int argc, char **argv) #define C_COUNT 02 #define C_IF 04 #define C_OF 010 +#define C_SKIP 020 struct DdInfo { unsigned int flags; @@ -3817,6 +3819,7 @@ struct DdIo { int bsz; /* Block size */ char *filename; uint8_t *buf; + int64_t offset; }; struct DdOpts { @@ -3877,6 +3880,22 @@ static int img_dd_of(const char *arg, return 0; } +static int img_dd_skip(const char *arg, + struct DdIo *in, struct DdIo *out, + struct DdInfo *dd) +{ + char *end; + + in->offset = qemu_strtosz_suffix(arg, &end, QEMU_STRTOSZ_DEFSUFFIX_B); + + if (in->offset < 0 || *end) { + error_report("invalid number: '%s'", arg); + return 1; + } + + return 0; +} + static int img_dd(int argc, char **argv) { int ret = 0; @@ -3900,12 +3919,14 @@ static int img_dd(int argc, char **argv) struct DdIo in = { .bsz = 512, /* Block size is by default 512 bytes */ .filename = NULL, - .buf = NULL + .buf = NULL, + .offset = 0 }; struct DdIo out = { .bsz = 512, .filename = NULL, - .buf = NULL + .buf = NULL, + .offset = 0 }; const struct DdOpts options[] = { @@ -3913,6 +3934,7 @@ static int img_dd(int argc, char **argv) { "count", img_dd_count, C_COUNT }, { "if", img_dd_if, C_IF }, { "of", img_dd_of, C_OF }, + { "skip", img_dd_skip, C_SKIP }, { NULL, NULL, 0 } }; const struct option long_options[] = { @@ -4032,7 +4054,14 @@ static int img_dd(int argc, char **argv) size = dd.count * in.bsz; } - qemu_opt_set_number(opts, BLOCK_OPT_SIZE, size, &error_abort); + /* Overflow means the specified offset is beyond input image's size */ + if (dd.flags & C_SKIP && (in.offset > INT64_MAX / in.bsz || + size < in.bsz * in.offset)) { + qemu_opt_set_number(opts, BLOCK_OPT_SIZE, 0, &error_abort); + } else { + qemu_opt_set_number(opts, BLOCK_OPT_SIZE, + size - in.bsz * in.offset, &error_abort); + } ret = bdrv_create(drv, out.filename, opts, &local_err); if (ret < 0) { @@ -4051,9 +4080,20 @@ static int img_dd(int argc, char **argv) goto out; } + if (dd.flags & C_SKIP && (in.offset > INT64_MAX / in.bsz || + size < in.offset * in.bsz)) { + /* We give a warning if the skip option is bigger than the input + * size and create an empty output disk image (i.e. like dd(1)). + */ + error_report("%s: cannot skip to specified offset", in.filename); + in_pos = size; + } else { + in_pos = in.offset * in.bsz; + } + in.buf = g_new(uint8_t, in.bsz); - for (in_pos = 0, out_pos = 0; in_pos < size; block_count++) { + for (out_pos = 0; in_pos < size; block_count++) { int in_ret, out_ret; if (in_pos + in.bsz > size) { diff --git a/qemu-img.texi b/qemu-img.texi index 880293aefa5..174aae38b75 100644 --- a/qemu-img.texi +++ b/qemu-img.texi @@ -151,6 +151,8 @@ sets the number of input blocks to copy sets the input file @item of=@var{output} sets the output file +@item skip=@var{blocks} +sets the number of input blocks to skip @end table Command description: @@ -324,7 +326,7 @@ skipped. This is useful for formats such as @code{rbd} if the target volume has already been created with site specific options that cannot be supplied through qemu-img. -@item dd [-f @var{fmt}] [-O @var{output_fmt}] [bs=@var{block_size}] [count=@var{blocks}] if=@var{input} of=@var{output} +@item dd [-f @var{fmt}] [-O @var{output_fmt}] [bs=@var{block_size}] [count=@var{blocks}] [skip=@var{blocks}] if=@var{input} of=@var{output} Dd copies from @var{input} file to @var{output} file converting it from @var{fmt} format to @var{output_fmt} format. diff --git a/tests/qemu-iotests/160 b/tests/qemu-iotests/160 new file mode 100755 index 00000000000..5c910e5bfc1 --- /dev/null +++ b/tests/qemu-iotests/160 @@ -0,0 +1,72 @@ +#! /bin/bash +# +# qemu-img dd test for the skip option +# +# Copyright (C) 2016 Reda Sallahi +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +owner=fullmanet@gmail.com + +seq="$(basename $0)" +echo "QA output created by $seq" + +here="$PWD" +status=1 + +_cleanup() +{ + _cleanup_test_img + rm -f "$TEST_IMG.out" "$TEST_IMG.out.dd" +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +. ./common.rc +. ./common.filter +. ./common.pattern + +_supported_fmt raw +_supported_proto file +_supported_os Linux + +TEST_SKIP_BLOCKS="1 2 30 30K" + +for skip in $TEST_SKIP_BLOCKS; do + echo + echo "== Creating image ==" + + size=1M + _make_test_img $size + _check_test_img + $QEMU_IO -c "write -P 0xa 24 512k" "$TEST_IMG" | _filter_qemu_io + + echo + echo "== Converting the image with dd with skip=$skip ==" + + $QEMU_IMG dd if="$TEST_IMG" of="$TEST_IMG.out" skip="$skip" -O "$IMGFMT" \ + 2> /dev/null + TEST_IMG="$TEST_IMG.out" _check_test_img + dd if="$TEST_IMG" of="$TEST_IMG.out.dd" skip="$skip" status=none + + echo + echo "== Compare the images with qemu-img compare ==" + + $QEMU_IMG compare "$TEST_IMG.out.dd" "$TEST_IMG.out" +done + +echo +echo "*** done" +rm -f "$seq.full" +status=0 diff --git a/tests/qemu-iotests/160.out b/tests/qemu-iotests/160.out new file mode 100644 index 00000000000..9cedc803566 --- /dev/null +++ b/tests/qemu-iotests/160.out @@ -0,0 +1,51 @@ +QA output created by 160 + +== Creating image == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 +No errors were found on the image. +wrote 524288/524288 bytes at offset 24 +512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== Converting the image with dd with skip=1 == +No errors were found on the image. + +== Compare the images with qemu-img compare == +Images are identical. + +== Creating image == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 +No errors were found on the image. +wrote 524288/524288 bytes at offset 24 +512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== Converting the image with dd with skip=2 == +No errors were found on the image. + +== Compare the images with qemu-img compare == +Images are identical. + +== Creating image == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 +No errors were found on the image. +wrote 524288/524288 bytes at offset 24 +512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== Converting the image with dd with skip=30 == +No errors were found on the image. + +== Compare the images with qemu-img compare == +Images are identical. + +== Creating image == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 +No errors were found on the image. +wrote 524288/524288 bytes at offset 24 +512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== Converting the image with dd with skip=30K == +No errors were found on the image. + +== Compare the images with qemu-img compare == +Images are identical. + +*** done diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index c46beb1b0dd..a57fc9218f5 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -158,5 +158,6 @@ 156 rw auto quick 157 auto 159 rw auto quick +160 rw auto quick 162 auto quick 170 rw auto quick From f57b4b5fb127b60e1aade2684a8b16bc4f630b29 Mon Sep 17 00:00:00 2001 From: Colin Lord Date: Fri, 12 Aug 2016 09:27:01 -0400 Subject: [PATCH 105/723] blockdev: prepare iSCSI block driver for dynamic loading This commit moves the initialization of the QemuOptsList qemu_iscsi_opts struct out of block/iscsi.c in order to allow the iscsi module to be dynamically loaded. Signed-off-by: Colin Lord Reviewed-by: Fam Zheng Reviewed-by: Stefan Hajnoczi Message-id: 1471008424-16465-2-git-send-email-clord@redhat.com Reviewed-by: Max Reitz Signed-off-by: Max Reitz --- block/iscsi.c | 36 ------------------------------------ vl.c | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 36 deletions(-) diff --git a/block/iscsi.c b/block/iscsi.c index 95ce9e139eb..c4a09374192 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -2010,45 +2010,9 @@ static BlockDriver bdrv_iscsi = { .bdrv_attach_aio_context = iscsi_attach_aio_context, }; -static QemuOptsList qemu_iscsi_opts = { - .name = "iscsi", - .head = QTAILQ_HEAD_INITIALIZER(qemu_iscsi_opts.head), - .desc = { - { - .name = "user", - .type = QEMU_OPT_STRING, - .help = "username for CHAP authentication to target", - },{ - .name = "password", - .type = QEMU_OPT_STRING, - .help = "password for CHAP authentication to target", - },{ - .name = "password-secret", - .type = QEMU_OPT_STRING, - .help = "ID of the secret providing password for CHAP " - "authentication to target", - },{ - .name = "header-digest", - .type = QEMU_OPT_STRING, - .help = "HeaderDigest setting. " - "{CRC32C|CRC32C-NONE|NONE-CRC32C|NONE}", - },{ - .name = "initiator-name", - .type = QEMU_OPT_STRING, - .help = "Initiator iqn name to use when connecting", - },{ - .name = "timeout", - .type = QEMU_OPT_NUMBER, - .help = "Request timeout in seconds (default 0 = no timeout)", - }, - { /* end of list */ } - }, -}; - static void iscsi_block_init(void) { bdrv_register(&bdrv_iscsi); - qemu_add_opts(&qemu_iscsi_opts); } block_init(iscsi_block_init); diff --git a/vl.c b/vl.c index fca04871675..fd321e2fd44 100644 --- a/vl.c +++ b/vl.c @@ -507,6 +507,43 @@ static QemuOptsList qemu_fw_cfg_opts = { }, }; +#ifdef CONFIG_LIBISCSI +static QemuOptsList qemu_iscsi_opts = { + .name = "iscsi", + .head = QTAILQ_HEAD_INITIALIZER(qemu_iscsi_opts.head), + .desc = { + { + .name = "user", + .type = QEMU_OPT_STRING, + .help = "username for CHAP authentication to target", + },{ + .name = "password", + .type = QEMU_OPT_STRING, + .help = "password for CHAP authentication to target", + },{ + .name = "password-secret", + .type = QEMU_OPT_STRING, + .help = "ID of the secret providing password for CHAP " + "authentication to target", + },{ + .name = "header-digest", + .type = QEMU_OPT_STRING, + .help = "HeaderDigest setting. " + "{CRC32C|CRC32C-NONE|NONE-CRC32C|NONE}", + },{ + .name = "initiator-name", + .type = QEMU_OPT_STRING, + .help = "Initiator iqn name to use when connecting", + },{ + .name = "timeout", + .type = QEMU_OPT_NUMBER, + .help = "Request timeout in seconds (default 0 = no timeout)", + }, + { /* end of list */ } + }, +}; +#endif + /** * Get machine options * @@ -3017,6 +3054,9 @@ int main(int argc, char **argv, char **envp) qemu_add_opts(&qemu_icount_opts); qemu_add_opts(&qemu_semihosting_config_opts); qemu_add_opts(&qemu_fw_cfg_opts); +#ifdef CONFIG_LIBISCSI + qemu_add_opts(&qemu_iscsi_opts); +#endif module_call_init(MODULE_INIT_OPTS); runstate_init(); From 0c0c1fd973013671ea63680fcd9802766c1d04fe Mon Sep 17 00:00:00 2001 From: Marc Mari Date: Fri, 12 Aug 2016 09:27:02 -0400 Subject: [PATCH 106/723] blockdev: Add dynamic generation of module_block.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To simplify the addition of new block modules, add a script that generates module_block.h automatically from the modules' source code. This script assumes that the QEMU coding style rules are followed. Signed-off-by: Marc Marí Signed-off-by: Colin Lord Reviewed-by: Stefan Hajnoczi Message-id: 1471008424-16465-3-git-send-email-clord@redhat.com Reviewed-by: Max Reitz Signed-off-by: Max Reitz --- Makefile | 7 +++ scripts/modules/module_block.py | 108 ++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 scripts/modules/module_block.py diff --git a/Makefile b/Makefile index 444ae37bd30..b7d1200c166 100644 --- a/Makefile +++ b/Makefile @@ -76,6 +76,8 @@ GENERATED_HEADERS += trace/generated-ust-provider.h GENERATED_SOURCES += trace/generated-ust.c endif +GENERATED_HEADERS += module_block.h + # Don't try to regenerate Makefile or configure # We don't generate any of them Makefile: ; @@ -352,6 +354,11 @@ ivshmem-client$(EXESUF): $(ivshmem-client-obj-y) libqemuutil.a libqemustub.a ivshmem-server$(EXESUF): $(ivshmem-server-obj-y) libqemuutil.a libqemustub.a $(call LINK, $^) +module_block.h: $(SRC_PATH)/scripts/modules/module_block.py config-host.mak + $(call quiet-command,$(PYTHON) $< $@ \ + $(addprefix $(SRC_PATH)/,$(patsubst %.mo,%.c,$(block-obj-m))), \ + " GEN $@") + clean: # avoid old build problems by removing potentially incorrect old files rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h diff --git a/scripts/modules/module_block.py b/scripts/modules/module_block.py new file mode 100644 index 00000000000..db4fb540cdc --- /dev/null +++ b/scripts/modules/module_block.py @@ -0,0 +1,108 @@ +#!/usr/bin/python +# +# Module information generator +# +# Copyright Red Hat, Inc. 2015 - 2016 +# +# Authors: +# Marc Mari +# +# This work is licensed under the terms of the GNU GPL, version 2. +# See the COPYING file in the top-level directory. + +from __future__ import print_function +import sys +import os + +def get_string_struct(line): + data = line.split() + + # data[0] -> struct element name + # data[1] -> = + # data[2] -> value + + return data[2].replace('"', '')[:-1] + +def add_module(fheader, library, format_name, protocol_name): + lines = [] + lines.append('.library_name = "' + library + '",') + if format_name != "": + lines.append('.format_name = "' + format_name + '",') + if protocol_name != "": + lines.append('.protocol_name = "' + protocol_name + '",') + + text = '\n '.join(lines) + fheader.write('\n {\n ' + text + '\n },') + +def process_file(fheader, filename): + # This parser assumes the coding style rules are being followed + with open(filename, "r") as cfile: + found_something = False + found_start = False + library, _ = os.path.splitext(os.path.basename(filename)) + for line in cfile: + if found_start: + line = line.replace('\n', '') + if line.find(".format_name") != -1: + format_name = get_string_struct(line) + elif line.find(".protocol_name") != -1: + protocol_name = get_string_struct(line) + elif line == "};": + add_module(fheader, library, format_name, protocol_name) + found_start = False + elif line.find("static BlockDriver") != -1: + found_something = True + found_start = True + format_name = "" + protocol_name = "" + + if not found_something: + print("No BlockDriver struct found in " + filename + ". \ + Is this really a module?", file=sys.stderr) + sys.exit(1) + +def print_top(fheader): + fheader.write('''/* AUTOMATICALLY GENERATED, DO NOT MODIFY */ +/* + * QEMU Block Module Infrastructure + * + * Authors: + * Marc Mari + */ + +''') + + fheader.write('''#ifndef QEMU_MODULE_BLOCK_H +#define QEMU_MODULE_BLOCK_H + +#include "qemu-common.h" + +static const struct { + const char *format_name; + const char *protocol_name; + const char *library_name; +} block_driver_modules[] = {''') + +def print_bottom(fheader): + fheader.write(''' +}; + +#endif +''') + +# First argument: output file +# All other arguments: modules source files (.c) +output_file = sys.argv[1] +with open(output_file, 'w') as fheader: + print_top(fheader) + + for filename in sys.argv[2:]: + if os.path.isfile(filename): + process_file(fheader, filename) + else: + print("File " + filename + " does not exist.", file=sys.stderr) + sys.exit(1) + + print_bottom(fheader) + +sys.exit(0) From 88d88798b7efeb0be15b1a60e58b1f8ba4c2f700 Mon Sep 17 00:00:00 2001 From: Marc Mari Date: Fri, 12 Aug 2016 09:27:03 -0400 Subject: [PATCH 107/723] blockdev: Add dynamic module loading for block drivers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extend the current module interface to allow for block drivers to be loaded dynamically on request. The only block drivers that can be converted into modules are the drivers that don't perform any init operation except for registering themselves. In addition, only the protocol drivers are being modularized, as they are the only ones which see significant performance benefits. The format drivers do not generally link to external libraries, so modularizing them is of no benefit from a performance perspective. All the necessary module information is located in a new structure found in module_block.h This spoils the purpose of 5505e8b76f (block/dmg: make it modular). Before this patch, if module build is enabled, block-dmg.so is linked to libbz2, whereas the main binary is not. In downstream, theoretically, it means only the qemu-block-extra package depends on libbz2, while the main QEMU package needn't to. With this patch, we (temporarily) change the case so that the main QEMU depends on libbz2 again. Signed-off-by: Marc Marí Signed-off-by: Colin Lord Reviewed-by: Stefan Hajnoczi Message-id: 1471008424-16465-4-git-send-email-clord@redhat.com Reviewed-by: Max Reitz [mreitz: Do a signed comparison against the length of block_driver_modules[], so it will not cause a compile error when empty] Signed-off-by: Max Reitz --- Makefile | 3 --- block.c | 62 ++++++++++++++++++++++++++++++++++++++----- block/Makefile.objs | 3 +-- include/qemu/module.h | 3 +++ util/module.c | 38 ++++++++------------------ 5 files changed, 70 insertions(+), 39 deletions(-) diff --git a/Makefile b/Makefile index b7d1200c166..f10361675da 100644 --- a/Makefile +++ b/Makefile @@ -247,9 +247,6 @@ Makefile: $(version-obj-y) $(version-lobj-y) libqemustub.a: $(stub-obj-y) libqemuutil.a: $(util-obj-y) -block-modules = $(foreach o,$(block-obj-m),"$(basename $(subst /,-,$o))",) NULL -util/module.o-cflags = -D'CONFIG_BLOCK_MODULES=$(block-modules)' - ###################################################################### qemu-img.o: qemu-img-cmds.h diff --git a/block.c b/block.c index 66ed1c03219..afaff93423d 100644 --- a/block.c +++ b/block.c @@ -27,6 +27,7 @@ #include "block/blockjob.h" #include "block/nbd.h" #include "qemu/error-report.h" +#include "module_block.h" #include "qemu/module.h" #include "qapi/qmp/qerror.h" #include "qapi/qmp/qbool.h" @@ -242,17 +243,40 @@ BlockDriverState *bdrv_new(void) return bs; } -BlockDriver *bdrv_find_format(const char *format_name) +static BlockDriver *bdrv_do_find_format(const char *format_name) { BlockDriver *drv1; + QLIST_FOREACH(drv1, &bdrv_drivers, list) { if (!strcmp(drv1->format_name, format_name)) { return drv1; } } + return NULL; } +BlockDriver *bdrv_find_format(const char *format_name) +{ + BlockDriver *drv1; + int i; + + drv1 = bdrv_do_find_format(format_name); + if (drv1) { + return drv1; + } + + /* The driver isn't registered, maybe we need to load a module */ + for (i = 0; i < (int)ARRAY_SIZE(block_driver_modules); ++i) { + if (!strcmp(block_driver_modules[i].format_name, format_name)) { + block_module_load_one(block_driver_modules[i].library_name); + break; + } + } + + return bdrv_do_find_format(format_name); +} + static int bdrv_is_whitelisted(BlockDriver *drv, bool read_only) { static const char *whitelist_rw[] = { @@ -461,6 +485,19 @@ static BlockDriver *find_hdev_driver(const char *filename) return drv; } +static BlockDriver *bdrv_do_find_protocol(const char *protocol) +{ + BlockDriver *drv1; + + QLIST_FOREACH(drv1, &bdrv_drivers, list) { + if (drv1->protocol_name && !strcmp(drv1->protocol_name, protocol)) { + return drv1; + } + } + + return NULL; +} + BlockDriver *bdrv_find_protocol(const char *filename, bool allow_protocol_prefix, Error **errp) @@ -469,6 +506,7 @@ BlockDriver *bdrv_find_protocol(const char *filename, char protocol[128]; int len; const char *p; + int i; /* TODO Drivers without bdrv_file_open must be specified explicitly */ @@ -495,15 +533,25 @@ BlockDriver *bdrv_find_protocol(const char *filename, len = sizeof(protocol) - 1; memcpy(protocol, filename, len); protocol[len] = '\0'; - QLIST_FOREACH(drv1, &bdrv_drivers, list) { - if (drv1->protocol_name && - !strcmp(drv1->protocol_name, protocol)) { - return drv1; + + drv1 = bdrv_do_find_protocol(protocol); + if (drv1) { + return drv1; + } + + for (i = 0; i < (int)ARRAY_SIZE(block_driver_modules); ++i) { + if (block_driver_modules[i].protocol_name && + !strcmp(block_driver_modules[i].protocol_name, protocol)) { + block_module_load_one(block_driver_modules[i].library_name); + break; } } - error_setg(errp, "Unknown protocol '%s'", protocol); - return NULL; + drv1 = bdrv_do_find_protocol(protocol); + if (!drv1) { + error_setg(errp, "Unknown protocol '%s'", protocol); + } + return drv1; } /* diff --git a/block/Makefile.objs b/block/Makefile.objs index 55da6266fe4..3da471e3886 100644 --- a/block/Makefile.objs +++ b/block/Makefile.objs @@ -1,4 +1,4 @@ -block-obj-y += raw_bsd.o qcow.o vdi.o vmdk.o cloop.o bochs.o vpc.o vvfat.o +block-obj-y += raw_bsd.o qcow.o vdi.o vmdk.o cloop.o bochs.o vpc.o vvfat.o dmg.o block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o block-obj-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o block-obj-y += qed-check.o @@ -40,7 +40,6 @@ gluster.o-libs := $(GLUSTERFS_LIBS) ssh.o-cflags := $(LIBSSH2_CFLAGS) ssh.o-libs := $(LIBSSH2_LIBS) archipelago.o-libs := $(ARCHIPELAGO_LIBS) -block-obj-m += dmg.o dmg.o-libs := $(BZIP2_LIBS) qcow.o-libs := -lz linux-aio.o-libs := -laio diff --git a/include/qemu/module.h b/include/qemu/module.h index 2370708445a..dc2c9d4c4ee 100644 --- a/include/qemu/module.h +++ b/include/qemu/module.h @@ -52,9 +52,12 @@ typedef enum { #define qapi_init(function) module_init(function, MODULE_INIT_QAPI) #define type_init(function) module_init(function, MODULE_INIT_QOM) +#define block_module_load_one(lib) module_load_one("block-", lib) + void register_module_init(void (*fn)(void), module_init_type type); void register_dso_module_init(void (*fn)(void), module_init_type type); void module_call_init(module_init_type type); +void module_load_one(const char *prefix, const char *lib_name); #endif diff --git a/util/module.c b/util/module.c index 86e3f7aba00..a5f7fbd9413 100644 --- a/util/module.c +++ b/util/module.c @@ -87,14 +87,11 @@ void register_dso_module_init(void (*fn)(void), module_init_type type) QTAILQ_INSERT_TAIL(&dso_init_list, e, node); } -static void module_load(module_init_type type); - void module_call_init(module_init_type type) { ModuleTypeList *l; ModuleEntry *e; - module_load(type); l = find_type(type); QTAILQ_FOREACH(e, l, node) { @@ -145,6 +142,7 @@ static int module_load_file(const char *fname) ret = -EINVAL; } else { QTAILQ_FOREACH(e, &dso_init_list, node) { + e->init(); register_module_init(e->init, e->type); } ret = 0; @@ -159,14 +157,10 @@ static int module_load_file(const char *fname) } #endif -static void module_load(module_init_type type) +void module_load_one(const char *prefix, const char *lib_name) { #ifdef CONFIG_MODULES char *fname = NULL; - const char **mp; - static const char *block_modules[] = { - CONFIG_BLOCK_MODULES - }; char *exec_dir; char *dirs[3]; int i = 0; @@ -177,15 +171,6 @@ static void module_load(module_init_type type) return; } - switch (type) { - case MODULE_INIT_BLOCK: - mp = block_modules; - break; - default: - /* no other types have dynamic modules for now*/ - return; - } - exec_dir = qemu_get_exec_dir(); dirs[i++] = g_strdup_printf("%s", CONFIG_QEMU_MODDIR); dirs[i++] = g_strdup_printf("%s/..", exec_dir ? : ""); @@ -194,16 +179,15 @@ static void module_load(module_init_type type) g_free(exec_dir); exec_dir = NULL; - for ( ; *mp; mp++) { - for (i = 0; i < ARRAY_SIZE(dirs); i++) { - fname = g_strdup_printf("%s/%s%s", dirs[i], *mp, HOST_DSOSUF); - ret = module_load_file(fname); - g_free(fname); - fname = NULL; - /* Try loading until loaded a module file */ - if (!ret) { - break; - } + for (i = 0; i < ARRAY_SIZE(dirs); i++) { + fname = g_strdup_printf("%s/%s%s%s", + dirs[i], prefix, lib_name, HOST_DSOSUF); + ret = module_load_file(fname); + g_free(fname); + fname = NULL; + /* Try loading until loaded a module file */ + if (!ret) { + break; } } From 4be4879ff8b4a6504ed981c470f3cb6b57eddb1d Mon Sep 17 00:00:00 2001 From: Colin Lord Date: Fri, 12 Aug 2016 09:27:04 -0400 Subject: [PATCH 108/723] blockdev: Modularize nfs block driver Modularizes the nfs block driver so that it gets dynamically loaded. Signed-off-by: Colin Lord Reviewed-by: Stefan Hajnoczi Message-id: 1471008424-16465-5-git-send-email-clord@redhat.com Reviewed-by: Max Reitz Signed-off-by: Max Reitz --- block/Makefile.objs | 1 + configure | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/block/Makefile.objs b/block/Makefile.objs index 3da471e3886..cb158e9275f 100644 --- a/block/Makefile.objs +++ b/block/Makefile.objs @@ -29,6 +29,7 @@ block-obj-y += crypto.o common-obj-y += stream.o +nfs.o-libs := $(LIBNFS_LIBS) iscsi.o-cflags := $(LIBISCSI_CFLAGS) iscsi.o-libs := $(LIBISCSI_LIBS) curl.o-cflags := $(CURL_CFLAGS) diff --git a/configure b/configure index 7d083bdd859..2efc3382e15 100755 --- a/configure +++ b/configure @@ -4578,7 +4578,6 @@ if test "$libnfs" != "no" ; then if $pkg_config --atleast-version=1.9.3 libnfs; then libnfs="yes" libnfs_libs=$($pkg_config --libs libnfs) - LIBS="$LIBS $libnfs_libs" else if test "$libnfs" = "yes" ; then feature_not_found "libnfs" "Install libnfs devel >= 1.9.3" @@ -5351,7 +5350,8 @@ if test "$libiscsi" = "yes" ; then fi if test "$libnfs" = "yes" ; then - echo "CONFIG_LIBNFS=y" >> $config_host_mak + echo "CONFIG_LIBNFS=m" >> $config_host_mak + echo "LIBNFS_LIBS=$libnfs_libs" >> $config_host_mak fi if test "$seccomp" = "yes"; then From 4d6f8cbba75eb3bf389cd0edb779c9e33f4b03a6 Mon Sep 17 00:00:00 2001 From: Alberto Garcia Date: Sun, 21 Aug 2016 23:36:03 -0400 Subject: [PATCH 109/723] commit: get the overlay node before manipulating the backing chain The 'block-commit' command has a 'top' parameter to specify the topmost node from which the data is going to be copied. [E] <- [D] <- [C] <- [B] <- [A] In this case if [C] is the top node then this is the result: [E] <- [B] <- [A] [B] must be modified so its backing image string points to [E] instead of [C]. commit_start() takes care of reopening [B] in read-write mode, and commit_complete() puts it back in read-only mode once the operation has finished. In order to find [B] (the overlay node) we look for the node that has [C] (the top node) as its backing image. However in commit_complete() we're doing it after [C] has been removed from the chain, so [B] is never found and remains in read-write mode. This patch gets the overlay node before the backing chain is manipulated. Signed-off-by: Alberto Garcia Message-id: 1471836963-28548-1-git-send-email-berto@igalia.com Signed-off-by: Max Reitz --- block/commit.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/block/commit.c b/block/commit.c index 553e18da52e..a02539bacc1 100644 --- a/block/commit.c +++ b/block/commit.c @@ -83,7 +83,7 @@ static void commit_complete(BlockJob *job, void *opaque) BlockDriverState *active = s->active; BlockDriverState *top = blk_bs(s->top); BlockDriverState *base = blk_bs(s->base); - BlockDriverState *overlay_bs; + BlockDriverState *overlay_bs = bdrv_find_overlay(active, top); int ret = data->ret; if (!block_job_is_cancelled(&s->common) && ret == 0) { @@ -97,7 +97,6 @@ static void commit_complete(BlockJob *job, void *opaque) if (s->base_flags != bdrv_get_flags(base)) { bdrv_reopen(base, s->base_flags, NULL); } - overlay_bs = bdrv_find_overlay(active, top); if (overlay_bs && s->orig_overlay_flags != bdrv_get_flags(overlay_bs)) { bdrv_reopen(overlay_bs, s->orig_overlay_flags, NULL); } From 819cec0114eeca80444a21f2e3526ef62d729385 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Tue, 9 Aug 2016 16:15:23 +0300 Subject: [PATCH 110/723] iotest 055: refactor and speed up Source disk is created and filled with test data before each test case. Instead initialize it once for the whole unit. Test disk filling patterns are merged into one pattern. Also TestSetSpeed used different image_len for source and target (by mistake) - this is automatically fixed here. Signed-off-by: Vladimir Sementsov-Ogievskiy Message-id: 1470748523-13856-1-git-send-email-vsementsov@virtuozzo.com Reviewed-by: Pavel Butsykin Reviewed-by: Max Reitz Signed-off-by: Max Reitz --- tests/qemu-iotests/055 | 52 +++++++++++++++--------------------------- 1 file changed, 18 insertions(+), 34 deletions(-) diff --git a/tests/qemu-iotests/055 b/tests/qemu-iotests/055 index ff4535e3ea4..1d3fd04b656 100755 --- a/tests/qemu-iotests/055 +++ b/tests/qemu-iotests/055 @@ -29,17 +29,24 @@ test_img = os.path.join(iotests.test_dir, 'test.img') target_img = os.path.join(iotests.test_dir, 'target.img') blockdev_target_img = os.path.join(iotests.test_dir, 'blockdev-target.img') -class TestSingleDrive(iotests.QMPTestCase): - image_len = 64 * 1024 * 1024 # MB +image_len = 64 * 1024 * 1024 # MB + +def setUpModule(): + qemu_img('create', '-f', iotests.imgfmt, test_img, str(image_len)) + qemu_io('-f', iotests.imgfmt, '-c', 'write -P0x11 0 64k', test_img) + qemu_io('-f', iotests.imgfmt, '-c', 'write -P0x00 64k 128k', test_img) + qemu_io('-f', iotests.imgfmt, '-c', 'write -P0x22 162k 32k', test_img) + qemu_io('-f', iotests.imgfmt, '-c', 'write -P0xd5 1M 32k', test_img) + qemu_io('-f', iotests.imgfmt, '-c', 'write -P0xdc 32M 124k', test_img) + qemu_io('-f', iotests.imgfmt, '-c', 'write -P0x33 67043328 64k', test_img) +def tearDownModule(): + os.remove(test_img) + + +class TestSingleDrive(iotests.QMPTestCase): def setUp(self): - # Write data to the image so we can compare later - qemu_img('create', '-f', iotests.imgfmt, test_img, str(TestSingleDrive.image_len)) - qemu_io('-f', iotests.imgfmt, '-c', 'write -P0x5d 0 64k', test_img) - qemu_io('-f', iotests.imgfmt, '-c', 'write -P0xd5 1M 32k', test_img) - qemu_io('-f', iotests.imgfmt, '-c', 'write -P0xdc 32M 124k', test_img) - qemu_io('-f', iotests.imgfmt, '-c', 'write -P0xdc 67043328 64k', test_img) - qemu_img('create', '-f', iotests.imgfmt, blockdev_target_img, str(TestSingleDrive.image_len)) + qemu_img('create', '-f', iotests.imgfmt, blockdev_target_img, str(image_len)) self.vm = iotests.VM().add_drive(test_img).add_drive(blockdev_target_img) if iotests.qemu_default_machine == 'pc': @@ -48,7 +55,6 @@ class TestSingleDrive(iotests.QMPTestCase): def tearDown(self): self.vm.shutdown() - os.remove(test_img) os.remove(blockdev_target_img) try: os.remove(target_img) @@ -155,19 +161,14 @@ class TestSingleDrive(iotests.QMPTestCase): self.assert_qmp(result, 'error/class', 'GenericError') class TestSetSpeed(iotests.QMPTestCase): - image_len = 80 * 1024 * 1024 # MB - def setUp(self): - qemu_img('create', '-f', iotests.imgfmt, test_img, str(TestSetSpeed.image_len)) - qemu_io('-f', iotests.imgfmt, '-c', 'write -P1 0 512', test_img) - qemu_img('create', '-f', iotests.imgfmt, blockdev_target_img, str(TestSingleDrive.image_len)) + qemu_img('create', '-f', iotests.imgfmt, blockdev_target_img, str(image_len)) self.vm = iotests.VM().add_drive(test_img).add_drive(blockdev_target_img) self.vm.launch() def tearDown(self): self.vm.shutdown() - os.remove(test_img) os.remove(blockdev_target_img) try: os.remove(target_img) @@ -243,15 +244,8 @@ class TestSetSpeed(iotests.QMPTestCase): self.do_test_set_speed_invalid('blockdev-backup', 'drive1') class TestSingleTransaction(iotests.QMPTestCase): - image_len = 64 * 1024 * 1024 # MB - def setUp(self): - qemu_img('create', '-f', iotests.imgfmt, test_img, str(TestSingleTransaction.image_len)) - qemu_io('-f', iotests.imgfmt, '-c', 'write -P0x5d 0 64k', test_img) - qemu_io('-f', iotests.imgfmt, '-c', 'write -P0xd5 1M 32k', test_img) - qemu_io('-f', iotests.imgfmt, '-c', 'write -P0xdc 32M 124k', test_img) - qemu_io('-f', iotests.imgfmt, '-c', 'write -P0xdc 67043328 64k', test_img) - qemu_img('create', '-f', iotests.imgfmt, blockdev_target_img, str(TestSingleDrive.image_len)) + qemu_img('create', '-f', iotests.imgfmt, blockdev_target_img, str(image_len)) self.vm = iotests.VM().add_drive(test_img).add_drive(blockdev_target_img) if iotests.qemu_default_machine == 'pc': @@ -260,7 +254,6 @@ class TestSingleTransaction(iotests.QMPTestCase): def tearDown(self): self.vm.shutdown() - os.remove(test_img) os.remove(blockdev_target_img) try: os.remove(target_img) @@ -454,17 +447,8 @@ class TestDriveCompression(iotests.QMPTestCase): fmt_supports_compression = [{'type': 'qcow2', 'args': ()}, {'type': 'vmdk', 'args': ('-o', 'subformat=streamOptimized')}] - def setUp(self): - # Write data to the image so we can compare later - qemu_img('create', '-f', iotests.imgfmt, test_img, str(TestDriveCompression.image_len)) - qemu_io('-f', iotests.imgfmt, '-c', 'write -P0x11 0 64k', test_img) - qemu_io('-f', iotests.imgfmt, '-c', 'write -P0x00 64k 128k', test_img) - qemu_io('-f', iotests.imgfmt, '-c', 'write -P0x22 162k 32k', test_img) - qemu_io('-f', iotests.imgfmt, '-c', 'write -P0x33 67043328 64k', test_img) - def tearDown(self): self.vm.shutdown() - os.remove(test_img) os.remove(blockdev_target_img) try: os.remove(target_img) From cf9dc9e4807464a9d0b3d7368b818323e14921eb Mon Sep 17 00:00:00 2001 From: Eduardo Otubo Date: Wed, 21 Sep 2016 11:09:22 +0200 Subject: [PATCH 111/723] seccomp: adding getrusage to the whitelist getrusage is used in a number of places throughout the qemu codebase (notably, in crypto/pbkdf.c). Without this syscall being whitelisted, qemu ends up getting killed by the kernel whenever you try to connect to a VNC console. Signed-off-by: Brian Rak Acked-by: Eduardo Otubo --- qemu-seccomp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/qemu-seccomp.c b/qemu-seccomp.c index cb569dc0582..df75d9c4710 100644 --- a/qemu-seccomp.c +++ b/qemu-seccomp.c @@ -65,6 +65,7 @@ static const struct QemuSeccompSyscall seccomp_whitelist[] = { { SCMP_SYS(prctl), 245 }, { SCMP_SYS(signalfd), 245 }, { SCMP_SYS(getrlimit), 245 }, + { SCMP_SYS(getrusage), 245 }, { SCMP_SYS(set_tid_address), 245 }, { SCMP_SYS(statfs), 245 }, { SCMP_SYS(unlink), 245 }, From dab32b321f4d510ed5171b12f68bd5aa7a02cffe Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 15 Jul 2016 14:57:26 +0100 Subject: [PATCH 112/723] linux-user: Fix handling of iovec counts In the kernel the length of an iovec is generally handled as an unsigned long, not an integer; fix the parameter to lock_iovec() accordingly. Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/syscall.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index ca06943f3b2..71f40e3ab80 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -3119,7 +3119,7 @@ static abi_long do_getsockopt(int sockfd, int level, int optname, } static struct iovec *lock_iovec(int type, abi_ulong target_addr, - int count, int copy) + abi_ulong count, int copy) { struct target_iovec *target_vec; struct iovec *vec; @@ -3132,7 +3132,7 @@ static struct iovec *lock_iovec(int type, abi_ulong target_addr, errno = 0; return NULL; } - if (count < 0 || count > IOV_MAX) { + if (count > IOV_MAX) { errno = EINVAL; return NULL; } @@ -3207,7 +3207,7 @@ static struct iovec *lock_iovec(int type, abi_ulong target_addr, } static void unlock_iovec(struct iovec *vec, abi_ulong target_addr, - int count, int copy) + abi_ulong count, int copy) { struct target_iovec *target_vec; int i; @@ -3462,7 +3462,7 @@ static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp, { abi_long ret, len; struct msghdr msg; - int count; + abi_ulong count; struct iovec *vec; abi_ulong target_vec; From 97b079703350ec0f6625788fb380f1fa14d0e2c4 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 15 Jul 2016 14:57:27 +0100 Subject: [PATCH 113/723] linux-user: Fix errno for sendrecvmsg with large iovec length The sendmsg and recvmsg syscalls use a different errno to indicate an overlarge iovec length from readv and writev. Handle this special case in do_sendrcvmsg_locked() to avoid getting the default errno returned by lock_iovec(). Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/syscall.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 71f40e3ab80..9d183264673 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -3485,6 +3485,15 @@ static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp, count = tswapal(msgp->msg_iovlen); target_vec = tswapal(msgp->msg_iov); + + if (count > IOV_MAX) { + /* sendrcvmsg returns a different errno for this condition than + * readv/writev, so we must catch it here before lock_iovec() does. + */ + ret = -TARGET_EMSGSIZE; + goto out2; + } + vec = lock_iovec(send ? VERIFY_READ : VERIFY_WRITE, target_vec, count, send); if (vec == NULL) { From 26a6fc96e0ca7522b855c2164bc6098240c286f6 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 15 Jul 2016 14:57:28 +0100 Subject: [PATCH 114/723] linux-user: Allow bad msg_name for recvfrom on connected socket The POSIX standard mandates that for a connected socket recvfrom() must ignore the msg_name and msg_namelen fields. This is awkward for QEMU because we will attempt to copy them from guest address space. Handle this by not immediately returning a TARGET_EFAULT if the copy failed, but instead passing a known-bad address to the host kernel, which can then return EFAULT or ignore the value appropriately. Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/syscall.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 9d183264673..51f558d47d7 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -3472,7 +3472,14 @@ static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp, ret = target_to_host_sockaddr(fd, msg.msg_name, tswapal(msgp->msg_name), msg.msg_namelen); - if (ret) { + if (ret == -TARGET_EFAULT) { + /* For connected sockets msg_name and msg_namelen must + * be ignored, so returning EFAULT immediately is wrong. + * Instead, pass a bad msg_name to the host kernel, and + * let it decide whether to return EFAULT or not. + */ + msg.msg_name = (void *)-1; + } else if (ret) { goto out2; } } else { @@ -3534,7 +3541,7 @@ static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp, } if (!is_error(ret)) { msgp->msg_namelen = tswap32(msg.msg_namelen); - if (msg.msg_name != NULL) { + if (msg.msg_name != NULL && msg.msg_name != (void *)-1) { ret = host_to_target_sockaddr(tswapal(msgp->msg_name), msg.msg_name, msg.msg_namelen); if (ret) { From 6080723102d1ad3b553769834d6a23e3f3d8250f Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 15 Jul 2016 18:44:45 +0100 Subject: [PATCH 115/723] linux-user: Implement FS_IOC_GETFLAGS and FS_IOC_SETFLAGS ioctls Implement the FS_IOC_GETFLAGS and FS_IOC_SETFLAGS ioctls, as used by chattr. Note that the type information encoded in these ioctl numbers is at odds with the actual type the kernel accesses, as discussed in http://thread.gmane.org/gmane.linux.file-systems/80164. Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/ioctls.h | 3 +++ linux-user/syscall_defs.h | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index 7e2c133ba11..1bad701481a 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h @@ -120,6 +120,9 @@ MK_PTR(MK_STRUCT(STRUCT_fiemap))) #endif + IOCTL(FS_IOC_GETFLAGS, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(FS_IOC_SETFLAGS, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(SIOCATMARK, IOC_R, MK_PTR(TYPE_INT)) IOCTL(SIOCGIFNAME, IOC_RW, MK_PTR(TYPE_INT)) IOCTL(SIOCGIFFLAGS, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_short_ifreq))) diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index c0c9b5887c0..c0e5cb0010b 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -998,6 +998,12 @@ struct target_pollfd { #define TARGET_FIBMAP TARGET_IO(0x00,1) /* bmap access */ #define TARGET_FIGETBSZ TARGET_IO(0x00,2) /* get the block size used for bmap */ +/* Note that the ioctl numbers claim type "long" but the actual type + * used by the kernel is "int". + */ +#define TARGET_FS_IOC_GETFLAGS TARGET_IOR('f', 1, long) +#define TARGET_FS_IOC_SETFLAGS TARGET_IOW('f', 2, long) + #define TARGET_FS_IOC_FIEMAP TARGET_IOWR('f',11,struct fiemap) /* cdrom commands */ From 700fa58e4b9100d6bd77df06d2e5d1f457720c4d Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 18 Jul 2016 11:47:55 +0100 Subject: [PATCH 116/723] linux-user: Use direct syscall for utimensat The linux utimensat syscall differs in semantics from the libc function because the syscall combines the features of utimensat() and futimens(). Rather than trying to split these apart in order to call the two libc functions which then call the same underlying syscall, just always directly make the host syscall. This fixes bugs in some of the corner cases which should return errors from the syscall but which we were incorrectly directing to futimens(). This doesn't reduce the set of hosts that our syscall implementation will work on, because if the direct syscall fails ENOSYS then the libc functions would also fail ENOSYS. (The system call has been in the kernel since 2.6.22 anyway.) Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/syscall.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 51f558d47d7..21ae996dd16 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -520,16 +520,7 @@ static int sys_getcwd1(char *buf, size_t size) } #ifdef TARGET_NR_utimensat -#ifdef CONFIG_UTIMENSAT -static int sys_utimensat(int dirfd, const char *pathname, - const struct timespec times[2], int flags) -{ - if (pathname == NULL) - return futimens(dirfd, times); - else - return utimensat(dirfd, pathname, times, flags); -} -#elif defined(__NR_utimensat) +#if defined(__NR_utimensat) #define __NR_sys_utimensat __NR_utimensat _syscall4(int,sys_utimensat,int,dirfd,const char *,pathname, const struct timespec *,tsp,int,flags) From 2ba7fae3bd688f5bb6cb08defc731d77e6bd943c Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 18 Jul 2016 15:35:59 +0100 Subject: [PATCH 117/723] linux-user: Check for bad event numbers in epoll_wait The kernel checks that the maxevents parameter to epoll_wait is non-negative and not larger than EP_MAX_EVENTS. Add this check to our implementation, so that: * we fail these cases EINVAL rather than EFAULT * we don't pass negative or overflowing values to the lock_user() size calculation Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/syscall.c | 5 +++++ linux-user/syscall_defs.h | 3 +++ 2 files changed, 8 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 21ae996dd16..eecccbb25c5 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -11501,6 +11501,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, int maxevents = arg3; int timeout = arg4; + if (maxevents <= 0 || maxevents > TARGET_EP_MAX_EVENTS) { + ret = -TARGET_EINVAL; + break; + } + target_ep = lock_user(VERIFY_WRITE, arg2, maxevents * sizeof(struct target_epoll_event), 1); if (!target_ep) { diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index c0e5cb0010b..5c19c5ca192 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -2585,6 +2585,9 @@ struct target_epoll_event { abi_uint events; target_epoll_data_t data; } TARGET_EPOLL_PACKED; + +#define TARGET_EP_MAX_EVENTS (INT_MAX / sizeof(struct target_epoll_event)) + #endif struct target_rlimit64 { uint64_t rlim_cur; From ce9c139d93db03e464341385976606b7568b768f Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 18 Jul 2016 16:30:36 +0100 Subject: [PATCH 118/723] linux-user: Range check the nfds argument to ppoll syscall Do an initial range check on the ppoll syscall's nfds argument, to avoid possible overflow in the calculation of the lock_user() size argument. The host kernel will later apply the rather lower limit based on RLIMIT_NOFILE as appropriate. Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/syscall.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index eecccbb25c5..7a50a57d4bf 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -9661,6 +9661,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, pfd = NULL; target_pfd = NULL; if (nfds) { + if (nfds > (INT_MAX / sizeof(struct target_pollfd))) { + ret = -TARGET_EINVAL; + break; + } + target_pfd = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_pollfd) * nfds, 1); if (!target_pfd) { From 0cb581d6bdc5aa808ae1a9789d02657fe531cb39 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 18 Jul 2016 18:12:24 +0100 Subject: [PATCH 119/723] linux-user: report signals being taken in strace output Native strace reports when the process being traced takes a signal: --- SIGSEGV {si_signo=SIGSEGV, si_code=SI_KERNEL, si_addr=0} --- Report something similar when QEMU is doing its internal strace of the guest process and is about to deliver it a signal. Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/qemu.h | 10 +++++ linux-user/signal.c | 4 ++ linux-user/strace.c | 106 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+) diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 815447f5fc9..61808f6f357 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -362,6 +362,16 @@ void print_syscall(int num, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6); void print_syscall_ret(int num, abi_long arg1); +/** + * print_taken_signal: + * @target_signum: target signal being taken + * @tinfo: target_siginfo_t which will be passed to the guest for the signal + * + * Print strace output indicating that this signal is being taken by the guest, + * in a format similar to: + * --- SIGSEGV {si_signo=SIGSEGV, si_code=SI_KERNEL, si_addr=0} --- + */ +void print_taken_signal(int target_signum, const target_siginfo_t *tinfo); extern int do_strace; /* signal.c */ diff --git a/linux-user/signal.c b/linux-user/signal.c index d3ac0e25652..3337f1e5631 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -5849,6 +5849,10 @@ static void handle_pending_signal(CPUArchState *cpu_env, int sig, handler = sa->_sa_handler; } + if (do_strace) { + print_taken_signal(sig, &k->info); + } + if (handler == TARGET_SIG_DFL) { /* default handler : ignore some signal. The other are job control or fatal */ if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) { diff --git a/linux-user/strace.c b/linux-user/strace.c index cc10dc47031..1e5136098e7 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -154,6 +154,100 @@ print_signal(abi_ulong arg, int last) gemu_log("%s%s", signal_name, get_comma(last)); } +static void print_si_code(int arg) +{ + const char *codename = NULL; + + switch (arg) { + case SI_USER: + codename = "SI_USER"; + break; + case SI_KERNEL: + codename = "SI_KERNEL"; + break; + case SI_QUEUE: + codename = "SI_QUEUE"; + break; + case SI_TIMER: + codename = "SI_TIMER"; + break; + case SI_MESGQ: + codename = "SI_MESGQ"; + break; + case SI_ASYNCIO: + codename = "SI_ASYNCIO"; + break; + case SI_SIGIO: + codename = "SI_SIGIO"; + break; + case SI_TKILL: + codename = "SI_TKILL"; + break; + default: + gemu_log("%d", arg); + return; + } + gemu_log("%s", codename); +} + +static void print_siginfo(const target_siginfo_t *tinfo) +{ + /* Print a target_siginfo_t in the format desired for printing + * signals being taken. We assume the target_siginfo_t is in the + * internal form where the top 16 bits of si_code indicate which + * part of the union is valid, rather than in the guest-visible + * form where the bottom 16 bits are sign-extended into the top 16. + */ + int si_type = extract32(tinfo->si_code, 16, 16); + int si_code = sextract32(tinfo->si_code, 0, 16); + + gemu_log("{si_signo="); + print_signal(tinfo->si_signo, 1); + gemu_log(", si_code="); + print_si_code(si_code); + + switch (si_type) { + case QEMU_SI_KILL: + gemu_log(", si_pid = %u, si_uid = %u", + (unsigned int)tinfo->_sifields._kill._pid, + (unsigned int)tinfo->_sifields._kill._uid); + break; + case QEMU_SI_TIMER: + gemu_log(", si_timer1 = %u, si_timer2 = %u", + tinfo->_sifields._timer._timer1, + tinfo->_sifields._timer._timer2); + break; + case QEMU_SI_POLL: + gemu_log(", si_band = %d, si_fd = %d", + tinfo->_sifields._sigpoll._band, + tinfo->_sifields._sigpoll._fd); + break; + case QEMU_SI_FAULT: + gemu_log(", si_addr = "); + print_pointer(tinfo->_sifields._sigfault._addr, 1); + break; + case QEMU_SI_CHLD: + gemu_log(", si_pid = %u, si_uid = %u, si_status = %d" + ", si_utime=" TARGET_ABI_FMT_ld + ", si_stime=" TARGET_ABI_FMT_ld, + (unsigned int)(tinfo->_sifields._sigchld._pid), + (unsigned int)(tinfo->_sifields._sigchld._uid), + tinfo->_sifields._sigchld._status, + tinfo->_sifields._sigchld._utime, + tinfo->_sifields._sigchld._stime); + break; + case QEMU_SI_RT: + gemu_log(", si_pid = %u, si_uid = %u, si_sigval = " TARGET_ABI_FMT_ld, + (unsigned int)tinfo->_sifields._rt._pid, + (unsigned int)tinfo->_sifields._rt._uid, + tinfo->_sifields._rt._sigval.sival_ptr); + break; + default: + g_assert_not_reached(); + } + gemu_log("}"); +} + static void print_sockaddr(abi_ulong addr, abi_long addrlen) { @@ -2190,3 +2284,15 @@ print_syscall_ret(int num, abi_long ret) break; } } + +void print_taken_signal(int target_signum, const target_siginfo_t *tinfo) +{ + /* Print the strace output for a signal being taken: + * --- SIGSEGV {si_signo=SIGSEGV, si_code=SI_KERNEL, si_addr=0} --- + */ + gemu_log("--- "); + print_signal(target_signum, 1); + gemu_log(" "); + print_siginfo(tinfo); + gemu_log(" ---\n"); +} From 68754b442b756e8cb5f143b00937fb7330a51a81 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 12 Jul 2016 13:02:12 +0100 Subject: [PATCH 120/723] linux-user: Pass missing MAP_ANONYMOUS to target_mmap() call A target_mmap() call in load_elf_binary() was missing the MAP_ANONYMOUS flag. (Spotted by Coverity, because target_mmap() will try to use -1 as the filedescriptor in this case.) This has never been noticed because the code in question is for handling ancient SVr4 iBCS2 binaries. Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/elfload.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 29455e4e478..e9a3882bef9 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -2233,7 +2233,7 @@ int load_elf_binary(struct linux_binprm *bprm, struct image_info *info) we do not have the power to recompile these, we emulate the SVr4 behavior. Sigh. */ target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC, - MAP_FIXED | MAP_PRIVATE, -1, 0); + MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); } } From 3211215e741f6e4824ddfc4919428e8d1b82a3c2 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 12 Jul 2016 13:02:13 +0100 Subject: [PATCH 121/723] linux-user: Check lock_user() return value for NULL lock_user() can return NULL, which typically means the syscall should fail with EFAULT. Add checks in various places where Coverity spotted that we were missing them. Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/syscall.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 7a50a57d4bf..efcc17a3b01 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -5008,6 +5008,11 @@ static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd, host_data = (char*)host_dm + host_dm->data_start; argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1); + if (!argptr) { + ret = -TARGET_EFAULT; + goto out; + } + switch (ie->host_cmd) { case DM_REMOVE_ALL: case DM_LIST_DEVICES: @@ -11271,6 +11276,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_mq_unlink: p = lock_user_string(arg1 - 1); + if (!p) { + ret = -TARGET_EFAULT; + break; + } ret = get_errno(mq_unlink(p)); unlock_user (p, arg1, 0); break; From f9757b1d9649cb739ecf544c7137c0885281f6e8 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 12 Jul 2016 13:02:14 +0100 Subject: [PATCH 122/723] linux-user: Fix incorrect use of host errno in do_ioctl_dm() do_ioctl_dm() should return target errno values, not host ones; correct an accidental use of a host errno in an error path. Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/syscall.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index efcc17a3b01..e28690713aa 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -5001,7 +5001,7 @@ static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd, guest_data = arg + host_dm->data_start; if ((guest_data - arg) < 0) { - ret = -EINVAL; + ret = -TARGET_EINVAL; goto out; } guest_data_size = host_dm->data_size - host_dm->data_start; From e5a869ed569a97fa676e9827952629086ec41f4e Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 12 Jul 2016 13:02:15 +0100 Subject: [PATCH 123/723] linux-user: Fix error handling in flatload.c target_pread() The flatload.c target_pread() function is supposed to return 0 on success or negative host errnos; however it wasn't checking lock_user() for failure or returning the errno from the pread() call. Fix these problems (the first of which is noted by Coverity). Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/flatload.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/linux-user/flatload.c b/linux-user/flatload.c index 42d1079a241..a35a5609049 100644 --- a/linux-user/flatload.c +++ b/linux-user/flatload.c @@ -95,7 +95,13 @@ static int target_pread(int fd, abi_ulong ptr, abi_ulong len, int ret; buf = lock_user(VERIFY_WRITE, ptr, len, 0); + if (!buf) { + return -EFAULT; + } ret = pread(fd, buf, len, offset); + if (ret < 0) { + ret = -errno; + } unlock_user(buf, ptr, len); return ret; } From 772034b63e9c0caf6c92e31413f2d8df2ee69c88 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 12 Jul 2016 13:02:17 +0100 Subject: [PATCH 124/723] linux-user: Check dump_write() return in elf_core_dump() One of the calls to dump_write() in elf_core_dump() was missing a check for failure (spotted by Coverity). Add the check to bring it into line with the other calls from this function. Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/elfload.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index e9a3882bef9..0d07b85cb8f 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -3050,7 +3050,9 @@ static int elf_core_dump(int signr, const CPUArchState *env) phdr.p_align = ELF_EXEC_PAGESIZE; bswap_phdr(&phdr, 1); - dump_write(fd, &phdr, sizeof (phdr)); + if (dump_write(fd, &phdr, sizeof(phdr)) != 0) { + goto out; + } } /* From 0ef9ea290ed9319cb788ea40be06dd18b32ba05a Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 12 Jul 2016 13:02:18 +0100 Subject: [PATCH 125/723] linux-user: Use glib malloc functions in load_symbols() Switch to using the glib malloc functions in load_symbols(); this deals with a Coverity complaint about possible integer overflow calculating the allocation size with 'nsyms * sizeof(*syms)'. Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/elfload.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 0d07b85cb8f..3d751f85239 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -2111,19 +2111,19 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias) found: /* Now know where the strtab and symtab are. Snarf them. */ - s = malloc(sizeof(*s)); + s = g_try_new(struct syminfo, 1); if (!s) { goto give_up; } i = shdr[str_idx].sh_size; - s->disas_strtab = strings = malloc(i); + s->disas_strtab = strings = g_try_malloc(i); if (!strings || pread(fd, strings, i, shdr[str_idx].sh_offset) != i) { goto give_up; } i = shdr[sym_idx].sh_size; - syms = malloc(i); + syms = g_try_malloc(i); if (!syms || pread(fd, syms, i, shdr[sym_idx].sh_offset) != i) { goto give_up; } @@ -2157,7 +2157,7 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias) that we threw away. Whether or not this has any effect on the memory allocation depends on the malloc implementation and how many symbols we managed to discard. */ - new_syms = realloc(syms, nsyms * sizeof(*syms)); + new_syms = g_try_renew(struct elf_sym, syms, nsyms); if (new_syms == NULL) { goto give_up; } @@ -2178,9 +2178,9 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias) return; give_up: - free(s); - free(strings); - free(syms); + g_free(s); + g_free(strings); + g_free(syms); } int load_elf_binary(struct linux_binprm *bprm, struct image_info *info) From ee8e76141b4dd00f8e97fda274876a17f9a46bbe Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 11 Jul 2016 16:48:11 +0100 Subject: [PATCH 126/723] linux-user: Use correct target SHMLBA in shmat() The shmat() handling needs to do target-specific handling of the attach address for shmat(): * if the SHM_RND flag is passed, the address is rounded down to a SHMLBA boundary * if SHM_RND is not passed, then the call is failed EINVAL if the address is not a multiple of SHMLBA Since SHMLBA is target-specific, we need to do this checking and rounding in QEMU and can't leave it up to the host syscall. Allow targets to define TARGET_FORCE_SHMLBA and provide a target_shmlba() function if appropriate, and update do_shmat() to honour them. Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/arm/target_syscall.h | 7 +++++ linux-user/mips/target_syscall.h | 7 +++++ linux-user/mips64/target_syscall.h | 7 +++++ linux-user/sh4/target_syscall.h | 7 +++++ linux-user/sparc/target_syscall.h | 16 +++++++++++ linux-user/syscall.c | 45 ++++++++++++++++++++++++++---- 6 files changed, 83 insertions(+), 6 deletions(-) diff --git a/linux-user/arm/target_syscall.h b/linux-user/arm/target_syscall.h index cd021ff598c..0879b4d4a86 100644 --- a/linux-user/arm/target_syscall.h +++ b/linux-user/arm/target_syscall.h @@ -33,4 +33,11 @@ struct target_pt_regs { #define TARGET_MLOCKALL_MCL_CURRENT 1 #define TARGET_MLOCKALL_MCL_FUTURE 2 +#define TARGET_FORCE_SHMLBA + +static inline abi_ulong target_shmlba(CPUARMState *env) +{ + return 4 * 4096; +} + #endif /* ARM_TARGET_SYSCALL_H */ diff --git a/linux-user/mips/target_syscall.h b/linux-user/mips/target_syscall.h index 2b4f3907292..6c666dcb730 100644 --- a/linux-user/mips/target_syscall.h +++ b/linux-user/mips/target_syscall.h @@ -230,4 +230,11 @@ struct target_pt_regs { #define TARGET_MLOCKALL_MCL_CURRENT 1 #define TARGET_MLOCKALL_MCL_FUTURE 2 +#define TARGET_FORCE_SHMLBA + +static inline abi_ulong target_shmlba(CPUMIPSState *env) +{ + return 0x40000; +} + #endif /* MIPS_TARGET_SYSCALL_H */ diff --git a/linux-user/mips64/target_syscall.h b/linux-user/mips64/target_syscall.h index 8da9c1f9cc4..a9c17f7edfb 100644 --- a/linux-user/mips64/target_syscall.h +++ b/linux-user/mips64/target_syscall.h @@ -227,4 +227,11 @@ struct target_pt_regs { #define TARGET_MLOCKALL_MCL_CURRENT 1 #define TARGET_MLOCKALL_MCL_FUTURE 2 +#define TARGET_FORCE_SHMLBA + +static inline abi_ulong target_shmlba(CPUMIPSState *env) +{ + return 0x40000; +} + #endif /* MIPS64_TARGET_SYSCALL_H */ diff --git a/linux-user/sh4/target_syscall.h b/linux-user/sh4/target_syscall.h index 78d55571246..2b5f75be13d 100644 --- a/linux-user/sh4/target_syscall.h +++ b/linux-user/sh4/target_syscall.h @@ -19,4 +19,11 @@ struct target_pt_regs { #define TARGET_MLOCKALL_MCL_CURRENT 1 #define TARGET_MLOCKALL_MCL_FUTURE 2 +#define TARGET_FORCE_SHMLBA + +static inline abi_ulong target_shmlba(CPUSH4State *env) +{ + return 0x4000; +} + #endif /* SH4_TARGET_SYSCALL_H */ diff --git a/linux-user/sparc/target_syscall.h b/linux-user/sparc/target_syscall.h index 326f674b4e7..f97aa6b0751 100644 --- a/linux-user/sparc/target_syscall.h +++ b/linux-user/sparc/target_syscall.h @@ -22,4 +22,20 @@ struct target_pt_regs { #define TARGET_MLOCKALL_MCL_CURRENT 0x2000 #define TARGET_MLOCKALL_MCL_FUTURE 0x4000 +/* For SPARC SHMLBA is determined at runtime in the kernel, and + * libc has to runtime-detect it using the hwcaps (see glibc + * sysdeps/unix/sysv/linux/sparc/getshmlba; we follow the same + * logic here, though we know we're not the sparc v9 64-bit case). + */ +#define TARGET_FORCE_SHMLBA + +static inline abi_ulong target_shmlba(CPUSPARCState *env) +{ + if (!(env->def->features & CPU_FEATURE_FLUSH)) { + return 64 * 1024; + } else { + return 256 * 1024; + } +} + #endif /* SPARC_TARGET_SYSCALL_H */ diff --git a/linux-user/syscall.c b/linux-user/syscall.c index e28690713aa..85699f9f31b 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -4575,12 +4575,34 @@ static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf) return ret; } -static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg) +#ifndef TARGET_FORCE_SHMLBA +/* For most architectures, SHMLBA is the same as the page size; + * some architectures have larger values, in which case they should + * define TARGET_FORCE_SHMLBA and provide a target_shmlba() function. + * This corresponds to the kernel arch code defining __ARCH_FORCE_SHMLBA + * and defining its own value for SHMLBA. + * + * The kernel also permits SHMLBA to be set by the architecture to a + * value larger than the page size without setting __ARCH_FORCE_SHMLBA; + * this means that addresses are rounded to the large size if + * SHM_RND is set but addresses not aligned to that size are not rejected + * as long as they are at least page-aligned. Since the only architecture + * which uses this is ia64 this code doesn't provide for that oddity. + */ +static inline abi_ulong target_shmlba(CPUArchState *cpu_env) +{ + return TARGET_PAGE_SIZE; +} +#endif + +static inline abi_ulong do_shmat(CPUArchState *cpu_env, + int shmid, abi_ulong shmaddr, int shmflg) { abi_long raddr; void *host_raddr; struct shmid_ds shm_info; int i,ret; + abi_ulong shmlba; /* find out the length of the shared memory segment */ ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info)); @@ -4589,6 +4611,16 @@ static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg) return ret; } + shmlba = target_shmlba(cpu_env); + + if (shmaddr & (shmlba - 1)) { + if (shmflg & SHM_RND) { + shmaddr &= ~(shmlba - 1); + } else { + return -TARGET_EINVAL; + } + } + mmap_lock(); if (shmaddr) @@ -4647,7 +4679,8 @@ static inline abi_long do_shmdt(abi_ulong shmaddr) #ifdef TARGET_NR_ipc /* ??? This only works with linear mappings. */ /* do_ipc() must return target values and target errnos. */ -static abi_long do_ipc(unsigned int call, abi_long first, +static abi_long do_ipc(CPUArchState *cpu_env, + unsigned int call, abi_long first, abi_long second, abi_long third, abi_long ptr, abi_long fifth) { @@ -4716,7 +4749,7 @@ static abi_long do_ipc(unsigned int call, abi_long first, default: { abi_ulong raddr; - raddr = do_shmat(first, ptr, second); + raddr = do_shmat(cpu_env, first, ptr, second); if (is_error(raddr)) return get_errno(raddr); if (put_user_ual(raddr, third)) @@ -9304,8 +9337,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #ifdef TARGET_NR_ipc case TARGET_NR_ipc: - ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6); - break; + ret = do_ipc(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6); + break; #endif #ifdef TARGET_NR_semget case TARGET_NR_semget: @@ -9354,7 +9387,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif #ifdef TARGET_NR_shmat case TARGET_NR_shmat: - ret = do_shmat(arg1, arg2, arg3); + ret = do_shmat(cpu_env, arg1, arg2, arg3); break; #endif #ifdef TARGET_NR_shmdt From c836112997e19966565cd6eb68e0836c8972720b Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Fri, 22 Jul 2016 17:18:05 +0200 Subject: [PATCH 127/723] linux-user: ppc64: set MSR_CM bit for BookE 2.06 MMU 64 bit user mode doesn't work for the e5500 core because the MSR_CM bit is not set which enables the 64 bit mode for this MMU model. Memory addresses are truncated to 32 bit, which results in "Invalid data memory access" error messages. Fix it by setting the MSR_CM bit for this MMU model. Signed-off-by: Michael Walle Reviewed-by: Alexander Graf Signed-off-by: Riku Voipio --- linux-user/main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index 3ad70f8a6ee..2aeda8a10dc 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -4615,10 +4615,11 @@ int main(int argc, char **argv, char **envp) int i; #if defined(TARGET_PPC64) + int flag = (env->insns_flags2 & PPC2_BOOKE206) ? MSR_CM : MSR_SF; #if defined(TARGET_ABI32) - env->msr &= ~((target_ulong)1 << MSR_SF); + env->msr &= ~((target_ulong)1 << flag); #else - env->msr |= (target_ulong)1 << MSR_SF; + env->msr |= (target_ulong)1 << flag; #endif #endif env->nip = regs->nip; From 8bd3773cce1885c46e5cf09a72b9138ccba5fbf2 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 28 Jul 2016 16:44:45 +0100 Subject: [PATCH 128/723] linux-user: Recheck for pending synchronous signals too In process_pending_signals() we restart the scan of possible pending signals after calling handle_pending_signal() in case some other signal has been generated. This rescan should also include a check for a new synchronous signal since those are in fact the only kind of new signal that the signal frame setup process might produce. Reviewed-by: Richard Henderson Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/signal.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index 3337f1e5631..f2c9f8e474c 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -5925,6 +5925,7 @@ void process_pending_signals(CPUArchState *cpu_env) sigfillset(&set); sigprocmask(SIG_SETMASK, &set, 0); + restart_scan: sig = ts->sync_signal.pending; if (sig) { /* Synchronous signals are forced, @@ -5952,8 +5953,10 @@ void process_pending_signals(CPUArchState *cpu_env) (!sigismember(blocked_set, target_to_host_signal_table[sig]))) { handle_pending_signal(cpu_env, sig, &ts->sigtab[sig - 1]); - /* Restart scan from the beginning */ - sig = 1; + /* Restart scan from the beginning, as handle_pending_signal + * might have resulted in a new synchronous signal (eg SIGSEGV). + */ + goto restart_scan; } } From 9d2803f720d5b71937c0f564bb2c16d8f5e18c8c Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 28 Jul 2016 16:44:46 +0100 Subject: [PATCH 129/723] linux-user: Pass si_type information to queue_signal() explicitly Instead of assuming in queue_signal() that all callers are passing a siginfo structure which uses the _sifields._sigfault part of the union (and thus a si_type of QEMU_SI_FAULT), make callers pass the si_type they require in as an argument. [RV adjusted to apply] Reviewed-by: Richard Henderson Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/main.c | 124 +++++++++++++++++++++---------------------- linux-user/qemu.h | 3 +- linux-user/signal.c | 10 ++-- linux-user/syscall.c | 6 ++- 4 files changed, 71 insertions(+), 72 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index 2aeda8a10dc..aba58c78bc4 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -339,7 +339,7 @@ void cpu_loop(CPUX86State *env) info.si_errno = 0; info.si_code = TARGET_SI_KERNEL; info._sifields._sigfault._addr = 0; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case EXCP0D_GPF: /* XXX: potential problem if ABI32 */ @@ -353,7 +353,7 @@ void cpu_loop(CPUX86State *env) info.si_errno = 0; info.si_code = TARGET_SI_KERNEL; info._sifields._sigfault._addr = 0; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } break; case EXCP0E_PAGE: @@ -364,7 +364,7 @@ void cpu_loop(CPUX86State *env) else info.si_code = TARGET_SEGV_ACCERR; info._sifields._sigfault._addr = env->cr[2]; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case EXCP00_DIVZ: #ifndef TARGET_X86_64 @@ -378,7 +378,7 @@ void cpu_loop(CPUX86State *env) info.si_errno = 0; info.si_code = TARGET_FPE_INTDIV; info._sifields._sigfault._addr = env->eip; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } break; case EXCP01_DB: @@ -398,7 +398,7 @@ void cpu_loop(CPUX86State *env) info.si_code = TARGET_SI_KERNEL; info._sifields._sigfault._addr = 0; } - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } break; case EXCP04_INTO: @@ -413,7 +413,7 @@ void cpu_loop(CPUX86State *env) info.si_errno = 0; info.si_code = TARGET_SI_KERNEL; info._sifields._sigfault._addr = 0; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } break; case EXCP06_ILLOP: @@ -421,7 +421,7 @@ void cpu_loop(CPUX86State *env) info.si_errno = 0; info.si_code = TARGET_ILL_ILLOPN; info._sifields._sigfault._addr = env->eip; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case EXCP_INTERRUPT: /* just indicate that signals should be handled asap */ @@ -436,7 +436,7 @@ void cpu_loop(CPUX86State *env) info.si_signo = sig; info.si_errno = 0; info.si_code = TARGET_TRAP_BRKPT; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } } break; @@ -576,7 +576,7 @@ static void arm_kernel_cmpxchg64_helper(CPUARMState *env) /* XXX: check env->error_code */ info.si_code = TARGET_SEGV_MAPERR; info._sifields._sigfault._addr = env->exception.vaddress; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } /* Handle a jump to the kernel code page. */ @@ -755,7 +755,7 @@ void cpu_loop(CPUARMState *env) info.si_errno = 0; info.si_code = TARGET_ILL_ILLOPN; info._sifields._sigfault._addr = env->regs[15]; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } else if (rc < 0) { /* FP exception */ int arm_fpe=0; @@ -786,7 +786,7 @@ void cpu_loop(CPUARMState *env) if (arm_fpe & BIT_IOC) info.si_code = TARGET_FPE_FLTINV; info._sifields._sigfault._addr = env->regs[15]; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } else { env->regs[15] += 4; } @@ -907,7 +907,7 @@ void cpu_loop(CPUARMState *env) /* XXX: check env->error_code */ info.si_code = TARGET_SEGV_MAPERR; info._sifields._sigfault._addr = addr; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } break; case EXCP_DEBUG: @@ -921,7 +921,7 @@ void cpu_loop(CPUARMState *env) info.si_signo = sig; info.si_errno = 0; info.si_code = TARGET_TRAP_BRKPT; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } } break; @@ -1099,7 +1099,7 @@ void cpu_loop(CPUARMState *env) info.si_errno = 0; info.si_code = TARGET_ILL_ILLOPN; info._sifields._sigfault._addr = env->pc; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case EXCP_STREX: if (!do_strex_a64(env)) { @@ -1113,7 +1113,7 @@ void cpu_loop(CPUARMState *env) /* XXX: check env->error_code */ info.si_code = TARGET_SEGV_MAPERR; info._sifields._sigfault._addr = env->exception.vaddress; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case EXCP_DEBUG: case EXCP_BKPT: @@ -1122,7 +1122,7 @@ void cpu_loop(CPUARMState *env) info.si_signo = sig; info.si_errno = 0; info.si_code = TARGET_TRAP_BRKPT; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } break; case EXCP_SEMIHOST: @@ -1202,7 +1202,7 @@ void cpu_loop(CPUUniCore32State *env) /* XXX: check env->error_code */ info.si_code = TARGET_SEGV_MAPERR; info._sifields._sigfault._addr = env->cp0.c4_faultaddr; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case EXCP_INTERRUPT: /* just indicate that signals should be handled asap */ @@ -1216,7 +1216,7 @@ void cpu_loop(CPUUniCore32State *env) info.si_signo = sig; info.si_errno = 0; info.si_code = TARGET_TRAP_BRKPT; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } } break; @@ -1431,7 +1431,7 @@ void cpu_loop (CPUSPARCState *env) /* XXX: check env->error_code */ info.si_code = TARGET_SEGV_MAPERR; info._sifields._sigfault._addr = env->mmuregs[4]; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } break; #else @@ -1452,7 +1452,7 @@ void cpu_loop (CPUSPARCState *env) info._sifields._sigfault._addr = env->dmmuregs[4]; else info._sifields._sigfault._addr = cpu_tsptr(env)->tpc; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } break; #ifndef TARGET_ABI32 @@ -1475,7 +1475,7 @@ void cpu_loop (CPUSPARCState *env) info.si_errno = 0; info.si_code = TARGET_ILL_ILLOPC; info._sifields._sigfault._addr = env->pc; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } break; case EXCP_DEBUG: @@ -1488,7 +1488,7 @@ void cpu_loop (CPUSPARCState *env) info.si_signo = sig; info.si_errno = 0; info.si_code = TARGET_TRAP_BRKPT; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } } break; @@ -1679,7 +1679,7 @@ void cpu_loop(CPUPPCState *env) break; } info._sifields._sigfault._addr = env->nip; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case POWERPC_EXCP_ISI: /* Instruction storage exception */ /* XXX: check this */ @@ -1705,7 +1705,7 @@ void cpu_loop(CPUPPCState *env) break; } info._sifields._sigfault._addr = env->nip - 4; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case POWERPC_EXCP_EXTERNAL: /* External input */ cpu_abort(cs, "External interrupt while in user mode. " @@ -1717,7 +1717,7 @@ void cpu_loop(CPUPPCState *env) info.si_errno = 0; info.si_code = TARGET_BUS_ADRALN; info._sifields._sigfault._addr = env->nip; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case POWERPC_EXCP_PROGRAM: /* Program exception */ case POWERPC_EXCP_HV_EMU: /* HV emulation */ @@ -1808,14 +1808,14 @@ void cpu_loop(CPUPPCState *env) break; } info._sifields._sigfault._addr = env->nip; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */ info.si_signo = TARGET_SIGILL; info.si_errno = 0; info.si_code = TARGET_ILL_COPROC; info._sifields._sigfault._addr = env->nip; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case POWERPC_EXCP_SYSCALL: /* System call exception */ cpu_abort(cs, "Syscall exception while in user mode. " @@ -1826,7 +1826,7 @@ void cpu_loop(CPUPPCState *env) info.si_errno = 0; info.si_code = TARGET_ILL_COPROC; info._sifields._sigfault._addr = env->nip; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case POWERPC_EXCP_DECR: /* Decrementer exception */ cpu_abort(cs, "Decrementer interrupt while in user mode. " @@ -1853,7 +1853,7 @@ void cpu_loop(CPUPPCState *env) info.si_errno = 0; info.si_code = TARGET_ILL_COPROC; info._sifields._sigfault._addr = env->nip; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case POWERPC_EXCP_EFPDI: /* Embedded floating-point data IRQ */ cpu_abort(cs, "Embedded floating-point data IRQ not handled\n"); @@ -1916,7 +1916,7 @@ void cpu_loop(CPUPPCState *env) info.si_errno = 0; info.si_code = TARGET_ILL_COPROC; info._sifields._sigfault._addr = env->nip; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case POWERPC_EXCP_PIT: /* Programmable interval timer IRQ */ cpu_abort(cs, "Programmable interval timer interrupt " @@ -2010,7 +2010,7 @@ void cpu_loop(CPUPPCState *env) info.si_errno = 0; info.si_code = TARGET_SEGV_MAPERR; info._sifields._sigfault._addr = env->nip; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } break; case EXCP_DEBUG: @@ -2022,7 +2022,7 @@ void cpu_loop(CPUPPCState *env) info.si_signo = sig; info.si_errno = 0; info.si_code = TARGET_TRAP_BRKPT; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } } break; @@ -2456,13 +2456,13 @@ static int do_break(CPUMIPSState *env, target_siginfo_t *info, info->si_signo = TARGET_SIGFPE; info->si_errno = 0; info->si_code = (code == BRK_OVERFLOW) ? FPE_INTOVF : FPE_INTDIV; - queue_signal(env, info->si_signo, &*info); + queue_signal(env, info->si_signo, QEMU_SI_FAULT, &*info); ret = 0; break; default: info->si_signo = TARGET_SIGTRAP; info->si_errno = 0; - queue_signal(env, info->si_signo, &*info); + queue_signal(env, info->si_signo, QEMU_SI_FAULT, &*info); ret = 0; break; } @@ -2560,14 +2560,14 @@ void cpu_loop(CPUMIPSState *env) /* XXX: check env->error_code */ info.si_code = TARGET_SEGV_MAPERR; info._sifields._sigfault._addr = env->CP0_BadVAddr; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case EXCP_CpU: case EXCP_RI: info.si_signo = TARGET_SIGILL; info.si_errno = 0; info.si_code = 0; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case EXCP_INTERRUPT: /* just indicate that signals should be handled asap */ @@ -2582,7 +2582,7 @@ void cpu_loop(CPUMIPSState *env) info.si_signo = sig; info.si_errno = 0; info.si_code = TARGET_TRAP_BRKPT; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } } break; @@ -2592,14 +2592,14 @@ void cpu_loop(CPUMIPSState *env) info.si_errno = 0; info.si_code = TARGET_SEGV_MAPERR; info._sifields._sigfault._addr = env->active_tc.PC; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } break; case EXCP_DSPDIS: info.si_signo = TARGET_SIGILL; info.si_errno = 0; info.si_code = TARGET_ILL_ILLOPC; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; /* The code below was inspired by the MIPS Linux kernel trap * handling code in arch/mips/kernel/traps.c. @@ -2850,7 +2850,7 @@ void cpu_loop(CPUSH4State *env) info.si_signo = sig; info.si_errno = 0; info.si_code = TARGET_TRAP_BRKPT; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } } break; @@ -2860,7 +2860,7 @@ void cpu_loop(CPUSH4State *env) info.si_errno = 0; info.si_code = TARGET_SEGV_MAPERR; info._sifields._sigfault._addr = env->tea; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; default: @@ -2892,7 +2892,7 @@ void cpu_loop(CPUCRISState *env) /* XXX: check env->error_code */ info.si_code = TARGET_SEGV_MAPERR; info._sifields._sigfault._addr = env->pregs[PR_EDA]; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } break; case EXCP_INTERRUPT: @@ -2924,7 +2924,7 @@ void cpu_loop(CPUCRISState *env) info.si_signo = sig; info.si_errno = 0; info.si_code = TARGET_TRAP_BRKPT; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } } break; @@ -2957,7 +2957,7 @@ void cpu_loop(CPUMBState *env) /* XXX: check env->error_code */ info.si_code = TARGET_SEGV_MAPERR; info._sifields._sigfault._addr = 0; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } break; case EXCP_INTERRUPT: @@ -3006,7 +3006,7 @@ void cpu_loop(CPUMBState *env) info.si_errno = 0; info.si_code = TARGET_FPE_FLTDIV; info._sifields._sigfault._addr = 0; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case ESR_EC_FPU: info.si_signo = TARGET_SIGFPE; @@ -3018,7 +3018,7 @@ void cpu_loop(CPUMBState *env) info.si_code = TARGET_FPE_FLTDIV; } info._sifields._sigfault._addr = 0; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; default: printf ("Unhandled hw-exception: 0x%x\n", @@ -3038,7 +3038,7 @@ void cpu_loop(CPUMBState *env) info.si_signo = sig; info.si_errno = 0; info.si_code = TARGET_TRAP_BRKPT; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } } break; @@ -3092,7 +3092,7 @@ void cpu_loop(CPUM68KState *env) info.si_errno = 0; info.si_code = TARGET_ILL_ILLOPN; info._sifields._sigfault._addr = env->pc; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case EXCP_TRAP0: { @@ -3126,7 +3126,7 @@ void cpu_loop(CPUM68KState *env) /* XXX: check env->error_code */ info.si_code = TARGET_SEGV_MAPERR; info._sifields._sigfault._addr = env->mmu.ar; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } break; case EXCP_DEBUG: @@ -3139,7 +3139,7 @@ void cpu_loop(CPUM68KState *env) info.si_signo = sig; info.si_errno = 0; info.si_code = TARGET_TRAP_BRKPT; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } } break; @@ -3195,7 +3195,7 @@ static void do_store_exclusive(CPUAlphaState *env, int reg, int quad) info.si_errno = 0; info.si_code = TARGET_SEGV_MAPERR; info._sifields._sigfault._addr = addr; - queue_signal(env, TARGET_SIGSEGV, &info); + queue_signal(env, TARGET_SIGSEGV, QEMU_SI_FAULT, &info); } void cpu_loop(CPUAlphaState *env) @@ -3237,7 +3237,7 @@ void cpu_loop(CPUAlphaState *env) info.si_code = (page_get_flags(env->trap_arg0) & PAGE_VALID ? TARGET_SEGV_ACCERR : TARGET_SEGV_MAPERR); info._sifields._sigfault._addr = env->trap_arg0; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case EXCP_UNALIGN: env->lock_addr = -1; @@ -3245,7 +3245,7 @@ void cpu_loop(CPUAlphaState *env) info.si_errno = 0; info.si_code = TARGET_BUS_ADRALN; info._sifields._sigfault._addr = env->trap_arg0; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case EXCP_OPCDEC: do_sigill: @@ -3254,7 +3254,7 @@ void cpu_loop(CPUAlphaState *env) info.si_errno = 0; info.si_code = TARGET_ILL_ILLOPC; info._sifields._sigfault._addr = env->pc; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case EXCP_ARITH: env->lock_addr = -1; @@ -3262,7 +3262,7 @@ void cpu_loop(CPUAlphaState *env) info.si_errno = 0; info.si_code = TARGET_FPE_FLTINV; info._sifields._sigfault._addr = env->pc; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case EXCP_FEN: /* No-op. Linux simply re-enables the FPU. */ @@ -3276,7 +3276,7 @@ void cpu_loop(CPUAlphaState *env) info.si_errno = 0; info.si_code = TARGET_TRAP_BRKPT; info._sifields._sigfault._addr = env->pc; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case 0x81: /* BUGCHK */ @@ -3284,7 +3284,7 @@ void cpu_loop(CPUAlphaState *env) info.si_errno = 0; info.si_code = 0; info._sifields._sigfault._addr = env->pc; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case 0x83: /* CALLSYS */ @@ -3356,7 +3356,7 @@ void cpu_loop(CPUAlphaState *env) } info.si_errno = 0; info._sifields._sigfault._addr = env->pc; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; default: goto do_sigill; @@ -3368,7 +3368,7 @@ void cpu_loop(CPUAlphaState *env) env->lock_addr = -1; info.si_errno = 0; info.si_code = TARGET_TRAP_BRKPT; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } break; case EXCP_STL_C: @@ -3502,7 +3502,7 @@ void cpu_loop(CPUS390XState *env) info.si_errno = 0; info.si_code = n; info._sifields._sigfault._addr = addr; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; default: @@ -3526,7 +3526,7 @@ static void gen_sigill_reg(CPUTLGState *env) info.si_errno = 0; info.si_code = TARGET_ILL_PRVREG; info._sifields._sigfault._addr = env->pc; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } static void do_signal(CPUTLGState *env, int signo, int sigcode) @@ -3550,7 +3550,7 @@ static void do_signal(CPUTLGState *env, int signo, int sigcode) } info.si_code = sigcode; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } static void gen_sigsegv_maperr(CPUTLGState *env, target_ulong addr) diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 61808f6f357..da73a01106b 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -377,7 +377,8 @@ extern int do_strace; /* signal.c */ void process_pending_signals(CPUArchState *cpu_env); void signal_init(void); -int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info); +int queue_signal(CPUArchState *env, int sig, int si_type, + target_siginfo_t *info); void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info); void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo); int target_to_host_signal(int sig); diff --git a/linux-user/signal.c b/linux-user/signal.c index f2c9f8e474c..93a92936415 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -569,19 +569,15 @@ static void QEMU_NORETURN force_sig(int target_sig) /* queue a signal so that it will be send to the virtual CPU as soon as possible */ -int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info) +int queue_signal(CPUArchState *env, int sig, int si_type, + target_siginfo_t *info) { CPUState *cpu = ENV_GET_CPU(env); TaskState *ts = cpu->opaque; trace_user_queue_signal(env, sig); - /* Currently all callers define siginfo structures which - * use the _sifields._sigfault union member, so we can - * set the type here. If that changes we should push this - * out so the si_type is passed in by callers. - */ - info->si_code = deposit32(info->si_code, 16, 16, QEMU_SI_FAULT); + info->si_code = deposit32(info->si_code, 16, 16, si_type); ts->sync_signal.info = *info; ts->sync_signal.pending = sig; diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 85699f9f31b..27ad6a2a6cd 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -10577,7 +10577,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, info.si_code = si_code; info._sifields._sigfault._addr = ((CPUArchState *)cpu_env)->pc; - queue_signal((CPUArchState *)cpu_env, info.si_signo, &info); + queue_signal((CPUArchState *)cpu_env, info.si_signo, + QEMU_SI_FAULT, &info); } } break; @@ -11665,7 +11666,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, info.si_errno = 0; info.si_code = TARGET_SEGV_MAPERR; info._sifields._sigfault._addr = arg6; - queue_signal((CPUArchState *)cpu_env, info.si_signo, &info); + queue_signal((CPUArchState *)cpu_env, info.si_signo, + QEMU_SI_FAULT, &info); ret = 0xdeadbeef; } From 09391669975a0e2882c181982d4ddee35a0080bb Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 28 Jul 2016 16:44:47 +0100 Subject: [PATCH 130/723] linux-user: SIGSEGV on signal entry need not be fatal A failed write to memory trying to set up the signal frame should trigger a SIGSEGV, but this need not be fatal: the guest has a chance to catch it. Implement this via a force_sigsegv() function with the same behaviour as the kernel function of that name: make sure that we don't try to re-take a failed SIGSEGV, and force a synchronous signal. Reviewed-by: Richard Henderson Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/signal.c | 87 +++++++++++++++++++++++++-------------------- 1 file changed, 49 insertions(+), 38 deletions(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index 93a92936415..892b527a37f 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -512,6 +512,33 @@ void signal_init(void) } } +#if !((defined(TARGET_ARM) && !defined(TARGET_AARCH64)) || \ + defined(TARGET_X86_64) || defined(TARGET_UNICORE32)) + +/* Force a SIGSEGV if we couldn't write to memory trying to set + * up the signal frame. oldsig is the signal we were trying to handle + * at the point of failure. + */ +static void force_sigsegv(int oldsig) +{ + CPUState *cpu = thread_cpu; + CPUArchState *env = cpu->env_ptr; + target_siginfo_t info; + + if (oldsig == SIGSEGV) { + /* Make sure we don't try to deliver the signal again; this will + * end up with handle_pending_signal() calling force_sig(). + */ + sigact_table[oldsig - 1]._sa_handler = TARGET_SIG_DFL; + } + info.si_signo = TARGET_SIGSEGV; + info.si_errno = 0; + info.si_code = TARGET_SI_KERNEL; + info._sifields._kill._pid = 0; + info._sifields._kill._uid = 0; + queue_signal(env, info.si_signo, QEMU_SI_KILL, &info); +} +#endif /* abort execution with signal */ static void QEMU_NORETURN force_sig(int target_sig) @@ -1011,10 +1038,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, return; give_sigsegv: - if (sig == TARGET_SIGSEGV) { - ka->_sa_handler = TARGET_SIG_DFL; - } - force_sig(TARGET_SIGSEGV /* , current */); + force_sigsegv(sig); } /* compare linux/arch/i386/kernel/signal.c:setup_rt_frame() */ @@ -1084,10 +1108,7 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, return; give_sigsegv: - if (sig == TARGET_SIGSEGV) { - ka->_sa_handler = TARGET_SIG_DFL; - } - force_sig(TARGET_SIGSEGV /* , current */); + force_sigsegv(sig); } static int @@ -1416,7 +1437,7 @@ static void target_setup_frame(int usig, struct target_sigaction *ka, give_sigsegv: unlock_user_struct(frame, frame_addr, 1); - force_sig(TARGET_SIGSEGV); + force_sigsegv(usig); } static void setup_rt_frame(int sig, struct target_sigaction *ka, @@ -2441,7 +2462,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, #endif sigsegv: unlock_user(sf, sf_addr, sizeof(struct target_signal_frame)); - force_sig(TARGET_SIGSEGV); + force_sigsegv(sig); } static void setup_rt_frame(int sig, struct target_sigaction *ka, @@ -3033,7 +3054,7 @@ static void setup_frame(int sig, struct target_sigaction * ka, return; give_sigsegv: - force_sig(TARGET_SIGSEGV/*, current*/); + force_sigsegv(sig); } long do_sigreturn(CPUMIPSState *regs) @@ -3142,7 +3163,7 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, give_sigsegv: unlock_user_struct(frame, frame_addr, 1); - force_sig(TARGET_SIGSEGV/*, current*/); + force_sigsegv(sig); } long do_rt_sigreturn(CPUMIPSState *env) @@ -3345,7 +3366,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, give_sigsegv: unlock_user_struct(frame, frame_addr, 1); - force_sig(TARGET_SIGSEGV); + force_sigsegv(sig); } static void setup_rt_frame(int sig, struct target_sigaction *ka, @@ -3405,7 +3426,7 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, give_sigsegv: unlock_user_struct(frame, frame_addr, 1); - force_sig(TARGET_SIGSEGV); + force_sigsegv(sig); } long do_sigreturn(CPUSH4State *regs) @@ -3652,7 +3673,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, unlock_user_struct(frame, frame_addr, 1); return; badframe: - force_sig(TARGET_SIGSEGV); + force_sigsegv(sig); } static void setup_rt_frame(int sig, struct target_sigaction *ka, @@ -3822,7 +3843,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, unlock_user_struct(frame, frame_addr, 1); return; badframe: - force_sig(TARGET_SIGSEGV); + force_sigsegv(sig); } static void setup_rt_frame(int sig, struct target_sigaction *ka, @@ -4061,10 +4082,7 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, give_sigsegv: unlock_user_struct(frame, frame_addr, 1); - if (sig == TARGET_SIGSEGV) { - ka->_sa_handler = TARGET_SIG_DFL; - } - force_sig(TARGET_SIGSEGV); + force_sigsegv(sig); } long do_sigreturn(CPUOpenRISCState *env) @@ -4245,7 +4263,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, return; give_sigsegv: - force_sig(TARGET_SIGSEGV); + force_sigsegv(sig); } static void setup_rt_frame(int sig, struct target_sigaction *ka, @@ -4300,7 +4318,7 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, return; give_sigsegv: - force_sig(TARGET_SIGSEGV); + force_sigsegv(sig); } static int @@ -4811,7 +4829,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, sigsegv: unlock_user_struct(frame, frame_addr, 1); - force_sig(TARGET_SIGSEGV); + force_sigsegv(sig); } static void setup_rt_frame(int sig, struct target_sigaction *ka, @@ -4906,7 +4924,7 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, sigsegv: unlock_user_struct(rt_sf, rt_sf_addr, 1); - force_sig(TARGET_SIGSEGV); + force_sigsegv(sig); } @@ -5155,7 +5173,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, return; give_sigsegv: - force_sig(TARGET_SIGSEGV); + force_sigsegv(sig); } static inline int target_rt_setup_ucontext(struct target_ucontext *uc, @@ -5294,7 +5312,7 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, give_sigsegv: unlock_user_struct(frame, frame_addr, 1); - force_sig(TARGET_SIGSEGV); + force_sigsegv(sig); } long do_sigreturn(CPUM68KState *env) @@ -5501,10 +5519,8 @@ static void setup_frame(int sig, struct target_sigaction *ka, if (err) { give_sigsegv: - if (sig == TARGET_SIGSEGV) { - ka->_sa_handler = TARGET_SIG_DFL; - } - force_sig(TARGET_SIGSEGV); + force_sigsegv(sig); + return; } env->ir[IR_RA] = r26; @@ -5558,10 +5574,8 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, if (err) { give_sigsegv: - if (sig == TARGET_SIGSEGV) { - ka->_sa_handler = TARGET_SIG_DFL; - } - force_sig(TARGET_SIGSEGV); + force_sigsegv(sig); + return; } env->ir[IR_RA] = r26; @@ -5758,10 +5772,7 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, return; give_sigsegv: - if (sig == TARGET_SIGSEGV) { - ka->_sa_handler = TARGET_SIG_DFL; - } - force_sig(TARGET_SIGSEGV /* , current */); + force_sigsegv(sig); } long do_rt_sigreturn(CPUTLGState *env) From 28298c912e2c379f2b7767b351beeb77f001f27f Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 28 Jul 2016 16:44:48 +0100 Subject: [PATCH 131/723] linux-user: ARM: Give SIGSEGV if signal frame setup fails The 32-bit ARM signal frame setup code was just bailing out on error returns from lock_user_struct calls, without generating the SIGSEGV that should happen here. Wire up error return codes to call force_sigsegv(). Reviewed-by: Richard Henderson Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/signal.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index 892b527a37f..43836960c15 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -512,8 +512,7 @@ void signal_init(void) } } -#if !((defined(TARGET_ARM) && !defined(TARGET_AARCH64)) || \ - defined(TARGET_X86_64) || defined(TARGET_UNICORE32)) +#if !(defined(TARGET_X86_64) || defined(TARGET_UNICORE32)) /* Force a SIGSEGV if we couldn't write to memory trying to set * up the signal frame. oldsig is the signal we were trying to handle @@ -1789,7 +1788,7 @@ static void setup_frame_v1(int usig, struct target_sigaction *ka, trace_user_setup_frame(regs, frame_addr); if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { - return; + goto sigsegv; } setup_sigcontext(&frame->sc, regs, set->sig[0]); @@ -1802,6 +1801,9 @@ static void setup_frame_v1(int usig, struct target_sigaction *ka, frame_addr + offsetof(struct sigframe_v1, retcode)); unlock_user_struct(frame, frame_addr, 1); + return; +sigsegv: + force_sigsegv(usig); } static void setup_frame_v2(int usig, struct target_sigaction *ka, @@ -1812,7 +1814,7 @@ static void setup_frame_v2(int usig, struct target_sigaction *ka, trace_user_setup_frame(regs, frame_addr); if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { - return; + goto sigsegv; } setup_sigframe_v2(&frame->uc, set, regs); @@ -1821,6 +1823,9 @@ static void setup_frame_v2(int usig, struct target_sigaction *ka, frame_addr + offsetof(struct sigframe_v2, retcode)); unlock_user_struct(frame, frame_addr, 1); + return; +sigsegv: + force_sigsegv(usig); } static void setup_frame(int usig, struct target_sigaction *ka, @@ -1846,7 +1851,7 @@ static void setup_rt_frame_v1(int usig, struct target_sigaction *ka, trace_user_setup_rt_frame(env, frame_addr); if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { - return /* 1 */; + goto sigsegv; } info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info); @@ -1876,6 +1881,9 @@ static void setup_rt_frame_v1(int usig, struct target_sigaction *ka, env->regs[2] = uc_addr; unlock_user_struct(frame, frame_addr, 1); + return; +sigsegv: + force_sigsegv(usig); } static void setup_rt_frame_v2(int usig, struct target_sigaction *ka, @@ -1888,7 +1896,7 @@ static void setup_rt_frame_v2(int usig, struct target_sigaction *ka, trace_user_setup_rt_frame(env, frame_addr); if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { - return /* 1 */; + goto sigsegv; } info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info); @@ -1904,6 +1912,9 @@ static void setup_rt_frame_v2(int usig, struct target_sigaction *ka, env->regs[2] = uc_addr; unlock_user_struct(frame, frame_addr, 1); + return; +sigsegv: + force_sigsegv(usig); } static void setup_rt_frame(int usig, struct target_sigaction *ka, From c599d4d6d6e9bfdb64e54c33a22cb26e3496b96d Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 28 Jul 2016 16:44:49 +0100 Subject: [PATCH 132/723] linux-user: SIGSEGV from sigreturn need not be fatal If the sigreturn syscall fails to read memory then this causes a SIGSEGV, but this is not necessarily a fatal signal -- the guest process can catch it. We don't implement this correctly because the behaviour of QEMU's force_sig() function has drifted away from the kernel function of the same name -- ours now does "always do a guest core dump and abort execution", whereas the kernel version simply forces the guest to take a signal, which may or may not eventually cause a core dump. Rename our force_sig() to dump_core_and_abort(), and provide a force_sig() which acts more like the kernel version as the sigreturn implementations expect it to. Since force_sig() now returns, we must update all the callsites to return -TARGET_QEMU_ESIGRETURN so that the main loop doesn't change the guest registers before the signal handler is invoked. Reviewed-by: Richard Henderson Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/signal.c | 81 ++++++++++++++++++++++++++++++--------------- 1 file changed, 54 insertions(+), 27 deletions(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index 43836960c15..60fda18117b 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -512,6 +512,27 @@ void signal_init(void) } } +#if !defined(TARGET_OPENRISC) && !defined(TARGET_UNICORE32) && \ + !defined(TARGET_X86_64) +/* Force a synchronously taken signal. The kernel force_sig() function + * also forces the signal to "not blocked, not ignored", but for QEMU + * that work is done in process_pending_signals(). + */ +static void force_sig(int sig) +{ + CPUState *cpu = thread_cpu; + CPUArchState *env = cpu->env_ptr; + target_siginfo_t info; + + info.si_signo = sig; + info.si_errno = 0; + info.si_code = TARGET_SI_KERNEL; + info._sifields._kill._pid = 0; + info._sifields._kill._uid = 0; + queue_signal(env, info.si_signo, QEMU_SI_KILL, &info); +} +#endif + #if !(defined(TARGET_X86_64) || defined(TARGET_UNICORE32)) /* Force a SIGSEGV if we couldn't write to memory trying to set @@ -526,7 +547,7 @@ static void force_sigsegv(int oldsig) if (oldsig == SIGSEGV) { /* Make sure we don't try to deliver the signal again; this will - * end up with handle_pending_signal() calling force_sig(). + * end up with handle_pending_signal() calling dump_core_and_abort(). */ sigact_table[oldsig - 1]._sa_handler = TARGET_SIG_DFL; } @@ -540,7 +561,7 @@ static void force_sigsegv(int oldsig) #endif /* abort execution with signal */ -static void QEMU_NORETURN force_sig(int target_sig) +static void QEMU_NORETURN dump_core_and_abort(int target_sig) { CPUState *cpu = thread_cpu; CPUArchState *env = cpu->env_ptr; @@ -1181,7 +1202,7 @@ long do_sigreturn(CPUX86State *env) badframe: unlock_user_struct(frame, frame_addr, 0); force_sig(TARGET_SIGSEGV); - return 0; + return -TARGET_QEMU_ESIGRETURN; } long do_rt_sigreturn(CPUX86State *env) @@ -1212,7 +1233,7 @@ long do_rt_sigreturn(CPUX86State *env) badframe: unlock_user_struct(frame, frame_addr, 0); force_sig(TARGET_SIGSEGV); - return 0; + return -TARGET_QEMU_ESIGRETURN; } #elif defined(TARGET_AARCH64) @@ -1482,7 +1503,7 @@ long do_rt_sigreturn(CPUARMState *env) badframe: unlock_user_struct(frame, frame_addr, 0); force_sig(TARGET_SIGSEGV); - return 0; + return -TARGET_QEMU_ESIGRETURN; } long do_sigreturn(CPUARMState *env) @@ -2004,8 +2025,8 @@ static long do_sigreturn_v1(CPUARMState *env) return -TARGET_QEMU_ESIGRETURN; badframe: - force_sig(TARGET_SIGSEGV /* , current */); - return 0; + force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; } static abi_ulong *restore_sigframe_v2_vfp(CPUARMState *env, abi_ulong *regspace) @@ -2131,8 +2152,8 @@ static long do_sigreturn_v2(CPUARMState *env) badframe: unlock_user_struct(frame, frame_addr, 0); - force_sig(TARGET_SIGSEGV /* , current */); - return 0; + force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; } long do_sigreturn(CPUARMState *env) @@ -2185,8 +2206,8 @@ static long do_rt_sigreturn_v1(CPUARMState *env) badframe: unlock_user_struct(frame, frame_addr, 0); - force_sig(TARGET_SIGSEGV /* , current */); - return 0; + force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; } static long do_rt_sigreturn_v2(CPUARMState *env) @@ -2218,8 +2239,8 @@ static long do_rt_sigreturn_v2(CPUARMState *env) badframe: unlock_user_struct(frame, frame_addr, 0); - force_sig(TARGET_SIGSEGV /* , current */); - return 0; + force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; } long do_rt_sigreturn(CPUARMState *env) @@ -2553,6 +2574,7 @@ long do_sigreturn(CPUSPARCState *env) segv_and_exit: unlock_user_struct(sf, sf_addr, 0); force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; } long do_rt_sigreturn(CPUSPARCState *env) @@ -3110,8 +3132,8 @@ long do_sigreturn(CPUMIPSState *regs) return -TARGET_QEMU_ESIGRETURN; badframe: - force_sig(TARGET_SIGSEGV/*, current*/); - return 0; + force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; } # endif /* O32 */ @@ -3207,8 +3229,8 @@ long do_rt_sigreturn(CPUMIPSState *env) return -TARGET_QEMU_ESIGRETURN; badframe: - force_sig(TARGET_SIGSEGV/*, current*/); - return 0; + force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; } #elif defined(TARGET_SH4) @@ -3474,7 +3496,7 @@ long do_sigreturn(CPUSH4State *regs) badframe: unlock_user_struct(frame, frame_addr, 0); force_sig(TARGET_SIGSEGV); - return 0; + return -TARGET_QEMU_ESIGRETURN; } long do_rt_sigreturn(CPUSH4State *regs) @@ -3506,7 +3528,7 @@ long do_rt_sigreturn(CPUSH4State *regs) badframe: unlock_user_struct(frame, frame_addr, 0); force_sig(TARGET_SIGSEGV); - return 0; + return -TARGET_QEMU_ESIGRETURN; } #elif defined(TARGET_MICROBLAZE) @@ -3725,6 +3747,7 @@ long do_sigreturn(CPUMBState *env) return -TARGET_QEMU_ESIGRETURN; badframe: force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; } long do_rt_sigreturn(CPUMBState *env) @@ -3892,6 +3915,7 @@ long do_sigreturn(CPUCRISState *env) return -TARGET_QEMU_ESIGRETURN; badframe: force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; } long do_rt_sigreturn(CPUCRISState *env) @@ -4383,7 +4407,7 @@ long do_sigreturn(CPUS390XState *env) badframe: force_sig(TARGET_SIGSEGV); - return 0; + return -TARGET_QEMU_ESIGRETURN; } long do_rt_sigreturn(CPUS390XState *env) @@ -4414,7 +4438,7 @@ long do_rt_sigreturn(CPUS390XState *env) badframe: unlock_user_struct(frame, frame_addr, 0); force_sig(TARGET_SIGSEGV); - return 0; + return -TARGET_QEMU_ESIGRETURN; } #elif defined(TARGET_PPC) @@ -4973,7 +4997,7 @@ long do_sigreturn(CPUPPCState *env) unlock_user_struct(sr, sr_addr, 1); unlock_user_struct(sc, sc_addr, 1); force_sig(TARGET_SIGSEGV); - return 0; + return -TARGET_QEMU_ESIGRETURN; } /* See arch/powerpc/kernel/signal_32.c. */ @@ -5028,7 +5052,7 @@ long do_rt_sigreturn(CPUPPCState *env) sigsegv: unlock_user_struct(rt_sf, rt_sf_addr, 1); force_sig(TARGET_SIGSEGV); - return 0; + return -TARGET_QEMU_ESIGRETURN; } #elif defined(TARGET_M68K) @@ -5358,7 +5382,7 @@ long do_sigreturn(CPUM68KState *env) badframe: force_sig(TARGET_SIGSEGV); - return 0; + return -TARGET_QEMU_ESIGRETURN; } long do_rt_sigreturn(CPUM68KState *env) @@ -5391,7 +5415,7 @@ long do_rt_sigreturn(CPUM68KState *env) badframe: unlock_user_struct(frame, frame_addr, 0); force_sig(TARGET_SIGSEGV); - return 0; + return -TARGET_QEMU_ESIGRETURN; } #elif defined(TARGET_ALPHA) @@ -5620,6 +5644,7 @@ long do_sigreturn(CPUAlphaState *env) badframe: force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; } long do_rt_sigreturn(CPUAlphaState *env) @@ -5649,6 +5674,7 @@ long do_rt_sigreturn(CPUAlphaState *env) badframe: unlock_user_struct(frame, frame_addr, 0); force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; } #elif defined(TARGET_TILEGX) @@ -5813,6 +5839,7 @@ long do_rt_sigreturn(CPUTLGState *env) badframe: unlock_user_struct(frame, frame_addr, 0); force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; } #else @@ -5879,12 +5906,12 @@ static void handle_pending_signal(CPUArchState *cpu_env, int sig, sig != TARGET_SIGURG && sig != TARGET_SIGWINCH && sig != TARGET_SIGCONT) { - force_sig(sig); + dump_core_and_abort(sig); } } else if (handler == TARGET_SIG_IGN) { /* ignore sig */ } else if (handler == TARGET_SIG_ERR) { - force_sig(sig); + dump_core_and_abort(sig); } else { /* compute the blocked signals during the handler execution */ sigset_t *blocked_set; From c4b3574402053a88612eab3b66a53825a00145a2 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 28 Jul 2016 16:44:50 +0100 Subject: [PATCH 133/723] linux-user: Implement force_sigsegv() via force_sig() Now that we have a force_sig() with the semantics we need, we can implement force_sigsegv() to call it rather than open-coding the call to queue_signal(). Reviewed-by: Richard Henderson Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/signal.c | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index 60fda18117b..900ee3515a5 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -512,8 +512,7 @@ void signal_init(void) } } -#if !defined(TARGET_OPENRISC) && !defined(TARGET_UNICORE32) && \ - !defined(TARGET_X86_64) +#if !(defined(TARGET_X86_64) || defined(TARGET_UNICORE32)) /* Force a synchronously taken signal. The kernel force_sig() function * also forces the signal to "not blocked, not ignored", but for QEMU * that work is done in process_pending_signals(). @@ -531,9 +530,6 @@ static void force_sig(int sig) info._sifields._kill._uid = 0; queue_signal(env, info.si_signo, QEMU_SI_KILL, &info); } -#endif - -#if !(defined(TARGET_X86_64) || defined(TARGET_UNICORE32)) /* Force a SIGSEGV if we couldn't write to memory trying to set * up the signal frame. oldsig is the signal we were trying to handle @@ -541,22 +537,13 @@ static void force_sig(int sig) */ static void force_sigsegv(int oldsig) { - CPUState *cpu = thread_cpu; - CPUArchState *env = cpu->env_ptr; - target_siginfo_t info; - if (oldsig == SIGSEGV) { /* Make sure we don't try to deliver the signal again; this will * end up with handle_pending_signal() calling dump_core_and_abort(). */ sigact_table[oldsig - 1]._sa_handler = TARGET_SIG_DFL; } - info.si_signo = TARGET_SIGSEGV; - info.si_errno = 0; - info.si_code = TARGET_SI_KERNEL; - info._sifields._kill._pid = 0; - info._sifields._kill._uid = 0; - queue_signal(env, info.si_signo, QEMU_SI_KILL, &info); + force_sig(TARGET_SIGSEGV); } #endif From 7cfbd386b92e93fbfae033b9ac89a20d1fe72573 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 2 Aug 2016 18:41:26 +0100 Subject: [PATCH 134/723] linux-user: Remove unnecessary nptl_flags variable from do_fork() The 'nptl_flags' variable in do_fork() is set to a copy of 'flags', and then the CLONE_NPTL_FLAGS are cleared out of 'flags'. However the only effect of this is that the later check on "if (flags & CLONE_PARENT_SETTID)" is never true. Since we will already have done the setting of parent_tidptr in clone_func() in the child thread, we don't need to do it again. Delete the dead if() and the clearing of CLONE_NPTL_FLAGS from 'flags', and then use 'flags' where we were previously using 'nptl_flags', so we can delete the unnecessary variable. Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/syscall.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 27ad6a2a6cd..3b7b51f6c78 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -6011,7 +6011,6 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, TaskState *ts; CPUState *new_cpu; CPUArchState *new_env; - unsigned int nptl_flags; sigset_t sigmask; /* Emulate vfork() with fork() */ @@ -6034,15 +6033,14 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, ts->bprm = parent_ts->bprm; ts->info = parent_ts->info; ts->signal_mask = parent_ts->signal_mask; - nptl_flags = flags; - flags &= ~CLONE_NPTL_FLAGS2; - if (nptl_flags & CLONE_CHILD_CLEARTID) { + if (flags & CLONE_CHILD_CLEARTID) { ts->child_tidptr = child_tidptr; } - if (nptl_flags & CLONE_SETTLS) + if (flags & CLONE_SETTLS) { cpu_set_tls (new_env, newtls); + } /* Grab a mutex so that thread setup appears atomic. */ pthread_mutex_lock(&clone_lock); @@ -6052,10 +6050,12 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, pthread_mutex_lock(&info.mutex); pthread_cond_init(&info.cond, NULL); info.env = new_env; - if (nptl_flags & CLONE_CHILD_SETTID) + if (flags & CLONE_CHILD_SETTID) { info.child_tidptr = child_tidptr; - if (nptl_flags & CLONE_PARENT_SETTID) + } + if (flags & CLONE_PARENT_SETTID) { info.parent_tidptr = parent_tidptr; + } ret = pthread_attr_init(&attr); ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE); @@ -6074,8 +6074,6 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, /* Wait for the child to initialize. */ pthread_cond_wait(&info.cond, &info.mutex); ret = info.tid; - if (flags & CLONE_PARENT_SETTID) - put_user_u32(ret, parent_tidptr); } else { ret = -1; } From 5ea2fc84da1bffce749c9d0848f5336def2818bb Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 2 Aug 2016 18:41:27 +0100 Subject: [PATCH 135/723] linux-user: Sanity check clone flags We currently make no checks on the flags passed to the clone syscall, which means we will not fail clone attempts which ask for features that we can't implement. Add sanity checking of the flags to clone (which we were already doing in the "this is a fork" path, but not for the "this is a new thread" path), tidy up the checking in the fork path to match it, and check that the fork case isn't trying to specify a custom termination signal. This is helpful in causing some LTP test cases to fail cleanly rather than behaving bizarrely when we let the clone succeed but didn't provide the semantics requested by the flags. Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/syscall.c | 66 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 3 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 3b7b51f6c78..d7e4d9ff2f3 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -112,8 +112,56 @@ int __clone2(int (*fn)(void *), void *child_stack_base, #include "qemu.h" -#define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \ - CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID) +#ifndef CLONE_IO +#define CLONE_IO 0x80000000 /* Clone io context */ +#endif + +/* We can't directly call the host clone syscall, because this will + * badly confuse libc (breaking mutexes, for example). So we must + * divide clone flags into: + * * flag combinations that look like pthread_create() + * * flag combinations that look like fork() + * * flags we can implement within QEMU itself + * * flags we can't support and will return an error for + */ +/* For thread creation, all these flags must be present; for + * fork, none must be present. + */ +#define CLONE_THREAD_FLAGS \ + (CLONE_VM | CLONE_FS | CLONE_FILES | \ + CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM) + +/* These flags are ignored: + * CLONE_DETACHED is now ignored by the kernel; + * CLONE_IO is just an optimisation hint to the I/O scheduler + */ +#define CLONE_IGNORED_FLAGS \ + (CLONE_DETACHED | CLONE_IO) + +/* Flags for fork which we can implement within QEMU itself */ +#define CLONE_OPTIONAL_FORK_FLAGS \ + (CLONE_SETTLS | CLONE_PARENT_SETTID | \ + CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID) + +/* Flags for thread creation which we can implement within QEMU itself */ +#define CLONE_OPTIONAL_THREAD_FLAGS \ + (CLONE_SETTLS | CLONE_PARENT_SETTID | \ + CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID | CLONE_PARENT) + +#define CLONE_INVALID_FORK_FLAGS \ + (~(CSIGNAL | CLONE_OPTIONAL_FORK_FLAGS | CLONE_IGNORED_FLAGS)) + +#define CLONE_INVALID_THREAD_FLAGS \ + (~(CSIGNAL | CLONE_THREAD_FLAGS | CLONE_OPTIONAL_THREAD_FLAGS | \ + CLONE_IGNORED_FLAGS)) + +/* CLONE_VFORK is special cased early in do_fork(). The other flag bits + * have almost all been allocated. We cannot support any of + * CLONE_NEWNS, CLONE_NEWCGROUP, CLONE_NEWUTS, CLONE_NEWIPC, + * CLONE_NEWUSER, CLONE_NEWPID, CLONE_NEWNET, CLONE_PTRACE, CLONE_UNTRACED. + * The checks against the invalid thread masks above will catch these. + * (The one remaining unallocated bit is 0x1000 which used to be CLONE_PID.) + */ //#define DEBUG /* Define DEBUG_ERESTARTSYS to force every syscall to be restarted @@ -6013,6 +6061,8 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, CPUArchState *new_env; sigset_t sigmask; + flags &= ~CLONE_IGNORED_FLAGS; + /* Emulate vfork() with fork() */ if (flags & CLONE_VFORK) flags &= ~(CLONE_VFORK | CLONE_VM); @@ -6022,6 +6072,11 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, new_thread_info info; pthread_attr_t attr; + if (((flags & CLONE_THREAD_FLAGS) != CLONE_THREAD_FLAGS) || + (flags & CLONE_INVALID_THREAD_FLAGS)) { + return -TARGET_EINVAL; + } + ts = g_new0(TaskState, 1); init_task_state(ts); /* we create a new CPU instance. */ @@ -6083,7 +6138,12 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, pthread_mutex_unlock(&clone_lock); } else { /* if no CLONE_VM, we consider it is a fork */ - if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0) { + if (flags & CLONE_INVALID_FORK_FLAGS) { + return -TARGET_EINVAL; + } + + /* We can't support custom termination signals */ + if ((flags & CSIGNAL) != TARGET_SIGCHLD) { return -TARGET_EINVAL; } From 45eafb4d32ced9ff1dcb3800c89f8beaf47b61cc Mon Sep 17 00:00:00 2001 From: Timothy E Baldwin Date: Fri, 9 Sep 2016 19:35:58 +0100 Subject: [PATCH 136/723] linux-user: Fix incorrect offset of tuc_stack in ARM do_sigframe_return_v2 struct target_ucontext_v2 is not at the begining of the signal frame, therefore do_sigaltstack was being passed bogus arguments. As the offset depends on the type of signal frame fixed by passing in the beginning of the context from do_sigreturn_v2 and do_rt_sigreturn_v2. Suggested-by: Peter Maydell Reviewed-by: Peter Maydell Signed-off-by: Timothy Edward Baldwin Signed-off-by: Riku Voipio --- linux-user/signal.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index 900ee3515a5..e4eea697b44 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -2071,7 +2071,8 @@ static abi_ulong *restore_sigframe_v2_iwmmxt(CPUARMState *env, return (abi_ulong*)(iwmmxtframe + 1); } -static int do_sigframe_return_v2(CPUARMState *env, target_ulong frame_addr, +static int do_sigframe_return_v2(CPUARMState *env, + target_ulong context_addr, struct target_ucontext_v2 *uc) { sigset_t host_set; @@ -2098,8 +2099,11 @@ static int do_sigframe_return_v2(CPUARMState *env, target_ulong frame_addr, } } - if (do_sigaltstack(frame_addr + offsetof(struct target_ucontext_v2, tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) + if (do_sigaltstack(context_addr + + offsetof(struct target_ucontext_v2, tuc_stack), + 0, get_sp_from_cpustate(env)) == -EFAULT) { return 1; + } #if 0 /* Send SIGTRAP if we're single-stepping */ @@ -2130,7 +2134,10 @@ static long do_sigreturn_v2(CPUARMState *env) goto badframe; } - if (do_sigframe_return_v2(env, frame_addr, &frame->uc)) { + if (do_sigframe_return_v2(env, + frame_addr + + offsetof(struct sigframe_v2, uc), + &frame->uc)) { goto badframe; } @@ -2217,7 +2224,10 @@ static long do_rt_sigreturn_v2(CPUARMState *env) goto badframe; } - if (do_sigframe_return_v2(env, frame_addr, &frame->uc)) { + if (do_sigframe_return_v2(env, + frame_addr + + offsetof(struct rt_sigframe_v2, uc), + &frame->uc)) { goto badframe; } From 5457dc9e37fe0a29989bd64306c63941074864ce Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Fri, 8 Jul 2016 01:17:27 +0200 Subject: [PATCH 137/723] linux-user: fix TARGET_NR_select TARGET_NR_select can have three different implementations: 1- to always return -ENOSYS microblaze, ppc, ppc64 -> TARGET_WANT_NI_OLD_SELECT 2- to take parameters from a structure pointed by arg1 (kernel sys_old_select) i386, arm, m68k -> TARGET_WANT_OLD_SYS_SELECT 3- to take parameters from arg[1-5] (kernel sys_select) x86_64, alpha, s390x, cris, sparc, sparc64 Some (new) architectures don't define NR_select, 4- but only NR__newselect with sys_select: mips, mips64, sh 5- don't define NR__newselect, and use pselect6 syscall: aarch64, openrisc, tilegx, unicore32 Reported-by: Timothy Pearson Reported-by: Allan Wirth Suggested-by: Peter Maydell Reviewed-by: Peter Maydell Signed-off-by: Laurent Vivier Signed-off-by: Riku Voipio --- linux-user/arm/target_syscall.h | 1 + linux-user/i386/target_syscall.h | 1 + linux-user/m68k/target_syscall.h | 2 ++ linux-user/microblaze/target_syscall.h | 2 ++ linux-user/openrisc/syscall_nr.h | 2 -- linux-user/ppc/target_syscall.h | 1 + linux-user/sh4/syscall_nr.h | 2 +- linux-user/syscall.c | 48 +++++++++++++++++--------- linux-user/tilegx/syscall_nr.h | 1 - 9 files changed, 39 insertions(+), 21 deletions(-) diff --git a/linux-user/arm/target_syscall.h b/linux-user/arm/target_syscall.h index 0879b4d4a86..94e2a42cb2e 100644 --- a/linux-user/arm/target_syscall.h +++ b/linux-user/arm/target_syscall.h @@ -32,6 +32,7 @@ struct target_pt_regs { #define TARGET_MINSIGSTKSZ 2048 #define TARGET_MLOCKALL_MCL_CURRENT 1 #define TARGET_MLOCKALL_MCL_FUTURE 2 +#define TARGET_WANT_OLD_SYS_SELECT #define TARGET_FORCE_SHMLBA diff --git a/linux-user/i386/target_syscall.h b/linux-user/i386/target_syscall.h index b4e895fd9c0..2854758134d 100644 --- a/linux-user/i386/target_syscall.h +++ b/linux-user/i386/target_syscall.h @@ -153,5 +153,6 @@ struct target_vm86plus_struct { #define TARGET_MINSIGSTKSZ 2048 #define TARGET_MLOCKALL_MCL_CURRENT 1 #define TARGET_MLOCKALL_MCL_FUTURE 2 +#define TARGET_WANT_OLD_SYS_SELECT #endif /* I386_TARGET_SYSCALL_H */ diff --git a/linux-user/m68k/target_syscall.h b/linux-user/m68k/target_syscall.h index db2be4f1012..632ee4fcf89 100644 --- a/linux-user/m68k/target_syscall.h +++ b/linux-user/m68k/target_syscall.h @@ -24,6 +24,8 @@ struct target_pt_regs { #define TARGET_MLOCKALL_MCL_CURRENT 1 #define TARGET_MLOCKALL_MCL_FUTURE 2 +#define TARGET_WANT_OLD_SYS_SELECT + void do_m68k_simcall(CPUM68KState *, int); #endif /* M68K_TARGET_SYSCALL_H */ diff --git a/linux-user/microblaze/target_syscall.h b/linux-user/microblaze/target_syscall.h index 0b6980c8998..4141cbaa5ec 100644 --- a/linux-user/microblaze/target_syscall.h +++ b/linux-user/microblaze/target_syscall.h @@ -53,4 +53,6 @@ struct target_pt_regs { #define TARGET_MLOCKALL_MCL_CURRENT 1 #define TARGET_MLOCKALL_MCL_FUTURE 2 +#define TARGET_WANT_NI_OLD_SELECT + #endif diff --git a/linux-user/openrisc/syscall_nr.h b/linux-user/openrisc/syscall_nr.h index 6b1c7d265e1..04059d020cc 100644 --- a/linux-user/openrisc/syscall_nr.h +++ b/linux-user/openrisc/syscall_nr.h @@ -459,8 +459,6 @@ #define TARGET_NR_getdents 1065 #define __ARCH_WANT_SYS_GETDENTS #define TARGET_NR_futimesat 1066 -#define TARGET_NR_select 1067 -#define __ARCH_WANT_SYS_SELECT #define TARGET_NR_poll 1068 #define TARGET_NR_epoll_wait 1069 #define TARGET_NR_ustat 1070 diff --git a/linux-user/ppc/target_syscall.h b/linux-user/ppc/target_syscall.h index a8662f48562..afc0570410d 100644 --- a/linux-user/ppc/target_syscall.h +++ b/linux-user/ppc/target_syscall.h @@ -74,5 +74,6 @@ struct target_revectored_struct { #define TARGET_MINSIGSTKSZ 2048 #define TARGET_MLOCKALL_MCL_CURRENT 0x2000 #define TARGET_MLOCKALL_MCL_FUTURE 0x4000 +#define TARGET_WANT_NI_OLD_SELECT #endif /* PPC_TARGET_SYSCALL_H */ diff --git a/linux-user/sh4/syscall_nr.h b/linux-user/sh4/syscall_nr.h index 50099846d22..e99f73589d2 100644 --- a/linux-user/sh4/syscall_nr.h +++ b/linux-user/sh4/syscall_nr.h @@ -84,7 +84,7 @@ #define TARGET_NR_settimeofday 79 #define TARGET_NR_getgroups 80 #define TARGET_NR_setgroups 81 -#define TARGET_NR_select 82 + /* 82 was sys_oldselect */ #define TARGET_NR_symlink 83 #define TARGET_NR_oldlstat 84 #define TARGET_NR_readlink 85 diff --git a/linux-user/syscall.c b/linux-user/syscall.c index d7e4d9ff2f3..7aa2c1d7206 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1444,6 +1444,29 @@ static abi_long do_select(int n, return ret; } + +#if defined(TARGET_WANT_OLD_SYS_SELECT) +static abi_long do_old_select(abi_ulong arg1) +{ + struct target_sel_arg_struct *sel; + abi_ulong inp, outp, exp, tvp; + long nsel; + + if (!lock_user_struct(VERIFY_READ, sel, arg1, 1)) { + return -TARGET_EFAULT; + } + + nsel = tswapal(sel->n); + inp = tswapal(sel->inp); + outp = tswapal(sel->outp); + exp = tswapal(sel->exp); + tvp = tswapal(sel->tvp); + + unlock_user_struct(sel, arg1, 0); + + return do_select(nsel, inp, outp, exp, tvp); +} +#endif #endif static abi_long do_pipe2(int host_pipe[], int flags) @@ -8668,24 +8691,15 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #if defined(TARGET_NR_select) case TARGET_NR_select: -#if defined(TARGET_S390X) || defined(TARGET_ALPHA) - ret = do_select(arg1, arg2, arg3, arg4, arg5); +#if defined(TARGET_WANT_NI_OLD_SELECT) + /* some architectures used to have old_select here + * but now ENOSYS it. + */ + ret = -TARGET_ENOSYS; +#elif defined(TARGET_WANT_OLD_SYS_SELECT) + ret = do_old_select(arg1); #else - { - struct target_sel_arg_struct *sel; - abi_ulong inp, outp, exp, tvp; - long nsel; - - if (!lock_user_struct(VERIFY_READ, sel, arg1, 1)) - goto efault; - nsel = tswapal(sel->n); - inp = tswapal(sel->inp); - outp = tswapal(sel->outp); - exp = tswapal(sel->exp); - tvp = tswapal(sel->tvp); - unlock_user_struct(sel, arg1, 0); - ret = do_select(nsel, inp, outp, exp, tvp); - } + ret = do_select(arg1, arg2, arg3, arg4, arg5); #endif break; #endif diff --git a/linux-user/tilegx/syscall_nr.h b/linux-user/tilegx/syscall_nr.h index 8e30cd1ae96..c104b94230b 100644 --- a/linux-user/tilegx/syscall_nr.h +++ b/linux-user/tilegx/syscall_nr.h @@ -311,7 +311,6 @@ #define TARGET_NR_creat 1064 #define TARGET_NR_getdents 1065 #define TARGET_NR_futimesat 1066 -#define TARGET_NR_select 1067 #define TARGET_NR_poll 1068 #define TARGET_NR_epoll_wait 1069 #define TARGET_NR_ustat 1070 From 73e1b8f2f9b8a90361f9c1af306ee17bfcfd592d Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 22 Sep 2016 14:50:00 +0200 Subject: [PATCH 138/723] target-i386: introduce kvm_put_one_msr Avoid further code duplication in the next patch. Signed-off-by: Paolo Bonzini --- target-i386/kvm.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/target-i386/kvm.c b/target-i386/kvm.c index f1ad805665a..c57b01b558a 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -1532,6 +1532,14 @@ static void kvm_msr_entry_add(X86CPU *cpu, uint32_t index, uint64_t value) msrs->nmsrs++; } +static int kvm_put_one_msr(X86CPU *cpu, int index, uint64_t value) +{ + kvm_msr_buf_reset(cpu); + kvm_msr_entry_add(cpu, index, value); + + return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_MSRS, cpu->kvm_msr_buf); +} + static int kvm_put_tscdeadline_msr(X86CPU *cpu) { CPUX86State *env = &cpu->env; @@ -1541,10 +1549,7 @@ static int kvm_put_tscdeadline_msr(X86CPU *cpu) return 0; } - kvm_msr_buf_reset(cpu); - kvm_msr_entry_add(cpu, MSR_IA32_TSCDEADLINE, env->tsc_deadline); - - ret = kvm_vcpu_ioctl(CPU(cpu), KVM_SET_MSRS, cpu->kvm_msr_buf); + ret = kvm_put_one_msr(cpu, MSR_IA32_TSCDEADLINE, env->tsc_deadline); if (ret < 0) { return ret; } @@ -1567,11 +1572,8 @@ static int kvm_put_msr_feature_control(X86CPU *cpu) return 0; } - kvm_msr_buf_reset(cpu); - kvm_msr_entry_add(cpu, MSR_IA32_FEATURE_CONTROL, - cpu->env.msr_ia32_feature_control); - - ret = kvm_vcpu_ioctl(CPU(cpu), KVM_SET_MSRS, cpu->kvm_msr_buf); + ret = kvm_put_one_msr(cpu, MSR_IA32_FEATURE_CONTROL, + cpu->env.msr_ia32_feature_control); if (ret < 0) { return ret; } From f8d9ccf8d5f9f4b7d364100871c4c7303b546de5 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Thu, 22 Sep 2016 14:49:17 +0200 Subject: [PATCH 139/723] kvm: apic: set APIC base as part of kvm_apic_put The parsing of KVM_SET_LAPIC's input depends on the current value of the APIC base MSR---which indeed is stored in APICCommonState---but for historical reasons APIC base is set through KVM_SET_SREGS together with cr8 (which is really just the APIC TPR) and the actual "special CPU registers". APIC base must now be set before the actual LAPIC registers, so do that in kvm_apic_put. It will be set again to the same value with KVM_SET_SREGS, but that's not a big issue. This only happens since Linux 4.8, which checks for x2apic mode in KVM_SET_LAPIC. However it's really a QEMU bug; until the recent commit 78d6a05 ("x86/lapic: Load LAPIC state at post_load", 2016-09-13) QEMU was indeed setting APIC base (via KVM_SET_SREGS) before the other LAPIC registers. Signed-off-by: Dr. David Alan Gilbert Signed-off-by: Paolo Bonzini --- hw/i386/kvm/apic.c | 2 ++ target-i386/kvm.c | 8 ++++++++ target-i386/kvm_i386.h | 2 ++ 3 files changed, 12 insertions(+) diff --git a/hw/i386/kvm/apic.c b/hw/i386/kvm/apic.c index feb00024f20..f57fed1cb00 100644 --- a/hw/i386/kvm/apic.c +++ b/hw/i386/kvm/apic.c @@ -15,6 +15,7 @@ #include "hw/i386/apic_internal.h" #include "hw/pci/msi.h" #include "sysemu/kvm.h" +#include "target-i386/kvm_i386.h" static inline void kvm_apic_set_reg(struct kvm_lapic_state *kapic, int reg_id, uint32_t val) @@ -130,6 +131,7 @@ static void kvm_apic_put(void *data) struct kvm_lapic_state kapic; int ret; + kvm_put_apicbase(s->cpu, s->apicbase); kvm_put_apic_state(s, &kapic); ret = kvm_vcpu_ioctl(CPU(s->cpu), KVM_SET_LAPIC, &kapic); diff --git a/target-i386/kvm.c b/target-i386/kvm.c index c57b01b558a..f236dafae5f 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -1540,6 +1540,14 @@ static int kvm_put_one_msr(X86CPU *cpu, int index, uint64_t value) return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_MSRS, cpu->kvm_msr_buf); } +void kvm_put_apicbase(X86CPU *cpu, uint64_t value) +{ + int ret; + + ret = kvm_put_one_msr(cpu, MSR_IA32_APICBASE, value); + assert(ret == 1); +} + static int kvm_put_tscdeadline_msr(X86CPU *cpu) { CPUX86State *env = &cpu->env; diff --git a/target-i386/kvm_i386.h b/target-i386/kvm_i386.h index 42b00af1b1c..36407e0a5dc 100644 --- a/target-i386/kvm_i386.h +++ b/target-i386/kvm_i386.h @@ -41,4 +41,6 @@ int kvm_device_msix_set_vector(KVMState *s, uint32_t dev_id, uint32_t vector, int kvm_device_msix_assign(KVMState *s, uint32_t dev_id); int kvm_device_msix_deassign(KVMState *s, uint32_t dev_id); +void kvm_put_apicbase(X86CPU *cpu, uint64_t value); + #endif From dcf578ed8cec89543158b103940e854ebd21a8cf Mon Sep 17 00:00:00 2001 From: Andrey Yurovsky Date: Thu, 22 Sep 2016 18:13:05 +0100 Subject: [PATCH 140/723] arm: add Cortex A7 CPU parameters Add the "cortex-a7" CPU with features and registers matching the Cortex-A7 MPCore Technical Reference Manual and the Cortex-A7 Floating-Point Unit Technical Reference Manual. The A7 is very similar to the A15. Signed-off-by: Andrey Yurovsky Reviewed-by: Peter Maydell Message-id: 1473185229-4597-1-git-send-email-yurovsky@gmail.com Signed-off-by: Peter Maydell --- target-arm/cpu.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/target-arm/cpu.c b/target-arm/cpu.c index ce8b8f4a5ba..1b9540e0850 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -1129,6 +1129,51 @@ static const ARMCPRegInfo cortexa15_cp_reginfo[] = { REGINFO_SENTINEL }; +static void cortex_a7_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "arm,cortex-a7"; + set_feature(&cpu->env, ARM_FEATURE_V7); + set_feature(&cpu->env, ARM_FEATURE_VFP4); + set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_THUMB2EE); + set_feature(&cpu->env, ARM_FEATURE_ARM_DIV); + set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); + set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); + set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); + set_feature(&cpu->env, ARM_FEATURE_LPAE); + set_feature(&cpu->env, ARM_FEATURE_EL3); + cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A7; + cpu->midr = 0x410fc075; + cpu->reset_fpsid = 0x41023075; + cpu->mvfr0 = 0x10110222; + cpu->mvfr1 = 0x11111111; + cpu->ctr = 0x84448003; + cpu->reset_sctlr = 0x00c50078; + cpu->id_pfr0 = 0x00001131; + cpu->id_pfr1 = 0x00011011; + cpu->id_dfr0 = 0x02010555; + cpu->pmceid0 = 0x00000000; + cpu->pmceid1 = 0x00000000; + cpu->id_afr0 = 0x00000000; + cpu->id_mmfr0 = 0x10101105; + cpu->id_mmfr1 = 0x40000000; + cpu->id_mmfr2 = 0x01240000; + cpu->id_mmfr3 = 0x02102211; + cpu->id_isar0 = 0x01101110; + cpu->id_isar1 = 0x13112111; + cpu->id_isar2 = 0x21232041; + cpu->id_isar3 = 0x11112131; + cpu->id_isar4 = 0x10011142; + cpu->dbgdidr = 0x3515f005; + cpu->clidr = 0x0a200023; + cpu->ccsidr[0] = 0x701fe00a; /* 32K L1 dcache */ + cpu->ccsidr[1] = 0x201fe00a; /* 32K L1 icache */ + cpu->ccsidr[2] = 0x711fe07a; /* 4096K L2 unified cache */ + define_arm_cp_regs(cpu, cortexa15_cp_reginfo); /* Same as A15 */ +} + static void cortex_a15_initfn(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); @@ -1385,6 +1430,7 @@ static const ARMCPUInfo arm_cpus[] = { { .name = "cortex-m4", .initfn = cortex_m4_initfn, .class_init = arm_v7m_class_init }, { .name = "cortex-r5", .initfn = cortex_r5_initfn }, + { .name = "cortex-a7", .initfn = cortex_a7_initfn }, { .name = "cortex-a8", .initfn = cortex_a8_initfn }, { .name = "cortex-a9", .initfn = cortex_a9_initfn }, { .name = "cortex-a15", .initfn = cortex_a15_initfn }, From 00442402eaf818c8e0a9c7e79b68c957ea5f1f53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Thu, 22 Sep 2016 18:13:05 +0100 Subject: [PATCH 141/723] ast2400: rename the Aspeed SoC files to aspeed_soc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's prepare for new Aspeed SoCs and rename the ast2400 file to a more generic one. There are no changes in the code apart from the header file include. Signed-off-by: Cédric Le Goater Reviewed-by: Andrew Jeffery Reviewed-by: Peter Maydell Message-id: 1473438177-26079-2-git-send-email-clg@kaod.org Signed-off-by: Peter Maydell --- hw/arm/Makefile.objs | 2 +- hw/arm/{ast2400.c => aspeed_soc.c} | 2 +- hw/arm/palmetto-bmc.c | 2 +- include/hw/arm/{ast2400.h => aspeed_soc.h} | 0 4 files changed, 3 insertions(+), 3 deletions(-) rename hw/arm/{ast2400.c => aspeed_soc.c} (99%) rename include/hw/arm/{ast2400.h => aspeed_soc.h} (100%) diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs index 12764ef2b71..7901294630b 100644 --- a/hw/arm/Makefile.objs +++ b/hw/arm/Makefile.objs @@ -17,4 +17,4 @@ obj-$(CONFIG_XLNX_ZYNQMP) += xlnx-zynqmp.o xlnx-ep108.o obj-$(CONFIG_FSL_IMX25) += fsl-imx25.o imx25_pdk.o obj-$(CONFIG_FSL_IMX31) += fsl-imx31.o kzm.o obj-$(CONFIG_FSL_IMX6) += fsl-imx6.o sabrelite.o -obj-$(CONFIG_ASPEED_SOC) += ast2400.o palmetto-bmc.o +obj-$(CONFIG_ASPEED_SOC) += aspeed_soc.o palmetto-bmc.o diff --git a/hw/arm/ast2400.c b/hw/arm/aspeed_soc.c similarity index 99% rename from hw/arm/ast2400.c rename to hw/arm/aspeed_soc.c index 136bf6464e1..b272f4e48cf 100644 --- a/hw/arm/ast2400.c +++ b/hw/arm/aspeed_soc.c @@ -15,7 +15,7 @@ #include "qemu-common.h" #include "cpu.h" #include "exec/address-spaces.h" -#include "hw/arm/ast2400.h" +#include "hw/arm/aspeed_soc.h" #include "hw/char/serial.h" #include "qemu/log.h" #include "hw/i2c/aspeed_i2c.h" diff --git a/hw/arm/palmetto-bmc.c b/hw/arm/palmetto-bmc.c index 54e29a865d8..67676a8a804 100644 --- a/hw/arm/palmetto-bmc.c +++ b/hw/arm/palmetto-bmc.c @@ -15,7 +15,7 @@ #include "cpu.h" #include "exec/address-spaces.h" #include "hw/arm/arm.h" -#include "hw/arm/ast2400.h" +#include "hw/arm/aspeed_soc.h" #include "hw/boards.h" #include "qemu/log.h" #include "sysemu/block-backend.h" diff --git a/include/hw/arm/ast2400.h b/include/hw/arm/aspeed_soc.h similarity index 100% rename from include/hw/arm/ast2400.h rename to include/hw/arm/aspeed_soc.h From ff90606f9ae5efd78f2ae98f31207c735e8580a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Thu, 22 Sep 2016 18:13:05 +0100 Subject: [PATCH 142/723] ast2400: replace ast2400 with aspeed_soc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a name replacement to prepare ground for other SoCs. Let's also remove the AST2400_SMC_BASE definition from the address space mappings, as it is not used. This controller was removed from the Aspeed SoC AST2500, so this provides us a better common base for the address space mapping on both SoCs. Signed-off-by: Cédric Le Goater Reviewed-by: Andrew Jeffery Reviewed-by: Peter Maydell Message-id: 1473438177-26079-3-git-send-email-clg@kaod.org Signed-off-by: Peter Maydell --- hw/arm/aspeed_soc.c | 95 ++++++++++++++++++------------------- hw/arm/palmetto-bmc.c | 4 +- include/hw/arm/aspeed_soc.h | 16 +++---- 3 files changed, 57 insertions(+), 58 deletions(-) diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index b272f4e48cf..1bec478fef6 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -1,5 +1,5 @@ /* - * AST2400 SoC + * ASPEED SoC family * * Andrew Jeffery * Jeremy Kerr @@ -20,20 +20,19 @@ #include "qemu/log.h" #include "hw/i2c/aspeed_i2c.h" -#define AST2400_UART_5_BASE 0x00184000 -#define AST2400_IOMEM_SIZE 0x00200000 -#define AST2400_IOMEM_BASE 0x1E600000 -#define AST2400_SMC_BASE AST2400_IOMEM_BASE /* Legacy SMC */ -#define AST2400_FMC_BASE 0X1E620000 -#define AST2400_SPI_BASE 0X1E630000 -#define AST2400_VIC_BASE 0x1E6C0000 -#define AST2400_SDMC_BASE 0x1E6E0000 -#define AST2400_SCU_BASE 0x1E6E2000 -#define AST2400_TIMER_BASE 0x1E782000 -#define AST2400_I2C_BASE 0x1E78A000 - -#define AST2400_FMC_FLASH_BASE 0x20000000 -#define AST2400_SPI_FLASH_BASE 0x30000000 +#define ASPEED_SOC_UART_5_BASE 0x00184000 +#define ASPEED_SOC_IOMEM_SIZE 0x00200000 +#define ASPEED_SOC_IOMEM_BASE 0x1E600000 +#define ASPEED_SOC_FMC_BASE 0x1E620000 +#define ASPEED_SOC_SPI_BASE 0x1E630000 +#define ASPEED_SOC_VIC_BASE 0x1E6C0000 +#define ASPEED_SOC_SDMC_BASE 0x1E6E0000 +#define ASPEED_SOC_SCU_BASE 0x1E6E2000 +#define ASPEED_SOC_TIMER_BASE 0x1E782000 +#define ASPEED_SOC_I2C_BASE 0x1E78A000 + +#define ASPEED_SOC_FMC_FLASH_BASE 0x20000000 +#define ASPEED_SOC_SPI_FLASH_BASE 0x30000000 static const int uart_irqs[] = { 9, 32, 33, 34, 10 }; static const int timer_irqs[] = { 16, 17, 18, 35, 36, 37, 38, 39, }; @@ -43,29 +42,29 @@ static const int timer_irqs[] = { 16, 17, 18, 35, 36, 37, 38, 39, }; * handled by a device mapping. */ -static uint64_t ast2400_io_read(void *p, hwaddr offset, unsigned size) +static uint64_t aspeed_soc_io_read(void *p, hwaddr offset, unsigned size) { qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx " [%u]\n", __func__, offset, size); return 0; } -static void ast2400_io_write(void *opaque, hwaddr offset, uint64_t value, +static void aspeed_soc_io_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx " <- 0x%" PRIx64 " [%u]\n", __func__, offset, value, size); } -static const MemoryRegionOps ast2400_io_ops = { - .read = ast2400_io_read, - .write = ast2400_io_write, +static const MemoryRegionOps aspeed_soc_io_ops = { + .read = aspeed_soc_io_read, + .write = aspeed_soc_io_write, .endianness = DEVICE_LITTLE_ENDIAN, }; -static void ast2400_init(Object *obj) +static void aspeed_soc_init(Object *obj) { - AST2400State *s = AST2400(obj); + AspeedSoCState *s = ASPEED_SOC(obj); s->cpu = cpu_arm_init("arm926"); @@ -106,17 +105,17 @@ static void ast2400_init(Object *obj) AST2400_A0_SILICON_REV); } -static void ast2400_realize(DeviceState *dev, Error **errp) +static void aspeed_soc_realize(DeviceState *dev, Error **errp) { int i; - AST2400State *s = AST2400(dev); + AspeedSoCState *s = ASPEED_SOC(dev); Error *err = NULL, *local_err = NULL; /* IO space */ - memory_region_init_io(&s->iomem, NULL, &ast2400_io_ops, NULL, - "ast2400.io", AST2400_IOMEM_SIZE); - memory_region_add_subregion_overlap(get_system_memory(), AST2400_IOMEM_BASE, - &s->iomem, -1); + memory_region_init_io(&s->iomem, NULL, &aspeed_soc_io_ops, NULL, + "aspeed_soc.io", ASPEED_SOC_IOMEM_SIZE); + memory_region_add_subregion_overlap(get_system_memory(), + ASPEED_SOC_IOMEM_BASE, &s->iomem, -1); /* VIC */ object_property_set_bool(OBJECT(&s->vic), true, "realized", &err); @@ -124,7 +123,7 @@ static void ast2400_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->vic), 0, AST2400_VIC_BASE); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->vic), 0, ASPEED_SOC_VIC_BASE); sysbus_connect_irq(SYS_BUS_DEVICE(&s->vic), 0, qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_IRQ)); sysbus_connect_irq(SYS_BUS_DEVICE(&s->vic), 1, @@ -136,7 +135,7 @@ static void ast2400_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->timerctrl), 0, AST2400_TIMER_BASE); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->timerctrl), 0, ASPEED_SOC_TIMER_BASE); for (i = 0; i < ARRAY_SIZE(timer_irqs); i++) { qemu_irq irq = qdev_get_gpio_in(DEVICE(&s->vic), timer_irqs[i]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->timerctrl), i, irq); @@ -148,12 +147,12 @@ static void ast2400_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->scu), 0, AST2400_SCU_BASE); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->scu), 0, ASPEED_SOC_SCU_BASE); /* UART - attach an 8250 to the IO space as our UART5 */ if (serial_hds[0]) { qemu_irq uart5 = qdev_get_gpio_in(DEVICE(&s->vic), uart_irqs[4]); - serial_mm_init(&s->iomem, AST2400_UART_5_BASE, 2, + serial_mm_init(&s->iomem, ASPEED_SOC_UART_5_BASE, 2, uart5, 38400, serial_hds[0], DEVICE_LITTLE_ENDIAN); } @@ -163,7 +162,7 @@ static void ast2400_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c), 0, AST2400_I2C_BASE); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c), 0, ASPEED_SOC_I2C_BASE); sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c), 0, qdev_get_gpio_in(DEVICE(&s->vic), 12)); @@ -175,8 +174,8 @@ static void ast2400_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->smc), 0, AST2400_FMC_BASE); - sysbus_mmio_map(SYS_BUS_DEVICE(&s->smc), 1, AST2400_FMC_FLASH_BASE); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->smc), 0, ASPEED_SOC_FMC_BASE); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->smc), 1, ASPEED_SOC_FMC_FLASH_BASE); sysbus_connect_irq(SYS_BUS_DEVICE(&s->smc), 0, qdev_get_gpio_in(DEVICE(&s->vic), 19)); @@ -188,8 +187,8 @@ static void ast2400_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi), 0, AST2400_SPI_BASE); - sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi), 1, AST2400_SPI_FLASH_BASE); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi), 0, ASPEED_SOC_SPI_BASE); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi), 1, ASPEED_SOC_SPI_FLASH_BASE); /* SDMC - SDRAM Memory Controller */ object_property_set_bool(OBJECT(&s->sdmc), true, "realized", &err); @@ -197,14 +196,14 @@ static void ast2400_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdmc), 0, AST2400_SDMC_BASE); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdmc), 0, ASPEED_SOC_SDMC_BASE); } -static void ast2400_class_init(ObjectClass *oc, void *data) +static void aspeed_soc_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); - dc->realize = ast2400_realize; + dc->realize = aspeed_soc_realize; /* * Reason: creates an ARM CPU, thus use after free(), see @@ -213,17 +212,17 @@ static void ast2400_class_init(ObjectClass *oc, void *data) dc->cannot_destroy_with_object_finalize_yet = true; } -static const TypeInfo ast2400_type_info = { - .name = TYPE_AST2400, +static const TypeInfo aspeed_soc_type_info = { + .name = TYPE_ASPEED_SOC, .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(AST2400State), - .instance_init = ast2400_init, - .class_init = ast2400_class_init, + .instance_size = sizeof(AspeedSoCState), + .instance_init = aspeed_soc_init, + .class_init = aspeed_soc_class_init, }; -static void ast2400_register_types(void) +static void aspeed_soc_register_types(void) { - type_register_static(&ast2400_type_info); + type_register_static(&aspeed_soc_type_info); } -type_init(ast2400_register_types) +type_init(aspeed_soc_register_types) diff --git a/hw/arm/palmetto-bmc.c b/hw/arm/palmetto-bmc.c index 67676a8a804..4d11905cfb1 100644 --- a/hw/arm/palmetto-bmc.c +++ b/hw/arm/palmetto-bmc.c @@ -28,7 +28,7 @@ static struct arm_boot_info palmetto_bmc_binfo = { }; typedef struct PalmettoBMCState { - AST2400State soc; + AspeedSoCState soc; MemoryRegion ram; } PalmettoBMCState; @@ -63,7 +63,7 @@ static void palmetto_bmc_init(MachineState *machine) PalmettoBMCState *bmc; bmc = g_new0(PalmettoBMCState, 1); - object_initialize(&bmc->soc, (sizeof(bmc->soc)), TYPE_AST2400); + object_initialize(&bmc->soc, (sizeof(bmc->soc)), TYPE_ASPEED_SOC); object_property_add_child(OBJECT(machine), "soc", OBJECT(&bmc->soc), &error_abort); diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h index e68807d475b..bf63ae90cab 100644 --- a/include/hw/arm/aspeed_soc.h +++ b/include/hw/arm/aspeed_soc.h @@ -1,5 +1,5 @@ /* - * ASPEED AST2400 SoC + * ASPEED SoC family * * Andrew Jeffery * @@ -9,8 +9,8 @@ * the COPYING file in the top-level directory. */ -#ifndef AST2400_H -#define AST2400_H +#ifndef ASPEED_SOC_H +#define ASPEED_SOC_H #include "hw/arm/arm.h" #include "hw/intc/aspeed_vic.h" @@ -20,7 +20,7 @@ #include "hw/i2c/aspeed_i2c.h" #include "hw/ssi/aspeed_smc.h" -typedef struct AST2400State { +typedef struct AspeedSoCState { /*< private >*/ DeviceState parent; @@ -34,11 +34,11 @@ typedef struct AST2400State { AspeedSMCState smc; AspeedSMCState spi; AspeedSDMCState sdmc; -} AST2400State; +} AspeedSoCState; -#define TYPE_AST2400 "ast2400" -#define AST2400(obj) OBJECT_CHECK(AST2400State, (obj), TYPE_AST2400) +#define TYPE_ASPEED_SOC "aspeed-soc" +#define ASPEED_SOC(obj) OBJECT_CHECK(AspeedSoCState, (obj), TYPE_ASPEED_SOC) #define AST2400_SDRAM_BASE 0x40000000 -#endif /* AST2400_H */ +#endif /* ASPEED_SOC_H */ From b033271f11a17debc1cc3e56f6b9fa319ebe2c45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Thu, 22 Sep 2016 18:13:05 +0100 Subject: [PATCH 143/723] aspeed-soc: provide a framework to add new SoCs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's define an object class for each Aspeed SoC we support. A AspeedSoCInfo struct gathers the SoC specifications which can later be used by an instance of the class or by a board using the SoC. Signed-off-by: Cédric Le Goater Reviewed-by: Andrew Jeffery Message-id: 1473438177-26079-4-git-send-email-clg@kaod.org Signed-off-by: Peter Maydell --- hw/arm/aspeed_soc.c | 38 +++++++++++++++++++++++++++++-------- hw/arm/palmetto-bmc.c | 12 ++++++++---- include/hw/arm/aspeed_soc.h | 17 ++++++++++++++++- 3 files changed, 54 insertions(+), 13 deletions(-) diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index 1bec478fef6..07c9c90d7d3 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -37,6 +37,13 @@ static const int uart_irqs[] = { 9, 32, 33, 34, 10 }; static const int timer_irqs[] = { 16, 17, 18, 35, 36, 37, 38, 39, }; +#define AST2400_SDRAM_BASE 0x40000000 + +static const AspeedSoCInfo aspeed_socs[] = { + { "ast2400-a0", "arm926", AST2400_A0_SILICON_REV, AST2400_SDRAM_BASE }, + { "ast2400", "arm926", AST2400_A0_SILICON_REV, AST2400_SDRAM_BASE }, +}; + /* * IO handlers: simply catch any reads/writes to IO addresses that aren't * handled by a device mapping. @@ -65,8 +72,9 @@ static const MemoryRegionOps aspeed_soc_io_ops = { static void aspeed_soc_init(Object *obj) { AspeedSoCState *s = ASPEED_SOC(obj); + AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); - s->cpu = cpu_arm_init("arm926"); + s->cpu = cpu_arm_init(sc->info->cpu_model); object_initialize(&s->vic, sizeof(s->vic), TYPE_ASPEED_VIC); object_property_add_child(obj, "vic", OBJECT(&s->vic), NULL); @@ -84,7 +92,7 @@ static void aspeed_soc_init(Object *obj) object_property_add_child(obj, "scu", OBJECT(&s->scu), NULL); qdev_set_parent_bus(DEVICE(&s->scu), sysbus_get_default()); qdev_prop_set_uint32(DEVICE(&s->scu), "silicon-rev", - AST2400_A0_SILICON_REV); + sc->info->silicon_rev); object_property_add_alias(obj, "hw-strap1", OBJECT(&s->scu), "hw-strap1", &error_abort); object_property_add_alias(obj, "hw-strap2", OBJECT(&s->scu), @@ -102,7 +110,7 @@ static void aspeed_soc_init(Object *obj) object_property_add_child(obj, "sdmc", OBJECT(&s->sdmc), NULL); qdev_set_parent_bus(DEVICE(&s->sdmc), sysbus_get_default()); qdev_prop_set_uint32(DEVICE(&s->sdmc), "silicon-rev", - AST2400_A0_SILICON_REV); + sc->info->silicon_rev); } static void aspeed_soc_realize(DeviceState *dev, Error **errp) @@ -202,7 +210,9 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) static void aspeed_soc_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); + AspeedSoCClass *sc = ASPEED_SOC_CLASS(oc); + sc->info = (AspeedSoCInfo *) data; dc->realize = aspeed_soc_realize; /* @@ -213,16 +223,28 @@ static void aspeed_soc_class_init(ObjectClass *oc, void *data) } static const TypeInfo aspeed_soc_type_info = { - .name = TYPE_ASPEED_SOC, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(AspeedSoCState), - .instance_init = aspeed_soc_init, - .class_init = aspeed_soc_class_init, + .name = TYPE_ASPEED_SOC, + .parent = TYPE_DEVICE, + .instance_init = aspeed_soc_init, + .instance_size = sizeof(AspeedSoCState), + .class_size = sizeof(AspeedSoCClass), + .abstract = true, }; static void aspeed_soc_register_types(void) { + int i; + type_register_static(&aspeed_soc_type_info); + for (i = 0; i < ARRAY_SIZE(aspeed_socs); ++i) { + TypeInfo ti = { + .name = aspeed_socs[i].name, + .parent = TYPE_ASPEED_SOC, + .class_init = aspeed_soc_class_init, + .class_data = (void *) &aspeed_socs[i], + }; + type_register(&ti); + } } type_init(aspeed_soc_register_types) diff --git a/hw/arm/palmetto-bmc.c b/hw/arm/palmetto-bmc.c index 4d11905cfb1..43191210f3e 100644 --- a/hw/arm/palmetto-bmc.c +++ b/hw/arm/palmetto-bmc.c @@ -22,8 +22,7 @@ #include "sysemu/blockdev.h" static struct arm_boot_info palmetto_bmc_binfo = { - .loader_start = AST2400_SDRAM_BASE, - .board_id = 0, + .board_id = -1, /* device-tree-only board */ .nb_cpus = 1, }; @@ -61,14 +60,17 @@ static void palmetto_bmc_init_flashes(AspeedSMCState *s, const char *flashtype, static void palmetto_bmc_init(MachineState *machine) { PalmettoBMCState *bmc; + AspeedSoCClass *sc; bmc = g_new0(PalmettoBMCState, 1); - object_initialize(&bmc->soc, (sizeof(bmc->soc)), TYPE_ASPEED_SOC); + object_initialize(&bmc->soc, (sizeof(bmc->soc)), "ast2400-a0"); object_property_add_child(OBJECT(machine), "soc", OBJECT(&bmc->soc), &error_abort); + sc = ASPEED_SOC_GET_CLASS(&bmc->soc); + memory_region_allocate_system_memory(&bmc->ram, NULL, "ram", ram_size); - memory_region_add_subregion(get_system_memory(), AST2400_SDRAM_BASE, + memory_region_add_subregion(get_system_memory(), sc->info->sdram_base, &bmc->ram); object_property_add_const_link(OBJECT(&bmc->soc), "ram", OBJECT(&bmc->ram), &error_abort); @@ -84,6 +86,8 @@ static void palmetto_bmc_init(MachineState *machine) palmetto_bmc_binfo.initrd_filename = machine->initrd_filename; palmetto_bmc_binfo.kernel_cmdline = machine->kernel_cmdline; palmetto_bmc_binfo.ram_size = ram_size; + palmetto_bmc_binfo.loader_start = sc->info->sdram_base; + arm_load_kernel(ARM_CPU(first_cpu), &palmetto_bmc_binfo); } diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h index bf63ae90cab..932704c380f 100644 --- a/include/hw/arm/aspeed_soc.h +++ b/include/hw/arm/aspeed_soc.h @@ -39,6 +39,21 @@ typedef struct AspeedSoCState { #define TYPE_ASPEED_SOC "aspeed-soc" #define ASPEED_SOC(obj) OBJECT_CHECK(AspeedSoCState, (obj), TYPE_ASPEED_SOC) -#define AST2400_SDRAM_BASE 0x40000000 +typedef struct AspeedSoCInfo { + const char *name; + const char *cpu_model; + uint32_t silicon_rev; + hwaddr sdram_base; +} AspeedSoCInfo; + +typedef struct AspeedSoCClass { + DeviceClass parent_class; + AspeedSoCInfo *info; +} AspeedSoCClass; + +#define ASPEED_SOC_CLASS(klass) \ + OBJECT_CLASS_CHECK(AspeedSoCClass, (klass), TYPE_ASPEED_SOC) +#define ASPEED_SOC_GET_CLASS(obj) \ + OBJECT_GET_CLASS(AspeedSoCClass, (obj), TYPE_ASPEED_SOC) #endif /* ASPEED_SOC_H */ From aaf4e67f0efce49ca5cf2648706bf0b834d2535f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Thu, 22 Sep 2016 18:13:05 +0100 Subject: [PATCH 144/723] palmetto-bmc: rename the Aspeed board file to aspeed.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We plan to add more Aspeed boards to this file. There are no changes in the code. Signed-off-by: Cédric Le Goater Reviewed-by: Andrew Jeffery Reviewed-by: Peter Maydell Message-id: 1473438177-26079-5-git-send-email-clg@kaod.org Signed-off-by: Peter Maydell --- hw/arm/Makefile.objs | 2 +- hw/arm/{palmetto-bmc.c => aspeed.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename hw/arm/{palmetto-bmc.c => aspeed.c} (100%) diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs index 7901294630b..4c5c4ee76c1 100644 --- a/hw/arm/Makefile.objs +++ b/hw/arm/Makefile.objs @@ -17,4 +17,4 @@ obj-$(CONFIG_XLNX_ZYNQMP) += xlnx-zynqmp.o xlnx-ep108.o obj-$(CONFIG_FSL_IMX25) += fsl-imx25.o imx25_pdk.o obj-$(CONFIG_FSL_IMX31) += fsl-imx31.o kzm.o obj-$(CONFIG_FSL_IMX6) += fsl-imx6.o sabrelite.o -obj-$(CONFIG_ASPEED_SOC) += aspeed_soc.o palmetto-bmc.o +obj-$(CONFIG_ASPEED_SOC) += aspeed_soc.o aspeed.o diff --git a/hw/arm/palmetto-bmc.c b/hw/arm/aspeed.c similarity index 100% rename from hw/arm/palmetto-bmc.c rename to hw/arm/aspeed.c From 74fb1f38071f557154558141ed8d3a57914b0996 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Thu, 22 Sep 2016 18:13:05 +0100 Subject: [PATCH 145/723] palmetto-bmc: replace palmetto_bmc with aspeed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is mostly a name replacement to prepare ground for other SoCs specificities. It also adds a TypeInfo struct for the palmetto-bmc board with a custom initialization for the same reason. Signed-off-by: Cédric Le Goater Reviewed-by: Andrew Jeffery Reviewed-by: Peter Maydell Message-id: 1473438177-26079-6-git-send-email-clg@kaod.org Signed-off-by: Peter Maydell --- hw/arm/aspeed.c | 54 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 43191210f3e..3b901eaa6fb 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -21,17 +21,17 @@ #include "sysemu/block-backend.h" #include "sysemu/blockdev.h" -static struct arm_boot_info palmetto_bmc_binfo = { +static struct arm_boot_info aspeed_board_binfo = { .board_id = -1, /* device-tree-only board */ .nb_cpus = 1, }; -typedef struct PalmettoBMCState { +typedef struct AspeedBoardState { AspeedSoCState soc; MemoryRegion ram; -} PalmettoBMCState; +} AspeedBoardState; -static void palmetto_bmc_init_flashes(AspeedSMCState *s, const char *flashtype, +static void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype, Error **errp) { int i ; @@ -57,12 +57,12 @@ static void palmetto_bmc_init_flashes(AspeedSMCState *s, const char *flashtype, } } -static void palmetto_bmc_init(MachineState *machine) +static void aspeed_board_init(MachineState *machine) { - PalmettoBMCState *bmc; + AspeedBoardState *bmc; AspeedSoCClass *sc; - bmc = g_new0(PalmettoBMCState, 1); + bmc = g_new0(AspeedBoardState, 1); object_initialize(&bmc->soc, (sizeof(bmc->soc)), "ast2400-a0"); object_property_add_child(OBJECT(machine), "soc", OBJECT(&bmc->soc), &error_abort); @@ -79,21 +79,28 @@ static void palmetto_bmc_init(MachineState *machine) object_property_set_bool(OBJECT(&bmc->soc), true, "realized", &error_abort); - palmetto_bmc_init_flashes(&bmc->soc.smc, "n25q256a", &error_abort); - palmetto_bmc_init_flashes(&bmc->soc.spi, "mx25l25635e", &error_abort); + aspeed_board_init_flashes(&bmc->soc.smc, "n25q256a", &error_abort); + aspeed_board_init_flashes(&bmc->soc.spi, "mx25l25635e", &error_abort); + + aspeed_board_binfo.kernel_filename = machine->kernel_filename; + aspeed_board_binfo.initrd_filename = machine->initrd_filename; + aspeed_board_binfo.kernel_cmdline = machine->kernel_cmdline; + aspeed_board_binfo.ram_size = ram_size; + aspeed_board_binfo.loader_start = sc->info->sdram_base; - palmetto_bmc_binfo.kernel_filename = machine->kernel_filename; - palmetto_bmc_binfo.initrd_filename = machine->initrd_filename; - palmetto_bmc_binfo.kernel_cmdline = machine->kernel_cmdline; - palmetto_bmc_binfo.ram_size = ram_size; - palmetto_bmc_binfo.loader_start = sc->info->sdram_base; + arm_load_kernel(ARM_CPU(first_cpu), &aspeed_board_binfo); +} - arm_load_kernel(ARM_CPU(first_cpu), &palmetto_bmc_binfo); +static void palmetto_bmc_init(MachineState *machine) +{ + aspeed_board_init(machine); } -static void palmetto_bmc_machine_init(MachineClass *mc) +static void palmetto_bmc_class_init(ObjectClass *oc, void *data) { - mc->desc = "OpenPOWER Palmetto BMC"; + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "OpenPOWER Palmetto BMC (ARM926EJ-S)"; mc->init = palmetto_bmc_init; mc->max_cpus = 1; mc->no_sdcard = 1; @@ -103,4 +110,15 @@ static void palmetto_bmc_machine_init(MachineClass *mc) mc->no_parallel = 1; } -DEFINE_MACHINE("palmetto-bmc", palmetto_bmc_machine_init); +static const TypeInfo palmetto_bmc_type = { + .name = MACHINE_TYPE_NAME("palmetto-bmc"), + .parent = TYPE_MACHINE, + .class_init = palmetto_bmc_class_init, +}; + +static void aspeed_machine_init(void) +{ + type_register_static(&palmetto_bmc_type); +} + +type_init(aspeed_machine_init) From c3ba99f723af21f27d0f6c839443b218c75b0dc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Thu, 22 Sep 2016 18:13:05 +0100 Subject: [PATCH 146/723] palmetto-bmc: add board specific configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit aspeed_board_init() now uses a board identifier to customize some values specific to the board. Signed-off-by: Cédric Le Goater Reviewed-by: Andrew Jeffery Reviewed-by: Peter Maydell Message-id: 1473438177-26079-7-git-send-email-clg@kaod.org Signed-off-by: Peter Maydell --- hw/arm/aspeed.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 3b901eaa6fb..b4eb8049af9 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -31,6 +31,19 @@ typedef struct AspeedBoardState { MemoryRegion ram; } AspeedBoardState; +typedef struct AspeedBoardConfig { + const char *soc_name; + uint32_t hw_strap1; +} AspeedBoardConfig; + +enum { + PALMETTO_BMC, +}; + +static const AspeedBoardConfig aspeed_boards[] = { + [PALMETTO_BMC] = { "ast2400-a0", 0x120CE416 }, +}; + static void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype, Error **errp) { @@ -57,13 +70,14 @@ static void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype, } } -static void aspeed_board_init(MachineState *machine) +static void aspeed_board_init(MachineState *machine, + const AspeedBoardConfig *cfg) { AspeedBoardState *bmc; AspeedSoCClass *sc; bmc = g_new0(AspeedBoardState, 1); - object_initialize(&bmc->soc, (sizeof(bmc->soc)), "ast2400-a0"); + object_initialize(&bmc->soc, (sizeof(bmc->soc)), cfg->soc_name); object_property_add_child(OBJECT(machine), "soc", OBJECT(&bmc->soc), &error_abort); @@ -74,7 +88,7 @@ static void aspeed_board_init(MachineState *machine) &bmc->ram); object_property_add_const_link(OBJECT(&bmc->soc), "ram", OBJECT(&bmc->ram), &error_abort); - object_property_set_int(OBJECT(&bmc->soc), 0x120CE416, "hw-strap1", + object_property_set_int(OBJECT(&bmc->soc), cfg->hw_strap1, "hw-strap1", &error_abort); object_property_set_bool(OBJECT(&bmc->soc), true, "realized", &error_abort); @@ -93,7 +107,7 @@ static void aspeed_board_init(MachineState *machine) static void palmetto_bmc_init(MachineState *machine) { - aspeed_board_init(machine); + aspeed_board_init(machine, &aspeed_boards[PALMETTO_BMC]); } static void palmetto_bmc_class_init(ObjectClass *oc, void *data) From 8da33ef757d6d49b41432a22e4ab357652ec0e14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Thu, 22 Sep 2016 18:13:05 +0100 Subject: [PATCH 147/723] hw/misc: use macros to define hw-strap1 register on the AST2400 Aspeed SoC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This gives some explanation behind the magic number 0x120CE416. Signed-off-by: Cédric Le Goater Reviewed-by: Andrew Jeffery Reviewed-by: Peter Maydell Message-id: 1473438177-26079-8-git-send-email-clg@kaod.org Signed-off-by: Peter Maydell --- hw/arm/aspeed.c | 15 ++++- include/hw/misc/aspeed_scu.h | 118 +++++++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+), 1 deletion(-) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index b4eb8049af9..c08213c04e3 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -40,8 +40,21 @@ enum { PALMETTO_BMC, }; +#define PALMETTO_BMC_HW_STRAP1 ( \ + SCU_AST2400_HW_STRAP_DRAM_SIZE(DRAM_SIZE_256MB) | \ + SCU_AST2400_HW_STRAP_DRAM_CONFIG(2 /* DDR3 with CL=6, CWL=5 */) | \ + SCU_AST2400_HW_STRAP_ACPI_DIS | \ + SCU_AST2400_HW_STRAP_SET_CLK_SOURCE(AST2400_CLK_48M_IN) | \ + SCU_HW_STRAP_VGA_CLASS_CODE | \ + SCU_HW_STRAP_LPC_RESET_PIN | \ + SCU_HW_STRAP_SPI_MODE(SCU_HW_STRAP_SPI_M_S_EN) | \ + SCU_AST2400_HW_STRAP_SET_CPU_AHB_RATIO(AST2400_CPU_AHB_RATIO_2_1) | \ + SCU_HW_STRAP_SPI_WIDTH | \ + SCU_HW_STRAP_VGA_SIZE_SET(VGA_16M_DRAM) | \ + SCU_AST2400_HW_STRAP_BOOT_MODE(AST2400_SPI_BOOT)) + static const AspeedBoardConfig aspeed_boards[] = { - [PALMETTO_BMC] = { "ast2400-a0", 0x120CE416 }, + [PALMETTO_BMC] = { "ast2400-a0", PALMETTO_BMC_HW_STRAP1 }, }; static void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype, diff --git a/include/hw/misc/aspeed_scu.h b/include/hw/misc/aspeed_scu.h index fdfd982288f..4d3e770cec2 100644 --- a/include/hw/misc/aspeed_scu.h +++ b/include/hw/misc/aspeed_scu.h @@ -36,4 +36,122 @@ typedef struct AspeedSCUState { extern bool is_supported_silicon_rev(uint32_t silicon_rev); +/* + * Extracted from Aspeed SDK v00.03.21. Fixes and extra definitions + * were added. + * + * Original header file : + * arch/arm/mach-aspeed/include/mach/regs-scu.h + * + * Copyright (C) 2012-2020 ASPEED Technology Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * History : + * 1. 2012/12/29 Ryan Chen Create + */ + +/* Hardware Strapping Register definition (for Aspeed AST2400 SOC) + * + * 31:29 Software defined strapping registers + * 28:27 DRAM size setting (for VGA driver use) + * 26:24 DRAM configuration setting + * 23 Enable 25 MHz reference clock input + * 22 Enable GPIOE pass-through mode + * 21 Enable GPIOD pass-through mode + * 20 Disable LPC to decode SuperIO 0x2E/0x4E address + * 19 Disable ACPI function + * 23,18 Clock source selection + * 17 Enable BMC 2nd boot watchdog timer + * 16 SuperIO configuration address selection + * 15 VGA Class Code selection + * 14 Enable LPC dedicated reset pin function + * 13:12 SPI mode selection + * 11:10 CPU/AHB clock frequency ratio selection + * 9:8 H-PLL default clock frequency selection + * 7 Define MAC#2 interface + * 6 Define MAC#1 interface + * 5 Enable VGA BIOS ROM + * 4 Boot flash memory extended option + * 3:2 VGA memory size selection + * 1:0 BMC CPU boot code selection + */ +#define SCU_AST2400_HW_STRAP_SW_DEFINE(x) ((x) << 29) +#define SCU_AST2400_HW_STRAP_SW_DEFINE_MASK (0x7 << 29) + +#define SCU_AST2400_HW_STRAP_DRAM_SIZE(x) ((x) << 27) +#define SCU_AST2400_HW_STRAP_DRAM_SIZE_MASK (0x3 << 27) +#define DRAM_SIZE_64MB 0 +#define DRAM_SIZE_128MB 1 +#define DRAM_SIZE_256MB 2 +#define DRAM_SIZE_512MB 3 + +#define SCU_AST2400_HW_STRAP_DRAM_CONFIG(x) ((x) << 24) +#define SCU_AST2400_HW_STRAP_DRAM_CONFIG_MASK (0x7 << 24) + +#define SCU_HW_STRAP_GPIOE_PT_EN (0x1 << 22) +#define SCU_HW_STRAP_GPIOD_PT_EN (0x1 << 21) +#define SCU_HW_STRAP_LPC_DEC_SUPER_IO (0x1 << 20) +#define SCU_AST2400_HW_STRAP_ACPI_DIS (0x1 << 19) + +/* bit 23, 18 [1,0] */ +#define SCU_AST2400_HW_STRAP_SET_CLK_SOURCE(x) (((((x) & 0x3) >> 1) << 23) \ + | (((x) & 0x1) << 18)) +#define SCU_AST2400_HW_STRAP_GET_CLK_SOURCE(x) (((((x) >> 23) & 0x1) << 1) \ + | (((x) >> 18) & 0x1)) +#define SCU_AST2400_HW_STRAP_CLK_SOURCE_MASK ((0x1 << 23) | (0x1 << 18)) +#define AST2400_CLK_25M_IN (0x1 << 23) +#define AST2400_CLK_24M_IN 0 +#define AST2400_CLK_48M_IN 1 +#define AST2400_CLK_25M_IN_24M_USB_CKI 2 +#define AST2400_CLK_25M_IN_48M_USB_CKI 3 + +#define SCU_HW_STRAP_2ND_BOOT_WDT (0x1 << 17) +#define SCU_HW_STRAP_SUPER_IO_CONFIG (0x1 << 16) +#define SCU_HW_STRAP_VGA_CLASS_CODE (0x1 << 15) +#define SCU_HW_STRAP_LPC_RESET_PIN (0x1 << 14) + +#define SCU_HW_STRAP_SPI_MODE(x) ((x) << 12) +#define SCU_HW_STRAP_SPI_MODE_MASK (0x3 << 12) +#define SCU_HW_STRAP_SPI_DIS 0 +#define SCU_HW_STRAP_SPI_MASTER 1 +#define SCU_HW_STRAP_SPI_M_S_EN 2 +#define SCU_HW_STRAP_SPI_PASS_THROUGH 3 + +#define SCU_AST2400_HW_STRAP_SET_CPU_AHB_RATIO(x) ((x) << 10) +#define SCU_AST2400_HW_STRAP_GET_CPU_AHB_RATIO(x) (((x) >> 10) & 3) +#define SCU_AST2400_HW_STRAP_CPU_AHB_RATIO_MASK (0x3 << 10) +#define AST2400_CPU_AHB_RATIO_1_1 0 +#define AST2400_CPU_AHB_RATIO_2_1 1 +#define AST2400_CPU_AHB_RATIO_4_1 2 +#define AST2400_CPU_AHB_RATIO_3_1 3 + +#define SCU_AST2400_HW_STRAP_GET_H_PLL_CLK(x) (((x) >> 8) & 0x3) +#define SCU_AST2400_HW_STRAP_H_PLL_CLK_MASK (0x3 << 8) +#define AST2400_CPU_384MHZ 0 +#define AST2400_CPU_360MHZ 1 +#define AST2400_CPU_336MHZ 2 +#define AST2400_CPU_408MHZ 3 + +#define SCU_HW_STRAP_MAC1_RGMII (0x1 << 7) +#define SCU_HW_STRAP_MAC0_RGMII (0x1 << 6) +#define SCU_HW_STRAP_VGA_BIOS_ROM (0x1 << 5) +#define SCU_HW_STRAP_SPI_WIDTH (0x1 << 4) + +#define SCU_HW_STRAP_VGA_SIZE_GET(x) (((x) >> 2) & 0x3) +#define SCU_HW_STRAP_VGA_MASK (0x3 << 2) +#define SCU_HW_STRAP_VGA_SIZE_SET(x) ((x) << 2) +#define VGA_8M_DRAM 0 +#define VGA_16M_DRAM 1 +#define VGA_32M_DRAM 2 +#define VGA_64M_DRAM 3 + +#define SCU_AST2400_HW_STRAP_BOOT_MODE(x) (x) +#define AST2400_NOR_BOOT 0 +#define AST2400_NAND_BOOT 1 +#define AST2400_SPI_BOOT 2 +#define AST2400_DIS_BOOT 3 + #endif /* ASPEED_SCU_H */ From 365aff1eaa370dc3bab2fb42b707496c46acb621 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Thu, 22 Sep 2016 18:13:05 +0100 Subject: [PATCH 148/723] aspeed: add a ast2500 SoC and support to the SCU and SDMC controllers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Based on previous work done by Andrew Jeffery . Signed-off-by: Cédric Le Goater Reviewed-by: Andrew Jeffery Reviewed-by: Peter Maydell Message-id: 1473438177-26079-9-git-send-email-clg@kaod.org Signed-off-by: Peter Maydell --- hw/arm/aspeed_soc.c | 2 + hw/misc/aspeed_scu.c | 45 +++++++++++++++++++++- hw/misc/aspeed_sdmc.c | 1 + include/hw/misc/aspeed_scu.h | 75 ++++++++++++++++++++++++++++++++++++ 4 files changed, 122 insertions(+), 1 deletion(-) diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index 07c9c90d7d3..93bc7bb66e4 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -38,10 +38,12 @@ static const int uart_irqs[] = { 9, 32, 33, 34, 10 }; static const int timer_irqs[] = { 16, 17, 18, 35, 36, 37, 38, 39, }; #define AST2400_SDRAM_BASE 0x40000000 +#define AST2500_SDRAM_BASE 0x80000000 static const AspeedSoCInfo aspeed_socs[] = { { "ast2400-a0", "arm926", AST2400_A0_SILICON_REV, AST2400_SDRAM_BASE }, { "ast2400", "arm926", AST2400_A0_SILICON_REV, AST2400_SDRAM_BASE }, + { "ast2500-a1", "arm1176", AST2500_A1_SILICON_REV, AST2500_SDRAM_BASE }, }; /* diff --git a/hw/misc/aspeed_scu.c b/hw/misc/aspeed_scu.c index c7e2c8263f5..b1f3e6f6b87 100644 --- a/hw/misc/aspeed_scu.c +++ b/hw/misc/aspeed_scu.c @@ -120,6 +120,41 @@ static const uint32_t ast2400_a0_resets[ASPEED_SCU_NR_REGS] = { [BMC_DEV_ID] = 0x00002402U }; +/* SCU70 bit 23: 0 24Mhz. bit 11:9: 0b001 AXI:ABH ratio 2:1 */ +/* AST2500 revision A1 */ + +static const uint32_t ast2500_a1_resets[ASPEED_SCU_NR_REGS] = { + [SYS_RST_CTRL] = 0xFFCFFEDCU, + [CLK_SEL] = 0xF3F40000U, + [CLK_STOP_CTRL] = 0x19FC3E8BU, + [D2PLL_PARAM] = 0x00026108U, + [MPLL_PARAM] = 0x00030291U, + [HPLL_PARAM] = 0x93000400U, + [MISC_CTRL1] = 0x00000010U, + [PCI_CTRL1] = 0x20001A03U, + [PCI_CTRL2] = 0x20001A03U, + [PCI_CTRL3] = 0x04000030U, + [SYS_RST_STATUS] = 0x00000001U, + [SOC_SCRATCH1] = 0x000000C0U, /* SoC completed DRAM init */ + [MISC_CTRL2] = 0x00000023U, + [RNG_CTRL] = 0x0000000EU, + [PINMUX_CTRL2] = 0x0000F000U, + [PINMUX_CTRL3] = 0x03000000U, + [PINMUX_CTRL4] = 0x00000000U, + [PINMUX_CTRL5] = 0x0000A000U, + [WDT_RST_CTRL] = 0x023FFFF3U, + [PINMUX_CTRL8] = 0xFFFF0000U, + [PINMUX_CTRL9] = 0x000FFFFFU, + [FREE_CNTR4] = 0x000000FFU, + [FREE_CNTR4_EXT] = 0x000000FFU, + [CPU2_BASE_SEG1] = 0x80000000U, + [CPU2_BASE_SEG4] = 0x1E600000U, + [CPU2_BASE_SEG5] = 0xC0000000U, + [UART_HPLL_CLK] = 0x00001903U, + [PCIE_CTRL] = 0x0000007BU, + [BMC_DEV_ID] = 0x00002402U +}; + static uint64_t aspeed_scu_read(void *opaque, hwaddr offset, unsigned size) { AspeedSCUState *s = ASPEED_SCU(opaque); @@ -198,6 +233,10 @@ static void aspeed_scu_reset(DeviceState *dev) case AST2400_A0_SILICON_REV: reset = ast2400_a0_resets; break; + case AST2500_A0_SILICON_REV: + case AST2500_A1_SILICON_REV: + reset = ast2500_a1_resets; + break; default: g_assert_not_reached(); } @@ -208,7 +247,11 @@ static void aspeed_scu_reset(DeviceState *dev) s->regs[HW_STRAP2] = s->hw_strap2; } -static uint32_t aspeed_silicon_revs[] = { AST2400_A0_SILICON_REV, }; +static uint32_t aspeed_silicon_revs[] = { + AST2400_A0_SILICON_REV, + AST2500_A0_SILICON_REV, + AST2500_A1_SILICON_REV, +}; bool is_supported_silicon_rev(uint32_t silicon_rev) { diff --git a/hw/misc/aspeed_sdmc.c b/hw/misc/aspeed_sdmc.c index fc4217b3ce6..244e5c0dc5e 100644 --- a/hw/misc/aspeed_sdmc.c +++ b/hw/misc/aspeed_sdmc.c @@ -196,6 +196,7 @@ static void aspeed_sdmc_reset(DeviceState *dev) break; case AST2500_A0_SILICON_REV: + case AST2500_A1_SILICON_REV: s->regs[R_CONF] |= ASPEED_SDMC_HW_VERSION(1) | ASPEED_SDMC_VGA_APERTURE(ASPEED_SDMC_VGA_64MB) | diff --git a/include/hw/misc/aspeed_scu.h b/include/hw/misc/aspeed_scu.h index 4d3e770cec2..14ffc43de80 100644 --- a/include/hw/misc/aspeed_scu.h +++ b/include/hw/misc/aspeed_scu.h @@ -33,6 +33,7 @@ typedef struct AspeedSCUState { #define AST2400_A0_SILICON_REV 0x02000303U #define AST2500_A0_SILICON_REV 0x04000303U +#define AST2500_A1_SILICON_REV 0x04010303U extern bool is_supported_silicon_rev(uint32_t silicon_rev); @@ -154,4 +155,78 @@ extern bool is_supported_silicon_rev(uint32_t silicon_rev); #define AST2400_SPI_BOOT 2 #define AST2400_DIS_BOOT 3 +/* + * Hardware strapping register definition (for Aspeed AST2500 SoC and + * higher) + * + * 31 Enable SPI Flash Strap Auto Fetch Mode + * 30 Enable GPIO Strap Mode + * 29 Select UART Debug Port + * 28 Reserved (1) + * 27 Enable fast reset mode for ARM ICE debugger + * 26 Enable eSPI flash mode + * 25 Enable eSPI mode + * 24 Select DDR4 SDRAM + * 23 Select 25 MHz reference clock input mode + * 22 Enable GPIOE pass-through mode + * 21 Enable GPIOD pass-through mode + * 20 Disable LPC to decode SuperIO 0x2E/0x4E address + * 19 Enable ACPI function + * 18 Select USBCKI input frequency + * 17 Enable BMC 2nd boot watchdog timer + * 16 SuperIO configuration address selection + * 15 VGA Class Code selection + * 14 Select dedicated LPC reset input + * 13:12 SPI mode selection + * 11:9 AXI/AHB clock frequency ratio selection + * 8 Reserved (0) + * 7 Define MAC#2 interface + * 6 Define MAC#1 interface + * 5 Enable dedicated VGA BIOS ROM + * 4 Reserved (0) + * 3:2 VGA memory size selection + * 1 Reserved (1) + * 0 Disable CPU boot + */ +#define SCU_AST2500_HW_STRAP_SPI_AUTOFETCH_ENABLE (0x1 << 31) +#define SCU_AST2500_HW_STRAP_GPIO_STRAP_ENABLE (0x1 << 30) +#define SCU_AST2500_HW_STRAP_UART_DEBUG (0x1 << 29) +#define UART_DEBUG_UART1 0 +#define UART_DEBUG_UART5 1 +#define SCU_AST2500_HW_STRAP_RESERVED28 (0x1 << 28) + +#define SCU_AST2500_HW_STRAP_FAST_RESET_DBG (0x1 << 27) +#define SCU_AST2500_HW_STRAP_ESPI_FLASH_ENABLE (0x1 << 26) +#define SCU_AST2500_HW_STRAP_ESPI_ENABLE (0x1 << 25) +#define SCU_AST2500_HW_STRAP_DDR4_ENABLE (0x1 << 24) + +#define SCU_AST2500_HW_STRAP_ACPI_ENABLE (0x1 << 19) +#define SCU_AST2500_HW_STRAP_USBCKI_FREQ (0x1 << 18) +#define USBCKI_FREQ_24MHZ 0 +#define USBCKI_FREQ_28MHZ 1 + +#define SCU_AST2500_HW_STRAP_SET_AXI_AHB_RATIO(x) ((x) << 9) +#define SCU_AST2500_HW_STRAP_GET_AXI_AHB_RATIO(x) (((x) >> 9) & 7) +#define SCU_AST2500_HW_STRAP_CPU_AXI_RATIO_MASK (0x7 << 9) +#define AXI_AHB_RATIO_UNDEFINED 0 +#define AXI_AHB_RATIO_2_1 1 +#define AXI_AHB_RATIO_3_1 2 +#define AXI_AHB_RATIO_4_1 3 +#define AXI_AHB_RATIO_5_1 4 +#define AXI_AHB_RATIO_6_1 5 +#define AXI_AHB_RATIO_7_1 6 +#define AXI_AHB_RATIO_8_1 7 + +#define SCU_AST2500_HW_STRAP_RESERVED1 (0x1 << 1) +#define SCU_AST2500_HW_STRAP_DIS_BOOT (0x1 << 0) + +#define AST2500_HW_STRAP1_DEFAULTS ( \ + SCU_AST2500_HW_STRAP_RESERVED28 | \ + SCU_HW_STRAP_2ND_BOOT_WDT | \ + SCU_HW_STRAP_VGA_CLASS_CODE | \ + SCU_HW_STRAP_LPC_RESET_PIN | \ + SCU_AST2500_HW_STRAP_SET_AXI_AHB_RATIO(AXI_AHB_RATIO_2_1) | \ + SCU_HW_STRAP_VGA_SIZE_SET(VGA_16M_DRAM) | \ + SCU_AST2500_HW_STRAP_RESERVED1) + #endif /* ASPEED_SCU_H */ From 9a7c17501187061e60102164bd84509a4d854d1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Thu, 22 Sep 2016 18:13:06 +0100 Subject: [PATCH 149/723] arm: add support for an ast2500 evaluation board MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ast2500 eval board has a hardware strapping register value of 0xF100C2E6 which we use for a definition of AST2500_EVB_HW_STRAP1 below. Signed-off-by: Cédric Le Goater Reviewed-by: Andrew Jeffery Reviewed-by: Peter Maydell Message-id: 1473438177-26079-10-git-send-email-clg@kaod.org Signed-off-by: Peter Maydell --- hw/arm/aspeed.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index c08213c04e3..2af9fe93444 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -38,6 +38,7 @@ typedef struct AspeedBoardConfig { enum { PALMETTO_BMC, + AST2500_EVB, }; #define PALMETTO_BMC_HW_STRAP1 ( \ @@ -53,8 +54,19 @@ enum { SCU_HW_STRAP_VGA_SIZE_SET(VGA_16M_DRAM) | \ SCU_AST2400_HW_STRAP_BOOT_MODE(AST2400_SPI_BOOT)) +#define AST2500_EVB_HW_STRAP1 (( \ + AST2500_HW_STRAP1_DEFAULTS | \ + SCU_AST2500_HW_STRAP_SPI_AUTOFETCH_ENABLE | \ + SCU_AST2500_HW_STRAP_GPIO_STRAP_ENABLE | \ + SCU_AST2500_HW_STRAP_UART_DEBUG | \ + SCU_AST2500_HW_STRAP_DDR4_ENABLE | \ + SCU_HW_STRAP_MAC1_RGMII | \ + SCU_HW_STRAP_MAC0_RGMII) & \ + ~SCU_HW_STRAP_2ND_BOOT_WDT) + static const AspeedBoardConfig aspeed_boards[] = { [PALMETTO_BMC] = { "ast2400-a0", PALMETTO_BMC_HW_STRAP1 }, + [AST2500_EVB] = { "ast2500-a1", AST2500_EVB_HW_STRAP1 }, }; static void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype, @@ -143,9 +155,34 @@ static const TypeInfo palmetto_bmc_type = { .class_init = palmetto_bmc_class_init, }; +static void ast2500_evb_init(MachineState *machine) +{ + aspeed_board_init(machine, &aspeed_boards[AST2500_EVB]); +} + +static void ast2500_evb_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "Aspeed AST2500 EVB (ARM1176)"; + mc->init = ast2500_evb_init; + mc->max_cpus = 1; + mc->no_sdcard = 1; + mc->no_floppy = 1; + mc->no_cdrom = 1; + mc->no_parallel = 1; +} + +static const TypeInfo ast2500_evb_type = { + .name = MACHINE_TYPE_NAME("ast2500-evb"), + .parent = TYPE_MACHINE, + .class_init = ast2500_evb_class_init, +}; + static void aspeed_machine_init(void) { type_register_static(&palmetto_bmc_type); + type_register_static(&ast2500_evb_type); } type_init(aspeed_machine_init) From 67077e301454069fd849de755e9d04da70474304 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Thu, 22 Sep 2016 18:13:06 +0100 Subject: [PATCH 150/723] palmetto-bmc: remove extra no_sdcard assignement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Cédric Le Goater Reviewed-by: Andrew Jeffery Reviewed-by: Peter Maydell Message-id: 1473438177-26079-11-git-send-email-clg@kaod.org Signed-off-by: Peter Maydell --- hw/arm/aspeed.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 2af9fe93444..9013d35a674 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -145,7 +145,6 @@ static void palmetto_bmc_class_init(ObjectClass *oc, void *data) mc->no_sdcard = 1; mc->no_floppy = 1; mc->no_cdrom = 1; - mc->no_sdcard = 1; mc->no_parallel = 1; } From 3755f9e3164360ca34dcc77d842ce1d41321db4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Thu, 22 Sep 2016 18:13:06 +0100 Subject: [PATCH 151/723] aspeed: calculate the RAM size bits at realize time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no need to do this at each reset as the RAM size will not change. Signed-off-by: Cédric Le Goater Reviewed-by: Andrew Jeffery Message-id: 1473438177-26079-12-git-send-email-clg@kaod.org Signed-off-by: Peter Maydell --- hw/misc/aspeed_sdmc.c | 16 ++++++++++++++-- include/hw/misc/aspeed_sdmc.h | 1 + 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/hw/misc/aspeed_sdmc.c b/hw/misc/aspeed_sdmc.c index 244e5c0dc5e..1d282523772 100644 --- a/hw/misc/aspeed_sdmc.c +++ b/hw/misc/aspeed_sdmc.c @@ -192,7 +192,7 @@ static void aspeed_sdmc_reset(DeviceState *dev) case AST2400_A0_SILICON_REV: s->regs[R_CONF] |= ASPEED_SDMC_VGA_COMPAT | - ASPEED_SDMC_DRAM_SIZE(ast2400_rambits()); + ASPEED_SDMC_DRAM_SIZE(s->ram_bits); break; case AST2500_A0_SILICON_REV: @@ -200,7 +200,7 @@ static void aspeed_sdmc_reset(DeviceState *dev) s->regs[R_CONF] |= ASPEED_SDMC_HW_VERSION(1) | ASPEED_SDMC_VGA_APERTURE(ASPEED_SDMC_VGA_64MB) | - ASPEED_SDMC_DRAM_SIZE(ast2500_rambits()); + ASPEED_SDMC_DRAM_SIZE(s->ram_bits); break; default: @@ -219,6 +219,18 @@ static void aspeed_sdmc_realize(DeviceState *dev, Error **errp) return; } + switch (s->silicon_rev) { + case AST2400_A0_SILICON_REV: + s->ram_bits = ast2400_rambits(); + break; + case AST2500_A0_SILICON_REV: + case AST2500_A1_SILICON_REV: + s->ram_bits = ast2500_rambits(); + break; + default: + g_assert_not_reached(); + } + memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_sdmc_ops, s, TYPE_ASPEED_SDMC, 0x1000); sysbus_init_mmio(sbd, &s->iomem); diff --git a/include/hw/misc/aspeed_sdmc.h b/include/hw/misc/aspeed_sdmc.h index 7e081f6d2b8..df7dce0eddd 100644 --- a/include/hw/misc/aspeed_sdmc.h +++ b/include/hw/misc/aspeed_sdmc.h @@ -25,6 +25,7 @@ typedef struct AspeedSDMCState { uint32_t regs[ASPEED_SDMC_NR_REGS]; uint32_t silicon_rev; + uint32_t ram_bits; } AspeedSDMCState; From b2fd45458d294e0a8a7c559881788d8642958bb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Thu, 22 Sep 2016 18:13:06 +0100 Subject: [PATCH 152/723] aspeed: use error_report instead of LOG_GUEST_ERROR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also change the default value used in case of an error. The minimum size is a bit severe, so let's just use an average RAM size. Signed-off-by: Cédric Le Goater Message-id: 1473438177-26079-13-git-send-email-clg@kaod.org Signed-off-by: Peter Maydell --- hw/misc/aspeed_sdmc.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/hw/misc/aspeed_sdmc.c b/hw/misc/aspeed_sdmc.c index 1d282523772..20bcdb52c4d 100644 --- a/hw/misc/aspeed_sdmc.c +++ b/hw/misc/aspeed_sdmc.c @@ -9,6 +9,7 @@ #include "qemu/osdep.h" #include "qemu/log.h" +#include "qemu/error-report.h" #include "hw/misc/aspeed_sdmc.h" #include "hw/misc/aspeed_scu.h" #include "hw/qdev-properties.h" @@ -151,13 +152,13 @@ static int ast2400_rambits(void) case 512: return ASPEED_SDMC_DRAM_512MB; default: - qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid RAM size: 0x" - RAM_ADDR_FMT "\n", __func__, ram_size); break; } - /* set a minimum default */ - return ASPEED_SDMC_DRAM_64MB; + /* use a common default */ + error_report("warning: Invalid RAM size 0x" RAM_ADDR_FMT + ". Using default 256M", ram_size); + return ASPEED_SDMC_DRAM_256MB; } static int ast2500_rambits(void) @@ -172,13 +173,13 @@ static int ast2500_rambits(void) case 1024: return ASPEED_SDMC_AST2500_1024MB; default: - qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid RAM size: 0x" - RAM_ADDR_FMT "\n", __func__, ram_size); break; } - /* set a minimum default */ - return ASPEED_SDMC_AST2500_128MB; + /* use a common default */ + error_report("warning: Invalid RAM size 0x" RAM_ADDR_FMT + ". Using default 512M", ram_size); + return ASPEED_SDMC_AST2500_512MB; } static void aspeed_sdmc_reset(DeviceState *dev) From c6c7cfb01a00be0553f6694bbe71d45fc5e068c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Thu, 22 Sep 2016 18:13:06 +0100 Subject: [PATCH 153/723] aspeed: add a ram_size property to the memory controller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Configure the size of the RAM of the SOC using a property to propagate the value down to the memory controller from the board level. Signed-off-by: Cédric Le Goater Reviewed-by: Andrew Jeffery Message-id: 1473438177-26079-14-git-send-email-clg@kaod.org Signed-off-by: Peter Maydell --- hw/arm/aspeed.c | 2 ++ hw/arm/aspeed_soc.c | 2 ++ hw/misc/aspeed_sdmc.c | 23 +++++++++++++---------- include/hw/misc/aspeed_sdmc.h | 1 + 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 9013d35a674..562bbb25339 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -113,6 +113,8 @@ static void aspeed_board_init(MachineState *machine, &bmc->ram); object_property_add_const_link(OBJECT(&bmc->soc), "ram", OBJECT(&bmc->ram), &error_abort); + object_property_set_int(OBJECT(&bmc->soc), ram_size, "ram-size", + &error_abort); object_property_set_int(OBJECT(&bmc->soc), cfg->hw_strap1, "hw-strap1", &error_abort); object_property_set_bool(OBJECT(&bmc->soc), true, "realized", diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index 93bc7bb66e4..c0a31020584 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -113,6 +113,8 @@ static void aspeed_soc_init(Object *obj) qdev_set_parent_bus(DEVICE(&s->sdmc), sysbus_get_default()); qdev_prop_set_uint32(DEVICE(&s->sdmc), "silicon-rev", sc->info->silicon_rev); + object_property_add_alias(obj, "ram-size", OBJECT(&s->sdmc), + "ram-size", &error_abort); } static void aspeed_soc_realize(DeviceState *dev, Error **errp) diff --git a/hw/misc/aspeed_sdmc.c b/hw/misc/aspeed_sdmc.c index 20bcdb52c4d..8830dc084c3 100644 --- a/hw/misc/aspeed_sdmc.c +++ b/hw/misc/aspeed_sdmc.c @@ -140,9 +140,9 @@ static const MemoryRegionOps aspeed_sdmc_ops = { .valid.max_access_size = 4, }; -static int ast2400_rambits(void) +static int ast2400_rambits(AspeedSDMCState *s) { - switch (ram_size >> 20) { + switch (s->ram_size >> 20) { case 64: return ASPEED_SDMC_DRAM_64MB; case 128: @@ -156,14 +156,15 @@ static int ast2400_rambits(void) } /* use a common default */ - error_report("warning: Invalid RAM size 0x" RAM_ADDR_FMT - ". Using default 256M", ram_size); + error_report("warning: Invalid RAM size 0x%" PRIx64 + ". Using default 256M", s->ram_size); + s->ram_size = 256 << 20; return ASPEED_SDMC_DRAM_256MB; } -static int ast2500_rambits(void) +static int ast2500_rambits(AspeedSDMCState *s) { - switch (ram_size >> 20) { + switch (s->ram_size >> 20) { case 128: return ASPEED_SDMC_AST2500_128MB; case 256: @@ -177,8 +178,9 @@ static int ast2500_rambits(void) } /* use a common default */ - error_report("warning: Invalid RAM size 0x" RAM_ADDR_FMT - ". Using default 512M", ram_size); + error_report("warning: Invalid RAM size 0x%" PRIx64 + ". Using default 512M", s->ram_size); + s->ram_size = 512 << 20; return ASPEED_SDMC_AST2500_512MB; } @@ -222,11 +224,11 @@ static void aspeed_sdmc_realize(DeviceState *dev, Error **errp) switch (s->silicon_rev) { case AST2400_A0_SILICON_REV: - s->ram_bits = ast2400_rambits(); + s->ram_bits = ast2400_rambits(s); break; case AST2500_A0_SILICON_REV: case AST2500_A1_SILICON_REV: - s->ram_bits = ast2500_rambits(); + s->ram_bits = ast2500_rambits(s); break; default: g_assert_not_reached(); @@ -249,6 +251,7 @@ static const VMStateDescription vmstate_aspeed_sdmc = { static Property aspeed_sdmc_properties[] = { DEFINE_PROP_UINT32("silicon-rev", AspeedSDMCState, silicon_rev, 0), + DEFINE_PROP_UINT64("ram-size", AspeedSDMCState, ram_size, 0), DEFINE_PROP_END_OF_LIST(), }; diff --git a/include/hw/misc/aspeed_sdmc.h b/include/hw/misc/aspeed_sdmc.h index df7dce0eddd..551c8afdf4b 100644 --- a/include/hw/misc/aspeed_sdmc.h +++ b/include/hw/misc/aspeed_sdmc.h @@ -26,6 +26,7 @@ typedef struct AspeedSDMCState { uint32_t regs[ASPEED_SDMC_NR_REGS]; uint32_t silicon_rev; uint32_t ram_bits; + uint64_t ram_size; } AspeedSDMCState; From de46f5f46c1bb169045432a8208a9e10a662b55d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Thu, 22 Sep 2016 18:13:06 +0100 Subject: [PATCH 154/723] aspeed: allocate RAM after the memory controller has checked the size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the RAM size is invalid, the memory controller will use a default value. Signed-off-by: Cédric Le Goater Reviewed-by: Andrew Jeffery Message-id: 1473438177-26079-15-git-send-email-clg@kaod.org Signed-off-by: Peter Maydell --- hw/arm/aspeed.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 562bbb25339..6b18c7f1727 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -108,11 +108,6 @@ static void aspeed_board_init(MachineState *machine, sc = ASPEED_SOC_GET_CLASS(&bmc->soc); - memory_region_allocate_system_memory(&bmc->ram, NULL, "ram", ram_size); - memory_region_add_subregion(get_system_memory(), sc->info->sdram_base, - &bmc->ram); - object_property_add_const_link(OBJECT(&bmc->soc), "ram", OBJECT(&bmc->ram), - &error_abort); object_property_set_int(OBJECT(&bmc->soc), ram_size, "ram-size", &error_abort); object_property_set_int(OBJECT(&bmc->soc), cfg->hw_strap1, "hw-strap1", @@ -120,6 +115,19 @@ static void aspeed_board_init(MachineState *machine, object_property_set_bool(OBJECT(&bmc->soc), true, "realized", &error_abort); + /* + * Allocate RAM after the memory controller has checked the size + * was valid. If not, a default value is used. + */ + ram_size = object_property_get_int(OBJECT(&bmc->soc), "ram-size", + &error_abort); + + memory_region_allocate_system_memory(&bmc->ram, NULL, "ram", ram_size); + memory_region_add_subregion(get_system_memory(), sc->info->sdram_base, + &bmc->ram); + object_property_add_const_link(OBJECT(&bmc->soc), "ram", OBJECT(&bmc->ram), + &error_abort); + aspeed_board_init_flashes(&bmc->soc.smc, "n25q256a", &error_abort); aspeed_board_init_flashes(&bmc->soc.spi, "mx25l25635e", &error_abort); From 780d23e54e4a62c1bc37641b72e0188b6d13e861 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Thu, 22 Sep 2016 18:13:06 +0100 Subject: [PATCH 155/723] hw/ptimer: Actually stop the timer in case of error Running with counter / period = 0 is treated as a error case, printing error message claiming that timer has been disabled. However, timer is only marked as disabled, keeping to tick till expired and triggering after being claimed as disabled. Stop the QEMU timer to avoid confusion. Signed-off-by: Dmitry Osipenko Message-id: 1e9bae4fae3c36430d7c28b0f486a0c71aff7eb3.1473252818.git.digetx@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/core/ptimer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/core/ptimer.c b/hw/core/ptimer.c index 30829ee97bc..02c313542d7 100644 --- a/hw/core/ptimer.c +++ b/hw/core/ptimer.c @@ -44,6 +44,7 @@ static void ptimer_reload(ptimer_state *s) } if (s->delta == 0 || s->period == 0) { fprintf(stderr, "Timer with period zero, disabling\n"); + timer_del(s->timer); s->enabled = 0; return; } From e7ea81c37d6f8b4202f63abbac35267bba1c8260 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Thu, 22 Sep 2016 18:13:06 +0100 Subject: [PATCH 156/723] hw/ptimer: Introduce timer policy feature Some of the timer devices may behave differently from what ptimer provides. Introduce ptimer policy feature that allows ptimer users to change default and wrong timer behaviour, for example to continuously trigger periodic timer when load value is equal to "0". Signed-off-by: Dmitry Osipenko Message-id: 994cd608ec392da6e58f0643800dda595edb9d97.1473252818.git.digetx@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/musicpal.c | 2 +- hw/core/ptimer.c | 4 +++- hw/dma/xilinx_axidma.c | 2 +- hw/m68k/mcf5206.c | 2 +- hw/m68k/mcf5208.c | 2 +- hw/net/fsl_etsec/etsec.c | 2 +- hw/net/lan9118.c | 2 +- hw/timer/allwinner-a10-pit.c | 2 +- hw/timer/arm_timer.c | 2 +- hw/timer/digic-timer.c | 2 +- hw/timer/etraxfs_timer.c | 6 +++--- hw/timer/exynos4210_mct.c | 7 ++++--- hw/timer/exynos4210_pwm.c | 2 +- hw/timer/exynos4210_rtc.c | 4 ++-- hw/timer/grlib_gptimer.c | 2 +- hw/timer/imx_epit.c | 4 ++-- hw/timer/imx_gpt.c | 2 +- hw/timer/lm32_timer.c | 2 +- hw/timer/milkymist-sysctl.c | 4 ++-- hw/timer/puv3_ost.c | 2 +- hw/timer/sh_timer.c | 2 +- hw/timer/slavio_timer.c | 2 +- hw/timer/xilinx_timer.c | 2 +- include/hw/ptimer.h | 25 ++++++++++++++++++++++++- 24 files changed, 57 insertions(+), 31 deletions(-) diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c index cc50ace13de..7527037c23e 100644 --- a/hw/arm/musicpal.c +++ b/hw/arm/musicpal.c @@ -837,7 +837,7 @@ static void mv88w8618_timer_init(SysBusDevice *dev, mv88w8618_timer_state *s, s->freq = freq; bh = qemu_bh_new(mv88w8618_timer_tick, s); - s->ptimer = ptimer_init(bh); + s->ptimer = ptimer_init(bh, PTIMER_POLICY_DEFAULT); } static uint64_t mv88w8618_pit_read(void *opaque, hwaddr offset, diff --git a/hw/core/ptimer.c b/hw/core/ptimer.c index 02c313542d7..00fdf157fdc 100644 --- a/hw/core/ptimer.c +++ b/hw/core/ptimer.c @@ -21,6 +21,7 @@ struct ptimer_state int64_t period; int64_t last_event; int64_t next_event; + uint8_t policy_mask; QEMUBH *bh; QEMUTimer *timer; }; @@ -243,12 +244,13 @@ const VMStateDescription vmstate_ptimer = { } }; -ptimer_state *ptimer_init(QEMUBH *bh) +ptimer_state *ptimer_init(QEMUBH *bh, uint8_t policy_mask) { ptimer_state *s; s = (ptimer_state *)g_malloc0(sizeof(ptimer_state)); s->bh = bh; s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ptimer_tick, s); + s->policy_mask = policy_mask; return s; } diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c index a4753e55a2d..b135a5ff12a 100644 --- a/hw/dma/xilinx_axidma.c +++ b/hw/dma/xilinx_axidma.c @@ -548,7 +548,7 @@ static void xilinx_axidma_realize(DeviceState *dev, Error **errp) st->nr = i; st->bh = qemu_bh_new(timer_hit, st); - st->ptimer = ptimer_init(st->bh); + st->ptimer = ptimer_init(st->bh, PTIMER_POLICY_DEFAULT); ptimer_set_freq(st->ptimer, s->freqhz); } return; diff --git a/hw/m68k/mcf5206.c b/hw/m68k/mcf5206.c index e14896e5292..b81901fdfda 100644 --- a/hw/m68k/mcf5206.c +++ b/hw/m68k/mcf5206.c @@ -139,7 +139,7 @@ static m5206_timer_state *m5206_timer_init(qemu_irq irq) s = (m5206_timer_state *)g_malloc0(sizeof(m5206_timer_state)); bh = qemu_bh_new(m5206_timer_trigger, s); - s->timer = ptimer_init(bh); + s->timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT); s->irq = irq; m5206_timer_reset(s); return s; diff --git a/hw/m68k/mcf5208.c b/hw/m68k/mcf5208.c index 24155574f22..9240ebf9af4 100644 --- a/hw/m68k/mcf5208.c +++ b/hw/m68k/mcf5208.c @@ -183,7 +183,7 @@ static void mcf5208_sys_init(MemoryRegion *address_space, qemu_irq *pic) for (i = 0; i < 2; i++) { s = (m5208_timer_state *)g_malloc0(sizeof(m5208_timer_state)); bh = qemu_bh_new(m5208_timer_trigger, s); - s->timer = ptimer_init(bh); + s->timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT); memory_region_init_io(&s->iomem, NULL, &m5208_timer_ops, s, "m5208-timer", 0x00004000); memory_region_add_subregion(address_space, 0xfc080000 + 0x4000 * i, diff --git a/hw/net/fsl_etsec/etsec.c b/hw/net/fsl_etsec/etsec.c index b5c777fbf68..951c5f0038e 100644 --- a/hw/net/fsl_etsec/etsec.c +++ b/hw/net/fsl_etsec/etsec.c @@ -387,7 +387,7 @@ static void etsec_realize(DeviceState *dev, Error **errp) etsec->bh = qemu_bh_new(etsec_timer_hit, etsec); - etsec->ptimer = ptimer_init(etsec->bh); + etsec->ptimer = ptimer_init(etsec->bh, PTIMER_POLICY_DEFAULT); ptimer_set_freq(etsec->ptimer, 100); } diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c index 4615d873b1b..3db8937cac3 100644 --- a/hw/net/lan9118.c +++ b/hw/net/lan9118.c @@ -1345,7 +1345,7 @@ static int lan9118_init1(SysBusDevice *sbd) s->txp = &s->tx_packet; bh = qemu_bh_new(lan9118_tick, s); - s->timer = ptimer_init(bh); + s->timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT); ptimer_set_freq(s->timer, 10000); ptimer_set_limit(s->timer, 0xffff, 1); diff --git a/hw/timer/allwinner-a10-pit.c b/hw/timer/allwinner-a10-pit.c index 3385e5dc350..22ceabe1d48 100644 --- a/hw/timer/allwinner-a10-pit.c +++ b/hw/timer/allwinner-a10-pit.c @@ -267,7 +267,7 @@ static void a10_pit_init(Object *obj) tc->container = s; tc->index = i; bh[i] = qemu_bh_new(a10_pit_timer_cb, tc); - s->timer[i] = ptimer_init(bh[i]); + s->timer[i] = ptimer_init(bh[i], PTIMER_POLICY_DEFAULT); } } diff --git a/hw/timer/arm_timer.c b/hw/timer/arm_timer.c index 111a16db376..98fddd7ac10 100644 --- a/hw/timer/arm_timer.c +++ b/hw/timer/arm_timer.c @@ -171,7 +171,7 @@ static arm_timer_state *arm_timer_init(uint32_t freq) s->control = TIMER_CTRL_IE; bh = qemu_bh_new(arm_timer_tick, s); - s->timer = ptimer_init(bh); + s->timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT); vmstate_register(NULL, -1, &vmstate_arm_timer, s); return s; } diff --git a/hw/timer/digic-timer.c b/hw/timer/digic-timer.c index 0f21faf8761..e1fcf73c3e8 100644 --- a/hw/timer/digic-timer.c +++ b/hw/timer/digic-timer.c @@ -127,7 +127,7 @@ static void digic_timer_init(Object *obj) { DigicTimerState *s = DIGIC_TIMER(obj); - s->ptimer = ptimer_init(NULL); + s->ptimer = ptimer_init(NULL, PTIMER_POLICY_DEFAULT); /* * FIXME: there is no documentation on Digic timer diff --git a/hw/timer/etraxfs_timer.c b/hw/timer/etraxfs_timer.c index 36d8f462c48..8e18236c5a7 100644 --- a/hw/timer/etraxfs_timer.c +++ b/hw/timer/etraxfs_timer.c @@ -322,9 +322,9 @@ static int etraxfs_timer_init(SysBusDevice *dev) t->bh_t0 = qemu_bh_new(timer0_hit, t); t->bh_t1 = qemu_bh_new(timer1_hit, t); t->bh_wd = qemu_bh_new(watchdog_hit, t); - t->ptimer_t0 = ptimer_init(t->bh_t0); - t->ptimer_t1 = ptimer_init(t->bh_t1); - t->ptimer_wd = ptimer_init(t->bh_wd); + t->ptimer_t0 = ptimer_init(t->bh_t0, PTIMER_POLICY_DEFAULT); + t->ptimer_t1 = ptimer_init(t->bh_t1, PTIMER_POLICY_DEFAULT); + t->ptimer_wd = ptimer_init(t->bh_wd, PTIMER_POLICY_DEFAULT); sysbus_init_irq(dev, &t->irq); sysbus_init_irq(dev, &t->nmi); diff --git a/hw/timer/exynos4210_mct.c b/hw/timer/exynos4210_mct.c index ae69345f0d1..0c189348ae0 100644 --- a/hw/timer/exynos4210_mct.c +++ b/hw/timer/exynos4210_mct.c @@ -1431,15 +1431,16 @@ static void exynos4210_mct_init(Object *obj) /* Global timer */ bh[0] = qemu_bh_new(exynos4210_gfrc_event, s); - s->g_timer.ptimer_frc = ptimer_init(bh[0]); + s->g_timer.ptimer_frc = ptimer_init(bh[0], PTIMER_POLICY_DEFAULT); memset(&s->g_timer.reg, 0, sizeof(struct gregs)); /* Local timers */ for (i = 0; i < 2; i++) { bh[0] = qemu_bh_new(exynos4210_ltick_event, &s->l_timer[i]); bh[1] = qemu_bh_new(exynos4210_lfrc_event, &s->l_timer[i]); - s->l_timer[i].tick_timer.ptimer_tick = ptimer_init(bh[0]); - s->l_timer[i].ptimer_frc = ptimer_init(bh[1]); + s->l_timer[i].tick_timer.ptimer_tick = + ptimer_init(bh[0], PTIMER_POLICY_DEFAULT); + s->l_timer[i].ptimer_frc = ptimer_init(bh[1], PTIMER_POLICY_DEFAULT); s->l_timer[i].id = i; } diff --git a/hw/timer/exynos4210_pwm.c b/hw/timer/exynos4210_pwm.c index 0e9e2e9bf57..f5765075c72 100644 --- a/hw/timer/exynos4210_pwm.c +++ b/hw/timer/exynos4210_pwm.c @@ -390,7 +390,7 @@ static void exynos4210_pwm_init(Object *obj) for (i = 0; i < EXYNOS4210_PWM_TIMERS_NUM; i++) { bh = qemu_bh_new(exynos4210_pwm_tick, &s->timer[i]); sysbus_init_irq(dev, &s->timer[i].irq); - s->timer[i].ptimer = ptimer_init(bh); + s->timer[i].ptimer = ptimer_init(bh, PTIMER_POLICY_DEFAULT); s->timer[i].id = i; s->timer[i].parent = s; } diff --git a/hw/timer/exynos4210_rtc.c b/hw/timer/exynos4210_rtc.c index da4dd451b93..1a648c5d9e6 100644 --- a/hw/timer/exynos4210_rtc.c +++ b/hw/timer/exynos4210_rtc.c @@ -555,12 +555,12 @@ static void exynos4210_rtc_init(Object *obj) QEMUBH *bh; bh = qemu_bh_new(exynos4210_rtc_tick, s); - s->ptimer = ptimer_init(bh); + s->ptimer = ptimer_init(bh, PTIMER_POLICY_DEFAULT); ptimer_set_freq(s->ptimer, RTC_BASE_FREQ); exynos4210_rtc_update_freq(s, 0); bh = qemu_bh_new(exynos4210_rtc_1Hz_tick, s); - s->ptimer_1Hz = ptimer_init(bh); + s->ptimer_1Hz = ptimer_init(bh, PTIMER_POLICY_DEFAULT); ptimer_set_freq(s->ptimer_1Hz, RTC_BASE_FREQ); sysbus_init_irq(dev, &s->alm_irq); diff --git a/hw/timer/grlib_gptimer.c b/hw/timer/grlib_gptimer.c index dd000f5afa7..712d1aece5a 100644 --- a/hw/timer/grlib_gptimer.c +++ b/hw/timer/grlib_gptimer.c @@ -363,7 +363,7 @@ static int grlib_gptimer_init(SysBusDevice *dev) timer->unit = unit; timer->bh = qemu_bh_new(grlib_gptimer_hit, timer); - timer->ptimer = ptimer_init(timer->bh); + timer->ptimer = ptimer_init(timer->bh, PTIMER_POLICY_DEFAULT); timer->id = i; /* One IRQ line for each timer */ diff --git a/hw/timer/imx_epit.c b/hw/timer/imx_epit.c index eddf3481e8b..f34d7f7c777 100644 --- a/hw/timer/imx_epit.c +++ b/hw/timer/imx_epit.c @@ -314,10 +314,10 @@ static void imx_epit_realize(DeviceState *dev, Error **errp) 0x00001000); sysbus_init_mmio(sbd, &s->iomem); - s->timer_reload = ptimer_init(NULL); + s->timer_reload = ptimer_init(NULL, PTIMER_POLICY_DEFAULT); bh = qemu_bh_new(imx_epit_cmp, s); - s->timer_cmp = ptimer_init(bh); + s->timer_cmp = ptimer_init(bh, PTIMER_POLICY_DEFAULT); } static void imx_epit_class_init(ObjectClass *klass, void *data) diff --git a/hw/timer/imx_gpt.c b/hw/timer/imx_gpt.c index 82bc73cb868..f034d650362 100644 --- a/hw/timer/imx_gpt.c +++ b/hw/timer/imx_gpt.c @@ -461,7 +461,7 @@ static void imx_gpt_realize(DeviceState *dev, Error **errp) sysbus_init_mmio(sbd, &s->iomem); bh = qemu_bh_new(imx_gpt_timeout, s); - s->timer = ptimer_init(bh); + s->timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT); } static void imx_gpt_class_init(ObjectClass *klass, void *data) diff --git a/hw/timer/lm32_timer.c b/hw/timer/lm32_timer.c index e45a65bb9da..2a07b59524e 100644 --- a/hw/timer/lm32_timer.c +++ b/hw/timer/lm32_timer.c @@ -184,7 +184,7 @@ static void lm32_timer_init(Object *obj) sysbus_init_irq(dev, &s->irq); s->bh = qemu_bh_new(timer_hit, s); - s->ptimer = ptimer_init(s->bh); + s->ptimer = ptimer_init(s->bh, PTIMER_POLICY_DEFAULT); memory_region_init_io(&s->iomem, obj, &timer_ops, s, "timer", R_MAX * 4); diff --git a/hw/timer/milkymist-sysctl.c b/hw/timer/milkymist-sysctl.c index 21948328ceb..44885907c92 100644 --- a/hw/timer/milkymist-sysctl.c +++ b/hw/timer/milkymist-sysctl.c @@ -281,8 +281,8 @@ static void milkymist_sysctl_init(Object *obj) s->bh0 = qemu_bh_new(timer0_hit, s); s->bh1 = qemu_bh_new(timer1_hit, s); - s->ptimer0 = ptimer_init(s->bh0); - s->ptimer1 = ptimer_init(s->bh1); + s->ptimer0 = ptimer_init(s->bh0, PTIMER_POLICY_DEFAULT); + s->ptimer1 = ptimer_init(s->bh1, PTIMER_POLICY_DEFAULT); memory_region_init_io(&s->regs_region, obj, &sysctl_mmio_ops, s, "milkymist-sysctl", R_MAX * 4); diff --git a/hw/timer/puv3_ost.c b/hw/timer/puv3_ost.c index 93650b7990e..0b3d717e608 100644 --- a/hw/timer/puv3_ost.c +++ b/hw/timer/puv3_ost.c @@ -125,7 +125,7 @@ static int puv3_ost_init(SysBusDevice *dev) sysbus_init_irq(dev, &s->irq); s->bh = qemu_bh_new(puv3_ost_tick, s); - s->ptimer = ptimer_init(s->bh); + s->ptimer = ptimer_init(s->bh, PTIMER_POLICY_DEFAULT); ptimer_set_freq(s->ptimer, 50 * 1000 * 1000); memory_region_init_io(&s->iomem, OBJECT(s), &puv3_ost_ops, s, "puv3_ost", diff --git a/hw/timer/sh_timer.c b/hw/timer/sh_timer.c index 255b2fc9101..9afb2d048ce 100644 --- a/hw/timer/sh_timer.c +++ b/hw/timer/sh_timer.c @@ -203,7 +203,7 @@ static void *sh_timer_init(uint32_t freq, int feat, qemu_irq irq) s->irq = irq; bh = qemu_bh_new(sh_timer_tick, s); - s->timer = ptimer_init(bh); + s->timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT); sh_timer_write(s, OFFSET_TCOR >> 2, s->tcor); sh_timer_write(s, OFFSET_TCNT >> 2, s->tcnt); diff --git a/hw/timer/slavio_timer.c b/hw/timer/slavio_timer.c index fb3e08bedc8..bfee1f3027a 100644 --- a/hw/timer/slavio_timer.c +++ b/hw/timer/slavio_timer.c @@ -389,7 +389,7 @@ static int slavio_timer_init1(SysBusDevice *dev) tc->timer_index = i; bh = qemu_bh_new(slavio_timer_irq, tc); - s->cputimer[i].timer = ptimer_init(bh); + s->cputimer[i].timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT); ptimer_set_period(s->cputimer[i].timer, TIMER_PERIOD); size = i == 0 ? SYS_TIMER_SIZE : CPU_TIMER_SIZE; diff --git a/hw/timer/xilinx_timer.c b/hw/timer/xilinx_timer.c index 2ea970dc9d7..59439c05be5 100644 --- a/hw/timer/xilinx_timer.c +++ b/hw/timer/xilinx_timer.c @@ -218,7 +218,7 @@ static void xilinx_timer_realize(DeviceState *dev, Error **errp) xt->parent = t; xt->nr = i; xt->bh = qemu_bh_new(timer_hit, xt); - xt->ptimer = ptimer_init(xt->bh); + xt->ptimer = ptimer_init(xt->bh, PTIMER_POLICY_DEFAULT); ptimer_set_freq(xt->ptimer, t->freq_hz); } diff --git a/include/hw/ptimer.h b/include/hw/ptimer.h index e397db5bdb2..26c7fdcd754 100644 --- a/include/hw/ptimer.h +++ b/include/hw/ptimer.h @@ -12,11 +12,34 @@ #include "qemu/timer.h" #include "migration/vmstate.h" +/* The default ptimer policy retains backward compatibility with the legacy + * timers. Custom policies are adjusting the default one. Consider providing + * a correct policy for your timer. + * + * The rough edges of the default policy: + * - Starting to run with a period = 0 emits error message and stops the + * timer without a trigger. + * + * - Setting period to 0 of the running timer emits error message and + * stops the timer without a trigger. + * + * - Starting to run with counter = 0 or setting it to "0" while timer + * is running causes a trigger and reloads counter with a limit value. + * If limit = 0, ptimer emits error message and stops the timer. + * + * - Counter value of the running timer is one less than the actual value. + * + * - Changing period/frequency of the running timer loses time elapsed + * since the last period, effectively restarting the timer with a + * counter = counter value at the moment of change (.i.e. one less). + */ +#define PTIMER_POLICY_DEFAULT 0 + /* ptimer.c */ typedef struct ptimer_state ptimer_state; typedef void (*ptimer_cb)(void *opaque); -ptimer_state *ptimer_init(QEMUBH *bh); +ptimer_state *ptimer_init(QEMUBH *bh, uint8_t policy_mask); void ptimer_set_period(ptimer_state *s, int64_t period); void ptimer_set_freq(ptimer_state *s, uint32_t freq); uint64_t ptimer_get_limit(ptimer_state *s); From 2a8b58703e2144c136f6d26f609c6a338a03a3ca Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Thu, 22 Sep 2016 18:13:07 +0100 Subject: [PATCH 157/723] hw/ptimer: Suppress error messages under qtest Under qtest ptimer emits lots of warning messages. The messages are caused by the actual checking of the ptimer error conditions. Suppress those messages, so they do not distract. Signed-off-by: Dmitry Osipenko Message-id: 44877fff4ff03205590698d3dc189ad6d091472f.1473252818.git.digetx@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/core/ptimer.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/hw/core/ptimer.c b/hw/core/ptimer.c index 00fdf157fdc..c45c835a176 100644 --- a/hw/core/ptimer.c +++ b/hw/core/ptimer.c @@ -11,6 +11,7 @@ #include "hw/ptimer.h" #include "qemu/host-utils.h" #include "sysemu/replay.h" +#include "sysemu/qtest.h" struct ptimer_state { @@ -44,7 +45,9 @@ static void ptimer_reload(ptimer_state *s) s->delta = s->limit; } if (s->delta == 0 || s->period == 0) { - fprintf(stderr, "Timer with period zero, disabling\n"); + if (!qtest_enabled()) { + fprintf(stderr, "Timer with period zero, disabling\n"); + } timer_del(s->timer); s->enabled = 0; return; @@ -163,7 +166,9 @@ void ptimer_run(ptimer_state *s, int oneshot) bool was_disabled = !s->enabled; if (was_disabled && s->period == 0) { - fprintf(stderr, "Timer with period zero, disabling\n"); + if (!qtest_enabled()) { + fprintf(stderr, "Timer with period zero, disabling\n"); + } return; } s->enabled = oneshot ? 2 : 1; From 5b262bb697189f4c979353933e883b6ae0dd0233 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Thu, 22 Sep 2016 18:13:07 +0100 Subject: [PATCH 158/723] tests: Add ptimer tests Ptimer is a generic countdown timer helper that is used by many timer device models as well as by the QEMU core. Add QTests for the ptimer. Signed-off-by: Dmitry Osipenko Message-id: 1de89fe6e1ccaf6c8071ee3469e1a844df948359.1473252818.git.digetx@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- stubs/vmstate.c | 5 + tests/Makefile.include | 2 + tests/ptimer-test-stubs.c | 107 +++++++ tests/ptimer-test.c | 568 ++++++++++++++++++++++++++++++++++++++ tests/ptimer-test.h | 22 ++ 5 files changed, 704 insertions(+) create mode 100644 tests/ptimer-test-stubs.c create mode 100644 tests/ptimer-test.c create mode 100644 tests/ptimer-test.h diff --git a/stubs/vmstate.c b/stubs/vmstate.c index 65906271d25..94b831e2192 100644 --- a/stubs/vmstate.c +++ b/stubs/vmstate.c @@ -3,6 +3,11 @@ #include "migration/vmstate.h" const VMStateDescription vmstate_dummy = {}; +const VMStateInfo vmstate_info_uint8; +const VMStateInfo vmstate_info_uint32; +const VMStateInfo vmstate_info_uint64; +const VMStateInfo vmstate_info_int64; +const VMStateInfo vmstate_info_timer; int vmstate_register_with_alias_id(DeviceState *dev, int instance_id, diff --git a/tests/Makefile.include b/tests/Makefile.include index 6052a3828f6..1fb3866a99b 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -296,6 +296,7 @@ check-qtest-xtensaeb-y = $(check-qtest-xtensa-y) check-qtest-s390x-y = tests/boot-serial-test$(EXESUF) check-qtest-generic-y += tests/qom-test$(EXESUF) +check-qtest-generic-y += tests/ptimer-test$(EXESUF) qapi-schema += alternate-any.json qapi-schema += alternate-array.json @@ -658,6 +659,7 @@ tests/test-filter-mirror$(EXESUF): tests/test-filter-mirror.o $(qtest-obj-y) tests/test-filter-redirector$(EXESUF): tests/test-filter-redirector.o $(qtest-obj-y) tests/ivshmem-test$(EXESUF): tests/ivshmem-test.o contrib/ivshmem-server/ivshmem-server.o $(libqos-pc-obj-y) tests/vhost-user-bridge$(EXESUF): tests/vhost-user-bridge.o +tests/ptimer-test$(EXESUF): tests/ptimer-test.o tests/ptimer-test-stubs.o hw/core/ptimer.o tests/migration/stress$(EXESUF): tests/migration/stress.o $(call quiet-command, $(LINKPROG) -static -O3 $(PTHREAD_LIB) -o $@ $< ," LINK $(TARGET_DIR)$@") diff --git a/tests/ptimer-test-stubs.c b/tests/ptimer-test-stubs.c new file mode 100644 index 00000000000..92a22fbb095 --- /dev/null +++ b/tests/ptimer-test-stubs.c @@ -0,0 +1,107 @@ +/* + * Stubs for the ptimer-test + * + * Author: Dmitry Osipenko + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "qemu/main-loop.h" +#include "sysemu/replay.h" + +#include "ptimer-test.h" + +struct QEMUBH { + QEMUBHFunc *cb; + void *opaque; +}; + +QEMUTimerListGroup main_loop_tlg; + +int64_t ptimer_test_time_ns; + +void timer_init_tl(QEMUTimer *ts, + QEMUTimerList *timer_list, int scale, + QEMUTimerCB *cb, void *opaque) +{ + ts->timer_list = timer_list; + ts->cb = cb; + ts->opaque = opaque; + ts->scale = scale; + ts->expire_time = -1; +} + +void timer_mod(QEMUTimer *ts, int64_t expire_time) +{ + QEMUTimerList *timer_list = ts->timer_list; + QEMUTimer *t = &timer_list->active_timers; + + while (t->next != NULL) { + if (t->next == ts) { + break; + } + + t = t->next; + } + + ts->expire_time = MAX(expire_time * ts->scale, 0); + ts->next = NULL; + t->next = ts; +} + +void timer_del(QEMUTimer *ts) +{ + QEMUTimerList *timer_list = ts->timer_list; + QEMUTimer *t = &timer_list->active_timers; + + while (t->next != NULL) { + if (t->next == ts) { + t->next = ts->next; + return; + } + + t = t->next; + } +} + +int64_t qemu_clock_get_ns(QEMUClockType type) +{ + return ptimer_test_time_ns; +} + +int64_t qemu_clock_deadline_ns_all(QEMUClockType type) +{ + QEMUTimerList *timer_list = main_loop_tlg.tl[type]; + QEMUTimer *t = timer_list->active_timers.next; + int64_t deadline = -1; + + while (t != NULL) { + if (deadline == -1) { + deadline = t->expire_time; + } else { + deadline = MIN(deadline, t->expire_time); + } + + t = t->next; + } + + return deadline; +} + +QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque) +{ + QEMUBH *bh = g_new(QEMUBH, 1); + + bh->cb = cb; + bh->opaque = opaque; + + return bh; +} + +void replay_bh_schedule_event(QEMUBH *bh) +{ + bh->cb(bh->opaque); +} diff --git a/tests/ptimer-test.c b/tests/ptimer-test.c new file mode 100644 index 00000000000..f207eeb0eb5 --- /dev/null +++ b/tests/ptimer-test.c @@ -0,0 +1,568 @@ +/* + * QTest testcase for the ptimer + * + * Author: Dmitry Osipenko + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include + +#include "qemu/osdep.h" +#include "qemu/main-loop.h" +#include "hw/ptimer.h" + +#include "libqtest.h" +#include "ptimer-test.h" + +static bool triggered; + +static void ptimer_trigger(void *opaque) +{ + triggered = true; +} + +static void ptimer_test_expire_qemu_timers(int64_t expire_time, + QEMUClockType type) +{ + QEMUTimerList *timer_list = main_loop_tlg.tl[type]; + QEMUTimer *t = timer_list->active_timers.next; + + while (t != NULL) { + if (t->expire_time == expire_time) { + timer_del(t); + + if (t->cb != NULL) { + t->cb(t->opaque); + } + } + + t = t->next; + } +} + +static void ptimer_test_set_qemu_time_ns(int64_t ns) +{ + ptimer_test_time_ns = ns; +} + +static void qemu_clock_step(uint64_t ns) +{ + int64_t deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL); + int64_t advanced_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ns; + + while (deadline != -1 && deadline <= advanced_time) { + ptimer_test_set_qemu_time_ns(deadline); + ptimer_test_expire_qemu_timers(deadline, QEMU_CLOCK_VIRTUAL); + deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL); + } + + ptimer_test_set_qemu_time_ns(advanced_time); +} + +static void check_set_count(gconstpointer arg) +{ + const uint8_t *policy = arg; + QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL); + ptimer_state *ptimer = ptimer_init(bh, *policy); + + triggered = false; + + ptimer_set_count(ptimer, 1000); + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 1000); + g_assert_false(triggered); +} + +static void check_set_limit(gconstpointer arg) +{ + const uint8_t *policy = arg; + QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL); + ptimer_state *ptimer = ptimer_init(bh, *policy); + + triggered = false; + + ptimer_set_limit(ptimer, 1000, 0); + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0); + g_assert_cmpuint(ptimer_get_limit(ptimer), ==, 1000); + g_assert_false(triggered); + + ptimer_set_limit(ptimer, 2000, 1); + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 2000); + g_assert_cmpuint(ptimer_get_limit(ptimer), ==, 2000); + g_assert_false(triggered); +} + +static void check_oneshot(gconstpointer arg) +{ + const uint8_t *policy = arg; + QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL); + ptimer_state *ptimer = ptimer_init(bh, *policy); + + triggered = false; + + ptimer_set_period(ptimer, 2000000); + ptimer_set_count(ptimer, 10); + ptimer_run(ptimer, 1); + + qemu_clock_step(2000000 * 2 + 100000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 7); + g_assert_false(triggered); + + ptimer_stop(ptimer); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 7); + g_assert_false(triggered); + + qemu_clock_step(2000000 * 11); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 7); + g_assert_false(triggered); + + ptimer_run(ptimer, 1); + + qemu_clock_step(2000000 * 7 + 100000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0); + g_assert_true(triggered); + + triggered = false; + + qemu_clock_step(2000000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0); + g_assert_false(triggered); + + qemu_clock_step(4000000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0); + g_assert_false(triggered); + + ptimer_set_count(ptimer, 10); + + qemu_clock_step(20000000 + 100000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 10); + g_assert_false(triggered); + + ptimer_set_limit(ptimer, 9, 1); + + qemu_clock_step(20000000 + 100000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 9); + g_assert_false(triggered); + + ptimer_run(ptimer, 1); + + qemu_clock_step(2000000 + 100000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 7); + g_assert_false(triggered); + + ptimer_set_count(ptimer, 20); + + qemu_clock_step(2000000 * 19 + 100000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0); + g_assert_false(triggered); + + qemu_clock_step(2000000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0); + g_assert_true(triggered); + + ptimer_stop(ptimer); + + triggered = false; + + qemu_clock_step(2000000 * 12 + 100000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0); + g_assert_false(triggered); +} + +static void check_periodic(gconstpointer arg) +{ + const uint8_t *policy = arg; + QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL); + ptimer_state *ptimer = ptimer_init(bh, *policy); + + triggered = false; + + ptimer_set_period(ptimer, 2000000); + ptimer_set_limit(ptimer, 10, 1); + ptimer_run(ptimer, 0); + + qemu_clock_step(2000000 * 10 + 100000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 9); + g_assert_true(triggered); + + triggered = false; + + qemu_clock_step(2000000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 8); + g_assert_false(triggered); + + ptimer_set_count(ptimer, 20); + + qemu_clock_step(2000000 * 11 + 100000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 8); + g_assert_false(triggered); + + qemu_clock_step(2000000 * 10); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 8); + g_assert_true(triggered); + + ptimer_stop(ptimer); + triggered = false; + + qemu_clock_step(2000000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 8); + g_assert_false(triggered); + + ptimer_set_count(ptimer, 3); + ptimer_run(ptimer, 0); + + qemu_clock_step(2000000 * 3 + 100000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 9); + g_assert_true(triggered); + + triggered = false; + + qemu_clock_step(2000000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 8); + g_assert_false(triggered); + + ptimer_set_count(ptimer, 0); + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 10); + g_assert_true(triggered); + + triggered = false; + + qemu_clock_step(2000000 * 12 + 100000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 7); + g_assert_true(triggered); + + ptimer_stop(ptimer); + + triggered = false; + + qemu_clock_step(2000000 * 12 + 100000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 7); + g_assert_false(triggered); + + ptimer_run(ptimer, 0); + ptimer_set_period(ptimer, 0); + + qemu_clock_step(2000000 + 100000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 7); + g_assert_false(triggered); +} + +static void check_on_the_fly_mode_change(gconstpointer arg) +{ + const uint8_t *policy = arg; + QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL); + ptimer_state *ptimer = ptimer_init(bh, *policy); + + triggered = false; + + ptimer_set_period(ptimer, 2000000); + ptimer_set_limit(ptimer, 10, 1); + ptimer_run(ptimer, 1); + + qemu_clock_step(2000000 * 9 + 100000); + + ptimer_run(ptimer, 0); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0); + g_assert_false(triggered); + + qemu_clock_step(2000000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 9); + g_assert_true(triggered); + + triggered = false; + + qemu_clock_step(2000000 * 9); + + ptimer_run(ptimer, 1); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0); + g_assert_false(triggered); + + qemu_clock_step(2000000 * 3); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0); + g_assert_true(triggered); +} + +static void check_on_the_fly_period_change(gconstpointer arg) +{ + const uint8_t *policy = arg; + QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL); + ptimer_state *ptimer = ptimer_init(bh, *policy); + + triggered = false; + + ptimer_set_period(ptimer, 2000000); + ptimer_set_limit(ptimer, 8, 1); + ptimer_run(ptimer, 1); + + qemu_clock_step(2000000 * 4 + 100000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 3); + g_assert_false(triggered); + + ptimer_set_period(ptimer, 4000000); + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 3); + + qemu_clock_step(4000000 * 2 + 100000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0); + g_assert_false(triggered); + + qemu_clock_step(4000000 * 2); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0); + g_assert_true(triggered); +} + +static void check_on_the_fly_freq_change(gconstpointer arg) +{ + const uint8_t *policy = arg; + QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL); + ptimer_state *ptimer = ptimer_init(bh, *policy); + + triggered = false; + + ptimer_set_freq(ptimer, 500); + ptimer_set_limit(ptimer, 8, 1); + ptimer_run(ptimer, 1); + + qemu_clock_step(2000000 * 4 + 100000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 3); + g_assert_false(triggered); + + ptimer_set_freq(ptimer, 250); + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 3); + + qemu_clock_step(2000000 * 4 + 100000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0); + g_assert_false(triggered); + + qemu_clock_step(2000000 * 4); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0); + g_assert_true(triggered); +} + +static void check_run_with_period_0(gconstpointer arg) +{ + const uint8_t *policy = arg; + QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL); + ptimer_state *ptimer = ptimer_init(bh, *policy); + + triggered = false; + + ptimer_set_count(ptimer, 99); + ptimer_run(ptimer, 1); + + qemu_clock_step(10 * NANOSECONDS_PER_SECOND); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 99); + g_assert_false(triggered); +} + +static void check_run_with_delta_0(gconstpointer arg) +{ + const uint8_t *policy = arg; + QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL); + ptimer_state *ptimer = ptimer_init(bh, *policy); + + triggered = false; + + ptimer_set_period(ptimer, 2000000); + ptimer_set_limit(ptimer, 99, 0); + ptimer_run(ptimer, 1); + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 99); + g_assert_true(triggered); + + triggered = false; + + qemu_clock_step(2000000 + 100000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 97); + g_assert_false(triggered); + + qemu_clock_step(2000000 * 97); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0); + g_assert_false(triggered); + + qemu_clock_step(2000000 * 2); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0); + g_assert_true(triggered); + + triggered = false; + + ptimer_set_count(ptimer, 0); + ptimer_run(ptimer, 0); + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 99); + g_assert_true(triggered); + + triggered = false; + + qemu_clock_step(2000000 + 100000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 97); + g_assert_false(triggered); + + qemu_clock_step(2000000 * 98); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 98); + g_assert_true(triggered); + + ptimer_stop(ptimer); +} + +static void check_periodic_with_load_0(gconstpointer arg) +{ + const uint8_t *policy = arg; + QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL); + ptimer_state *ptimer = ptimer_init(bh, *policy); + + triggered = false; + + ptimer_set_period(ptimer, 2000000); + ptimer_run(ptimer, 0); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0); + g_assert_true(triggered); + + triggered = false; + + qemu_clock_step(2000000 + 100000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0); + g_assert_false(triggered); + + ptimer_stop(ptimer); +} + +static void check_oneshot_with_load_0(gconstpointer arg) +{ + const uint8_t *policy = arg; + QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL); + ptimer_state *ptimer = ptimer_init(bh, *policy); + + triggered = false; + + ptimer_set_period(ptimer, 2000000); + ptimer_run(ptimer, 1); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0); + g_assert_true(triggered); + + triggered = false; + + qemu_clock_step(2000000 + 100000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0); + g_assert_false(triggered); + + triggered = false; + + qemu_clock_step(2000000 + 100000); + + g_assert_false(triggered); +} + +static void add_ptimer_tests(uint8_t policy) +{ + uint8_t *ppolicy = g_malloc(1); + char *policy_name = g_malloc(64); + + *ppolicy = policy; + + if (policy == PTIMER_POLICY_DEFAULT) { + g_sprintf(policy_name, "default"); + } + + qtest_add_data_func( + g_strdup_printf("/ptimer/set_count policy=%s", policy_name), + ppolicy, check_set_count); + + qtest_add_data_func( + g_strdup_printf("/ptimer/set_limit policy=%s", policy_name), + ppolicy, check_set_limit); + + qtest_add_data_func( + g_strdup_printf("/ptimer/oneshot policy=%s", policy_name), + ppolicy, check_oneshot); + + qtest_add_data_func( + g_strdup_printf("/ptimer/periodic policy=%s", policy_name), + ppolicy, check_periodic); + + qtest_add_data_func( + g_strdup_printf("/ptimer/on_the_fly_mode_change policy=%s", policy_name), + ppolicy, check_on_the_fly_mode_change); + + qtest_add_data_func( + g_strdup_printf("/ptimer/on_the_fly_period_change policy=%s", policy_name), + ppolicy, check_on_the_fly_period_change); + + qtest_add_data_func( + g_strdup_printf("/ptimer/on_the_fly_freq_change policy=%s", policy_name), + ppolicy, check_on_the_fly_freq_change); + + qtest_add_data_func( + g_strdup_printf("/ptimer/run_with_period_0 policy=%s", policy_name), + ppolicy, check_run_with_period_0); + + qtest_add_data_func( + g_strdup_printf("/ptimer/run_with_delta_0 policy=%s", policy_name), + ppolicy, check_run_with_delta_0); + + qtest_add_data_func( + g_strdup_printf("/ptimer/periodic_with_load_0 policy=%s", policy_name), + ppolicy, check_periodic_with_load_0); + + qtest_add_data_func( + g_strdup_printf("/ptimer/oneshot_with_load_0 policy=%s", policy_name), + ppolicy, check_oneshot_with_load_0); +} + +int main(int argc, char **argv) +{ + int i; + + g_test_init(&argc, &argv, NULL); + + for (i = 0; i < QEMU_CLOCK_MAX; i++) { + main_loop_tlg.tl[i] = g_new0(QEMUTimerList, 1); + } + + add_ptimer_tests(PTIMER_POLICY_DEFAULT); + + qtest_allowed = true; + + return g_test_run(); +} diff --git a/tests/ptimer-test.h b/tests/ptimer-test.h new file mode 100644 index 00000000000..98d9b8f3477 --- /dev/null +++ b/tests/ptimer-test.h @@ -0,0 +1,22 @@ +/* + * QTest testcase for the ptimer + * + * Author: Dmitry Osipenko + * + * 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 PTIMER_TEST_H +#define PTIMER_TEST_H + +extern bool qtest_allowed; + +extern int64_t ptimer_test_time_ns; + +struct QEMUTimerList { + QEMUTimer active_timers; +}; + +#endif From bcb39a65f141ca0d5bc703435dc6c54d402112f1 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Thu, 22 Sep 2016 18:13:07 +0100 Subject: [PATCH 159/723] cadence_gem: QOMify Cadence GEM The sysbus_init_irq() call will eventually depend on a property so it needs to be in the realize function. Signed-off-by: Alistair Francis Reviewed-by: Peter Maydell Message-id: 486595809cf416d18a750aafbcfa1c81d7160c59.1469727764.git.alistair.francis@xilinx.com Signed-off-by: Peter Maydell --- hw/net/cadence_gem.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index db1b301e7f7..7adc2a880fd 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -1214,24 +1214,30 @@ static NetClientInfo net_gem_info = { .link_status_changed = gem_set_link, }; -static int gem_init(SysBusDevice *sbd) +static void gem_realize(DeviceState *dev, Error **errp) { - DeviceState *dev = DEVICE(sbd); CadenceGEMState *s = CADENCE_GEM(dev); + sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq); + + qemu_macaddr_default_if_unset(&s->conf.macaddr); + + s->nic = qemu_new_nic(&net_gem_info, &s->conf, + object_get_typename(OBJECT(dev)), dev->id, s); +} + +static void gem_init(Object *obj) +{ + CadenceGEMState *s = CADENCE_GEM(obj); + DeviceState *dev = DEVICE(obj); + DB_PRINT("\n"); gem_init_register_masks(s); memory_region_init_io(&s->iomem, OBJECT(s), &gem_ops, s, "enet", sizeof(s->regs)); - sysbus_init_mmio(sbd, &s->iomem); - sysbus_init_irq(sbd, &s->irq); - qemu_macaddr_default_if_unset(&s->conf.macaddr); - - s->nic = qemu_new_nic(&net_gem_info, &s->conf, - object_get_typename(OBJECT(dev)), dev->id, s); - return 0; + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); } static const VMStateDescription vmstate_cadence_gem = { @@ -1257,9 +1263,8 @@ static Property gem_properties[] = { static void gem_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); - sdc->init = gem_init; + dc->realize = gem_realize; dc->props = gem_properties; dc->vmsd = &vmstate_cadence_gem; dc->reset = gem_reset; @@ -1269,6 +1274,7 @@ static const TypeInfo gem_info = { .name = TYPE_CADENCE_GEM, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(CadenceGEMState), + .instance_init = gem_init, .class_init = gem_class_init, }; From 2bf57f73e3a324ecdfac338e050eca381aa2216c Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Thu, 22 Sep 2016 18:13:07 +0100 Subject: [PATCH 160/723] cadence_gem: Add the num-priority-queues property The Cadence GEM hardware supports N number priority queues, this patch is a step towards that by adding the property to set the queues. At the moment behaviour doesn't change as we only use queue 0. Signed-off-by: Alistair Francis Reviewed-by: Peter Maydell Message-id: 6543ec0d0c4bfd2678d0ed683efb197e91b17733.1469727764.git.alistair.francis@xilinx.com Signed-off-by: Peter Maydell --- hw/net/cadence_gem.c | 94 +++++++++++++++++++++--------------- include/hw/net/cadence_gem.h | 13 +++-- 2 files changed, 64 insertions(+), 43 deletions(-) diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index 7adc2a880fd..08b3747b8ad 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -26,6 +26,7 @@ #include /* For crc32 */ #include "hw/net/cadence_gem.h" +#include "qapi/error.h" #include "net/checksum.h" #ifdef CADENCE_GEM_ERR_DEBUG @@ -428,18 +429,18 @@ static int gem_can_receive(NetClientState *nc) return 0; } - if (rx_desc_get_ownership(s->rx_desc) == 1) { + if (rx_desc_get_ownership(s->rx_desc[0]) == 1) { if (s->can_rx_state != 2) { s->can_rx_state = 2; DB_PRINT("can't receive - busy buffer descriptor 0x%x\n", - s->rx_desc_addr); + s->rx_desc_addr[0]); } return 0; } if (s->can_rx_state != 0) { s->can_rx_state = 0; - DB_PRINT("can receive 0x%x\n", s->rx_desc_addr); + DB_PRINT("can receive 0x%x\n", s->rx_desc_addr[0]); } return 1; } @@ -452,7 +453,7 @@ static void gem_update_int_status(CadenceGEMState *s) { if (s->regs[GEM_ISR]) { DB_PRINT("asserting int. (0x%08x)\n", s->regs[GEM_ISR]); - qemu_set_irq(s->irq, 1); + qemu_set_irq(s->irq[0], 1); } } @@ -603,15 +604,15 @@ static int gem_mac_address_filter(CadenceGEMState *s, const uint8_t *packet) static void gem_get_rx_desc(CadenceGEMState *s) { - DB_PRINT("read descriptor 0x%x\n", (unsigned)s->rx_desc_addr); + DB_PRINT("read descriptor 0x%x\n", (unsigned)s->rx_desc_addr[0]); /* read current descriptor */ - cpu_physical_memory_read(s->rx_desc_addr, - (uint8_t *)s->rx_desc, sizeof(s->rx_desc)); + cpu_physical_memory_read(s->rx_desc_addr[0], + (uint8_t *)s->rx_desc[0], sizeof(s->rx_desc[0])); /* Descriptor owned by software ? */ - if (rx_desc_get_ownership(s->rx_desc) == 1) { + if (rx_desc_get_ownership(s->rx_desc[0]) == 1) { DB_PRINT("descriptor 0x%x owned by sw.\n", - (unsigned)s->rx_desc_addr); + (unsigned)s->rx_desc_addr[0]); s->regs[GEM_RXSTATUS] |= GEM_RXSTATUS_NOBUF; s->regs[GEM_ISR] |= GEM_INT_RXUSED & ~(s->regs[GEM_IMR]); /* Handle interrupt consequences */ @@ -632,6 +633,7 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) uint8_t *rxbuf_ptr; bool first_desc = true; int maf; + int q = 0; s = qemu_get_nic_opaque(nc); @@ -718,54 +720,56 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) } DB_PRINT("copy %d bytes to 0x%x\n", MIN(bytes_to_copy, rxbufsize), - rx_desc_get_buffer(s->rx_desc)); + rx_desc_get_buffer(s->rx_desc[q])); /* Copy packet data to emulated DMA buffer */ - cpu_physical_memory_write(rx_desc_get_buffer(s->rx_desc) + rxbuf_offset, + cpu_physical_memory_write(rx_desc_get_buffer(s->rx_desc[q]) + + rxbuf_offset, rxbuf_ptr, MIN(bytes_to_copy, rxbufsize)); rxbuf_ptr += MIN(bytes_to_copy, rxbufsize); bytes_to_copy -= MIN(bytes_to_copy, rxbufsize); /* Update the descriptor. */ if (first_desc) { - rx_desc_set_sof(s->rx_desc); + rx_desc_set_sof(s->rx_desc[q]); first_desc = false; } if (bytes_to_copy == 0) { - rx_desc_set_eof(s->rx_desc); - rx_desc_set_length(s->rx_desc, size); + rx_desc_set_eof(s->rx_desc[q]); + rx_desc_set_length(s->rx_desc[q], size); } - rx_desc_set_ownership(s->rx_desc); + rx_desc_set_ownership(s->rx_desc[q]); switch (maf) { case GEM_RX_PROMISCUOUS_ACCEPT: break; case GEM_RX_BROADCAST_ACCEPT: - rx_desc_set_broadcast(s->rx_desc); + rx_desc_set_broadcast(s->rx_desc[q]); break; case GEM_RX_UNICAST_HASH_ACCEPT: - rx_desc_set_unicast_hash(s->rx_desc); + rx_desc_set_unicast_hash(s->rx_desc[q]); break; case GEM_RX_MULTICAST_HASH_ACCEPT: - rx_desc_set_multicast_hash(s->rx_desc); + rx_desc_set_multicast_hash(s->rx_desc[q]); break; case GEM_RX_REJECT: abort(); default: /* SAR */ - rx_desc_set_sar(s->rx_desc, maf); + rx_desc_set_sar(s->rx_desc[q], maf); } /* Descriptor write-back. */ - cpu_physical_memory_write(s->rx_desc_addr, - (uint8_t *)s->rx_desc, sizeof(s->rx_desc)); + cpu_physical_memory_write(s->rx_desc_addr[q], + (uint8_t *)s->rx_desc[q], + sizeof(s->rx_desc[q])); /* Next descriptor */ - if (rx_desc_get_wrap(s->rx_desc)) { + if (rx_desc_get_wrap(s->rx_desc[q])) { DB_PRINT("wrapping RX descriptor list\n"); - s->rx_desc_addr = s->regs[GEM_RXQBASE]; + s->rx_desc_addr[q] = s->regs[GEM_RXQBASE]; } else { DB_PRINT("incrementing RX descriptor list\n"); - s->rx_desc_addr += 8; + s->rx_desc_addr[q] += 8; } gem_get_rx_desc(s); } @@ -839,6 +843,7 @@ static void gem_transmit(CadenceGEMState *s) uint8_t tx_packet[2048]; uint8_t *p; unsigned total_bytes; + int q = 0; /* Do nothing if transmit is not enabled. */ if (!(s->regs[GEM_NWCTRL] & GEM_NWCTRL_TXENA)) { @@ -855,7 +860,7 @@ static void gem_transmit(CadenceGEMState *s) total_bytes = 0; /* read current descriptor */ - packet_desc_addr = s->tx_desc_addr; + packet_desc_addr = s->tx_desc_addr[q]; DB_PRINT("read descriptor 0x%" HWADDR_PRIx "\n", packet_desc_addr); cpu_physical_memory_read(packet_desc_addr, @@ -902,18 +907,18 @@ static void gem_transmit(CadenceGEMState *s) /* Modify the 1st descriptor of this packet to be owned by * the processor. */ - cpu_physical_memory_read(s->tx_desc_addr, (uint8_t *)desc_first, + cpu_physical_memory_read(s->tx_desc_addr[q], (uint8_t *)desc_first, sizeof(desc_first)); tx_desc_set_used(desc_first); - cpu_physical_memory_write(s->tx_desc_addr, (uint8_t *)desc_first, + cpu_physical_memory_write(s->tx_desc_addr[q], (uint8_t *)desc_first, sizeof(desc_first)); /* Advance the hardware current descriptor past this packet */ if (tx_desc_get_wrap(desc)) { - s->tx_desc_addr = s->regs[GEM_TXQBASE]; + s->tx_desc_addr[q] = s->regs[GEM_TXQBASE]; } else { - s->tx_desc_addr = packet_desc_addr + 8; + s->tx_desc_addr[q] = packet_desc_addr + 8; } - DB_PRINT("TX descriptor next: 0x%08x\n", s->tx_desc_addr); + DB_PRINT("TX descriptor next: 0x%08x\n", s->tx_desc_addr[q]); s->regs[GEM_TXSTATUS] |= GEM_TXSTATUS_TXCMPL; s->regs[GEM_ISR] |= GEM_INT_TXCMPL & ~(s->regs[GEM_IMR]); @@ -1076,7 +1081,7 @@ static uint64_t gem_read(void *opaque, hwaddr offset, unsigned size) switch (offset) { case GEM_ISR: DB_PRINT("lowering irq on ISR read\n"); - qemu_set_irq(s->irq, 0); + qemu_set_irq(s->irq[0], 0); break; case GEM_PHYMNTNC: if (retval & GEM_PHYMNTNC_OP_R) { @@ -1139,7 +1144,7 @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val, } if (!(val & GEM_NWCTRL_TXENA)) { /* Reset to start of Q when transmit disabled. */ - s->tx_desc_addr = s->regs[GEM_TXQBASE]; + s->tx_desc_addr[0] = s->regs[GEM_TXQBASE]; } if (gem_can_receive(qemu_get_queue(s->nic))) { qemu_flush_queued_packets(qemu_get_queue(s->nic)); @@ -1150,10 +1155,10 @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val, gem_update_int_status(s); break; case GEM_RXQBASE: - s->rx_desc_addr = val; + s->rx_desc_addr[0] = val; break; case GEM_TXQBASE: - s->tx_desc_addr = val; + s->tx_desc_addr[0] = val; break; case GEM_RXSTATUS: gem_update_int_status(s); @@ -1218,7 +1223,14 @@ static void gem_realize(DeviceState *dev, Error **errp) { CadenceGEMState *s = CADENCE_GEM(dev); - sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq); + if (s->num_priority_queues == 0 || + s->num_priority_queues > MAX_PRIORITY_QUEUES) { + error_setg(errp, "Invalid num-priority-queues value: %" PRIx8, + s->num_priority_queues); + return; + } + + sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[0]); qemu_macaddr_default_if_unset(&s->conf.macaddr); @@ -1242,14 +1254,16 @@ static void gem_init(Object *obj) static const VMStateDescription vmstate_cadence_gem = { .name = "cadence_gem", - .version_id = 2, - .minimum_version_id = 2, + .version_id = 3, + .minimum_version_id = 3, .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, CadenceGEMState, CADENCE_GEM_MAXREG), VMSTATE_UINT16_ARRAY(phy_regs, CadenceGEMState, 32), VMSTATE_UINT8(phy_loop, CadenceGEMState), - VMSTATE_UINT32(rx_desc_addr, CadenceGEMState), - VMSTATE_UINT32(tx_desc_addr, CadenceGEMState), + VMSTATE_UINT32_ARRAY(rx_desc_addr, CadenceGEMState, + MAX_PRIORITY_QUEUES), + VMSTATE_UINT32_ARRAY(tx_desc_addr, CadenceGEMState, + MAX_PRIORITY_QUEUES), VMSTATE_BOOL_ARRAY(sar_active, CadenceGEMState, 4), VMSTATE_END_OF_LIST(), } @@ -1257,6 +1271,8 @@ static const VMStateDescription vmstate_cadence_gem = { static Property gem_properties[] = { DEFINE_NIC_PROPERTIES(CadenceGEMState, conf), + DEFINE_PROP_UINT8("num-priority-queues", CadenceGEMState, + num_priority_queues, 1), DEFINE_PROP_END_OF_LIST(), }; diff --git a/include/hw/net/cadence_gem.h b/include/hw/net/cadence_gem.h index f2e08e35754..77e05820530 100644 --- a/include/hw/net/cadence_gem.h +++ b/include/hw/net/cadence_gem.h @@ -32,6 +32,8 @@ #define CADENCE_GEM_MAXREG (0x00000640/4) /* Last valid GEM address */ +#define MAX_PRIORITY_QUEUES 8 + typedef struct CadenceGEMState { /*< private >*/ SysBusDevice parent_obj; @@ -40,7 +42,10 @@ typedef struct CadenceGEMState { MemoryRegion iomem; NICState *nic; NICConf conf; - qemu_irq irq; + qemu_irq irq[MAX_PRIORITY_QUEUES]; + + /* Static properties */ + uint8_t num_priority_queues; /* GEM registers backing store */ uint32_t regs[CADENCE_GEM_MAXREG]; @@ -59,12 +64,12 @@ typedef struct CadenceGEMState { uint8_t phy_loop; /* Are we in phy loopback? */ /* The current DMA descriptor pointers */ - uint32_t rx_desc_addr; - uint32_t tx_desc_addr; + uint32_t rx_desc_addr[MAX_PRIORITY_QUEUES]; + uint32_t tx_desc_addr[MAX_PRIORITY_QUEUES]; uint8_t can_rx_state; /* Debug only */ - unsigned rx_desc[2]; + unsigned rx_desc[MAX_PRIORITY_QUEUES][2]; bool sar_active[4]; } CadenceGEMState; From e8e4994313b7f9fa41c9867c2b507cf24ef78789 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Thu, 22 Sep 2016 18:13:07 +0100 Subject: [PATCH 161/723] cadence_gem: Add support for screening The Cadence GEM hardware allows incoming data to be 'screened' based on some register values. Add support for these screens. We also need to increase the max regs to avoid compilation failures. These new registers are implemented in the next patch. Signed-off-by: Alistair Francis Reviewed-by: Peter Maydell Message-id: 73e69a8ad9fa2763e9f68f71eaf2469dd5744fcc.1469727764.git.alistair.francis@xilinx.com Signed-off-by: Peter Maydell --- hw/net/cadence_gem.c | 171 ++++++++++++++++++++++++++++++++++- include/hw/net/cadence_gem.h | 6 +- 2 files changed, 174 insertions(+), 3 deletions(-) diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index 08b3747b8ad..49a63a785f9 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -27,6 +27,7 @@ #include "hw/net/cadence_gem.h" #include "qapi/error.h" +#include "qemu/log.h" #include "net/checksum.h" #ifdef CADENCE_GEM_ERR_DEBUG @@ -142,6 +143,37 @@ #define GEM_DESCONF6 (0x00000294/4) #define GEM_DESCONF7 (0x00000298/4) +#define GEM_SCREENING_TYPE1_REGISTER_0 (0x00000500 / 4) + +#define GEM_ST1R_UDP_PORT_MATCH_ENABLE (1 << 29) +#define GEM_ST1R_DSTC_ENABLE (1 << 28) +#define GEM_ST1R_UDP_PORT_MATCH_SHIFT (12) +#define GEM_ST1R_UDP_PORT_MATCH_WIDTH (27 - GEM_ST1R_UDP_PORT_MATCH_SHIFT + 1) +#define GEM_ST1R_DSTC_MATCH_SHIFT (4) +#define GEM_ST1R_DSTC_MATCH_WIDTH (11 - GEM_ST1R_DSTC_MATCH_SHIFT + 1) +#define GEM_ST1R_QUEUE_SHIFT (0) +#define GEM_ST1R_QUEUE_WIDTH (3 - GEM_ST1R_QUEUE_SHIFT + 1) + +#define GEM_SCREENING_TYPE2_REGISTER_0 (0x00000540 / 4) + +#define GEM_ST2R_COMPARE_A_ENABLE (1 << 18) +#define GEM_ST2R_COMPARE_A_SHIFT (13) +#define GEM_ST2R_COMPARE_WIDTH (17 - GEM_ST2R_COMPARE_A_SHIFT + 1) +#define GEM_ST2R_ETHERTYPE_ENABLE (1 << 12) +#define GEM_ST2R_ETHERTYPE_INDEX_SHIFT (9) +#define GEM_ST2R_ETHERTYPE_INDEX_WIDTH (11 - GEM_ST2R_ETHERTYPE_INDEX_SHIFT \ + + 1) +#define GEM_ST2R_QUEUE_SHIFT (0) +#define GEM_ST2R_QUEUE_WIDTH (3 - GEM_ST2R_QUEUE_SHIFT + 1) + +#define GEM_SCREENING_TYPE2_ETHERTYPE_REG_0 (0x000006e0 / 4) +#define GEM_TYPE2_COMPARE_0_WORD_0 (0x00000700 / 4) + +#define GEM_T2CW1_COMPARE_OFFSET_SHIFT (7) +#define GEM_T2CW1_COMPARE_OFFSET_WIDTH (8 - GEM_T2CW1_COMPARE_OFFSET_SHIFT + 1) +#define GEM_T2CW1_OFFSET_VALUE_SHIFT (0) +#define GEM_T2CW1_OFFSET_VALUE_WIDTH (6 - GEM_T2CW1_OFFSET_VALUE_SHIFT + 1) + /*****************************************/ #define GEM_NWCTRL_TXSTART 0x00000200 /* Transmit Enable */ #define GEM_NWCTRL_TXENA 0x00000008 /* Transmit Enable */ @@ -602,6 +634,126 @@ static int gem_mac_address_filter(CadenceGEMState *s, const uint8_t *packet) return GEM_RX_REJECT; } +/* Figure out which queue the received data should be sent to */ +static int get_queue_from_screen(CadenceGEMState *s, uint8_t *rxbuf_ptr, + unsigned rxbufsize) +{ + uint32_t reg; + bool matched, mismatched; + int i, j; + + for (i = 0; i < s->num_type1_screeners; i++) { + reg = s->regs[GEM_SCREENING_TYPE1_REGISTER_0 + i]; + matched = false; + mismatched = false; + + /* Screening is based on UDP Port */ + if (reg & GEM_ST1R_UDP_PORT_MATCH_ENABLE) { + uint16_t udp_port = rxbuf_ptr[14 + 22] << 8 | rxbuf_ptr[14 + 23]; + if (udp_port == extract32(reg, GEM_ST1R_UDP_PORT_MATCH_SHIFT, + GEM_ST1R_UDP_PORT_MATCH_WIDTH)) { + matched = true; + } else { + mismatched = true; + } + } + + /* Screening is based on DS/TC */ + if (reg & GEM_ST1R_DSTC_ENABLE) { + uint8_t dscp = rxbuf_ptr[14 + 1]; + if (dscp == extract32(reg, GEM_ST1R_DSTC_MATCH_SHIFT, + GEM_ST1R_DSTC_MATCH_WIDTH)) { + matched = true; + } else { + mismatched = true; + } + } + + if (matched && !mismatched) { + return extract32(reg, GEM_ST1R_QUEUE_SHIFT, GEM_ST1R_QUEUE_WIDTH); + } + } + + for (i = 0; i < s->num_type2_screeners; i++) { + reg = s->regs[GEM_SCREENING_TYPE2_REGISTER_0 + i]; + matched = false; + mismatched = false; + + if (reg & GEM_ST2R_ETHERTYPE_ENABLE) { + uint16_t type = rxbuf_ptr[12] << 8 | rxbuf_ptr[13]; + int et_idx = extract32(reg, GEM_ST2R_ETHERTYPE_INDEX_SHIFT, + GEM_ST2R_ETHERTYPE_INDEX_WIDTH); + + if (et_idx > s->num_type2_screeners) { + qemu_log_mask(LOG_GUEST_ERROR, "Out of range ethertype " + "register index: %d\n", et_idx); + } + if (type == s->regs[GEM_SCREENING_TYPE2_ETHERTYPE_REG_0 + + et_idx]) { + matched = true; + } else { + mismatched = true; + } + } + + /* Compare A, B, C */ + for (j = 0; j < 3; j++) { + uint32_t cr0, cr1, mask; + uint16_t rx_cmp; + int offset; + int cr_idx = extract32(reg, GEM_ST2R_COMPARE_A_SHIFT + j * 6, + GEM_ST2R_COMPARE_WIDTH); + + if (!(reg & (GEM_ST2R_COMPARE_A_ENABLE << (j * 6)))) { + continue; + } + if (cr_idx > s->num_type2_screeners) { + qemu_log_mask(LOG_GUEST_ERROR, "Out of range compare " + "register index: %d\n", cr_idx); + } + + cr0 = s->regs[GEM_TYPE2_COMPARE_0_WORD_0 + cr_idx * 2]; + cr1 = s->regs[GEM_TYPE2_COMPARE_0_WORD_0 + cr_idx * 2 + 1]; + offset = extract32(cr1, GEM_T2CW1_OFFSET_VALUE_SHIFT, + GEM_T2CW1_OFFSET_VALUE_WIDTH); + + switch (extract32(cr1, GEM_T2CW1_COMPARE_OFFSET_SHIFT, + GEM_T2CW1_COMPARE_OFFSET_WIDTH)) { + case 3: /* Skip UDP header */ + qemu_log_mask(LOG_UNIMP, "TCP compare offsets" + "unimplemented - assuming UDP\n"); + offset += 8; + /* Fallthrough */ + case 2: /* skip the IP header */ + offset += 20; + /* Fallthrough */ + case 1: /* Count from after the ethertype */ + offset += 14; + break; + case 0: + /* Offset from start of frame */ + break; + } + + rx_cmp = rxbuf_ptr[offset] << 8 | rxbuf_ptr[offset]; + mask = extract32(cr0, 0, 16); + + if ((rx_cmp & mask) == (extract32(cr0, 16, 16) & mask)) { + matched = true; + } else { + mismatched = true; + } + } + + if (matched && !mismatched) { + return extract32(reg, GEM_ST2R_QUEUE_SHIFT, GEM_ST2R_QUEUE_WIDTH); + } + } + + /* We made it here, assume it's queue 0 */ + return 0; +} + static void gem_get_rx_desc(CadenceGEMState *s) { DB_PRINT("read descriptor 0x%x\n", (unsigned)s->rx_desc_addr[0]); @@ -712,6 +864,9 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) DB_PRINT("config bufsize: %d packet size: %ld\n", rxbufsize, size); + /* Find which queue we are targetting */ + q = get_queue_from_screen(s, rxbuf_ptr, rxbufsize); + while (bytes_to_copy) { /* Do nothing if receive is not enabled. */ if (!gem_can_receive(nc)) { @@ -1228,6 +1383,14 @@ static void gem_realize(DeviceState *dev, Error **errp) error_setg(errp, "Invalid num-priority-queues value: %" PRIx8, s->num_priority_queues); return; + } else if (s->num_type1_screeners > MAX_TYPE1_SCREENERS) { + error_setg(errp, "Invalid num-type1-screeners value: %" PRIx8, + s->num_type1_screeners); + return; + } else if (s->num_type2_screeners > MAX_TYPE2_SCREENERS) { + error_setg(errp, "Invalid num-type2-screeners value: %" PRIx8, + s->num_type2_screeners); + return; } sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[0]); @@ -1254,8 +1417,8 @@ static void gem_init(Object *obj) static const VMStateDescription vmstate_cadence_gem = { .name = "cadence_gem", - .version_id = 3, - .minimum_version_id = 3, + .version_id = 4, + .minimum_version_id = 4, .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, CadenceGEMState, CADENCE_GEM_MAXREG), VMSTATE_UINT16_ARRAY(phy_regs, CadenceGEMState, 32), @@ -1273,6 +1436,10 @@ static Property gem_properties[] = { DEFINE_NIC_PROPERTIES(CadenceGEMState, conf), DEFINE_PROP_UINT8("num-priority-queues", CadenceGEMState, num_priority_queues, 1), + DEFINE_PROP_UINT8("num-type1-screeners", CadenceGEMState, + num_type1_screeners, 4), + DEFINE_PROP_UINT8("num-type2-screeners", CadenceGEMState, + num_type2_screeners, 4), DEFINE_PROP_END_OF_LIST(), }; diff --git a/include/hw/net/cadence_gem.h b/include/hw/net/cadence_gem.h index 77e05820530..c469ffe69bb 100644 --- a/include/hw/net/cadence_gem.h +++ b/include/hw/net/cadence_gem.h @@ -30,9 +30,11 @@ #include "net/net.h" #include "hw/sysbus.h" -#define CADENCE_GEM_MAXREG (0x00000640/4) /* Last valid GEM address */ +#define CADENCE_GEM_MAXREG (0x00000800 / 4) /* Last valid GEM address */ #define MAX_PRIORITY_QUEUES 8 +#define MAX_TYPE1_SCREENERS 16 +#define MAX_TYPE2_SCREENERS 16 typedef struct CadenceGEMState { /*< private >*/ @@ -46,6 +48,8 @@ typedef struct CadenceGEMState { /* Static properties */ uint8_t num_priority_queues; + uint8_t num_type1_screeners; + uint8_t num_type2_screeners; /* GEM registers backing store */ uint32_t regs[CADENCE_GEM_MAXREG]; From 6710172501bedaf5181b6cac5a3d81e6deb2e136 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Thu, 22 Sep 2016 18:13:07 +0100 Subject: [PATCH 162/723] cadence_gem: Add queue support Signed-off-by: Alistair Francis Reviewed-by: Peter Maydell Message-id: 28921252217b1d14f16889bafa88675f5b7a66cb.1469727764.git.alistair.francis@xilinx.com Signed-off-by: Peter Maydell --- hw/net/cadence_gem.c | 131 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 107 insertions(+), 24 deletions(-) diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index 49a63a785f9..c46fff4cb83 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -143,6 +143,30 @@ #define GEM_DESCONF6 (0x00000294/4) #define GEM_DESCONF7 (0x00000298/4) +#define GEM_INT_Q1_STATUS (0x00000400 / 4) +#define GEM_INT_Q1_MASK (0x00000640 / 4) + +#define GEM_TRANSMIT_Q1_PTR (0x00000440 / 4) +#define GEM_TRANSMIT_Q15_PTR (GEM_TRANSMIT_Q1_PTR + 14) + +#define GEM_RECEIVE_Q1_PTR (0x00000480 / 4) +#define GEM_RECEIVE_Q15_PTR (GEM_RECEIVE_Q1_PTR + 14) + +#define GEM_INT_Q1_ENABLE (0x00000600 / 4) +#define GEM_INT_Q7_ENABLE (GEM_INT_Q1_ENABLE + 6) +#define GEM_INT_Q8_ENABLE (0x00000660 / 4) +#define GEM_INT_Q15_ENABLE (GEM_INT_Q8_ENABLE + 7) + +#define GEM_INT_Q1_DISABLE (0x00000620 / 4) +#define GEM_INT_Q7_DISABLE (GEM_INT_Q1_DISABLE + 6) +#define GEM_INT_Q8_DISABLE (0x00000680 / 4) +#define GEM_INT_Q15_DISABLE (GEM_INT_Q8_DISABLE + 7) + +#define GEM_INT_Q1_MASK (0x00000640 / 4) +#define GEM_INT_Q7_MASK (GEM_INT_Q1_MASK + 6) +#define GEM_INT_Q8_MASK (0x000006A0 / 4) +#define GEM_INT_Q15_MASK (GEM_INT_Q8_MASK + 7) + #define GEM_SCREENING_TYPE1_REGISTER_0 (0x00000500 / 4) #define GEM_ST1R_UDP_PORT_MATCH_ENABLE (1 << 29) @@ -317,9 +341,9 @@ static inline unsigned tx_desc_get_length(unsigned *desc) return desc[1] & DESC_1_LENGTH; } -static inline void print_gem_tx_desc(unsigned *desc) +static inline void print_gem_tx_desc(unsigned *desc, uint8_t queue) { - DB_PRINT("TXDESC:\n"); + DB_PRINT("TXDESC (queue %" PRId8 "):\n", queue); DB_PRINT("bufaddr: 0x%08x\n", *desc); DB_PRINT("used_hw: %d\n", tx_desc_get_used(desc)); DB_PRINT("wrap: %d\n", tx_desc_get_wrap(desc)); @@ -449,6 +473,7 @@ static void phy_update_link(CadenceGEMState *s) static int gem_can_receive(NetClientState *nc) { CadenceGEMState *s; + int i; s = qemu_get_nic_opaque(nc); @@ -461,18 +486,20 @@ static int gem_can_receive(NetClientState *nc) return 0; } - if (rx_desc_get_ownership(s->rx_desc[0]) == 1) { - if (s->can_rx_state != 2) { - s->can_rx_state = 2; - DB_PRINT("can't receive - busy buffer descriptor 0x%x\n", - s->rx_desc_addr[0]); + for (i = 0; i < s->num_priority_queues; i++) { + if (rx_desc_get_ownership(s->rx_desc[i]) == 1) { + if (s->can_rx_state != 2) { + s->can_rx_state = 2; + DB_PRINT("can't receive - busy buffer descriptor (q%d) 0x%x\n", + i, s->rx_desc_addr[i]); + } + return 0; } - return 0; } if (s->can_rx_state != 0) { s->can_rx_state = 0; - DB_PRINT("can receive 0x%x\n", s->rx_desc_addr[0]); + DB_PRINT("can receive\n"); } return 1; } @@ -483,9 +510,20 @@ static int gem_can_receive(NetClientState *nc) */ static void gem_update_int_status(CadenceGEMState *s) { - if (s->regs[GEM_ISR]) { - DB_PRINT("asserting int. (0x%08x)\n", s->regs[GEM_ISR]); + int i; + + if ((s->num_priority_queues == 1) && s->regs[GEM_ISR]) { + /* No priority queues, just trigger the interrupt */ + DB_PRINT("asserting int.\n", i); qemu_set_irq(s->irq[0], 1); + return; + } + + for (i = 0; i < s->num_priority_queues; ++i) { + if (s->regs[GEM_INT_Q1_STATUS + i]) { + DB_PRINT("asserting int. (q=%d)\n", i); + qemu_set_irq(s->irq[i], 1); + } } } @@ -754,17 +792,17 @@ static int get_queue_from_screen(CadenceGEMState *s, uint8_t *rxbuf_ptr, return 0; } -static void gem_get_rx_desc(CadenceGEMState *s) +static void gem_get_rx_desc(CadenceGEMState *s, int q) { - DB_PRINT("read descriptor 0x%x\n", (unsigned)s->rx_desc_addr[0]); + DB_PRINT("read descriptor 0x%x\n", (unsigned)s->rx_desc_addr[q]); /* read current descriptor */ cpu_physical_memory_read(s->rx_desc_addr[0], (uint8_t *)s->rx_desc[0], sizeof(s->rx_desc[0])); /* Descriptor owned by software ? */ - if (rx_desc_get_ownership(s->rx_desc[0]) == 1) { + if (rx_desc_get_ownership(s->rx_desc[q]) == 1) { DB_PRINT("descriptor 0x%x owned by sw.\n", - (unsigned)s->rx_desc_addr[0]); + (unsigned)s->rx_desc_addr[q]); s->regs[GEM_RXSTATUS] |= GEM_RXSTATUS_NOBUF; s->regs[GEM_ISR] |= GEM_INT_RXUSED & ~(s->regs[GEM_IMR]); /* Handle interrupt consequences */ @@ -926,7 +964,8 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) DB_PRINT("incrementing RX descriptor list\n"); s->rx_desc_addr[q] += 8; } - gem_get_rx_desc(s); + + gem_get_rx_desc(s, q); } /* Count it */ @@ -1014,6 +1053,7 @@ static void gem_transmit(CadenceGEMState *s) p = tx_packet; total_bytes = 0; + for (q = s->num_priority_queues - 1; q >= 0; q--) { /* read current descriptor */ packet_desc_addr = s->tx_desc_addr[q]; @@ -1027,7 +1067,7 @@ static void gem_transmit(CadenceGEMState *s) if (!(s->regs[GEM_NWCTRL] & GEM_NWCTRL_TXENA)) { return; } - print_gem_tx_desc(desc); + print_gem_tx_desc(desc, q); /* The real hardware would eat this (and possibly crash). * For QEMU let's lend a helping hand. @@ -1078,6 +1118,12 @@ static void gem_transmit(CadenceGEMState *s) s->regs[GEM_TXSTATUS] |= GEM_TXSTATUS_TXCMPL; s->regs[GEM_ISR] |= GEM_INT_TXCMPL & ~(s->regs[GEM_IMR]); + /* Update queue interrupt status */ + if (s->num_priority_queues > 1) { + s->regs[GEM_INT_Q1_STATUS + q] |= + GEM_INT_TXCMPL & ~(s->regs[GEM_INT_Q1_MASK + q]); + } + /* Handle interrupt consequences */ gem_update_int_status(s); @@ -1119,6 +1165,7 @@ static void gem_transmit(CadenceGEMState *s) s->regs[GEM_ISR] |= GEM_INT_TXUSED & ~(s->regs[GEM_IMR]); gem_update_int_status(s); } + } } static void gem_phy_reset(CadenceGEMState *s) @@ -1225,7 +1272,7 @@ static uint64_t gem_read(void *opaque, hwaddr offset, unsigned size) { CadenceGEMState *s; uint32_t retval; - + int i; s = (CadenceGEMState *)opaque; offset >>= 2; @@ -1235,8 +1282,10 @@ static uint64_t gem_read(void *opaque, hwaddr offset, unsigned size) switch (offset) { case GEM_ISR: - DB_PRINT("lowering irq on ISR read\n"); - qemu_set_irq(s->irq[0], 0); + DB_PRINT("lowering irqs on ISR read\n"); + for (i = 0; i < s->num_priority_queues; ++i) { + qemu_set_irq(s->irq[i], 0); + } break; case GEM_PHYMNTNC: if (retval & GEM_PHYMNTNC_OP_R) { @@ -1261,6 +1310,7 @@ static uint64_t gem_read(void *opaque, hwaddr offset, unsigned size) retval &= ~(s->regs_wo[offset]); DB_PRINT("0x%08x\n", retval); + gem_update_int_status(s); return retval; } @@ -1273,6 +1323,7 @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val, { CadenceGEMState *s = (CadenceGEMState *)opaque; uint32_t readonly; + int i; DB_PRINT("offset: 0x%04x write: 0x%08x ", (unsigned)offset, (unsigned)val); offset >>= 2; @@ -1292,14 +1343,18 @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val, switch (offset) { case GEM_NWCTRL: if (val & GEM_NWCTRL_RXENA) { - gem_get_rx_desc(s); + for (i = 0; i < s->num_priority_queues; ++i) { + gem_get_rx_desc(s, i); + } } if (val & GEM_NWCTRL_TXSTART) { gem_transmit(s); } if (!(val & GEM_NWCTRL_TXENA)) { /* Reset to start of Q when transmit disabled. */ - s->tx_desc_addr[0] = s->regs[GEM_TXQBASE]; + for (i = 0; i < s->num_priority_queues; i++) { + s->tx_desc_addr[i] = s->regs[GEM_TXQBASE]; + } } if (gem_can_receive(qemu_get_queue(s->nic))) { qemu_flush_queued_packets(qemu_get_queue(s->nic)); @@ -1312,9 +1367,15 @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val, case GEM_RXQBASE: s->rx_desc_addr[0] = val; break; + case GEM_RECEIVE_Q1_PTR ... GEM_RECEIVE_Q15_PTR: + s->rx_desc_addr[offset - GEM_RECEIVE_Q1_PTR + 1] = val; + break; case GEM_TXQBASE: s->tx_desc_addr[0] = val; break; + case GEM_TRANSMIT_Q1_PTR ... GEM_TRANSMIT_Q15_PTR: + s->tx_desc_addr[offset - GEM_TRANSMIT_Q1_PTR + 1] = val; + break; case GEM_RXSTATUS: gem_update_int_status(s); break; @@ -1322,10 +1383,26 @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val, s->regs[GEM_IMR] &= ~val; gem_update_int_status(s); break; + case GEM_INT_Q1_ENABLE ... GEM_INT_Q7_ENABLE: + s->regs[GEM_INT_Q1_MASK + offset - GEM_INT_Q1_ENABLE] &= ~val; + gem_update_int_status(s); + break; + case GEM_INT_Q8_ENABLE ... GEM_INT_Q15_ENABLE: + s->regs[GEM_INT_Q8_MASK + offset - GEM_INT_Q8_ENABLE] &= ~val; + gem_update_int_status(s); + break; case GEM_IDR: s->regs[GEM_IMR] |= val; gem_update_int_status(s); break; + case GEM_INT_Q1_DISABLE ... GEM_INT_Q7_DISABLE: + s->regs[GEM_INT_Q1_MASK + offset - GEM_INT_Q1_DISABLE] |= val; + gem_update_int_status(s); + break; + case GEM_INT_Q8_DISABLE ... GEM_INT_Q15_DISABLE: + s->regs[GEM_INT_Q8_MASK + offset - GEM_INT_Q8_DISABLE] |= val; + gem_update_int_status(s); + break; case GEM_SPADDR1LO: case GEM_SPADDR2LO: case GEM_SPADDR3LO: @@ -1362,8 +1439,11 @@ static const MemoryRegionOps gem_ops = { static void gem_set_link(NetClientState *nc) { + CadenceGEMState *s = qemu_get_nic_opaque(nc); + DB_PRINT("\n"); - phy_update_link(qemu_get_nic_opaque(nc)); + phy_update_link(s); + gem_update_int_status(s); } static NetClientInfo net_gem_info = { @@ -1377,6 +1457,7 @@ static NetClientInfo net_gem_info = { static void gem_realize(DeviceState *dev, Error **errp) { CadenceGEMState *s = CADENCE_GEM(dev); + int i; if (s->num_priority_queues == 0 || s->num_priority_queues > MAX_PRIORITY_QUEUES) { @@ -1393,7 +1474,9 @@ static void gem_realize(DeviceState *dev, Error **errp) return; } - sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[0]); + for (i = 0; i < s->num_priority_queues; ++i) { + sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[i]); + } qemu_macaddr_default_if_unset(&s->conf.macaddr); From 77524d1157cf7c18b980c9d6f95879f2ce7e56e2 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Thu, 22 Sep 2016 18:13:07 +0100 Subject: [PATCH 163/723] cadence_gem: Correct indentation Fix up the indentation inside the for loop that was introduced in the previous patch. This commit is almost empty if viewed using 'git show -w', except for a few changes that were required to avoid the 80 charecter line limit. Signed-off-by: Alistair Francis Reviewed-by: Peter Maydell Message-id: b40d1b12d24be9f0ac5d72f86249103e0c1c720a.1469727764.git.alistair.francis@xilinx.com Signed-off-by: Peter Maydell --- hw/net/cadence_gem.c | 197 ++++++++++++++++++++++--------------------- 1 file changed, 101 insertions(+), 96 deletions(-) diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index c46fff4cb83..8618e7acac7 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -1054,117 +1054,122 @@ static void gem_transmit(CadenceGEMState *s) total_bytes = 0; for (q = s->num_priority_queues - 1; q >= 0; q--) { - /* read current descriptor */ - packet_desc_addr = s->tx_desc_addr[q]; - - DB_PRINT("read descriptor 0x%" HWADDR_PRIx "\n", packet_desc_addr); - cpu_physical_memory_read(packet_desc_addr, - (uint8_t *)desc, sizeof(desc)); - /* Handle all descriptors owned by hardware */ - while (tx_desc_get_used(desc) == 0) { - - /* Do nothing if transmit is not enabled. */ - if (!(s->regs[GEM_NWCTRL] & GEM_NWCTRL_TXENA)) { - return; - } - print_gem_tx_desc(desc, q); - - /* The real hardware would eat this (and possibly crash). - * For QEMU let's lend a helping hand. - */ - if ((tx_desc_get_buffer(desc) == 0) || - (tx_desc_get_length(desc) == 0)) { - DB_PRINT("Invalid TX descriptor @ 0x%x\n", - (unsigned)packet_desc_addr); - break; - } - - if (tx_desc_get_length(desc) > sizeof(tx_packet) - (p - tx_packet)) { - DB_PRINT("TX descriptor @ 0x%x too large: size 0x%x space 0x%x\n", - (unsigned)packet_desc_addr, - (unsigned)tx_desc_get_length(desc), - sizeof(tx_packet) - (p - tx_packet)); - break; - } + /* read current descriptor */ + packet_desc_addr = s->tx_desc_addr[q]; - /* Gather this fragment of the packet from "dma memory" to our contig. - * buffer. - */ - cpu_physical_memory_read(tx_desc_get_buffer(desc), p, - tx_desc_get_length(desc)); - p += tx_desc_get_length(desc); - total_bytes += tx_desc_get_length(desc); + DB_PRINT("read descriptor 0x%" HWADDR_PRIx "\n", packet_desc_addr); + cpu_physical_memory_read(packet_desc_addr, + (uint8_t *)desc, sizeof(desc)); + /* Handle all descriptors owned by hardware */ + while (tx_desc_get_used(desc) == 0) { - /* Last descriptor for this packet; hand the whole thing off */ - if (tx_desc_get_last(desc)) { - unsigned desc_first[2]; + /* Do nothing if transmit is not enabled. */ + if (!(s->regs[GEM_NWCTRL] & GEM_NWCTRL_TXENA)) { + return; + } + print_gem_tx_desc(desc, q); - /* Modify the 1st descriptor of this packet to be owned by - * the processor. + /* The real hardware would eat this (and possibly crash). + * For QEMU let's lend a helping hand. */ - cpu_physical_memory_read(s->tx_desc_addr[q], (uint8_t *)desc_first, - sizeof(desc_first)); - tx_desc_set_used(desc_first); - cpu_physical_memory_write(s->tx_desc_addr[q], (uint8_t *)desc_first, - sizeof(desc_first)); - /* Advance the hardware current descriptor past this packet */ - if (tx_desc_get_wrap(desc)) { - s->tx_desc_addr[q] = s->regs[GEM_TXQBASE]; - } else { - s->tx_desc_addr[q] = packet_desc_addr + 8; + if ((tx_desc_get_buffer(desc) == 0) || + (tx_desc_get_length(desc) == 0)) { + DB_PRINT("Invalid TX descriptor @ 0x%x\n", + (unsigned)packet_desc_addr); + break; } - DB_PRINT("TX descriptor next: 0x%08x\n", s->tx_desc_addr[q]); - - s->regs[GEM_TXSTATUS] |= GEM_TXSTATUS_TXCMPL; - s->regs[GEM_ISR] |= GEM_INT_TXCMPL & ~(s->regs[GEM_IMR]); - /* Update queue interrupt status */ - if (s->num_priority_queues > 1) { - s->regs[GEM_INT_Q1_STATUS + q] |= - GEM_INT_TXCMPL & ~(s->regs[GEM_INT_Q1_MASK + q]); + if (tx_desc_get_length(desc) > sizeof(tx_packet) - + (p - tx_packet)) { + DB_PRINT("TX descriptor @ 0x%x too large: size 0x%x space " \ + "0x%x\n", (unsigned)packet_desc_addr, + (unsigned)tx_desc_get_length(desc), + sizeof(tx_packet) - (p - tx_packet)); + break; } - /* Handle interrupt consequences */ - gem_update_int_status(s); - - /* Is checksum offload enabled? */ - if (s->regs[GEM_DMACFG] & GEM_DMACFG_TXCSUM_OFFL) { - net_checksum_calculate(tx_packet, total_bytes); + /* Gather this fragment of the packet from "dma memory" to our + * contig buffer. + */ + cpu_physical_memory_read(tx_desc_get_buffer(desc), p, + tx_desc_get_length(desc)); + p += tx_desc_get_length(desc); + total_bytes += tx_desc_get_length(desc); + + /* Last descriptor for this packet; hand the whole thing off */ + if (tx_desc_get_last(desc)) { + unsigned desc_first[2]; + + /* Modify the 1st descriptor of this packet to be owned by + * the processor. + */ + cpu_physical_memory_read(s->tx_desc_addr[q], + (uint8_t *)desc_first, + sizeof(desc_first)); + tx_desc_set_used(desc_first); + cpu_physical_memory_write(s->tx_desc_addr[q], + (uint8_t *)desc_first, + sizeof(desc_first)); + /* Advance the hardware current descriptor past this packet */ + if (tx_desc_get_wrap(desc)) { + s->tx_desc_addr[q] = s->regs[GEM_TXQBASE]; + } else { + s->tx_desc_addr[q] = packet_desc_addr + 8; + } + DB_PRINT("TX descriptor next: 0x%08x\n", s->tx_desc_addr[q]); + + s->regs[GEM_TXSTATUS] |= GEM_TXSTATUS_TXCMPL; + s->regs[GEM_ISR] |= GEM_INT_TXCMPL & ~(s->regs[GEM_IMR]); + + /* Update queue interrupt status */ + if (s->num_priority_queues > 1) { + s->regs[GEM_INT_Q1_STATUS + q] |= + GEM_INT_TXCMPL & ~(s->regs[GEM_INT_Q1_MASK + q]); + } + + /* Handle interrupt consequences */ + gem_update_int_status(s); + + /* Is checksum offload enabled? */ + if (s->regs[GEM_DMACFG] & GEM_DMACFG_TXCSUM_OFFL) { + net_checksum_calculate(tx_packet, total_bytes); + } + + /* Update MAC statistics */ + gem_transmit_updatestats(s, tx_packet, total_bytes); + + /* Send the packet somewhere */ + if (s->phy_loop || (s->regs[GEM_NWCTRL] & + GEM_NWCTRL_LOCALLOOP)) { + gem_receive(qemu_get_queue(s->nic), tx_packet, + total_bytes); + } else { + qemu_send_packet(qemu_get_queue(s->nic), tx_packet, + total_bytes); + } + + /* Prepare for next packet */ + p = tx_packet; + total_bytes = 0; } - /* Update MAC statistics */ - gem_transmit_updatestats(s, tx_packet, total_bytes); - - /* Send the packet somewhere */ - if (s->phy_loop || (s->regs[GEM_NWCTRL] & GEM_NWCTRL_LOCALLOOP)) { - gem_receive(qemu_get_queue(s->nic), tx_packet, total_bytes); + /* read next descriptor */ + if (tx_desc_get_wrap(desc)) { + tx_desc_set_last(desc); + packet_desc_addr = s->regs[GEM_TXQBASE]; } else { - qemu_send_packet(qemu_get_queue(s->nic), tx_packet, - total_bytes); + packet_desc_addr += 8; } - - /* Prepare for next packet */ - p = tx_packet; - total_bytes = 0; + DB_PRINT("read descriptor 0x%" HWADDR_PRIx "\n", packet_desc_addr); + cpu_physical_memory_read(packet_desc_addr, + (uint8_t *)desc, sizeof(desc)); } - /* read next descriptor */ - if (tx_desc_get_wrap(desc)) { - tx_desc_set_last(desc); - packet_desc_addr = s->regs[GEM_TXQBASE]; - } else { - packet_desc_addr += 8; + if (tx_desc_get_used(desc)) { + s->regs[GEM_TXSTATUS] |= GEM_TXSTATUS_USED; + s->regs[GEM_ISR] |= GEM_INT_TXUSED & ~(s->regs[GEM_IMR]); + gem_update_int_status(s); } - DB_PRINT("read descriptor 0x%" HWADDR_PRIx "\n", packet_desc_addr); - cpu_physical_memory_read(packet_desc_addr, - (uint8_t *)desc, sizeof(desc)); - } - - if (tx_desc_get_used(desc)) { - s->regs[GEM_TXSTATUS] |= GEM_TXSTATUS_USED; - s->regs[GEM_ISR] |= GEM_INT_TXUSED & ~(s->regs[GEM_IMR]); - gem_update_int_status(s); - } } } From 1372fc0b87b80634313ad332279f9c7ca0583862 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Thu, 22 Sep 2016 18:13:07 +0100 Subject: [PATCH 164/723] xlnx-zynqmp: Set the number of priority queues Set the ZynqMP number of priority queues to 2. Signed-off-by: Alistair Francis Reviewed-by: Peter Maydell Message-id: e047c338ee981a61afd7f765a317b3de25a4f629.1469727764.git.alistair.francis@xilinx.com Signed-off-by: Peter Maydell --- hw/arm/xlnx-zynqmp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c index 23c71998671..0d86ba35aec 100644 --- a/hw/arm/xlnx-zynqmp.c +++ b/hw/arm/xlnx-zynqmp.c @@ -332,6 +332,8 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) qemu_check_nic_model(nd, TYPE_CADENCE_GEM); qdev_set_nic_properties(DEVICE(&s->gem[i]), nd); } + object_property_set_int(OBJECT(&s->gem[i]), 2, "num-priority-queues", + &error_abort); object_property_set_bool(OBJECT(&s->gem[i]), true, "realized", &err); if (err) { error_propagate(errp, err); From 8cf6e9daca19e08216cf09e523d1dcdf3cfdaec7 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Thu, 22 Sep 2016 18:13:07 +0100 Subject: [PATCH 165/723] loader: Allow ELF loader to auto-detect the ELF arch If the caller didn't specify an architecture for the ELF machine the load_elf() function will auto detect it based on the ELF file. Signed-off-by: Alistair Francis Reviewed-by: Peter Maydell Message-id: f2d70b47fcad31445f947f8817a0e146d80a046b.1474331683.git.alistair.francis@xilinx.com Signed-off-by: Peter Maydell --- include/hw/elf_ops.h | 5 +++++ include/hw/loader.h | 2 ++ 2 files changed, 7 insertions(+) diff --git a/include/hw/elf_ops.h b/include/hw/elf_ops.h index f510e7ec2a1..5038c7f058b 100644 --- a/include/hw/elf_ops.h +++ b/include/hw/elf_ops.h @@ -280,6 +280,11 @@ static int glue(load_elf, SZ)(const char *name, int fd, glue(bswap_ehdr, SZ)(&ehdr); } + if (elf_machine <= EM_NONE) { + /* The caller didn't specify an ARCH, we can figure it out */ + elf_machine = ehdr.e_machine; + } + switch (elf_machine) { case EM_PPC64: if (ehdr.e_machine != EM_PPC64) { diff --git a/include/hw/loader.h b/include/hw/loader.h index 4879b63a2f5..c59673dfc55 100644 --- a/include/hw/loader.h +++ b/include/hw/loader.h @@ -68,6 +68,8 @@ const char *load_elf_strerror(int error); * load will fail if the target ELF does not match. Some architectures * have some architecture-specific behaviours that come into effect when * their particular values for @elf_machine are set. + * If @elf_machine is EM_NONE then the machine type will be read from the + * ELF header and no checks will be carried out against the machine type. */ int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t), From d6ac342a48d50bdceaa43abe2e57854230101d90 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Thu, 22 Sep 2016 18:13:08 +0100 Subject: [PATCH 166/723] loader: Use the specified MemoryRegion Prevously the specified MemoryRegion was ignored during the rom register reset. This patch uses the rom MemoryRegion is avaliable. Signed-off-by: Alistair Francis Reviewed-by: Peter Maydell Message-id: d63fef5524deeb88e0068ca9d3fd4c8344f54dd4.1474331683.git.alistair.francis@xilinx.com Signed-off-by: Peter Maydell --- hw/core/loader.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/core/loader.c b/hw/core/loader.c index 53e0e415549..6b61f290c31 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -1045,7 +1045,8 @@ int rom_check_and_register_reset(void) } addr = rom->addr; addr += rom->romsize; - section = memory_region_find(get_system_memory(), rom->addr, 1); + section = memory_region_find(rom->mr ? rom->mr : get_system_memory(), + rom->addr, 1); rom->isrom = int128_nz(section.size) && memory_region_is_rom(section.mr); memory_region_unref(section.mr); } From 3e76099aacb4dae0d37ebf95305369e03d1491e6 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Thu, 22 Sep 2016 18:13:08 +0100 Subject: [PATCH 167/723] loader: Allow a custom AddressSpace when loading ROMs When loading ROMs allow the caller to specify an AddressSpace to use for the load. Signed-off-by: Alistair Francis Message-id: 85f86b94ea94879e7ce8b12e85ac8de26658f7eb.1474331683.git.alistair.francis@xilinx.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/core/loader.c | 43 ++++++++++++++++++++++++++++++++++--------- include/hw/elf_ops.h | 2 +- include/hw/loader.h | 10 ++++++---- 3 files changed, 41 insertions(+), 14 deletions(-) diff --git a/hw/core/loader.c b/hw/core/loader.c index 6b61f290c31..56c593ead70 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -777,6 +777,7 @@ struct Rom { uint8_t *data; MemoryRegion *mr; + AddressSpace *as; int isrom; char *fw_dir; char *fw_file; @@ -788,6 +789,12 @@ struct Rom { static FWCfgState *fw_cfg; static QTAILQ_HEAD(, Rom) roms = QTAILQ_HEAD_INITIALIZER(roms); +static inline bool rom_order_compare(Rom *rom, Rom *item) +{ + return (rom->as > item->as) || + (rom->as == item->as && rom->addr >= item->addr); +} + static void rom_insert(Rom *rom) { Rom *item; @@ -796,10 +803,16 @@ static void rom_insert(Rom *rom) hw_error ("ROM images must be loaded at startup\n"); } - /* list is ordered by load address */ + /* The user didn't specify an address space, this is the default */ + if (!rom->as) { + rom->as = &address_space_memory; + } + + /* List is ordered by load address in the same address space */ QTAILQ_FOREACH(item, &roms, next) { - if (rom->addr >= item->addr) + if (rom_order_compare(rom, item)) { continue; + } QTAILQ_INSERT_BEFORE(item, rom, next); return; } @@ -833,16 +846,25 @@ static void *rom_set_mr(Rom *rom, Object *owner, const char *name) int rom_add_file(const char *file, const char *fw_dir, hwaddr addr, int32_t bootindex, - bool option_rom, MemoryRegion *mr) + bool option_rom, MemoryRegion *mr, + AddressSpace *as) { MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine()); Rom *rom; int rc, fd = -1; char devpath[100]; + if (as && mr) { + fprintf(stderr, "Specifying an Address Space and Memory Region is " \ + "not valid when loading a rom\n"); + /* We haven't allocated anything so we don't need any cleanup */ + return -1; + } + rom = g_malloc0(sizeof(*rom)); rom->name = g_strdup(file); rom->path = qemu_find_file(QEMU_FILE_TYPE_BIOS, rom->name); + rom->as = as; if (rom->path == NULL) { rom->path = g_strdup(file); } @@ -969,7 +991,7 @@ MemoryRegion *rom_add_blob(const char *name, const void *blob, size_t len, * memory ownership of "data", so we don't have to allocate and copy the buffer. */ int rom_add_elf_program(const char *name, void *data, size_t datasize, - size_t romsize, hwaddr addr) + size_t romsize, hwaddr addr, AddressSpace *as) { Rom *rom; @@ -979,18 +1001,19 @@ int rom_add_elf_program(const char *name, void *data, size_t datasize, rom->datasize = datasize; rom->romsize = romsize; rom->data = data; + rom->as = as; rom_insert(rom); return 0; } int rom_add_vga(const char *file) { - return rom_add_file(file, "vgaroms", 0, -1, true, NULL); + return rom_add_file(file, "vgaroms", 0, -1, true, NULL, NULL); } int rom_add_option(const char *file, int32_t bootindex) { - return rom_add_file(file, "genroms", 0, bootindex, true, NULL); + return rom_add_file(file, "genroms", 0, bootindex, true, NULL, NULL); } static void rom_reset(void *unused) @@ -1008,8 +1031,8 @@ static void rom_reset(void *unused) void *host = memory_region_get_ram_ptr(rom->mr); memcpy(host, rom->data, rom->datasize); } else { - cpu_physical_memory_write_rom(&address_space_memory, - rom->addr, rom->data, rom->datasize); + cpu_physical_memory_write_rom(rom->as, rom->addr, rom->data, + rom->datasize); } if (rom->isrom) { /* rom needs to be written only once */ @@ -1031,12 +1054,13 @@ int rom_check_and_register_reset(void) hwaddr addr = 0; MemoryRegionSection section; Rom *rom; + AddressSpace *as = NULL; QTAILQ_FOREACH(rom, &roms, next) { if (rom->fw_file) { continue; } - if (addr > rom->addr) { + if ((addr > rom->addr) && (as == rom->as)) { fprintf(stderr, "rom: requested regions overlap " "(rom %s. free=0x" TARGET_FMT_plx ", addr=0x" TARGET_FMT_plx ")\n", @@ -1049,6 +1073,7 @@ int rom_check_and_register_reset(void) rom->addr, 1); rom->isrom = int128_nz(section.size) && memory_region_is_rom(section.mr); memory_region_unref(section.mr); + as = rom->as; } qemu_register_reset(rom_reset, NULL); roms_loaded = 1; diff --git a/include/hw/elf_ops.h b/include/hw/elf_ops.h index 5038c7f058b..4744d110f3c 100644 --- a/include/hw/elf_ops.h +++ b/include/hw/elf_ops.h @@ -405,7 +405,7 @@ static int glue(load_elf, SZ)(const char *name, int fd, snprintf(label, sizeof(label), "phdr #%d: %s", i, name); /* rom_add_elf_program() seize the ownership of 'data' */ - rom_add_elf_program(label, data, file_size, mem_size, addr); + rom_add_elf_program(label, data, file_size, mem_size, addr, NULL); total_size += mem_size; if (addr < low) diff --git a/include/hw/loader.h b/include/hw/loader.h index c59673dfc55..815a8d6ad87 100644 --- a/include/hw/loader.h +++ b/include/hw/loader.h @@ -120,14 +120,14 @@ extern bool rom_file_has_mr; int rom_add_file(const char *file, const char *fw_dir, hwaddr addr, int32_t bootindex, - bool option_rom, MemoryRegion *mr); + bool option_rom, MemoryRegion *mr, AddressSpace *as); MemoryRegion *rom_add_blob(const char *name, const void *blob, size_t len, size_t max_len, hwaddr addr, const char *fw_file_name, FWCfgReadCallback fw_callback, void *callback_opaque); int rom_add_elf_program(const char *name, void *data, size_t datasize, - size_t romsize, hwaddr addr); + size_t romsize, hwaddr addr, AddressSpace *as); int rom_check_and_register_reset(void); void rom_set_fw(FWCfgState *f); void rom_set_order_override(int order); @@ -137,11 +137,13 @@ void *rom_ptr(hwaddr addr); void hmp_info_roms(Monitor *mon, const QDict *qdict); #define rom_add_file_fixed(_f, _a, _i) \ - rom_add_file(_f, NULL, _a, _i, false, NULL) + rom_add_file(_f, NULL, _a, _i, false, NULL, NULL) #define rom_add_blob_fixed(_f, _b, _l, _a) \ rom_add_blob(_f, _b, _l, _l, _a, NULL, NULL, NULL) #define rom_add_file_mr(_f, _mr, _i) \ - rom_add_file(_f, NULL, 0, _i, false, _mr) + rom_add_file(_f, NULL, 0, _i, false, _mr, NULL) +#define rom_add_file_as(_f, _as, _i) \ + rom_add_file(_f, NULL, 0, _i, false, NULL, _as) #define PC_ROM_MIN_VGA 0xc0000 #define PC_ROM_MIN_OPTION 0xc8000 From 70bb1d16f4e8576eb9370ae6be244312cd96df78 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Thu, 22 Sep 2016 18:13:08 +0100 Subject: [PATCH 168/723] loader: Add AddressSpace loading support to ELFs Add a new function load_elf_as() that allows the caller to specify an AddressSpace to use when loading the ELF. The original load_elf() function doesn't have any change in functionality. Signed-off-by: Alistair Francis Reviewed-by: Peter Maydell Message-id: 8b5cefecdf56fba4ccdff2db880f0b6b264cf16f.1474331683.git.alistair.francis@xilinx.com Signed-off-by: Peter Maydell --- hw/core/loader.c | 16 ++++++++++++++-- include/hw/elf_ops.h | 5 +++-- include/hw/loader.h | 13 ++++++++++++- 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/hw/core/loader.c b/hw/core/loader.c index 56c593ead70..31cbeacc2d0 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -416,6 +416,18 @@ int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t), void *translate_opaque, uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr, int big_endian, int elf_machine, int clear_lsb, int data_swab) +{ + return load_elf_as(filename, translate_fn, translate_opaque, pentry, + lowaddr, highaddr, big_endian, elf_machine, clear_lsb, + data_swab, NULL); +} + +/* return < 0 if error, otherwise the number of bytes loaded in memory */ +int load_elf_as(const char *filename, + uint64_t (*translate_fn)(void *, uint64_t), + void *translate_opaque, uint64_t *pentry, uint64_t *lowaddr, + uint64_t *highaddr, int big_endian, int elf_machine, + int clear_lsb, int data_swab, AddressSpace *as) { int fd, data_order, target_data_order, must_swab, ret = ELF_LOAD_FAILED; uint8_t e_ident[EI_NIDENT]; @@ -455,11 +467,11 @@ int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t), if (e_ident[EI_CLASS] == ELFCLASS64) { ret = load_elf64(filename, fd, translate_fn, translate_opaque, must_swab, pentry, lowaddr, highaddr, elf_machine, clear_lsb, - data_swab); + data_swab, as); } else { ret = load_elf32(filename, fd, translate_fn, translate_opaque, must_swab, pentry, lowaddr, highaddr, elf_machine, clear_lsb, - data_swab); + data_swab, as); } fail: diff --git a/include/hw/elf_ops.h b/include/hw/elf_ops.h index 4744d110f3c..25659b93bec 100644 --- a/include/hw/elf_ops.h +++ b/include/hw/elf_ops.h @@ -263,7 +263,8 @@ static int glue(load_elf, SZ)(const char *name, int fd, void *translate_opaque, int must_swab, uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr, - int elf_machine, int clear_lsb, int data_swab) + int elf_machine, int clear_lsb, int data_swab, + AddressSpace *as) { struct elfhdr ehdr; struct elf_phdr *phdr = NULL, *ph; @@ -405,7 +406,7 @@ static int glue(load_elf, SZ)(const char *name, int fd, snprintf(label, sizeof(label), "phdr #%d: %s", i, name); /* rom_add_elf_program() seize the ownership of 'data' */ - rom_add_elf_program(label, data, file_size, mem_size, addr, NULL); + rom_add_elf_program(label, data, file_size, mem_size, addr, as); total_size += mem_size; if (addr < low) diff --git a/include/hw/loader.h b/include/hw/loader.h index 815a8d6ad87..fdf0a51daf7 100644 --- a/include/hw/loader.h +++ b/include/hw/loader.h @@ -45,7 +45,7 @@ int load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz); #define ELF_LOAD_WRONG_ENDIAN -4 const char *load_elf_strerror(int error); -/** load_elf: +/** load_elf_as: * @filename: Path of ELF file * @translate_fn: optional function to translate load addresses * @translate_opaque: opaque data passed to @translate_fn @@ -59,6 +59,8 @@ const char *load_elf_strerror(int error); * @data_swab: Set to order of byte swapping for data. 0 for no swap, 1 * for swapping bytes within halfwords, 2 for bytes within * words and 3 for within doublewords. + * @as: The AddressSpace to load the ELF to. The value of address_space_memory + * is used if nothing is supplied here. * * Load an ELF file's contents to the emulated system's address space. * Clients may optionally specify a callback to perform address @@ -71,7 +73,16 @@ const char *load_elf_strerror(int error); * If @elf_machine is EM_NONE then the machine type will be read from the * ELF header and no checks will be carried out against the machine type. */ +int load_elf_as(const char *filename, + uint64_t (*translate_fn)(void *, uint64_t), + void *translate_opaque, uint64_t *pentry, uint64_t *lowaddr, + uint64_t *highaddr, int big_endian, int elf_machine, + int clear_lsb, int data_swab, AddressSpace *as); +/** load_elf: + * Same as load_elf_as(), but doesn't allow the caller to specify an + * AddressSpace. + */ int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t), void *translate_opaque, uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr, int big_endian, int elf_machine, From 5e774eb3bd264c76484906f4bd0fb38e00b8090e Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Thu, 22 Sep 2016 18:13:08 +0100 Subject: [PATCH 169/723] loader: Add AddressSpace loading support to uImages Add a new function load_uimage_as() that allows the caller to specify an AddressSpace to use when loading the uImage. The original load_uimage() function doesn't have any change in functionality. Signed-off-by: Alistair Francis Reviewed-by: Peter Maydell Message-id: 1254092e6b80d3cd3cfabafe165d56a96c54c0b5.1474331683.git.alistair.francis@xilinx.com Signed-off-by: Peter Maydell --- hw/core/loader.c | 17 +++++++++++++---- include/hw/loader.h | 26 ++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/hw/core/loader.c b/hw/core/loader.c index 31cbeacc2d0..86ed7841595 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -581,7 +581,7 @@ static ssize_t gunzip(void *dst, size_t dstlen, uint8_t *src, static int load_uboot_image(const char *filename, hwaddr *ep, hwaddr *loadaddr, int *is_linux, uint8_t image_type, uint64_t (*translate_fn)(void *, uint64_t), - void *translate_opaque) + void *translate_opaque, AddressSpace *as) { int fd; int size; @@ -682,7 +682,7 @@ static int load_uboot_image(const char *filename, hwaddr *ep, hwaddr *loadaddr, hdr->ih_size = bytes; } - rom_add_blob_fixed(filename, data, hdr->ih_size, address); + rom_add_blob_fixed_as(filename, data, hdr->ih_size, address, as); ret = hdr->ih_size; @@ -698,14 +698,23 @@ int load_uimage(const char *filename, hwaddr *ep, hwaddr *loadaddr, void *translate_opaque) { return load_uboot_image(filename, ep, loadaddr, is_linux, IH_TYPE_KERNEL, - translate_fn, translate_opaque); + translate_fn, translate_opaque, NULL); +} + +int load_uimage_as(const char *filename, hwaddr *ep, hwaddr *loadaddr, + int *is_linux, + uint64_t (*translate_fn)(void *, uint64_t), + void *translate_opaque, AddressSpace *as) +{ + return load_uboot_image(filename, ep, loadaddr, is_linux, IH_TYPE_KERNEL, + translate_fn, translate_opaque, as); } /* Load a ramdisk. */ int load_ramdisk(const char *filename, hwaddr addr, uint64_t max_sz) { return load_uboot_image(filename, NULL, &addr, NULL, IH_TYPE_RAMDISK, - NULL, NULL); + NULL, NULL, NULL); } /* Load a gzip-compressed kernel to a dynamically allocated buffer. */ diff --git a/include/hw/loader.h b/include/hw/loader.h index fdf0a51daf7..bce8f434ba3 100644 --- a/include/hw/loader.h +++ b/include/hw/loader.h @@ -102,6 +102,30 @@ void load_elf_hdr(const char *filename, void *hdr, bool *is64, Error **errp); int load_aout(const char *filename, hwaddr addr, int max_sz, int bswap_needed, hwaddr target_page_size); + +/** load_uimage_as: + * @filename: Path of uimage file + * @ep: Populated with program entry point. Ignored if NULL. + * @loadaddr: Populated with the load address. Ignored if NULL. + * @is_linux: Is set to true if the image loaded is Linux. Ignored if NULL. + * @translate_fn: optional function to translate load addresses + * @translate_opaque: opaque data passed to @translate_fn + * @as: The AddressSpace to load the ELF to. The value of address_space_memory + * is used if nothing is supplied here. + * + * Loads a u-boot image into memory. + * + * Returns the size of the loaded image on success, -1 otherwise. + */ +int load_uimage_as(const char *filename, hwaddr *ep, + hwaddr *loadaddr, int *is_linux, + uint64_t (*translate_fn)(void *, uint64_t), + void *translate_opaque, AddressSpace *as); + +/** load_uimage: + * Same as load_uimage_as(), but doesn't allow the caller to specify an + * AddressSpace. + */ int load_uimage(const char *filename, hwaddr *ep, hwaddr *loadaddr, int *is_linux, uint64_t (*translate_fn)(void *, uint64_t), @@ -155,6 +179,8 @@ void hmp_info_roms(Monitor *mon, const QDict *qdict); rom_add_file(_f, NULL, 0, _i, false, _mr, NULL) #define rom_add_file_as(_f, _as, _i) \ rom_add_file(_f, NULL, 0, _i, false, NULL, _as) +#define rom_add_blob_fixed_as(_f, _b, _l, _a, _as) \ + rom_add_blob(_f, _b, _l, _l, _a, NULL, NULL, _as) #define PC_ROM_MIN_VGA 0xc0000 #define PC_ROM_MIN_OPTION 0xc8000 From 93ffc7c766429350d788ae0a978ea54171d652bd Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Thu, 22 Sep 2016 18:13:08 +0100 Subject: [PATCH 170/723] loader: Add AddressSpace loading support to targphys Add a new function load_image_targphys_as() that allows the caller to specify an AddressSpace to use when loading a targphys. The original load_image_targphys() function doesn't have any change in functionality. Signed-off-by: Alistair Francis Reviewed-by: Peter Maydell Message-id: 87de45de7acf02cbe6bae9d6c4d6fb8f3aba4f61.1474331683.git.alistair.francis@xilinx.com Signed-off-by: Peter Maydell --- hw/core/loader.c | 10 ++++++++-- include/hw/loader.h | 22 ++++++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/hw/core/loader.c b/hw/core/loader.c index 86ed7841595..6e022b5ad58 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -133,9 +133,15 @@ ssize_t read_targphys(const char *name, return did; } -/* return the size or -1 if error */ int load_image_targphys(const char *filename, hwaddr addr, uint64_t max_sz) +{ + return load_image_targphys_as(filename, addr, max_sz, NULL); +} + +/* return the size or -1 if error */ +int load_image_targphys_as(const char *filename, + hwaddr addr, uint64_t max_sz, AddressSpace *as) { int size; @@ -144,7 +150,7 @@ int load_image_targphys(const char *filename, return -1; } if (size > 0) { - rom_add_file_fixed(filename, addr, -1); + rom_add_file_fixed_as(filename, addr, -1, as); } return size; } diff --git a/include/hw/loader.h b/include/hw/loader.h index bce8f434ba3..038170624d8 100644 --- a/include/hw/loader.h +++ b/include/hw/loader.h @@ -14,8 +14,28 @@ int get_image_size(const char *filename); int load_image(const char *filename, uint8_t *addr); /* deprecated */ ssize_t load_image_size(const char *filename, void *addr, size_t size); + +/**load_image_targphys_as: + * @filename: Path to the image file + * @addr: Address to load the image to + * @max_sz: The maximum size of the image to load + * @as: The AddressSpace to load the ELF to. The value of address_space_memory + * is used if nothing is supplied here. + * + * Load a fixed image into memory. + * + * Returns the size of the loaded image on success, -1 otherwise. + */ +int load_image_targphys_as(const char *filename, + hwaddr addr, uint64_t max_sz, AddressSpace *as); + +/** load_image_targphys: + * Same as load_image_targphys_as(), but doesn't allow the caller to specify + * an AddressSpace. + */ int load_image_targphys(const char *filename, hwaddr, uint64_t max_sz); + /** * load_image_mr: load an image into a memory region * @filename: Path to the image file @@ -179,6 +199,8 @@ void hmp_info_roms(Monitor *mon, const QDict *qdict); rom_add_file(_f, NULL, 0, _i, false, _mr, NULL) #define rom_add_file_as(_f, _as, _i) \ rom_add_file(_f, NULL, 0, _i, false, NULL, _as) +#define rom_add_file_fixed_as(_f, _a, _i, _as) \ + rom_add_file(_f, NULL, _a, _i, false, NULL, _as) #define rom_add_blob_fixed_as(_f, _b, _l, _a, _as) \ rom_add_blob(_f, _b, _l, _l, _a, NULL, NULL, _as) From a43639b12daff2230a98faffcffc79346c8ebf8c Mon Sep 17 00:00:00 2001 From: Nathan Rossi Date: Thu, 22 Sep 2016 18:13:08 +0100 Subject: [PATCH 171/723] dma: xlnx-zynq-devcfg: Fix up XLNX_ZYNQ_DEVCFG_R_MAX Whilst according to the Zynq TRM this device covers a register region of 0x000 - 0x120. The register region is also shared with XADCIF prefix registers at 0x100 and above. Due to how the devcfg and the xadc devices are implemented in QEMU these are separate models with individual mmio regions. As such the region registered by the devcfg overlaps with the xadc when initialized in a machine model (e.g. xilinx-zynq-a9). This patch fixes up the incorrect region size, where XLNX_ZYNQ_DEVCFG_R_MAX is missing its '/ 4' causing it to be 0x460 in size. As well as setting the region size to the 0x0 - 0x100 region so that an xadc device instance can be registered in the correct region to pair with the devcfg device instance. Mapping with XLNX_ZYNQ_DEVCFG_R_MAX = 0x118: dev: xlnx.ps7-dev-cfg, id "" mmio 00000000f8007000/0000000000000460 dev: xlnx,zynq-xadc, id "" mmio 00000000f8007100/0000000000000020 Mapping with XLNX_ZYNQ_DEVCFG_R_MAX = 0x100 / 4: dev: xlnx.ps7-dev-cfg, id "" mmio 00000000f8007000/0000000000000100 dev: xlnx,zynq-xadc, id "" mmio 00000000f8007100/0000000000000020 Signed-off-by: Nathan Rossi Reviewed-by: Alistair Francis Message-id: 20160921180911.32289-1-nathan@nathanrossi.com Signed-off-by: Peter Maydell --- include/hw/dma/xlnx-zynq-devcfg.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/hw/dma/xlnx-zynq-devcfg.h b/include/hw/dma/xlnx-zynq-devcfg.h index d40e5c8df6b..9f5119a89a3 100644 --- a/include/hw/dma/xlnx-zynq-devcfg.h +++ b/include/hw/dma/xlnx-zynq-devcfg.h @@ -34,7 +34,7 @@ #define XLNX_ZYNQ_DEVCFG(obj) \ OBJECT_CHECK(XlnxZynqDevcfg, (obj), TYPE_XLNX_ZYNQ_DEVCFG) -#define XLNX_ZYNQ_DEVCFG_R_MAX 0x118 +#define XLNX_ZYNQ_DEVCFG_R_MAX (0x100 / 4) #define XLNX_ZYNQ_DEVCFG_DMA_CMD_FIFO_LEN 10 From e7f76c521f4fd3c5bdbbb2cf97393523c05f6952 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Thu, 22 Sep 2016 18:13:08 +0100 Subject: [PATCH 172/723] vmstateify ssd0323 display Bumps version number because we now use the VMSTATE_SSI_SLAVE that only uses a byte rather than a 32bit (for saving a bool 'cs'). Signed-off-by: Dr. David Alan Gilbert Message-id: 1472035246-12483-2-git-send-email-dgilbert@redhat.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/display/ssd0323.c | 102 +++++++++++++++++-------------------------- 1 file changed, 40 insertions(+), 62 deletions(-) diff --git a/hw/display/ssd0323.c b/hw/display/ssd0323.c index 6d1faf44afd..e1828931575 100644 --- a/hw/display/ssd0323.c +++ b/hw/display/ssd0323.c @@ -48,18 +48,18 @@ typedef struct { SSISlave ssidev; QemuConsole *con; - int cmd_len; - int cmd; - int cmd_data[8]; - int row; - int row_start; - int row_end; - int col; - int col_start; - int col_end; - int redraw; - int remap; - enum ssd0323_mode mode; + uint32_t cmd_len; + int32_t cmd; + int32_t cmd_data[8]; + int32_t row; + int32_t row_start; + int32_t row_end; + int32_t col; + int32_t col_start; + int32_t col_end; + int32_t redraw; + int32_t remap; + uint32_t mode; uint8_t framebuffer[128 * 80 / 2]; } ssd0323_state; @@ -279,83 +279,62 @@ static void ssd0323_cd(void *opaque, int n, int level) s->mode = level ? SSD0323_DATA : SSD0323_CMD; } -static void ssd0323_save(QEMUFile *f, void *opaque) +static int ssd0323_post_load(void *opaque, int version_id) { - SSISlave *ss = SSI_SLAVE(opaque); ssd0323_state *s = (ssd0323_state *)opaque; - int i; - - qemu_put_be32(f, s->cmd_len); - qemu_put_be32(f, s->cmd); - for (i = 0; i < 8; i++) - qemu_put_be32(f, s->cmd_data[i]); - qemu_put_be32(f, s->row); - qemu_put_be32(f, s->row_start); - qemu_put_be32(f, s->row_end); - qemu_put_be32(f, s->col); - qemu_put_be32(f, s->col_start); - qemu_put_be32(f, s->col_end); - qemu_put_be32(f, s->redraw); - qemu_put_be32(f, s->remap); - qemu_put_be32(f, s->mode); - qemu_put_buffer(f, s->framebuffer, sizeof(s->framebuffer)); - - qemu_put_be32(f, ss->cs); -} - -static int ssd0323_load(QEMUFile *f, void *opaque, int version_id) -{ - SSISlave *ss = SSI_SLAVE(opaque); - ssd0323_state *s = (ssd0323_state *)opaque; - int i; - if (version_id != 1) - return -EINVAL; - - s->cmd_len = qemu_get_be32(f); - if (s->cmd_len < 0 || s->cmd_len > ARRAY_SIZE(s->cmd_data)) { + if (s->cmd_len > ARRAY_SIZE(s->cmd_data)) { return -EINVAL; } - s->cmd = qemu_get_be32(f); - for (i = 0; i < 8; i++) - s->cmd_data[i] = qemu_get_be32(f); - s->row = qemu_get_be32(f); if (s->row < 0 || s->row >= 80) { return -EINVAL; } - s->row_start = qemu_get_be32(f); if (s->row_start < 0 || s->row_start >= 80) { return -EINVAL; } - s->row_end = qemu_get_be32(f); if (s->row_end < 0 || s->row_end >= 80) { return -EINVAL; } - s->col = qemu_get_be32(f); if (s->col < 0 || s->col >= 64) { return -EINVAL; } - s->col_start = qemu_get_be32(f); if (s->col_start < 0 || s->col_start >= 64) { return -EINVAL; } - s->col_end = qemu_get_be32(f); if (s->col_end < 0 || s->col_end >= 64) { return -EINVAL; } - s->redraw = qemu_get_be32(f); - s->remap = qemu_get_be32(f); - s->mode = qemu_get_be32(f); if (s->mode != SSD0323_CMD && s->mode != SSD0323_DATA) { return -EINVAL; } - qemu_get_buffer(f, s->framebuffer, sizeof(s->framebuffer)); - - ss->cs = qemu_get_be32(f); return 0; } +static const VMStateDescription vmstate_ssd0323 = { + .name = "ssd0323_oled", + .version_id = 2, + .minimum_version_id = 2, + .post_load = ssd0323_post_load, + .fields = (VMStateField []) { + VMSTATE_UINT32(cmd_len, ssd0323_state), + VMSTATE_INT32(cmd, ssd0323_state), + VMSTATE_INT32_ARRAY(cmd_data, ssd0323_state, 8), + VMSTATE_INT32(row, ssd0323_state), + VMSTATE_INT32(row_start, ssd0323_state), + VMSTATE_INT32(row_end, ssd0323_state), + VMSTATE_INT32(col, ssd0323_state), + VMSTATE_INT32(col_start, ssd0323_state), + VMSTATE_INT32(col_end, ssd0323_state), + VMSTATE_INT32(redraw, ssd0323_state), + VMSTATE_INT32(remap, ssd0323_state), + VMSTATE_UINT32(mode, ssd0323_state), + VMSTATE_BUFFER(framebuffer, ssd0323_state), + VMSTATE_SSI_SLAVE(ssidev, ssd0323_state), + VMSTATE_END_OF_LIST() + } +}; + static const GraphicHwOps ssd0323_ops = { .invalidate = ssd0323_invalidate_display, .gfx_update = ssd0323_update_display, @@ -372,18 +351,17 @@ static void ssd0323_realize(SSISlave *d, Error **errp) qemu_console_resize(s->con, 128 * MAGNIFY, 64 * MAGNIFY); qdev_init_gpio_in(dev, ssd0323_cd, 1); - - register_savevm(dev, "ssd0323_oled", -1, 1, - ssd0323_save, ssd0323_load, s); } static void ssd0323_class_init(ObjectClass *klass, void *data) { + DeviceClass *dc = DEVICE_CLASS(klass); SSISlaveClass *k = SSI_SLAVE_CLASS(klass); k->realize = ssd0323_realize; k->transfer = ssd0323_transfer; k->cs_polarity = SSI_CS_HIGH; + dc->vmsd = &vmstate_ssd0323; } static const TypeInfo ssd0323_info = { From 2ccfd336dcdbc6f4f479380ed80003fac17a946e Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Thu, 22 Sep 2016 18:13:08 +0100 Subject: [PATCH 173/723] vmstateify ssi-sd Changed a few types to fixed sized types in the ssi_sd_state Now saving/loading a byte for the cmdarg/response bytes that were previously saved as uint32 Bumped version number to deal with those changes. Signed-off-by: Dr. David Alan Gilbert Message-id: 1472035246-12483-4-git-send-email-dgilbert@redhat.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/sd/ssi-sd.c | 70 ++++++++++++++++++++------------------------------ 1 file changed, 28 insertions(+), 42 deletions(-) diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c index 3ff0886dd55..24001dc3e6a 100644 --- a/hw/sd/ssi-sd.c +++ b/hw/sd/ssi-sd.c @@ -31,7 +31,7 @@ do { fprintf(stderr, "ssi_sd: error: " fmt , ## __VA_ARGS__);} while (0) #endif typedef enum { - SSI_SD_CMD, + SSI_SD_CMD = 0, SSI_SD_CMDARG, SSI_SD_RESPONSE, SSI_SD_DATA_START, @@ -40,13 +40,13 @@ typedef enum { typedef struct { SSISlave ssidev; - ssi_sd_mode mode; + uint32_t mode; int cmd; uint8_t cmdarg[4]; uint8_t response[5]; - int arglen; - int response_pos; - int stopping; + int32_t arglen; + int32_t response_pos; + int32_t stopping; SDState *sd; } ssi_sd_state; @@ -198,61 +198,46 @@ static uint32_t ssi_sd_transfer(SSISlave *dev, uint32_t val) return 0xff; } -static void ssi_sd_save(QEMUFile *f, void *opaque) +static int ssi_sd_post_load(void *opaque, int version_id) { - SSISlave *ss = SSI_SLAVE(opaque); ssi_sd_state *s = (ssi_sd_state *)opaque; - int i; - qemu_put_be32(f, s->mode); - qemu_put_be32(f, s->cmd); - for (i = 0; i < 4; i++) - qemu_put_be32(f, s->cmdarg[i]); - for (i = 0; i < 5; i++) - qemu_put_be32(f, s->response[i]); - qemu_put_be32(f, s->arglen); - qemu_put_be32(f, s->response_pos); - qemu_put_be32(f, s->stopping); - - qemu_put_be32(f, ss->cs); -} - -static int ssi_sd_load(QEMUFile *f, void *opaque, int version_id) -{ - SSISlave *ss = SSI_SLAVE(opaque); - ssi_sd_state *s = (ssi_sd_state *)opaque; - int i; - - if (version_id != 1) + if (s->mode > SSI_SD_DATA_READ) { return -EINVAL; - - s->mode = qemu_get_be32(f); - s->cmd = qemu_get_be32(f); - for (i = 0; i < 4; i++) - s->cmdarg[i] = qemu_get_be32(f); - for (i = 0; i < 5; i++) - s->response[i] = qemu_get_be32(f); - s->arglen = qemu_get_be32(f); + } if (s->mode == SSI_SD_CMDARG && (s->arglen < 0 || s->arglen >= ARRAY_SIZE(s->cmdarg))) { return -EINVAL; } - s->response_pos = qemu_get_be32(f); - s->stopping = qemu_get_be32(f); if (s->mode == SSI_SD_RESPONSE && (s->response_pos < 0 || s->response_pos >= ARRAY_SIZE(s->response) || (!s->stopping && s->arglen > ARRAY_SIZE(s->response)))) { return -EINVAL; } - ss->cs = qemu_get_be32(f); - return 0; } +static const VMStateDescription vmstate_ssi_sd = { + .name = "ssi_sd", + .version_id = 2, + .minimum_version_id = 2, + .post_load = ssi_sd_post_load, + .fields = (VMStateField []) { + VMSTATE_UINT32(mode, ssi_sd_state), + VMSTATE_INT32(cmd, ssi_sd_state), + VMSTATE_UINT8_ARRAY(cmdarg, ssi_sd_state, 4), + VMSTATE_UINT8_ARRAY(response, ssi_sd_state, 5), + VMSTATE_INT32(arglen, ssi_sd_state), + VMSTATE_INT32(response_pos, ssi_sd_state), + VMSTATE_INT32(stopping, ssi_sd_state), + VMSTATE_SSI_SLAVE(ssidev, ssi_sd_state), + VMSTATE_END_OF_LIST() + } +}; + static void ssi_sd_realize(SSISlave *d, Error **errp) { - DeviceState *dev = DEVICE(d); ssi_sd_state *s = FROM_SSI_SLAVE(ssi_sd_state, d); DriveInfo *dinfo; @@ -264,16 +249,17 @@ static void ssi_sd_realize(SSISlave *d, Error **errp) error_setg(errp, "Device initialization failed."); return; } - register_savevm(dev, "ssi_sd", -1, 1, ssi_sd_save, ssi_sd_load, s); } static void ssi_sd_class_init(ObjectClass *klass, void *data) { + DeviceClass *dc = DEVICE_CLASS(klass); SSISlaveClass *k = SSI_SLAVE_CLASS(klass); k->realize = ssi_sd_realize; k->transfer = ssi_sd_transfer; k->cs_polarity = SSI_CS_LOW; + dc->vmsd = &vmstate_ssi_sd; } static const TypeInfo ssi_sd_info = { From d486ccaa9ecdc37015ca0ecb330e3127ea948f8a Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 22 Sep 2016 18:13:09 +0100 Subject: [PATCH 174/723] disas/arm.c: Remove unused macro definitions The macros ISSPACE, strneq, NUM_ELEMS and NUM_ARM_REGNAMES are defined in disas/arm.c but never used. Remove the unnecessary definitions. Signed-off-by: Peter Maydell --- disas/arm.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/disas/arm.c b/disas/arm.c index 426270fe829..93c650344ce 100644 --- a/disas/arm.c +++ b/disas/arm.c @@ -24,7 +24,6 @@ #include "qemu/osdep.h" #include "disas/bfd.h" -#define ISSPACE(x) ((x) == ' ' || (x) == '\t' || (x) == '\n') #define ARM_EXT_V1 0 #define ARM_EXT_V2 0 @@ -73,15 +72,6 @@ static void floatformat_to_double (unsigned char *data, double *dest) /* End of qemu specific additions. */ -/* FIXME: Belongs in global header. */ -#ifndef strneq -#define strneq(a,b,n) (strncmp ((a), (b), (n)) == 0) -#endif - -#ifndef NUM_ELEM -#define NUM_ELEM(a) (sizeof (a) / sizeof (a)[0]) -#endif - struct opcode32 { unsigned long arch; /* Architecture defining this insn. */ @@ -1528,7 +1518,6 @@ static const char *const iwmmxt_cregnames[] = /* Default to GCC register name set. */ static unsigned int regname_selected = 1; -#define NUM_ARM_REGNAMES NUM_ELEM (regnames) #define arm_regnames regnames[regname_selected].reg_names static bfd_boolean force_thumb = false; From d675765a0244af1d65c292f2508009f1bd13e1b6 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 22 Sep 2016 18:13:09 +0100 Subject: [PATCH 175/723] imx: Use 'const char', not 'char const' 'char const' means the same thing as 'const char', but we use the former in only a handful of places and we use the latter over six thousand times. Switch the imx reg_name() functions to bring them in line with everything else. Signed-off-by: Peter Maydell --- hw/misc/imx25_ccm.c | 2 +- hw/misc/imx31_ccm.c | 2 +- hw/misc/imx6_ccm.c | 4 ++-- hw/misc/imx6_src.c | 2 +- hw/ssi/imx_spi.c | 2 +- hw/timer/imx_epit.c | 2 +- hw/timer/imx_gpt.c | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/hw/misc/imx25_ccm.c b/hw/misc/imx25_ccm.c index 5cd8c0a9a75..19e948a52d5 100644 --- a/hw/misc/imx25_ccm.c +++ b/hw/misc/imx25_ccm.c @@ -27,7 +27,7 @@ } \ } while (0) -static char const *imx25_ccm_reg_name(uint32_t reg) +static const char *imx25_ccm_reg_name(uint32_t reg) { static char unknown[20]; diff --git a/hw/misc/imx31_ccm.c b/hw/misc/imx31_ccm.c index 1c03e52c40d..b890c383be1 100644 --- a/hw/misc/imx31_ccm.c +++ b/hw/misc/imx31_ccm.c @@ -29,7 +29,7 @@ } \ } while (0) -static char const *imx31_ccm_reg_name(uint32_t reg) +static const char *imx31_ccm_reg_name(uint32_t reg) { static char unknown[20]; diff --git a/hw/misc/imx6_ccm.c b/hw/misc/imx6_ccm.c index 17e15d4c92e..1b421013a38 100644 --- a/hw/misc/imx6_ccm.c +++ b/hw/misc/imx6_ccm.c @@ -26,7 +26,7 @@ } \ } while (0) -static char const *imx6_ccm_reg_name(uint32_t reg) +static const char *imx6_ccm_reg_name(uint32_t reg) { static char unknown[20]; @@ -99,7 +99,7 @@ static char const *imx6_ccm_reg_name(uint32_t reg) } } -static char const *imx6_analog_reg_name(uint32_t reg) +static const char *imx6_analog_reg_name(uint32_t reg) { static char unknown[20]; diff --git a/hw/misc/imx6_src.c b/hw/misc/imx6_src.c index 8bb68295752..55b817b8d70 100644 --- a/hw/misc/imx6_src.c +++ b/hw/misc/imx6_src.c @@ -27,7 +27,7 @@ } \ } while (0) -static char const *imx6_src_reg_name(uint32_t reg) +static const char *imx6_src_reg_name(uint32_t reg) { static char unknown[20]; diff --git a/hw/ssi/imx_spi.c b/hw/ssi/imx_spi.c index 42261998112..e4e395fa679 100644 --- a/hw/ssi/imx_spi.c +++ b/hw/ssi/imx_spi.c @@ -25,7 +25,7 @@ } \ } while (0) -static char const *imx_spi_reg_name(uint32_t reg) +static const char *imx_spi_reg_name(uint32_t reg) { static char unknown[20]; diff --git a/hw/timer/imx_epit.c b/hw/timer/imx_epit.c index f34d7f7c777..8677b753b1f 100644 --- a/hw/timer/imx_epit.c +++ b/hw/timer/imx_epit.c @@ -30,7 +30,7 @@ } \ } while (0) -static char const *imx_epit_reg_name(uint32_t reg) +static const char *imx_epit_reg_name(uint32_t reg) { switch (reg) { case 0: diff --git a/hw/timer/imx_gpt.c b/hw/timer/imx_gpt.c index f034d650362..010ccbf207c 100644 --- a/hw/timer/imx_gpt.c +++ b/hw/timer/imx_gpt.c @@ -29,7 +29,7 @@ } \ } while (0) -static char const *imx_gpt_reg_name(uint32_t reg) +static const char *imx_gpt_reg_name(uint32_t reg) { switch (reg) { case 0: From 95eaa78537c734fa3cb3373d47ba8c0099a36ff0 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Wed, 7 Sep 2016 16:27:20 -0500 Subject: [PATCH 176/723] iscsi: Fix divide-by-zero regression on raw SG devices When qemu uses iscsi devices in sg mode, iscsilun->block_size is left at 0. Prior to commits cf081fca and similar, when block limits were tracked in sectors, this did not matter: various block limits were just left at 0. But when we started scaling by block size, this caused SIGFPE. Then, in a later patch, commit a5b8dd2c added an assertion to bdrv_open_common() that request_alignment is always non-zero; which was not true for SG mode. Rather than relax that assertion, we can just provide a sane value (we don't know of any SG device with a block size smaller than qemu's default sizing of 512 bytes). One possible solution for SG mode is to just blindly skip ALL of iscsi_refresh_limits(), since we already short circuit so many other things in sg mode. But this patch takes a slightly more conservative approach, and merely guarantees that scaling will succeed, while still using multiples of the original size where possible. Resulting limits may still be zero in SG mode (that is, we mostly only fix block_size used as a denominator or which affect assertions, not all uses). Reported-by: Holger Schranz Signed-off-by: Eric Blake CC: qemu-stable@nongnu.org Message-Id: <1473283640-15756-1-git-send-email-eblake@redhat.com> Signed-off-by: Paolo Bonzini --- block/iscsi.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/block/iscsi.c b/block/iscsi.c index 95ce9e139eb..b2b4e5d2a9c 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -1813,19 +1813,22 @@ static void iscsi_refresh_limits(BlockDriverState *bs, Error **errp) IscsiLun *iscsilun = bs->opaque; uint64_t max_xfer_len = iscsilun->use_16_for_rw ? 0xffffffff : 0xffff; + unsigned int block_size = MAX(BDRV_SECTOR_SIZE, iscsilun->block_size); - bs->bl.request_alignment = iscsilun->block_size; + assert(iscsilun->block_size >= BDRV_SECTOR_SIZE || bs->sg); + + bs->bl.request_alignment = block_size; if (iscsilun->bl.max_xfer_len) { max_xfer_len = MIN(max_xfer_len, iscsilun->bl.max_xfer_len); } - if (max_xfer_len * iscsilun->block_size < INT_MAX) { + if (max_xfer_len * block_size < INT_MAX) { bs->bl.max_transfer = max_xfer_len * iscsilun->block_size; } if (iscsilun->lbp.lbpu) { - if (iscsilun->bl.max_unmap < 0xffffffff / iscsilun->block_size) { + if (iscsilun->bl.max_unmap < 0xffffffff / block_size) { bs->bl.max_pdiscard = iscsilun->bl.max_unmap * iscsilun->block_size; } @@ -1835,7 +1838,7 @@ static void iscsi_refresh_limits(BlockDriverState *bs, Error **errp) bs->bl.pdiscard_alignment = iscsilun->block_size; } - if (iscsilun->bl.max_ws_len < 0xffffffff / iscsilun->block_size) { + if (iscsilun->bl.max_ws_len < 0xffffffff / block_size) { bs->bl.max_pwrite_zeroes = iscsilun->bl.max_ws_len * iscsilun->block_size; } @@ -1846,7 +1849,7 @@ static void iscsi_refresh_limits(BlockDriverState *bs, Error **errp) bs->bl.pwrite_zeroes_alignment = iscsilun->block_size; } if (iscsilun->bl.opt_xfer_len && - iscsilun->bl.opt_xfer_len < INT_MAX / iscsilun->block_size) { + iscsilun->bl.opt_xfer_len < INT_MAX / block_size) { bs->bl.opt_transfer = pow2floor(iscsilun->bl.opt_xfer_len * iscsilun->block_size); } From 9e14037f05e99ca3b8a33d8be9a2a636bbf09326 Mon Sep 17 00:00:00 2001 From: Lin Ma Date: Thu, 15 Sep 2016 22:31:58 +0800 Subject: [PATCH 177/723] msmouse: Fix segfault caused by free the chr before chardev cleanup. Segfault happens when leaving qemu with msmouse backend: #0 0x00007fa8526ac975 in raise () at /lib64/libc.so.6 #1 0x00007fa8526add8a in abort () at /lib64/libc.so.6 #2 0x0000558be78846ab in error_exit (err=16, msg=0x558be799da10 ... #3 0x0000558be7884717 in qemu_mutex_destroy (mutex=0x558be93be750) at ... #4 0x0000558be7549951 in qemu_chr_free_common (chr=0x558be93be750) at ... #5 0x0000558be754999c in qemu_chr_free (chr=0x558be93be750) at ... #6 0x0000558be7549a20 in qemu_chr_delete (chr=0x558be93be750) at ... #7 0x0000558be754a8ef in qemu_chr_cleanup () at qemu-char.c:4643 #8 0x0000558be755843e in main (argc=5, argv=0x7ffe925d7118, ... The chr was freed by msmouse close callback before chardev cleanup, Then qemu_mutex_destroy triggered raise(). Because freeing chr is handled by qemu_chr_free_common, Remove the free from msmouse_chr_close to avoid double free. Fixes: c1111a24a3358ecd2f17be7c8b117cfe8bc5e5f8 Cc: qemu-stable@nongnu.org Signed-off-by: Lin Ma Message-Id: <20160915143158.4796-1-lma@suse.com> Signed-off-by: Paolo Bonzini --- backends/msmouse.c | 1 - 1 file changed, 1 deletion(-) diff --git a/backends/msmouse.c b/backends/msmouse.c index aceb6dc4757..85d08f753e8 100644 --- a/backends/msmouse.c +++ b/backends/msmouse.c @@ -139,7 +139,6 @@ static void msmouse_chr_close (struct CharDriverState *chr) qemu_input_handler_unregister(mouse->hs); g_free(mouse); - g_free(chr); } static QemuInputHandler msmouse_handler = { From 6867783a804b5b7eb34a2e6f0d43d0eaf88ad2de Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 21 Sep 2016 21:42:22 +0200 Subject: [PATCH 178/723] scripts: Add a script to check for bug URLs in the git log Basic idea of this script is to check the git log for URLs to the QEMU bugtracker at launchpad.net and to figure out whether the related bug has been marked there as "Fix released" (i.e. closed) already. So this script can e.g. be used after each public release of QEMU to check whether there are any bug tickets that could be moved from "Fix committed" (or another state if the author of the patch forgot to update the bug ticket) to "Fix released". Signed-off-by: Thomas Huth Message-Id: <1474486942-18754-1-git-send-email-thuth@redhat.com> Signed-off-by: Paolo Bonzini --- scripts/show-fixed-bugs.sh | 91 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100755 scripts/show-fixed-bugs.sh diff --git a/scripts/show-fixed-bugs.sh b/scripts/show-fixed-bugs.sh new file mode 100755 index 00000000000..36f306898f9 --- /dev/null +++ b/scripts/show-fixed-bugs.sh @@ -0,0 +1,91 @@ +#!/bin/sh + +# This script checks the git log for URLs to the QEMU launchpad bugtracker +# and optionally checks whether the corresponding bugs are not closed yet. + +show_help () { + echo "Usage:" + echo " -s : Start searching at this commit" + echo " -e : End searching at this commit" + echo " -c : Check if bugs are still open" + echo " -b : Open bugs in browser" +} + +while getopts "s:e:cbh" opt; do + case "$opt" in + s) start="$OPTARG" ;; + e) end="$OPTARG" ;; + c) check_if_open=1 ;; + b) show_in_browser=1 ;; + h) show_help ; exit 0 ;; + *) echo "Use -h for help." ; exit 1 ;; + esac +done + +if [ "x$start" = "x" ]; then + start=`git tag -l 'v[0-9]*\.[0-9]*\.0' | tail -n 2 | head -n 1` +fi +if [ "x$end" = "x" ]; then + end=`git tag -l 'v[0-9]*\.[0-9]*\.0' | tail -n 1` +fi + +if [ "x$start" = "x" ] || [ "x$end" = "x" ]; then + echo "Could not determine start or end revision ... Please note that this" + echo "script must be run from a checked out git repository of QEMU." + exit 1 +fi + +echo "Searching git log for bugs in the range $start..$end" + +urlstr='https://bugs.launchpad.net/\(bugs\|qemu/+bug\)/' +bug_urls=`git log $start..$end \ + | sed -n '\,'"$urlstr"', s,\(.*\)\('"$urlstr"'\)\([0-9]*\).*,\2\4,p' \ + | sort -u` + +echo Found bug URLs: +for i in $bug_urls ; do echo " $i" ; done + +if [ "x$check_if_open" = "x1" ]; then + echo + echo "Checking which ones are still open..." + for i in $bug_urls ; do + if ! curl -s -L "$i" | grep "value status" | grep -q "Fix Released" ; then + echo " $i" + final_bug_urls="$final_bug_urls $i" + fi + done +else + final_bug_urls=$bug_urls +fi + +if [ "x$final_bug_urls" = "x" ]; then + echo "No open bugs found." +elif [ "x$show_in_browser" = "x1" ]; then + # Try to determine which browser we should use + if [ "x$BROWSER" != "x" ]; then + bugbrowser="$BROWSER" + elif command -v xdg-open >/dev/null 2>&1; then + bugbrowser=xdg-open + elif command -v gnome-open >/dev/null 2>&1; then + bugbrowser=gnome-open + elif [ "`uname`" = "Darwin" ]; then + bugbrowser=open + elif command -v sensible-browser >/dev/null 2>&1; then + bugbrowser=sensible-browser + else + echo "Please set the BROWSER variable to the browser of your choice." + exit 1 + fi + # Now show the bugs in the browser + first=1 + for i in $final_bug_urls; do + "$bugbrowser" "$i" + if [ $first = 1 ]; then + # if it is the first entry, give the browser some time to start + # (to avoid messages like "Firefox is already running, but is + # not responding...") + sleep 4 + first=0 + fi + done +fi From 68c6efe07a4729b54947658df4fceed84f3d0fef Mon Sep 17 00:00:00 2001 From: "Herongguang (Stephen)" Date: Thu, 22 Sep 2016 15:56:28 +0800 Subject: [PATCH 179/723] kvm: fix events.flags (KVM_VCPUEVENT_VALID_SMM) overwritten by 0 Fix events.flags (KVM_VCPUEVENT_VALID_SMM) overwritten by 0. Signed-off-by: He Rongguang Message-Id: <57E38EAC.3020108@huawei.com> Signed-off-by: Paolo Bonzini --- target-i386/kvm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-i386/kvm.c b/target-i386/kvm.c index f236dafae5f..a0e42b2c4ed 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -2452,6 +2452,7 @@ static int kvm_put_vcpu_events(X86CPU *cpu, int level) events.nmi.pad = 0; events.sipi_vector = env->sipi_vector; + events.flags = 0; if (has_msr_smbase) { events.smi.smm = !!(env->hflags & HF_SMM_MASK); @@ -2471,7 +2472,6 @@ static int kvm_put_vcpu_events(X86CPU *cpu, int level) events.flags |= KVM_VCPUEVENT_VALID_SMM; } - events.flags = 0; if (level >= KVM_PUT_RESET_STATE) { events.flags |= KVM_VCPUEVENT_VALID_NMI_PENDING | KVM_VCPUEVENT_VALID_SIPI_VECTOR; From b5d55020471aa426701938eb826193e95c43b515 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 5 Sep 2016 22:03:36 +0200 Subject: [PATCH 180/723] MAINTAINERS: Add some missing ppc-related files There are some powerpc related files in the QEMU source tree which are currently not covered by the MAINTAINERS file and thus not properly classified by the get_maintainer.pl script. So let's add them to the proper sections. Signed-off-by: Thomas Huth Signed-off-by: David Gibson --- MAINTAINERS | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 09d13bf1c0f..a9fab468527 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -172,6 +172,7 @@ L: qemu-ppc@nongnu.org S: Maintained F: target-ppc/ F: hw/ppc/ +F: include/hw/ppc/ F: disas/ppc.c S390 @@ -574,6 +575,9 @@ L: qemu-ppc@nongnu.org S: Supported F: hw/ppc/e500.[hc] F: hw/ppc/e500plat.c +F: include/hw/ppc/ppc_e500.h +F: include/hw/pci-host/ppce500.h +F: pc-bios/u-boot.e500 mpc8544ds M: Alexander Graf @@ -591,6 +595,8 @@ F: hw/ppc/mac_newworld.c F: hw/pci-host/uninorth.c F: hw/pci-bridge/dec.[hc] F: hw/misc/macio/ +F: include/hw/ppc/mac_dbdma.h +F: hw/nvram/mac_nvram.c Old World M: Alexander Graf @@ -618,6 +624,10 @@ F: include/hw/*/spapr* F: hw/*/xics* F: include/hw/*/xics* F: pc-bios/spapr-rtas/* +F: pc-bios/spapr-rtas.bin +F: pc-bios/slof.bin +F: docs/specs/ppc-spapr-hcalls.txt +F: docs/specs/ppc-spapr-hotplug.txt virtex_ml507 M: Edgar E. Iglesias @@ -815,6 +825,7 @@ M: Alexander Graf L: qemu-ppc@nongnu.org S: Odd Fixes F: hw/ppc/ppc4*.c +F: include/hw/ppc/ppc4xx.h ppce500 M: Alexander Graf From 6ca038c292d9274dc224d401a1ba16eb5a1dd501 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Thu, 8 Sep 2016 09:32:42 +0200 Subject: [PATCH 181/723] ppc: restrict the use of the rfi instruction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Power ISA 2.x has deleted the rfi instruction and rfid shoud be used instead on cpus following this instruction set or later. This will raise an invalid exception when rfi is used on such processors: Book3S 64-bit processors. Signed-off-by: Benjamin Herrenschmidt Reviewed-by: David Gibson [clg: the required fix in openbios, commit b747b6acc272 ('ppc: use rfid when running under a CPU from the 970 family.'), is now merged in qemu under commit 5cebd885d0d2 ('Update OpenBIOS images to b747b6a built from submodule.') ] Signed-off-by: Cédric Le Goater Reviewed-by: Thomas Huth Signed-off-by: David Gibson --- target-ppc/translate.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 618334ae51d..f01ce1ea68c 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -3585,10 +3585,13 @@ static void gen_rfi(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) GEN_PRIV; #else - /* FIXME: This instruction doesn't exist anymore on 64-bit server - * processors compliant with arch 2.x, we should remove it there, - * but we need to fix OpenBIOS not to use it on 970 first + /* This instruction doesn't exist anymore on 64-bit server + * processors compliant with arch 2.x */ + if (ctx->insns_flags & PPC_SEGMENT_64B) { + gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); + return; + } /* Restore CPU state */ CHK_SV; gen_update_cfar(ctx, ctx->nip - 4); From e7b1e06fbcb81ac66e2586214a6c42fdf15fadf3 Mon Sep 17 00:00:00 2001 From: Rajalakshmi Srinivasaraghavan Date: Tue, 6 Sep 2016 10:34:06 +0530 Subject: [PATCH 182/723] target-ppc: add vector insert instructions The following vector insert instructions are added from ISA 3.0. vinsertb - Vector Insert Byte vinserth - Vector Insert Halfword vinsertw - Vector Insert Word vinsertd - Vector Insert Doubleword Signed-off-by: Rajalakshmi Srinivasaraghavan Signed-off-by: David Gibson --- target-ppc/helper.h | 4 ++++ target-ppc/int_helper.c | 20 ++++++++++++++++++ target-ppc/translate.c | 2 ++ target-ppc/translate/vmx-impl.inc.c | 32 +++++++++++++++++++++++++++++ target-ppc/translate/vmx-ops.inc.c | 18 +++++++++++----- 5 files changed, 71 insertions(+), 5 deletions(-) diff --git a/target-ppc/helper.h b/target-ppc/helper.h index dcf3f950b61..5ae10bc10ea 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -250,6 +250,10 @@ DEF_HELPER_2(vspltisw, void, avr, i32) DEF_HELPER_3(vspltb, void, avr, avr, i32) DEF_HELPER_3(vsplth, void, avr, avr, i32) DEF_HELPER_3(vspltw, void, avr, avr, i32) +DEF_HELPER_3(vinsertb, void, avr, avr, i32) +DEF_HELPER_3(vinserth, void, avr, avr, i32) +DEF_HELPER_3(vinsertw, void, avr, avr, i32) +DEF_HELPER_3(vinsertd, void, avr, avr, i32) DEF_HELPER_2(vupkhpx, void, avr, avr) DEF_HELPER_2(vupklpx, void, avr, avr) DEF_HELPER_2(vupkhsb, void, avr, avr) diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c index 552b2e041b1..66a3d87c7ae 100644 --- a/target-ppc/int_helper.c +++ b/target-ppc/int_helper.c @@ -1792,6 +1792,26 @@ VSPLT(w, u32) #undef VSPLT #undef SPLAT_ELEMENT #undef _SPLAT_MASKED +#if defined(HOST_WORDS_BIGENDIAN) +#define VINSERT(suffix, element) \ + void helper_vinsert##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t index) \ + { \ + memmove(&r->u8[index], &b->u8[8 - sizeof(r->element)], \ + sizeof(r->element[0])); \ + } +#else +#define VINSERT(suffix, element) \ + void helper_vinsert##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t index) \ + { \ + uint32_t d = (16 - index) - sizeof(r->element[0]); \ + memmove(&r->u8[d], &b->u8[8], sizeof(r->element[0])); \ + } +#endif +VINSERT(b, u8) +VINSERT(h, u16) +VINSERT(w, u32) +VINSERT(d, u64) +#undef VINSERT #define VSPLTI(suffix, element, splat_type) \ void helper_vspltis##suffix(ppc_avr_t *r, uint32_t splat) \ diff --git a/target-ppc/translate.c b/target-ppc/translate.c index f01ce1ea68c..a27f45593bc 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -498,6 +498,8 @@ EXTRACT_HELPER(UIMM, 0, 16); EXTRACT_HELPER(SIMM5, 16, 5); /* 5 bits signed immediate value */ EXTRACT_HELPER(UIMM5, 16, 5); +/* 4 bits unsigned immediate value */ +EXTRACT_HELPER(UIMM4, 16, 4); /* Bit count */ EXTRACT_HELPER(NB, 11, 5); /* Shift count */ diff --git a/target-ppc/translate/vmx-impl.inc.c b/target-ppc/translate/vmx-impl.inc.c index b9841222ea3..59ae68ab133 100644 --- a/target-ppc/translate/vmx-impl.inc.c +++ b/target-ppc/translate/vmx-impl.inc.c @@ -639,13 +639,45 @@ static void glue(gen_, name)(DisasContext *ctx) \ tcg_temp_free_ptr(rd); \ } +#define GEN_VXFORM_UIMM_SPLAT(name, opc2, opc3, splat_max) \ +static void glue(gen_, name)(DisasContext *ctx) \ + { \ + TCGv_ptr rb, rd; \ + uint8_t uimm = UIMM4(ctx->opcode); \ + TCGv_i32 t0 = tcg_temp_new_i32(); \ + if (unlikely(!ctx->altivec_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VPU); \ + return; \ + } \ + if (uimm > splat_max) { \ + uimm = 0; \ + } \ + tcg_gen_movi_i32(t0, uimm); \ + rb = gen_avr_ptr(rB(ctx->opcode)); \ + rd = gen_avr_ptr(rD(ctx->opcode)); \ + gen_helper_##name(rd, rb, t0); \ + tcg_temp_free_i32(t0); \ + tcg_temp_free_ptr(rb); \ + tcg_temp_free_ptr(rd); \ + } + GEN_VXFORM_UIMM(vspltb, 6, 8); GEN_VXFORM_UIMM(vsplth, 6, 9); GEN_VXFORM_UIMM(vspltw, 6, 10); +GEN_VXFORM_UIMM_SPLAT(vinsertb, 6, 12, 15); +GEN_VXFORM_UIMM_SPLAT(vinserth, 6, 13, 14); +GEN_VXFORM_UIMM_SPLAT(vinsertw, 6, 14, 12); +GEN_VXFORM_UIMM_SPLAT(vinsertd, 6, 15, 8); GEN_VXFORM_UIMM_ENV(vcfux, 5, 12); GEN_VXFORM_UIMM_ENV(vcfsx, 5, 13); GEN_VXFORM_UIMM_ENV(vctuxs, 5, 14); GEN_VXFORM_UIMM_ENV(vctsxs, 5, 15); +GEN_VXFORM_DUAL(vspltisb, PPC_NONE, PPC2_ALTIVEC_207, + vinsertb, PPC_NONE, PPC2_ISA300); +GEN_VXFORM_DUAL(vspltish, PPC_NONE, PPC2_ALTIVEC_207, + vinserth, PPC_NONE, PPC2_ISA300); +GEN_VXFORM_DUAL(vspltisw, PPC_NONE, PPC2_ALTIVEC_207, + vinsertw, PPC_NONE, PPC2_ISA300); static void gen_vsldoi(DisasContext *ctx) { diff --git a/target-ppc/translate/vmx-ops.inc.c b/target-ppc/translate/vmx-ops.inc.c index 2a9f225e6ab..e6abeaee561 100644 --- a/target-ppc/translate/vmx-ops.inc.c +++ b/target-ppc/translate/vmx-ops.inc.c @@ -41,6 +41,9 @@ GEN_HANDLER_E(name, 0x04, opc2, opc3, 0x00000000, PPC_NONE, PPC2_ALTIVEC_207) #define GEN_VXFORM_300(name, opc2, opc3) \ GEN_HANDLER_E(name, 0x04, opc2, opc3, 0x00000000, PPC_NONE, PPC2_ISA300) +#define GEN_VXFORM_300_EXT(name, opc2, opc3, inval) \ +GEN_HANDLER_E(name, 0x04, opc2, opc3, inval, PPC_NONE, PPC2_ISA300) + #define GEN_VXFORM_DUAL(name0, name1, opc2, opc3, type0, type1) \ GEN_HANDLER_E(name0##_##name1, 0x4, opc2, opc3, 0x00000000, type0, type1) @@ -191,11 +194,16 @@ GEN_VXRFORM(vcmpgefp, 3, 7) GEN_VXRFORM_DUAL(vcmpgtfp, vcmpgtud, 3, 11, PPC_ALTIVEC, PPC_NONE) GEN_VXRFORM_DUAL(vcmpbfp, vcmpgtsd, 3, 15, PPC_ALTIVEC, PPC_NONE) -#define GEN_VXFORM_SIMM(name, opc2, opc3) \ - GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_ALTIVEC) -GEN_VXFORM_SIMM(vspltisb, 6, 12), -GEN_VXFORM_SIMM(vspltish, 6, 13), -GEN_VXFORM_SIMM(vspltisw, 6, 14), +#define GEN_VXFORM_DUAL_INV(name0, name1, opc2, opc3, inval0, inval1, type) \ +GEN_OPCODE_DUAL(name0##_##name1, 0x04, opc2, opc3, inval0, inval1, type, \ + PPC_NONE) +GEN_VXFORM_DUAL_INV(vspltisb, vinsertb, 6, 12, 0x00000000, 0x100000, + PPC2_ALTIVEC_207), +GEN_VXFORM_DUAL_INV(vspltish, vinserth, 6, 13, 0x00000000, 0x100000, + PPC2_ALTIVEC_207), +GEN_VXFORM_DUAL_INV(vspltisw, vinsertw, 6, 14, 0x00000000, 0x100000, + PPC2_ALTIVEC_207), +GEN_VXFORM_300_EXT(vinsertd, 6, 15, 0x100000), #define GEN_VXFORM_NOA(name, opc2, opc3) \ GEN_HANDLER(name, 0x04, opc2, opc3, 0x001f0000, PPC_ALTIVEC) From b5d569a1bb033354847c34d2e011fed812ff7428 Mon Sep 17 00:00:00 2001 From: Rajalakshmi Srinivasaraghavan Date: Tue, 6 Sep 2016 10:34:07 +0530 Subject: [PATCH 183/723] target-ppc: add vector extract instructions The following vector extract instructions are added from ISA 3.0. vextractub - Vector Extract Unsigned Byte vextractuh - Vector Extract Unsigned Halfword vextractuw - Vector Extract Unsigned Word vextractd - Vector Extract Unsigned Doubleword Signed-off-by: Rajalakshmi Srinivasaraghavan Signed-off-by: David Gibson --- target-ppc/helper.h | 4 ++++ target-ppc/int_helper.c | 25 +++++++++++++++++++++++++ target-ppc/translate/vmx-impl.inc.c | 10 ++++++++++ target-ppc/translate/vmx-ops.inc.c | 10 +++++++--- 4 files changed, 46 insertions(+), 3 deletions(-) diff --git a/target-ppc/helper.h b/target-ppc/helper.h index 5ae10bc10ea..686ce799e79 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -250,6 +250,10 @@ DEF_HELPER_2(vspltisw, void, avr, i32) DEF_HELPER_3(vspltb, void, avr, avr, i32) DEF_HELPER_3(vsplth, void, avr, avr, i32) DEF_HELPER_3(vspltw, void, avr, avr, i32) +DEF_HELPER_3(vextractub, void, avr, avr, i32) +DEF_HELPER_3(vextractuh, void, avr, avr, i32) +DEF_HELPER_3(vextractuw, void, avr, avr, i32) +DEF_HELPER_3(vextractd, void, avr, avr, i32) DEF_HELPER_3(vinsertb, void, avr, avr, i32) DEF_HELPER_3(vinserth, void, avr, avr, i32) DEF_HELPER_3(vinsertw, void, avr, avr, i32) diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c index 66a3d87c7ae..9b81d91d642 100644 --- a/target-ppc/int_helper.c +++ b/target-ppc/int_helper.c @@ -1812,6 +1812,31 @@ VINSERT(h, u16) VINSERT(w, u32) VINSERT(d, u64) #undef VINSERT +#if defined(HOST_WORDS_BIGENDIAN) +#define VEXTRACT(suffix, element) \ + void helper_vextract##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t index) \ + { \ + uint32_t es = sizeof(r->element[0]); \ + memmove(&r->u8[8 - es], &b->u8[index], es); \ + memset(&r->u8[8], 0, 8); \ + memset(&r->u8[0], 0, 8 - es); \ + } +#else +#define VEXTRACT(suffix, element) \ + void helper_vextract##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t index) \ + { \ + uint32_t es = sizeof(r->element[0]); \ + uint32_t s = (16 - index) - es; \ + memmove(&r->u8[8], &b->u8[s], es); \ + memset(&r->u8[0], 0, 8); \ + memset(&r->u8[8 + es], 0, 8 - es); \ + } +#endif +VEXTRACT(ub, u8) +VEXTRACT(uh, u16) +VEXTRACT(uw, u32) +VEXTRACT(d, u64) +#undef VEXTRACT #define VSPLTI(suffix, element, splat_type) \ void helper_vspltis##suffix(ppc_avr_t *r, uint32_t splat) \ diff --git a/target-ppc/translate/vmx-impl.inc.c b/target-ppc/translate/vmx-impl.inc.c index 59ae68ab133..8e66ea0a5cf 100644 --- a/target-ppc/translate/vmx-impl.inc.c +++ b/target-ppc/translate/vmx-impl.inc.c @@ -664,6 +664,10 @@ static void glue(gen_, name)(DisasContext *ctx) \ GEN_VXFORM_UIMM(vspltb, 6, 8); GEN_VXFORM_UIMM(vsplth, 6, 9); GEN_VXFORM_UIMM(vspltw, 6, 10); +GEN_VXFORM_UIMM_SPLAT(vextractub, 6, 8, 15); +GEN_VXFORM_UIMM_SPLAT(vextractuh, 6, 9, 14); +GEN_VXFORM_UIMM_SPLAT(vextractuw, 6, 10, 12); +GEN_VXFORM_UIMM_SPLAT(vextractd, 6, 11, 8); GEN_VXFORM_UIMM_SPLAT(vinsertb, 6, 12, 15); GEN_VXFORM_UIMM_SPLAT(vinserth, 6, 13, 14); GEN_VXFORM_UIMM_SPLAT(vinsertw, 6, 14, 12); @@ -672,6 +676,12 @@ GEN_VXFORM_UIMM_ENV(vcfux, 5, 12); GEN_VXFORM_UIMM_ENV(vcfsx, 5, 13); GEN_VXFORM_UIMM_ENV(vctuxs, 5, 14); GEN_VXFORM_UIMM_ENV(vctsxs, 5, 15); +GEN_VXFORM_DUAL(vspltb, PPC_NONE, PPC2_ALTIVEC_207, + vextractub, PPC_NONE, PPC2_ISA300); +GEN_VXFORM_DUAL(vsplth, PPC_NONE, PPC2_ALTIVEC_207, + vextractuh, PPC_NONE, PPC2_ISA300); +GEN_VXFORM_DUAL(vspltw, PPC_NONE, PPC2_ALTIVEC_207, + vextractuw, PPC_NONE, PPC2_ISA300); GEN_VXFORM_DUAL(vspltisb, PPC_NONE, PPC2_ALTIVEC_207, vinsertb, PPC_NONE, PPC2_ISA300); GEN_VXFORM_DUAL(vspltish, PPC_NONE, PPC2_ALTIVEC_207, diff --git a/target-ppc/translate/vmx-ops.inc.c b/target-ppc/translate/vmx-ops.inc.c index e6abeaee561..01d36bbb629 100644 --- a/target-ppc/translate/vmx-ops.inc.c +++ b/target-ppc/translate/vmx-ops.inc.c @@ -197,6 +197,13 @@ GEN_VXRFORM_DUAL(vcmpbfp, vcmpgtsd, 3, 15, PPC_ALTIVEC, PPC_NONE) #define GEN_VXFORM_DUAL_INV(name0, name1, opc2, opc3, inval0, inval1, type) \ GEN_OPCODE_DUAL(name0##_##name1, 0x04, opc2, opc3, inval0, inval1, type, \ PPC_NONE) +GEN_VXFORM_DUAL_INV(vspltb, vextractub, 6, 8, 0x00000000, 0x100000, + PPC2_ALTIVEC_207), +GEN_VXFORM_DUAL_INV(vsplth, vextractuh, 6, 9, 0x00000000, 0x100000, + PPC2_ALTIVEC_207), +GEN_VXFORM_DUAL_INV(vspltw, vextractuw, 6, 10, 0x00000000, 0x100000, + PPC2_ALTIVEC_207), +GEN_VXFORM_300_EXT(vextractd, 6, 11, 0x100000), GEN_VXFORM_DUAL_INV(vspltisb, vinsertb, 6, 12, 0x00000000, 0x100000, PPC2_ALTIVEC_207), GEN_VXFORM_DUAL_INV(vspltish, vinserth, 6, 13, 0x00000000, 0x100000, @@ -226,9 +233,6 @@ GEN_VXFORM_NOA(vrfiz, 5, 9), #define GEN_VXFORM_UIMM(name, opc2, opc3) \ GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_ALTIVEC) -GEN_VXFORM_UIMM(vspltb, 6, 8), -GEN_VXFORM_UIMM(vsplth, 6, 9), -GEN_VXFORM_UIMM(vspltw, 6, 10), GEN_VXFORM_UIMM(vcfux, 5, 12), GEN_VXFORM_UIMM(vcfsx, 5, 13), GEN_VXFORM_UIMM(vctuxs, 5, 14), From a5ad8fbf9d771d2accb583fc1eb58faf9931cfce Mon Sep 17 00:00:00 2001 From: Rajalakshmi Srinivasaraghavan Date: Tue, 6 Sep 2016 10:34:08 +0530 Subject: [PATCH 184/723] target-ppc: add vector count trailing zeros instructions The following vector count trailing zeros instructions are added from ISA 3.0. vctzb - Vector Count Trailing Zeros Byte vctzh - Vector Count Trailing Zeros Halfword vctzw - Vector Count Trailing Zeros Word vctzd - Vector Count Trailing Zeros Doubleword Signed-off-by: Rajalakshmi Srinivasaraghavan Reviewed-by: David Gibson Signed-off-by: David Gibson --- target-ppc/helper.h | 4 ++++ target-ppc/int_helper.c | 15 +++++++++++++++ target-ppc/translate/vmx-impl.inc.c | 19 +++++++++++++++++++ target-ppc/translate/vmx-ops.inc.c | 8 ++++++++ 4 files changed, 46 insertions(+) diff --git a/target-ppc/helper.h b/target-ppc/helper.h index 686ce799e79..b11c39ad906 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -325,6 +325,10 @@ DEF_HELPER_2(vclzb, void, avr, avr) DEF_HELPER_2(vclzh, void, avr, avr) DEF_HELPER_2(vclzw, void, avr, avr) DEF_HELPER_2(vclzd, void, avr, avr) +DEF_HELPER_2(vctzb, void, avr, avr) +DEF_HELPER_2(vctzh, void, avr, avr) +DEF_HELPER_2(vctzw, void, avr, avr) +DEF_HELPER_2(vctzd, void, avr, avr) DEF_HELPER_2(vpopcntb, void, avr, avr) DEF_HELPER_2(vpopcnth, void, avr, avr) DEF_HELPER_2(vpopcntw, void, avr, avr) diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c index 9b81d91d642..4d1582dba2b 100644 --- a/target-ppc/int_helper.c +++ b/target-ppc/int_helper.c @@ -2083,6 +2083,21 @@ VGENERIC_DO(clzd, u64) #undef clzw #undef clzd +#define ctzb(v) ((v) ? ctz32(v) : 8) +#define ctzh(v) ((v) ? ctz32(v) : 16) +#define ctzw(v) ctz32((v)) +#define ctzd(v) ctz64((v)) + +VGENERIC_DO(ctzb, u8) +VGENERIC_DO(ctzh, u16) +VGENERIC_DO(ctzw, u32) +VGENERIC_DO(ctzd, u64) + +#undef ctzb +#undef ctzh +#undef ctzw +#undef ctzd + #define popcntb(v) ctpop8(v) #define popcnth(v) ctpop16(v) #define popcntw(v) ctpop32(v) diff --git a/target-ppc/translate/vmx-impl.inc.c b/target-ppc/translate/vmx-impl.inc.c index 8e66ea0a5cf..982feff0462 100644 --- a/target-ppc/translate/vmx-impl.inc.c +++ b/target-ppc/translate/vmx-impl.inc.c @@ -569,6 +569,21 @@ static void glue(gen_, name)(DisasContext *ctx) \ tcg_temp_free_ptr(rd); \ } +#define GEN_VXFORM_NOA_2(name, opc2, opc3, opc4) \ +static void glue(gen_, name)(DisasContext *ctx) \ + { \ + TCGv_ptr rb, rd; \ + if (unlikely(!ctx->altivec_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VPU); \ + return; \ + } \ + rb = gen_avr_ptr(rB(ctx->opcode)); \ + rd = gen_avr_ptr(rD(ctx->opcode)); \ + gen_helper_##name(rd, rb); \ + tcg_temp_free_ptr(rb); \ + tcg_temp_free_ptr(rd); \ + } + GEN_VXFORM_NOA(vupkhsb, 7, 8); GEN_VXFORM_NOA(vupkhsh, 7, 9); GEN_VXFORM_NOA(vupkhsw, 7, 25); @@ -761,6 +776,10 @@ GEN_VXFORM_NOA(vclzb, 1, 28) GEN_VXFORM_NOA(vclzh, 1, 29) GEN_VXFORM_NOA(vclzw, 1, 30) GEN_VXFORM_NOA(vclzd, 1, 31) +GEN_VXFORM_NOA_2(vctzb, 1, 24, 28) +GEN_VXFORM_NOA_2(vctzh, 1, 24, 29) +GEN_VXFORM_NOA_2(vctzw, 1, 24, 30) +GEN_VXFORM_NOA_2(vctzd, 1, 24, 31) GEN_VXFORM_NOA(vpopcntb, 1, 28) GEN_VXFORM_NOA(vpopcnth, 1, 29) GEN_VXFORM_NOA(vpopcntw, 1, 30) diff --git a/target-ppc/translate/vmx-ops.inc.c b/target-ppc/translate/vmx-ops.inc.c index 01d36bbb629..7172cdc5423 100644 --- a/target-ppc/translate/vmx-ops.inc.c +++ b/target-ppc/translate/vmx-ops.inc.c @@ -44,6 +44,10 @@ GEN_HANDLER_E(name, 0x04, opc2, opc3, 0x00000000, PPC_NONE, PPC2_ISA300) #define GEN_VXFORM_300_EXT(name, opc2, opc3, inval) \ GEN_HANDLER_E(name, 0x04, opc2, opc3, inval, PPC_NONE, PPC2_ISA300) +#define GEN_VXFORM_300_EO(name, opc2, opc3, opc4) \ +GEN_HANDLER_E_2(name, 0x04, opc2, opc3, opc4, 0x00000000, PPC_NONE, \ + PPC2_ISA300) + #define GEN_VXFORM_DUAL(name0, name1, opc2, opc3, type0, type1) \ GEN_HANDLER_E(name0##_##name1, 0x4, opc2, opc3, 0x00000000, type0, type1) @@ -211,6 +215,10 @@ GEN_VXFORM_DUAL_INV(vspltish, vinserth, 6, 13, 0x00000000, 0x100000, GEN_VXFORM_DUAL_INV(vspltisw, vinsertw, 6, 14, 0x00000000, 0x100000, PPC2_ALTIVEC_207), GEN_VXFORM_300_EXT(vinsertd, 6, 15, 0x100000), +GEN_VXFORM_300_EO(vctzb, 0x01, 0x18, 0x1C), +GEN_VXFORM_300_EO(vctzh, 0x01, 0x18, 0x1D), +GEN_VXFORM_300_EO(vctzw, 0x01, 0x18, 0x1E), +GEN_VXFORM_300_EO(vctzd, 0x01, 0x18, 0x1F), #define GEN_VXFORM_NOA(name, opc2, opc3) \ GEN_HANDLER(name, 0x04, opc2, opc3, 0x001f0000, PPC_ALTIVEC) From 01fe9a470c4c49a18c386f411278780dedb65ad6 Mon Sep 17 00:00:00 2001 From: Rajalakshmi Srinivasaraghavan Date: Tue, 6 Sep 2016 10:34:09 +0530 Subject: [PATCH 185/723] target-ppc: add vector bit permute doubleword instruction Add vbpermd instruction from ISA 3.0. Signed-off-by: Rajalakshmi Srinivasaraghavan Signed-off-by: David Gibson --- target-ppc/helper.h | 1 + target-ppc/int_helper.c | 20 ++++++++++++++++++++ target-ppc/translate/vmx-impl.inc.c | 1 + target-ppc/translate/vmx-ops.inc.c | 1 + 4 files changed, 23 insertions(+) diff --git a/target-ppc/helper.h b/target-ppc/helper.h index b11c39ad906..e14886187e9 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -333,6 +333,7 @@ DEF_HELPER_2(vpopcntb, void, avr, avr) DEF_HELPER_2(vpopcnth, void, avr, avr) DEF_HELPER_2(vpopcntw, void, avr, avr) DEF_HELPER_2(vpopcntd, void, avr, avr) +DEF_HELPER_3(vbpermd, void, avr, avr, avr) DEF_HELPER_3(vbpermq, void, avr, avr, avr) DEF_HELPER_2(vgbbd, void, avr, avr) DEF_HELPER_3(vpmsumb, void, avr, avr, avr) diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c index 4d1582dba2b..b12af958778 100644 --- a/target-ppc/int_helper.c +++ b/target-ppc/int_helper.c @@ -1128,12 +1128,32 @@ void helper_vperm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, #if defined(HOST_WORDS_BIGENDIAN) #define VBPERMQ_INDEX(avr, i) ((avr)->u8[(i)]) +#define VBPERMD_INDEX(i) (i) #define VBPERMQ_DW(index) (((index) & 0x40) != 0) +#define EXTRACT_BIT(avr, i, index) (extract64((avr)->u64[i], index, 1)) #else #define VBPERMQ_INDEX(avr, i) ((avr)->u8[15-(i)]) +#define VBPERMD_INDEX(i) (1 - i) #define VBPERMQ_DW(index) (((index) & 0x40) == 0) +#define EXTRACT_BIT(avr, i, index) \ + (extract64((avr)->u64[1 - i], 63 - index, 1)) #endif +void helper_vbpermd(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) +{ + int i, j; + ppc_avr_t result = { .u64 = { 0, 0 } }; + VECTOR_FOR_INORDER_I(i, u64) { + for (j = 0; j < 8; j++) { + int index = VBPERMQ_INDEX(b, (i * 8) + j); + if (index < 64 && EXTRACT_BIT(a, i, index)) { + result.u64[VBPERMD_INDEX(i)] |= (0x80 >> j); + } + } + } + *r = result; +} + void helper_vbpermq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) { int i; diff --git a/target-ppc/translate/vmx-impl.inc.c b/target-ppc/translate/vmx-impl.inc.c index 982feff0462..cb8933080fa 100644 --- a/target-ppc/translate/vmx-impl.inc.c +++ b/target-ppc/translate/vmx-impl.inc.c @@ -792,6 +792,7 @@ GEN_VXFORM_DUAL(vclzw, PPC_NONE, PPC2_ALTIVEC_207, \ vpopcntw, PPC_NONE, PPC2_ALTIVEC_207) GEN_VXFORM_DUAL(vclzd, PPC_NONE, PPC2_ALTIVEC_207, \ vpopcntd, PPC_NONE, PPC2_ALTIVEC_207) +GEN_VXFORM(vbpermd, 6, 23); GEN_VXFORM(vbpermq, 6, 21); GEN_VXFORM_NOA(vgbbd, 6, 20); GEN_VXFORM(vpmsumb, 4, 16) diff --git a/target-ppc/translate/vmx-ops.inc.c b/target-ppc/translate/vmx-ops.inc.c index 7172cdc5423..a944671c1e9 100644 --- a/target-ppc/translate/vmx-ops.inc.c +++ b/target-ppc/translate/vmx-ops.inc.c @@ -261,6 +261,7 @@ GEN_VXFORM_DUAL(vclzh, vpopcnth, 1, 29, PPC_NONE, PPC2_ALTIVEC_207), GEN_VXFORM_DUAL(vclzw, vpopcntw, 1, 30, PPC_NONE, PPC2_ALTIVEC_207), GEN_VXFORM_DUAL(vclzd, vpopcntd, 1, 31, PPC_NONE, PPC2_ALTIVEC_207), +GEN_VXFORM_300(vbpermd, 6, 23), GEN_VXFORM_207(vbpermq, 6, 21), GEN_VXFORM_207(vgbbd, 6, 20), GEN_VXFORM_207(vpmsumb, 4, 16), From ab04543602b7fa8fbc33401c66f071ae4570da04 Mon Sep 17 00:00:00 2001 From: Rajalakshmi Srinivasaraghavan Date: Tue, 6 Sep 2016 10:34:10 +0530 Subject: [PATCH 186/723] target-ppc: add vector permute right indexed instruction Add vpermr instruction from ISA 3.0. Signed-off-by: Rajalakshmi Srinivasaraghavan Signed-off-by: David Gibson --- target-ppc/helper.h | 1 + target-ppc/int_helper.c | 23 +++++++++++++++++++++++ target-ppc/translate/vmx-impl.inc.c | 18 ++++++++++++++++++ target-ppc/translate/vmx-ops.inc.c | 1 + 4 files changed, 43 insertions(+) diff --git a/target-ppc/helper.h b/target-ppc/helper.h index e14886187e9..e75d0701c0e 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -270,6 +270,7 @@ DEF_HELPER_5(vmsumubm, void, env, avr, avr, avr, avr) DEF_HELPER_5(vmsummbm, void, env, avr, avr, avr, avr) DEF_HELPER_5(vsel, void, env, avr, avr, avr, avr) DEF_HELPER_5(vperm, void, env, avr, avr, avr, avr) +DEF_HELPER_5(vpermr, void, env, avr, avr, avr, avr) DEF_HELPER_4(vpkshss, void, env, avr, avr, avr) DEF_HELPER_4(vpkshus, void, env, avr, avr, avr) DEF_HELPER_4(vpkswss, void, env, avr, avr, avr) diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c index b12af958778..291fba03f65 100644 --- a/target-ppc/int_helper.c +++ b/target-ppc/int_helper.c @@ -1126,6 +1126,29 @@ void helper_vperm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, *r = result; } +void helper_vpermr(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, + ppc_avr_t *c) +{ + ppc_avr_t result; + int i; + + VECTOR_FOR_INORDER_I(i, u8) { + int s = c->u8[i] & 0x1f; +#if defined(HOST_WORDS_BIGENDIAN) + int index = 15 - (s & 0xf); +#else + int index = s & 0xf; +#endif + + if (s & 0x10) { + result.u8[i] = a->u8[index]; + } else { + result.u8[i] = b->u8[index]; + } + } + *r = result; +} + #if defined(HOST_WORDS_BIGENDIAN) #define VBPERMQ_INDEX(avr, i) ((avr)->u8[(i)]) #define VBPERMD_INDEX(i) (i) diff --git a/target-ppc/translate/vmx-impl.inc.c b/target-ppc/translate/vmx-impl.inc.c index cb8933080fa..024faf76fef 100644 --- a/target-ppc/translate/vmx-impl.inc.c +++ b/target-ppc/translate/vmx-impl.inc.c @@ -766,6 +766,24 @@ static void gen_vmladduhm(DisasContext *ctx) tcg_temp_free_ptr(rd); } +static void gen_vpermr(DisasContext *ctx) +{ + TCGv_ptr ra, rb, rc, rd; + if (unlikely(!ctx->altivec_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VPU); + return; + } + ra = gen_avr_ptr(rA(ctx->opcode)); + rb = gen_avr_ptr(rB(ctx->opcode)); + rc = gen_avr_ptr(rC(ctx->opcode)); + rd = gen_avr_ptr(rD(ctx->opcode)); + gen_helper_vpermr(cpu_env, rd, ra, rb, rc); + tcg_temp_free_ptr(ra); + tcg_temp_free_ptr(rb); + tcg_temp_free_ptr(rc); + tcg_temp_free_ptr(rd); +} + GEN_VAFORM_PAIRED(vmsumubm, vmsummbm, 18) GEN_VAFORM_PAIRED(vmsumuhm, vmsumuhs, 19) GEN_VAFORM_PAIRED(vmsumshm, vmsumshs, 20) diff --git a/target-ppc/translate/vmx-ops.inc.c b/target-ppc/translate/vmx-ops.inc.c index a944671c1e9..a7022a0de54 100644 --- a/target-ppc/translate/vmx-ops.inc.c +++ b/target-ppc/translate/vmx-ops.inc.c @@ -219,6 +219,7 @@ GEN_VXFORM_300_EO(vctzb, 0x01, 0x18, 0x1C), GEN_VXFORM_300_EO(vctzh, 0x01, 0x18, 0x1D), GEN_VXFORM_300_EO(vctzw, 0x01, 0x18, 0x1E), GEN_VXFORM_300_EO(vctzd, 0x01, 0x18, 0x1F), +GEN_VXFORM_300(vpermr, 0x1D, 0xFF), #define GEN_VXFORM_NOA(name, opc2, opc3) \ GEN_HANDLER(name, 0x04, opc2, opc3, 0x001f0000, PPC_ALTIVEC) From 95cda4c44ee2ae8616b2f9d8a2d68882cf437859 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 3 Aug 2016 22:38:51 +1000 Subject: [PATCH 187/723] ppc: Fix signal delivery in ppc-user and ppc64-user There were a number of bugs in the implementation: - The structure alignment was wrong for 64-bit. - Also 64-bit only does RT signals. - On 64-bit, we need to put a pointer to the (aligned) vector registers in the frame and use it for restoring - We had endian bugs when saving/restoring vector registers - My recent fixes for exception NIP broke sigreturn in user mode causing us to resume one instruction too far. - Add VSR second halves Signed-off-by: Benjamin Herrenschmidt Signed-off-by: David Gibson --- linux-user/main.c | 2 +- linux-user/ppc/syscall_nr.h | 2 + linux-user/signal.c | 124 +++++++++++++++++++++++++----------- 3 files changed, 90 insertions(+), 38 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index aba58c78bc4..8daebe07670 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1992,12 +1992,12 @@ void cpu_loop(CPUPPCState *env) if (ret == -TARGET_ERESTARTSYS) { break; } - env->nip += 4; if (ret == (target_ulong)(-TARGET_QEMU_ESIGRETURN)) { /* Returning from a successful sigreturn syscall. Avoid corrupting register state. */ break; } + env->nip += 4; if (ret > (target_ulong)(-515)) { env->crf[0] |= 0x1; ret = -ret; diff --git a/linux-user/ppc/syscall_nr.h b/linux-user/ppc/syscall_nr.h index 46ed8a68ce1..afa36544f15 100644 --- a/linux-user/ppc/syscall_nr.h +++ b/linux-user/ppc/syscall_nr.h @@ -120,7 +120,9 @@ #define TARGET_NR_sysinfo 116 #define TARGET_NR_ipc 117 #define TARGET_NR_fsync 118 +#if !defined(TARGET_PPC64) #define TARGET_NR_sigreturn 119 +#endif #define TARGET_NR_clone 120 #define TARGET_NR_setdomainname 121 #define TARGET_NR_uname 122 diff --git a/linux-user/signal.c b/linux-user/signal.c index e4eea697b44..c750053edde 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -4454,7 +4454,12 @@ struct target_mcontext { target_ulong mc_gregs[48]; /* Includes fpscr. */ uint64_t mc_fregs[33]; +#if defined(TARGET_PPC64) + /* Pointer to the vector regs */ + target_ulong v_regs; +#else target_ulong mc_pad[2]; +#endif /* We need to handle Altivec and SPE at the same time, which no kernel needs to do. Fortunately, the kernel defines this bit to be Altivec-register-large all the time, rather than trying to @@ -4464,15 +4469,30 @@ struct target_mcontext { uint32_t spe[33]; /* Altivec vector registers. The packing of VSCR and VRSAVE varies depending on whether we're PPC64 or not: PPC64 splits - them apart; PPC32 stuffs them together. */ + them apart; PPC32 stuffs them together. + We also need to account for the VSX registers on PPC64 + */ #if defined(TARGET_PPC64) -#define QEMU_NVRREG 34 +#define QEMU_NVRREG (34 + 16) + /* On ppc64, this mcontext structure is naturally *unaligned*, + * or rather it is aligned on a 8 bytes boundary but not on + * a 16 bytes one. This pad fixes it up. This is also why the + * vector regs are referenced by the v_regs pointer above so + * any amount of padding can be added here + */ + target_ulong pad; #else + /* On ppc32, we are already aligned to 16 bytes */ #define QEMU_NVRREG 33 #endif - ppc_avr_t altivec[QEMU_NVRREG]; + /* We cannot use ppc_avr_t here as we do *not* want the implied + * 16-bytes alignment that would result from it. This would have + * the effect of making the whole struct target_mcontext aligned + * which breaks the layout of struct target_ucontext on ppc64. + */ + uint64_t altivec[QEMU_NVRREG][2]; #undef QEMU_NVRREG - } mc_vregs __attribute__((__aligned__(16))); + } mc_vregs; }; /* See arch/powerpc/include/asm/sigcontext.h. */ @@ -4626,6 +4646,16 @@ static target_ulong get_sigframe(struct target_sigaction *ka, return (oldsp - frame_size) & ~0xFUL; } +#if ((defined(TARGET_WORDS_BIGENDIAN) && defined(HOST_WORDS_BIGENDIAN)) || \ + (!defined(HOST_WORDS_BIGENDIAN) && !defined(TARGET_WORDS_BIGENDIAN))) +#define PPC_VEC_HI 0 +#define PPC_VEC_LO 1 +#else +#define PPC_VEC_HI 1 +#define PPC_VEC_LO 0 +#endif + + static void save_user_regs(CPUPPCState *env, struct target_mcontext *frame) { target_ulong msr = env->msr; @@ -4652,18 +4682,33 @@ static void save_user_regs(CPUPPCState *env, struct target_mcontext *frame) /* Save Altivec registers if necessary. */ if (env->insns_flags & PPC_ALTIVEC) { + uint32_t *vrsave; for (i = 0; i < ARRAY_SIZE(env->avr); i++) { ppc_avr_t *avr = &env->avr[i]; - ppc_avr_t *vreg = &frame->mc_vregs.altivec[i]; + ppc_avr_t *vreg = (ppc_avr_t *)&frame->mc_vregs.altivec[i]; - __put_user(avr->u64[0], &vreg->u64[0]); - __put_user(avr->u64[1], &vreg->u64[1]); + __put_user(avr->u64[PPC_VEC_HI], &vreg->u64[0]); + __put_user(avr->u64[PPC_VEC_LO], &vreg->u64[1]); } /* Set MSR_VR in the saved MSR value to indicate that frame->mc_vregs contains valid data. */ msr |= MSR_VR; - __put_user((uint32_t)env->spr[SPR_VRSAVE], - &frame->mc_vregs.altivec[32].u32[3]); +#if defined(TARGET_PPC64) + vrsave = (uint32_t *)&frame->mc_vregs.altivec[33]; + /* 64-bit needs to put a pointer to the vectors in the frame */ + __put_user(h2g(frame->mc_vregs.altivec), &frame->v_regs); +#else + vrsave = (uint32_t *)&frame->mc_vregs.altivec[32]; +#endif + __put_user((uint32_t)env->spr[SPR_VRSAVE], vrsave); + } + + /* Save VSX second halves */ + if (env->insns_flags2 & PPC2_VSX) { + uint64_t *vsregs = (uint64_t *)&frame->mc_vregs.altivec[34]; + for (i = 0; i < ARRAY_SIZE(env->vsr); i++) { + __put_user(env->vsr[i], &vsregs[i]); + } } /* Save floating point registers. */ @@ -4743,17 +4788,39 @@ static void restore_user_regs(CPUPPCState *env, /* Restore Altivec registers if necessary. */ if (env->insns_flags & PPC_ALTIVEC) { + ppc_avr_t *v_regs; + uint32_t *vrsave; +#if defined(TARGET_PPC64) + uint64_t v_addr; + /* 64-bit needs to recover the pointer to the vectors from the frame */ + __get_user(v_addr, &frame->v_regs); + v_regs = g2h(v_addr); +#else + v_regs = (ppc_avr_t *)frame->mc_vregs.altivec; +#endif for (i = 0; i < ARRAY_SIZE(env->avr); i++) { ppc_avr_t *avr = &env->avr[i]; - ppc_avr_t *vreg = &frame->mc_vregs.altivec[i]; + ppc_avr_t *vreg = &v_regs[i]; - __get_user(avr->u64[0], &vreg->u64[0]); - __get_user(avr->u64[1], &vreg->u64[1]); + __get_user(avr->u64[PPC_VEC_HI], &vreg->u64[0]); + __get_user(avr->u64[PPC_VEC_LO], &vreg->u64[1]); } /* Set MSR_VEC in the saved MSR value to indicate that frame->mc_vregs contains valid data. */ - __get_user(env->spr[SPR_VRSAVE], - (target_ulong *)(&frame->mc_vregs.altivec[32].u32[3])); +#if defined(TARGET_PPC64) + vrsave = (uint32_t *)&v_regs[33]; +#else + vrsave = (uint32_t *)&v_regs[32]; +#endif + __get_user(env->spr[SPR_VRSAVE], vrsave); + } + + /* Restore VSX second halves */ + if (env->insns_flags2 & PPC2_VSX) { + uint64_t *vsregs = (uint64_t *)&frame->mc_vregs.altivec[34]; + for (i = 0; i < ARRAY_SIZE(env->vsr); i++) { + __get_user(env->vsr[i], &vsregs[i]); + } } /* Restore floating point registers. */ @@ -4784,6 +4851,7 @@ static void restore_user_regs(CPUPPCState *env, } } +#if !defined(TARGET_PPC64) static void setup_frame(int sig, struct target_sigaction *ka, target_sigset_t *set, CPUPPCState *env) { @@ -4791,9 +4859,6 @@ static void setup_frame(int sig, struct target_sigaction *ka, struct target_sigcontext *sc; target_ulong frame_addr, newsp; int err = 0; -#if defined(TARGET_PPC64) - struct image_info *image = ((TaskState *)thread_cpu->opaque)->info; -#endif frame_addr = get_sigframe(ka, env, sizeof(*frame)); trace_user_setup_frame(env, frame_addr); @@ -4803,11 +4868,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, __put_user(ka->_sa_handler, &sc->handler); __put_user(set->sig[0], &sc->oldmask); -#if TARGET_ABI_BITS == 64 - __put_user(set->sig[0] >> 32, &sc->_unused[3]); -#else __put_user(set->sig[1], &sc->_unused[3]); -#endif __put_user(h2g(&frame->mctx), &sc->regs); __put_user(sig, &sc->signal); @@ -4836,22 +4897,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, env->gpr[3] = sig; env->gpr[4] = frame_addr + offsetof(struct target_sigframe, sctx); -#if defined(TARGET_PPC64) - if (get_ppc64_abi(image) < 2) { - /* ELFv1 PPC64 function pointers are pointers to OPD entries. */ - struct target_func_ptr *handler = - (struct target_func_ptr *)g2h(ka->_sa_handler); - env->nip = tswapl(handler->entry); - env->gpr[2] = tswapl(handler->toc); - } else { - /* ELFv2 PPC64 function pointers are entry points, but R12 - * must also be set */ - env->nip = tswapl((target_ulong) ka->_sa_handler); - env->gpr[12] = env->nip; - } -#else env->nip = (target_ulong) ka->_sa_handler; -#endif /* Signal handlers are entered in big-endian mode. */ env->msr &= ~(1ull << MSR_LE); @@ -4863,6 +4909,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, unlock_user_struct(frame, frame_addr, 1); force_sigsegv(sig); } +#endif /* !defined(TARGET_PPC64) */ static void setup_rt_frame(int sig, struct target_sigaction *ka, target_siginfo_t *info, @@ -4960,6 +5007,7 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, } +#if !defined(TARGET_PPC64) long do_sigreturn(CPUPPCState *env) { struct target_sigcontext *sc = NULL; @@ -4996,6 +5044,7 @@ long do_sigreturn(CPUPPCState *env) force_sig(TARGET_SIGSEGV); return -TARGET_QEMU_ESIGRETURN; } +#endif /* !defined(TARGET_PPC64) */ /* See arch/powerpc/kernel/signal_32.c. */ static int do_setcontext(struct target_ucontext *ucp, CPUPPCState *env, int sig) @@ -5939,7 +5988,8 @@ static void handle_pending_signal(CPUArchState *cpu_env, int sig, #endif /* prepare the stack frame of the virtual CPU */ #if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64) \ - || defined(TARGET_OPENRISC) || defined(TARGET_TILEGX) + || defined(TARGET_OPENRISC) || defined(TARGET_TILEGX) \ + || defined(TARGET_PPC64) /* These targets do not have traditional signals. */ setup_rt_frame(sig, sa, &k->info, &target_old_set, cpu_env); #else From aa15f497178a8a3d489bf410171c3b6dfa0d9f49 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Tue, 13 Sep 2016 14:52:43 +0200 Subject: [PATCH 188/723] qtest: replace strtoXX() by qemu_strtoXX() Check the result of qemu_strtoXX() and assert if the string cannot be converted. Signed-off-by: Laurent Vivier Reviewed-by: David Gibson Reviewed-by: Greg Kurz Signed-off-by: David Gibson --- qtest.c | 49 ++++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/qtest.c b/qtest.c index ce4c6dbbf92..649f7b26c63 100644 --- a/qtest.c +++ b/qtest.c @@ -27,6 +27,7 @@ #include "qemu/config-file.h" #include "qemu/option.h" #include "qemu/error-report.h" +#include "qemu/cutils.h" #define MAX_IRQ 256 @@ -325,12 +326,13 @@ static void qtest_process_command(CharDriverState *chr, gchar **words) } else if (strcmp(words[0], "outb") == 0 || strcmp(words[0], "outw") == 0 || strcmp(words[0], "outl") == 0) { - uint16_t addr; - uint32_t value; + unsigned long addr; + unsigned long value; g_assert(words[1] && words[2]); - addr = strtoul(words[1], NULL, 0); - value = strtoul(words[2], NULL, 0); + g_assert(qemu_strtoul(words[1], NULL, 0, &addr) == 0); + g_assert(qemu_strtoul(words[2], NULL, 0, &value) == 0); + g_assert(addr <= 0xffff); if (words[0][3] == 'b') { cpu_outb(addr, value); @@ -344,11 +346,12 @@ static void qtest_process_command(CharDriverState *chr, gchar **words) } else if (strcmp(words[0], "inb") == 0 || strcmp(words[0], "inw") == 0 || strcmp(words[0], "inl") == 0) { - uint16_t addr; + unsigned long addr; uint32_t value = -1U; g_assert(words[1]); - addr = strtoul(words[1], NULL, 0); + g_assert(qemu_strtoul(words[1], NULL, 0, &addr) == 0); + g_assert(addr <= 0xffff); if (words[0][2] == 'b') { value = cpu_inb(addr); @@ -367,8 +370,8 @@ static void qtest_process_command(CharDriverState *chr, gchar **words) uint64_t value; g_assert(words[1] && words[2]); - addr = strtoull(words[1], NULL, 0); - value = strtoull(words[2], NULL, 0); + g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0); + g_assert(qemu_strtoull(words[2], NULL, 0, &value) == 0); if (words[0][5] == 'b') { uint8_t data = value; @@ -396,7 +399,7 @@ static void qtest_process_command(CharDriverState *chr, gchar **words) uint64_t value = UINT64_C(-1); g_assert(words[1]); - addr = strtoull(words[1], NULL, 0); + g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0); if (words[0][4] == 'b') { uint8_t data; @@ -422,8 +425,8 @@ static void qtest_process_command(CharDriverState *chr, gchar **words) char *enc; g_assert(words[1] && words[2]); - addr = strtoull(words[1], NULL, 0); - len = strtoull(words[2], NULL, 0); + g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0); + g_assert(qemu_strtoull(words[2], NULL, 0, &len) == 0); data = g_malloc(len); cpu_physical_memory_read(addr, data, len); @@ -444,8 +447,8 @@ static void qtest_process_command(CharDriverState *chr, gchar **words) gchar *b64_data; g_assert(words[1] && words[2]); - addr = strtoull(words[1], NULL, 0); - len = strtoull(words[2], NULL, 0); + g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0); + g_assert(qemu_strtoull(words[2], NULL, 0, &len) == 0); data = g_malloc(len); cpu_physical_memory_read(addr, data, len); @@ -461,8 +464,8 @@ static void qtest_process_command(CharDriverState *chr, gchar **words) size_t data_len; g_assert(words[1] && words[2] && words[3]); - addr = strtoull(words[1], NULL, 0); - len = strtoull(words[2], NULL, 0); + g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0); + g_assert(qemu_strtoull(words[2], NULL, 0, &len) == 0); data_len = strlen(words[3]); if (data_len < 3) { @@ -487,12 +490,12 @@ static void qtest_process_command(CharDriverState *chr, gchar **words) } else if (strcmp(words[0], "memset") == 0) { uint64_t addr, len; uint8_t *data; - uint8_t pattern; + unsigned long pattern; g_assert(words[1] && words[2] && words[3]); - addr = strtoull(words[1], NULL, 0); - len = strtoull(words[2], NULL, 0); - pattern = strtoull(words[3], NULL, 0); + g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0); + g_assert(qemu_strtoull(words[2], NULL, 0, &len) == 0); + g_assert(qemu_strtoul(words[3], NULL, 0, &pattern) == 0); if (len) { data = g_malloc(len); @@ -510,8 +513,8 @@ static void qtest_process_command(CharDriverState *chr, gchar **words) gsize out_len; g_assert(words[1] && words[2] && words[3]); - addr = strtoull(words[1], NULL, 0); - len = strtoull(words[2], NULL, 0); + g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0); + g_assert(qemu_strtoull(words[2], NULL, 0, &len) == 0); data_len = strlen(words[3]); if (data_len < 3) { @@ -535,7 +538,7 @@ static void qtest_process_command(CharDriverState *chr, gchar **words) int64_t ns; if (words[1]) { - ns = strtoll(words[1], NULL, 0); + g_assert(qemu_strtoll(words[1], NULL, 0, &ns) == 0); } else { ns = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL); } @@ -547,7 +550,7 @@ static void qtest_process_command(CharDriverState *chr, gchar **words) int64_t ns; g_assert(words[1]); - ns = strtoll(words[1], NULL, 0); + g_assert(qemu_strtoll(words[1], NULL, 0, &ns) == 0); qtest_clock_warp(ns); qtest_send_prefix(chr); qtest_sendf(chr, "OK %"PRIi64"\n", From 8d6ef7c9fe880c710dd55cfe7a0f076be475bede Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Tue, 13 Sep 2016 14:52:44 +0200 Subject: [PATCH 189/723] libqos: define SPAPR libqos functions Define spapr_alloc_init()/spapr_alloc_init_flags()/spapr_alloc_uninit() to allocate and use SPAPR guest memory Define qtest_spapr_vboot()/qtest_spapr_boot()/qtest_spapr_shutdown() to start SPAPR guest with QOSState initialized for it (memory management) Move qtest_irq_intercept_in() from generic part to PC part. Signed-off-by: Laurent Vivier Reviewed-by: Greg Kurz Reviewed-by: David Gibson Signed-off-by: David Gibson --- tests/Makefile.include | 2 ++ tests/libqos/libqos-pc.c | 2 ++ tests/libqos/libqos-spapr.c | 30 +++++++++++++++++++++++++++++ tests/libqos/libqos-spapr.h | 10 ++++++++++ tests/libqos/libqos.c | 1 - tests/libqos/malloc-spapr.c | 38 +++++++++++++++++++++++++++++++++++++ tests/libqos/malloc-spapr.h | 17 +++++++++++++++++ 7 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 tests/libqos/libqos-spapr.c create mode 100644 tests/libqos/libqos-spapr.h create mode 100644 tests/libqos/malloc-spapr.c create mode 100644 tests/libqos/malloc-spapr.h diff --git a/tests/Makefile.include b/tests/Makefile.include index 6052a3828f6..dba35a3e740 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -583,6 +583,8 @@ tests/test-crypto-block$(EXESUF): tests/test-crypto-block.o $(test-crypto-obj-y) libqos-obj-y = tests/libqos/pci.o tests/libqos/fw_cfg.o tests/libqos/malloc.o libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o +libqos-spapr-obj-y = $(libqos-obj-y) tests/libqos/malloc-spapr.o +libqos-spapr-obj-y += tests/libqos/libqos-spapr.o libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o libqos-pc-obj-y += tests/libqos/ahci.o diff --git a/tests/libqos/libqos-pc.c b/tests/libqos/libqos-pc.c index 72b5e3ba09b..df340928a65 100644 --- a/tests/libqos/libqos-pc.c +++ b/tests/libqos/libqos-pc.c @@ -21,6 +21,8 @@ QOSState *qtest_pc_boot(const char *cmdline_fmt, ...) qs = qtest_vboot(&qos_ops, cmdline_fmt, ap); va_end(ap); + qtest_irq_intercept_in(global_qtest, "ioapic"); + return qs; } diff --git a/tests/libqos/libqos-spapr.c b/tests/libqos/libqos-spapr.c new file mode 100644 index 00000000000..f19408be000 --- /dev/null +++ b/tests/libqos/libqos-spapr.c @@ -0,0 +1,30 @@ +#include "qemu/osdep.h" +#include "libqos/libqos-spapr.h" +#include "libqos/malloc-spapr.h" + +static QOSOps qos_ops = { + .init_allocator = spapr_alloc_init_flags, + .uninit_allocator = spapr_alloc_uninit +}; + +QOSState *qtest_spapr_vboot(const char *cmdline_fmt, va_list ap) +{ + return qtest_vboot(&qos_ops, cmdline_fmt, ap); +} + +QOSState *qtest_spapr_boot(const char *cmdline_fmt, ...) +{ + QOSState *qs; + va_list ap; + + va_start(ap, cmdline_fmt); + qs = qtest_vboot(&qos_ops, cmdline_fmt, ap); + va_end(ap); + + return qs; +} + +void qtest_spapr_shutdown(QOSState *qs) +{ + return qtest_shutdown(qs); +} diff --git a/tests/libqos/libqos-spapr.h b/tests/libqos/libqos-spapr.h new file mode 100644 index 00000000000..dcb5c43ad37 --- /dev/null +++ b/tests/libqos/libqos-spapr.h @@ -0,0 +1,10 @@ +#ifndef LIBQOS_SPAPR_H +#define LIBQOS_SPAPR_H + +#include "libqos/libqos.h" + +QOSState *qtest_spapr_vboot(const char *cmdline_fmt, va_list ap); +QOSState *qtest_spapr_boot(const char *cmdline_fmt, ...); +void qtest_spapr_shutdown(QOSState *qs); + +#endif diff --git a/tests/libqos/libqos.c b/tests/libqos/libqos.c index c7ba441d0bb..a852dc5f8e4 100644 --- a/tests/libqos/libqos.c +++ b/tests/libqos/libqos.c @@ -20,7 +20,6 @@ QOSState *qtest_vboot(QOSOps *ops, const char *cmdline_fmt, va_list ap) cmdline = g_strdup_vprintf(cmdline_fmt, ap); qs->qts = qtest_start(cmdline); qs->ops = ops; - qtest_irq_intercept_in(global_qtest, "ioapic"); if (ops && ops->init_allocator) { qs->alloc = ops->init_allocator(ALLOC_NO_FLAGS); } diff --git a/tests/libqos/malloc-spapr.c b/tests/libqos/malloc-spapr.c new file mode 100644 index 00000000000..006404af330 --- /dev/null +++ b/tests/libqos/malloc-spapr.c @@ -0,0 +1,38 @@ +/* + * libqos malloc support for SPAPR + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "libqos/malloc-spapr.h" + +#include "qemu-common.h" + +#define PAGE_SIZE 4096 + +/* Memory must be a multiple of 256 MB, + * so we have at least 256MB + */ +#define SPAPR_MIN_SIZE 0x10000000 + +void spapr_alloc_uninit(QGuestAllocator *allocator) +{ + alloc_uninit(allocator); +} + +QGuestAllocator *spapr_alloc_init_flags(QAllocOpts flags) +{ + QGuestAllocator *s; + + s = alloc_init_flags(flags, 1 << 20, SPAPR_MIN_SIZE); + alloc_set_page_size(s, PAGE_SIZE); + + return s; +} + +QGuestAllocator *spapr_alloc_init(void) +{ + return spapr_alloc_init_flags(ALLOC_NO_FLAGS); +} diff --git a/tests/libqos/malloc-spapr.h b/tests/libqos/malloc-spapr.h new file mode 100644 index 00000000000..64d0e770d12 --- /dev/null +++ b/tests/libqos/malloc-spapr.h @@ -0,0 +1,17 @@ +/* + * libqos malloc support for SPAPR + * + * 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 LIBQOS_MALLOC_SPAPR_H +#define LIBQOS_MALLOC_SPAPR_H + +#include "libqos/malloc.h" + +QGuestAllocator *spapr_alloc_init(void); +QGuestAllocator *spapr_alloc_init_flags(QAllocOpts flags); +void spapr_alloc_uninit(QGuestAllocator *allocator); + +#endif From eeddd59f59626302cdb7db2602140ac9a076dec9 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Tue, 13 Sep 2016 14:52:45 +0200 Subject: [PATCH 190/723] tests: add RTAS command in the protocol Add a first test to validate the protocol: - rtas/get-time-of-day compares the time from the guest with the time from the host. Signed-off-by: Laurent Vivier Reviewed-by: Greg Kurz Signed-off-by: David Gibson --- hw/ppc/spapr_rtas.c | 19 ++++++++++ include/hw/ppc/spapr_rtas.h | 10 ++++++ qtest.c | 17 +++++++++ tests/Makefile.include | 3 ++ tests/libqos/rtas.c | 71 +++++++++++++++++++++++++++++++++++++ tests/libqos/rtas.h | 11 ++++++ tests/libqtest.c | 10 ++++++ tests/libqtest.h | 15 ++++++++ tests/rtas-test.c | 41 +++++++++++++++++++++ 9 files changed, 197 insertions(+) create mode 100644 include/hw/ppc/spapr_rtas.h create mode 100644 tests/libqos/rtas.c create mode 100644 tests/libqos/rtas.h create mode 100644 tests/rtas-test.c diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c index 27b5ad4bc43..b80c1db0c67 100644 --- a/hw/ppc/spapr_rtas.c +++ b/hw/ppc/spapr_rtas.c @@ -37,6 +37,7 @@ #include "hw/ppc/spapr.h" #include "hw/ppc/spapr_vio.h" +#include "hw/ppc/spapr_rtas.h" #include "hw/ppc/ppc.h" #include "qapi-event.h" #include "hw/boards.h" @@ -692,6 +693,24 @@ target_ulong spapr_rtas_call(PowerPCCPU *cpu, sPAPRMachineState *spapr, return H_PARAMETER; } +uint64_t qtest_rtas_call(char *cmd, uint32_t nargs, uint64_t args, + uint32_t nret, uint64_t rets) +{ + int token; + + for (token = 0; token < RTAS_TOKEN_MAX - RTAS_TOKEN_BASE; token++) { + if (strcmp(cmd, rtas_table[token].name) == 0) { + sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); + PowerPCCPU *cpu = POWERPC_CPU(first_cpu); + + rtas_table[token].fn(cpu, spapr, token + RTAS_TOKEN_BASE, + nargs, args, nret, rets); + return H_SUCCESS; + } + } + return H_PARAMETER; +} + void spapr_rtas_register(int token, const char *name, spapr_rtas_fn fn) { assert((token >= RTAS_TOKEN_BASE) && (token < RTAS_TOKEN_MAX)); diff --git a/include/hw/ppc/spapr_rtas.h b/include/hw/ppc/spapr_rtas.h new file mode 100644 index 00000000000..383611f10f2 --- /dev/null +++ b/include/hw/ppc/spapr_rtas.h @@ -0,0 +1,10 @@ +#ifndef HW_SPAPR_RTAS_H +#define HW_SPAPR_RTAS_H +/* + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +uint64_t qtest_rtas_call(char *cmd, uint32_t nargs, uint64_t args, + uint32_t nret, uint64_t rets); +#endif /* HW_SPAPR_RTAS_H */ diff --git a/qtest.c b/qtest.c index 649f7b26c63..22482cc3592 100644 --- a/qtest.c +++ b/qtest.c @@ -28,6 +28,9 @@ #include "qemu/option.h" #include "qemu/error-report.h" #include "qemu/cutils.h" +#ifdef TARGET_PPC64 +#include "hw/ppc/spapr_rtas.h" +#endif #define MAX_IRQ 256 @@ -534,6 +537,20 @@ static void qtest_process_command(CharDriverState *chr, gchar **words) qtest_send_prefix(chr); qtest_send(chr, "OK\n"); +#ifdef TARGET_PPC64 + } else if (strcmp(words[0], "rtas") == 0) { + uint64_t res, args, ret; + unsigned long nargs, nret; + + g_assert(qemu_strtoul(words[2], NULL, 0, &nargs) == 0); + g_assert(qemu_strtoull(words[3], NULL, 0, &args) == 0); + g_assert(qemu_strtoul(words[4], NULL, 0, &nret) == 0); + g_assert(qemu_strtoull(words[5], NULL, 0, &ret) == 0); + res = qtest_rtas_call(words[1], nargs, args, nret, ret); + + qtest_send_prefix(chr); + qtest_sendf(chr, "OK %"PRIu64"\n", res); +#endif } else if (qtest_enabled() && strcmp(words[0], "clock_step") == 0) { int64_t ns; diff --git a/tests/Makefile.include b/tests/Makefile.include index dba35a3e740..aad96fdddeb 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -268,6 +268,7 @@ check-qtest-ppc64-y += tests/prom-env-test$(EXESUF) check-qtest-ppc64-y += tests/drive_del-test$(EXESUF) check-qtest-ppc64-y += tests/postcopy-test$(EXESUF) check-qtest-ppc64-y += tests/boot-serial-test$(EXESUF) +check-qtest-ppc64-y += tests/rtas-test$(EXESUF) check-qtest-sh4-y = tests/endianness-test$(EXESUF) @@ -585,6 +586,7 @@ libqos-obj-y = tests/libqos/pci.o tests/libqos/fw_cfg.o tests/libqos/malloc.o libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o libqos-spapr-obj-y = $(libqos-obj-y) tests/libqos/malloc-spapr.o libqos-spapr-obj-y += tests/libqos/libqos-spapr.o +libqos-spapr-obj-y += tests/libqos/rtas.o libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o libqos-pc-obj-y += tests/libqos/ahci.o @@ -599,6 +601,7 @@ tests/m48t59-test$(EXESUF): tests/m48t59-test.o tests/endianness-test$(EXESUF): tests/endianness-test.o tests/spapr-phb-test$(EXESUF): tests/spapr-phb-test.o $(libqos-obj-y) tests/prom-env-test$(EXESUF): tests/prom-env-test.o $(libqos-obj-y) +tests/rtas-test$(EXESUF): tests/rtas-test.o $(libqos-spapr-obj-y) tests/fdc-test$(EXESUF): tests/fdc-test.o tests/ide-test$(EXESUF): tests/ide-test.o $(libqos-pc-obj-y) tests/ahci-test$(EXESUF): tests/ahci-test.o $(libqos-pc-obj-y) diff --git a/tests/libqos/rtas.c b/tests/libqos/rtas.c new file mode 100644 index 00000000000..820321a3a7c --- /dev/null +++ b/tests/libqos/rtas.c @@ -0,0 +1,71 @@ +/* + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "libqtest.h" +#include "libqos/rtas.h" + +static void qrtas_copy_args(uint64_t target_args, uint32_t nargs, + uint32_t *args) +{ + int i; + + for (i = 0; i < nargs; i++) { + writel(target_args + i * sizeof(uint32_t), args[i]); + } +} + +static void qrtas_copy_ret(uint64_t target_ret, uint32_t nret, uint32_t *ret) +{ + int i; + + for (i = 0; i < nret; i++) { + ret[i] = readl(target_ret + i * sizeof(uint32_t)); + } +} + +static uint64_t qrtas_call(QGuestAllocator *alloc, const char *name, + uint32_t nargs, uint32_t *args, + uint32_t nret, uint32_t *ret) +{ + uint64_t res; + uint64_t target_args, target_ret; + + target_args = guest_alloc(alloc, nargs * sizeof(uint32_t)); + target_ret = guest_alloc(alloc, nret * sizeof(uint32_t)); + + qrtas_copy_args(target_args, nargs, args); + res = qtest_rtas_call(global_qtest, name, + nargs, target_args, nret, target_ret); + qrtas_copy_ret(target_ret, nret, ret); + + guest_free(alloc, target_ret); + guest_free(alloc, target_args); + + return res; +} + +int qrtas_get_time_of_day(QGuestAllocator *alloc, struct tm *tm, uint32_t *ns) +{ + int res; + uint32_t ret[8]; + + res = qrtas_call(alloc, "get-time-of-day", 0, NULL, 8, ret); + if (res != 0) { + return res; + } + + res = ret[0]; + memset(tm, 0, sizeof(*tm)); + tm->tm_year = ret[1] - 1900; + tm->tm_mon = ret[2] - 1; + tm->tm_mday = ret[3]; + tm->tm_hour = ret[4]; + tm->tm_min = ret[5]; + tm->tm_sec = ret[6]; + *ns = ret[7]; + + return res; +} diff --git a/tests/libqos/rtas.h b/tests/libqos/rtas.h new file mode 100644 index 00000000000..a1b60a8eb4b --- /dev/null +++ b/tests/libqos/rtas.h @@ -0,0 +1,11 @@ +/* + * 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 LIBQOS_RTAS_H +#define LIBQOS_RTAS_H +#include "libqos/malloc.h" + +int qrtas_get_time_of_day(QGuestAllocator *alloc, struct tm *tm, uint32_t *ns); +#endif /* LIBQOS_RTAS_H */ diff --git a/tests/libqtest.c b/tests/libqtest.c index 42ccb62f80f..6f6bdf142fb 100644 --- a/tests/libqtest.c +++ b/tests/libqtest.c @@ -751,6 +751,16 @@ void qtest_memread(QTestState *s, uint64_t addr, void *data, size_t size) g_strfreev(args); } +uint64_t qtest_rtas_call(QTestState *s, const char *name, + uint32_t nargs, uint64_t args, + uint32_t nret, uint64_t ret) +{ + qtest_sendf(s, "rtas %s %u 0x%"PRIx64" %u 0x%"PRIx64"\n", + name, nargs, args, nret, ret); + qtest_rsp(s, 0); + return 0; +} + void qtest_add_func(const char *str, void (*fn)(void)) { gchar *path = g_strdup_printf("/%s/%s", qtest_get_arch(), str); diff --git a/tests/libqtest.h b/tests/libqtest.h index d2b48535a65..f7402e0cc12 100644 --- a/tests/libqtest.h +++ b/tests/libqtest.h @@ -317,6 +317,21 @@ uint64_t qtest_readq(QTestState *s, uint64_t addr); */ void qtest_memread(QTestState *s, uint64_t addr, void *data, size_t size); +/** + * qtest_rtas_call: + * @s: #QTestState instance to operate on. + * @name: name of the command to call. + * @nargs: Number of args. + * @args: Guest address to read args from. + * @nret: Number of return value. + * @ret: Guest address to write return values to. + * + * Call an RTAS function + */ +uint64_t qtest_rtas_call(QTestState *s, const char *name, + uint32_t nargs, uint64_t args, + uint32_t nret, uint64_t ret); + /** * qtest_bufread: * @s: #QTestState instance to operate on. diff --git a/tests/rtas-test.c b/tests/rtas-test.c new file mode 100644 index 00000000000..73c780339b1 --- /dev/null +++ b/tests/rtas-test.c @@ -0,0 +1,41 @@ +#include "qemu/osdep.h" +#include "qemu/cutils.h" +#include "libqtest.h" + +#include "libqos/libqos-spapr.h" +#include "libqos/rtas.h" + +static void test_rtas_get_time_of_day(void) +{ + QOSState *qs; + struct tm tm; + uint32_t ns; + uint64_t ret; + time_t t1, t2; + + qs = qtest_spapr_boot("-machine pseries"); + g_assert(qs != NULL); + + t1 = time(NULL); + ret = qrtas_get_time_of_day(qs->alloc, &tm, &ns); + g_assert_cmpint(ret, ==, 0); + t2 = mktimegm(&tm); + g_assert(t2 - t1 < 5); /* 5 sec max to run the test */ + + qtest_spapr_shutdown(qs); +} + +int main(int argc, char *argv[]) +{ + const char *arch = qtest_get_arch(); + + g_test_init(&argc, &argv, NULL); + + if (strcmp(arch, "ppc64")) { + g_printerr("RTAS requires ppc64-softmmu/qemu-system-ppc64\n"); + exit(EXIT_FAILURE); + } + qtest_add_func("rtas/get-time-of-day", test_rtas_get_time_of_day); + + return g_test_run(); +} From a70ab357cd0b36c34f77803bd6710480cb2910d9 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Wed, 14 Sep 2016 13:23:57 +0200 Subject: [PATCH 191/723] MAINTAINERS: add sPAPR tests Signed-off-by: Greg Kurz Signed-off-by: David Gibson --- MAINTAINERS | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index a9fab468527..847b6142915 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -628,6 +628,10 @@ F: pc-bios/spapr-rtas.bin F: pc-bios/slof.bin F: docs/specs/ppc-spapr-hcalls.txt F: docs/specs/ppc-spapr-hotplug.txt +F: tests/spapr* +F: tests/libqos/*spapr* +F: tests/rtas* +F: tests/libqos/rtas* virtex_ml507 M: Edgar E. Iglesias From 5375c83b1e0e76972cfa0c78ce5b14e525e79104 Mon Sep 17 00:00:00 2001 From: John Arbuckle Date: Wed, 17 Aug 2016 22:27:47 -0400 Subject: [PATCH 192/723] adb-keys.h: initial commit Add the adb-keys.h file. It maps ADB transition key codes with values. Signed-off-by: John Arbuckle Signed-off-by: David Gibson --- include/hw/input/adb-keys.h | 141 ++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 include/hw/input/adb-keys.h diff --git a/include/hw/input/adb-keys.h b/include/hw/input/adb-keys.h new file mode 100644 index 00000000000..525fba8a610 --- /dev/null +++ b/include/hw/input/adb-keys.h @@ -0,0 +1,141 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2016 John Arbuckle + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +/* + * adb-keys.h + * + * Provides an enum of all the Macintosh keycodes. + * Additional information: http://www.archive.org/stream/apple-guide-macintosh-family-hardware/Apple_Guide_to_the_Macintosh_Family_Hardware_2e#page/n345/mode/2up + * page 308 + */ + +#ifndef ADB_KEYS_H +#define ADB_KEYS_H + +enum { + ADB_KEY_A = 0x00, + ADB_KEY_B = 0x0b, + ADB_KEY_C = 0x08, + ADB_KEY_D = 0x02, + ADB_KEY_E = 0x0e, + ADB_KEY_F = 0x03, + ADB_KEY_G = 0x05, + ADB_KEY_H = 0x04, + ADB_KEY_I = 0x22, + ADB_KEY_J = 0x26, + ADB_KEY_K = 0x28, + ADB_KEY_L = 0x25, + ADB_KEY_M = 0x2e, + ADB_KEY_N = 0x2d, + ADB_KEY_O = 0x1f, + ADB_KEY_P = 0x23, + ADB_KEY_Q = 0x0c, + ADB_KEY_R = 0x0f, + ADB_KEY_S = 0x01, + ADB_KEY_T = 0x11, + ADB_KEY_U = 0x20, + ADB_KEY_V = 0x09, + ADB_KEY_W = 0x0d, + ADB_KEY_X = 0x07, + ADB_KEY_Y = 0x10, + ADB_KEY_Z = 0x06, + + ADB_KEY_0 = 0x1d, + ADB_KEY_1 = 0x12, + ADB_KEY_2 = 0x13, + ADB_KEY_3 = 0x14, + ADB_KEY_4 = 0x15, + ADB_KEY_5 = 0x17, + ADB_KEY_6 = 0x16, + ADB_KEY_7 = 0x1a, + ADB_KEY_8 = 0x1c, + ADB_KEY_9 = 0x19, + + ADB_KEY_GRAVE_ACCENT = 0x32, + ADB_KEY_MINUS = 0x1b, + ADB_KEY_EQUAL = 0x18, + ADB_KEY_DELETE = 0x33, + ADB_KEY_CAPS_LOCK = 0x39, + ADB_KEY_TAB = 0x30, + ADB_KEY_RETURN = 0x24, + ADB_KEY_LEFT_BRACKET = 0x21, + ADB_KEY_RIGHT_BRACKET = 0x1e, + ADB_KEY_BACKSLASH = 0x2a, + ADB_KEY_SEMICOLON = 0x29, + ADB_KEY_APOSTROPHE = 0x27, + ADB_KEY_COMMA = 0x2b, + ADB_KEY_PERIOD = 0x2f, + ADB_KEY_FORWARD_SLASH = 0x2c, + ADB_KEY_LEFT_SHIFT = 0x38, + ADB_KEY_RIGHT_SHIFT = 0x7b, + ADB_KEY_SPACEBAR = 0x31, + ADB_KEY_LEFT_CONTROL = 0x36, + ADB_KEY_RIGHT_CONTROL = 0x7d, + ADB_KEY_LEFT_OPTION = 0x3a, + ADB_KEY_RIGHT_OPTION = 0x7c, + ADB_KEY_COMMAND = 0x37, + + ADB_KEY_KP_0 = 0x52, + ADB_KEY_KP_1 = 0x53, + ADB_KEY_KP_2 = 0x54, + ADB_KEY_KP_3 = 0x55, + ADB_KEY_KP_4 = 0x56, + ADB_KEY_KP_5 = 0x57, + ADB_KEY_KP_6 = 0x58, + ADB_KEY_KP_7 = 0x59, + ADB_KEY_KP_8 = 0x5b, + ADB_KEY_KP_9 = 0x5c, + ADB_KEY_KP_PERIOD = 0x41, + ADB_KEY_KP_ENTER = 0x4c, + ADB_KEY_KP_PLUS = 0x45, + ADB_KEY_KP_SUBTRACT = 0x4e, + ADB_KEY_KP_MULTIPLY = 0x43, + ADB_KEY_KP_DIVIDE = 0x4b, + ADB_KEY_KP_EQUAL = 0x51, + ADB_KEY_KP_CLEAR = 0x47, + + ADB_KEY_UP = 0x3e, + ADB_KEY_DOWN = 0x3d, + ADB_KEY_LEFT = 0x3b, + ADB_KEY_RIGHT = 0x3c, + + ADB_KEY_HELP = 0x72, + ADB_KEY_HOME = 0x73, + ADB_KEY_PAGE_UP = 0x74, + ADB_KEY_PAGE_DOWN = 0x79, + ADB_KEY_END = 0x77, + ADB_KEY_FORWARD_DELETE = 0x75, + + ADB_KEY_ESC = 0x35, + ADB_KEY_F1 = 0x7a, + ADB_KEY_F2 = 0x78, + ADB_KEY_F3 = 0x63, + ADB_KEY_F4 = 0x76, + ADB_KEY_F5 = 0x60, + ADB_KEY_F6 = 0x61, + ADB_KEY_F7 = 0x62, + ADB_KEY_F8 = 0x64, + ADB_KEY_F9 = 0x65, + ADB_KEY_F10 = 0x6d, + ADB_KEY_F11 = 0x67, + ADB_KEY_F12 = 0x6f, + ADB_KEY_F13 = 0x69, + ADB_KEY_F14 = 0x6b, + ADB_KEY_F15 = 0x71, + + ADB_KEY_VOLUME_UP = 0x48, + ADB_KEY_VOLUME_DOWN = 0x49, + ADB_KEY_VOLUME_MUTE = 0x4a, + ADB_KEY_POWER = 0x7f7f +}; + +/* Could not find the value for this key. */ +/* #define ADB_KEY_EJECT */ + +#endif /* ADB_KEYS_H */ From 5a1f4971863705f588ec79fce2ac8a3392e2a57e Mon Sep 17 00:00:00 2001 From: John Arbuckle Date: Wed, 17 Aug 2016 22:27:48 -0400 Subject: [PATCH 193/723] adb.c: add support for QKeyCode The old pc scancode translation is replaced with QEMU's QKeyCode. This is just a mechanical substitution, which a number of broken mappings left in. Signed-off-by: John Arbuckle Signed-off-by: David Gibson --- hw/input/adb.c | 234 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 189 insertions(+), 45 deletions(-) diff --git a/hw/input/adb.c b/hw/input/adb.c index f0ad0d44712..18c220bae8f 100644 --- a/hw/input/adb.c +++ b/hw/input/adb.c @@ -25,6 +25,9 @@ #include "hw/hw.h" #include "hw/input/adb.h" #include "ui/console.h" +#include "include/hw/input/adb-keys.h" +#include "ui/input.h" +#include "sysemu/sysemu.h" /* debug ADB */ //#define DEBUG_ADB @@ -187,23 +190,136 @@ typedef struct ADBKeyboardClass { DeviceRealize parent_realize; } ADBKeyboardClass; -static const uint8_t pc_to_adb_keycode[256] = { - 0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48, - 12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54, 0, 1, - 2, 3, 5, 4, 38, 40, 37, 41, 39, 50, 56, 42, 6, 7, 8, 9, - 11, 45, 46, 43, 47, 44,123, 67, 58, 49, 57,122,120, 99,118, 96, - 97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83, - 84, 85, 82, 65, 0, 0, 10,103,111, 0, 0,110, 81, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 94, 0, 93, 0, 0, 0, 0, 0, 0,104,102, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 76,125, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,105, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 75, 0, 0,124, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,115, 62,116, 0, 59, 0, 60, 0,119, - 61,121,114,117, 0, 0, 0, 0, 0, 0, 0, 55,126, 0,127, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +int qcode_to_adb_keycode[] = { + + [Q_KEY_CODE_SHIFT] = ADB_KEY_LEFT_SHIFT, + [Q_KEY_CODE_SHIFT_R] = ADB_KEY_RIGHT_SHIFT, + [Q_KEY_CODE_ALT] = ADB_KEY_LEFT_OPTION, + [Q_KEY_CODE_ALT_R] = ADB_KEY_RIGHT_OPTION, + [Q_KEY_CODE_ALTGR] = 0, + [Q_KEY_CODE_CTRL] = ADB_KEY_LEFT_CONTROL, + [Q_KEY_CODE_CTRL_R] = ADB_KEY_RIGHT_CONTROL, + [Q_KEY_CODE_META_L] = ADB_KEY_COMMAND, + [Q_KEY_CODE_META_R] = ADB_KEY_COMMAND, + [Q_KEY_CODE_SPC] = ADB_KEY_SPACEBAR, + + [Q_KEY_CODE_ESC] = ADB_KEY_ESC, + [Q_KEY_CODE_1] = ADB_KEY_1, + [Q_KEY_CODE_2] = ADB_KEY_2, + [Q_KEY_CODE_3] = ADB_KEY_3, + [Q_KEY_CODE_4] = ADB_KEY_4, + [Q_KEY_CODE_5] = ADB_KEY_5, + [Q_KEY_CODE_6] = ADB_KEY_6, + [Q_KEY_CODE_7] = ADB_KEY_7, + [Q_KEY_CODE_8] = ADB_KEY_8, + [Q_KEY_CODE_9] = ADB_KEY_9, + [Q_KEY_CODE_0] = ADB_KEY_0, + [Q_KEY_CODE_MINUS] = ADB_KEY_MINUS, + [Q_KEY_CODE_EQUAL] = ADB_KEY_EQUAL, + [Q_KEY_CODE_BACKSPACE] = ADB_KEY_DELETE, + [Q_KEY_CODE_TAB] = ADB_KEY_TAB, + [Q_KEY_CODE_Q] = ADB_KEY_Q, + [Q_KEY_CODE_W] = ADB_KEY_W, + [Q_KEY_CODE_E] = ADB_KEY_E, + [Q_KEY_CODE_R] = ADB_KEY_R, + [Q_KEY_CODE_T] = ADB_KEY_T, + [Q_KEY_CODE_Y] = ADB_KEY_Y, + [Q_KEY_CODE_U] = ADB_KEY_U, + [Q_KEY_CODE_I] = ADB_KEY_I, + [Q_KEY_CODE_O] = ADB_KEY_O, + [Q_KEY_CODE_P] = ADB_KEY_P, + [Q_KEY_CODE_BRACKET_LEFT] = ADB_KEY_LEFT_BRACKET, + [Q_KEY_CODE_BRACKET_RIGHT] = ADB_KEY_RIGHT_BRACKET, + [Q_KEY_CODE_RET] = ADB_KEY_RETURN, + [Q_KEY_CODE_A] = ADB_KEY_A, + [Q_KEY_CODE_S] = ADB_KEY_S, + [Q_KEY_CODE_D] = ADB_KEY_D, + [Q_KEY_CODE_F] = ADB_KEY_F, + [Q_KEY_CODE_G] = ADB_KEY_G, + [Q_KEY_CODE_H] = ADB_KEY_H, + [Q_KEY_CODE_J] = ADB_KEY_J, + [Q_KEY_CODE_K] = ADB_KEY_K, + [Q_KEY_CODE_L] = ADB_KEY_L, + [Q_KEY_CODE_SEMICOLON] = ADB_KEY_SEMICOLON, + [Q_KEY_CODE_APOSTROPHE] = ADB_KEY_APOSTROPHE, + [Q_KEY_CODE_GRAVE_ACCENT] = ADB_KEY_GRAVE_ACCENT, + [Q_KEY_CODE_BACKSLASH] = ADB_KEY_BACKSLASH, + [Q_KEY_CODE_Z] = ADB_KEY_Z, + [Q_KEY_CODE_X] = ADB_KEY_X, + [Q_KEY_CODE_C] = ADB_KEY_C, + [Q_KEY_CODE_V] = ADB_KEY_V, + [Q_KEY_CODE_B] = ADB_KEY_B, + [Q_KEY_CODE_N] = ADB_KEY_N, + [Q_KEY_CODE_M] = ADB_KEY_M, + [Q_KEY_CODE_COMMA] = ADB_KEY_COMMA, + [Q_KEY_CODE_DOT] = ADB_KEY_PERIOD, + [Q_KEY_CODE_SLASH] = ADB_KEY_FORWARD_SLASH, + [Q_KEY_CODE_ASTERISK] = ADB_KEY_KP_MULTIPLY, + [Q_KEY_CODE_CAPS_LOCK] = ADB_KEY_CAPS_LOCK, + + [Q_KEY_CODE_F1] = ADB_KEY_F1, + [Q_KEY_CODE_F2] = ADB_KEY_F2, + [Q_KEY_CODE_F3] = ADB_KEY_F3, + [Q_KEY_CODE_F4] = ADB_KEY_F4, + [Q_KEY_CODE_F5] = ADB_KEY_F5, + [Q_KEY_CODE_F6] = ADB_KEY_F6, + [Q_KEY_CODE_F7] = ADB_KEY_F7, + [Q_KEY_CODE_F8] = ADB_KEY_F8, + [Q_KEY_CODE_F9] = ADB_KEY_F9, + [Q_KEY_CODE_F10] = ADB_KEY_F10, + [Q_KEY_CODE_F11] = ADB_KEY_F11, + [Q_KEY_CODE_F12] = ADB_KEY_F12, + [Q_KEY_CODE_PRINT] = 0, + [Q_KEY_CODE_SYSRQ] = 0, + [Q_KEY_CODE_SCROLL_LOCK] = ADB_KEY_F14, + [Q_KEY_CODE_PAUSE] = 0, + + [Q_KEY_CODE_NUM_LOCK] = ADB_KEY_KP_CLEAR, + [Q_KEY_CODE_KP_EQUALS] = 0, + [Q_KEY_CODE_KP_DIVIDE] = ADB_KEY_KP_DIVIDE, + [Q_KEY_CODE_KP_MULTIPLY] = ADB_KEY_KP_MULTIPLY, + [Q_KEY_CODE_KP_SUBTRACT] = ADB_KEY_KP_SUBTRACT, + [Q_KEY_CODE_KP_ADD] = ADB_KEY_KP_PLUS, + [Q_KEY_CODE_KP_ENTER] = ADB_KEY_KP_ENTER, + [Q_KEY_CODE_KP_DECIMAL] = ADB_KEY_KP_PERIOD, + [Q_KEY_CODE_KP_0] = ADB_KEY_KP_0, + [Q_KEY_CODE_KP_1] = ADB_KEY_KP_1, + [Q_KEY_CODE_KP_2] = ADB_KEY_KP_2, + [Q_KEY_CODE_KP_3] = ADB_KEY_KP_3, + [Q_KEY_CODE_KP_4] = ADB_KEY_KP_4, + [Q_KEY_CODE_KP_5] = ADB_KEY_KP_5, + [Q_KEY_CODE_KP_6] = ADB_KEY_KP_6, + [Q_KEY_CODE_KP_7] = ADB_KEY_KP_7, + [Q_KEY_CODE_KP_8] = ADB_KEY_KP_8, + [Q_KEY_CODE_KP_9] = ADB_KEY_KP_9, + + [Q_KEY_CODE_UP] = ADB_KEY_UP, + [Q_KEY_CODE_DOWN] = ADB_KEY_DOWN, + [Q_KEY_CODE_LEFT] = ADB_KEY_LEFT, + [Q_KEY_CODE_RIGHT] = ADB_KEY_RIGHT, + + [Q_KEY_CODE_HELP] = 0, + [Q_KEY_CODE_INSERT] = ADB_KEY_HELP, + [Q_KEY_CODE_DELETE] = ADB_KEY_FORWARD_DELETE, + [Q_KEY_CODE_HOME] = ADB_KEY_HOME, + [Q_KEY_CODE_END] = ADB_KEY_END, + [Q_KEY_CODE_PGUP] = ADB_KEY_PAGE_UP, + [Q_KEY_CODE_PGDN] = ADB_KEY_PAGE_DOWN, + + [Q_KEY_CODE_LESS] = 0xa, + [Q_KEY_CODE_STOP] = 0, + [Q_KEY_CODE_AGAIN] = 0, + [Q_KEY_CODE_PROPS] = 0, + [Q_KEY_CODE_UNDO] = 0, + [Q_KEY_CODE_FRONT] = 0, + [Q_KEY_CODE_COPY] = 0, + [Q_KEY_CODE_OPEN] = 0, + [Q_KEY_CODE_PASTE] = 0, + [Q_KEY_CODE_FIND] = 0, + [Q_KEY_CODE_CUT] = 0, + [Q_KEY_CODE_LF] = 0, + [Q_KEY_CODE_COMPOSE] = 0, + [Q_KEY_CODE_POWER] = ADB_KEY_POWER }; static void adb_kbd_put_keycode(void *opaque, int keycode) @@ -220,35 +336,40 @@ static void adb_kbd_put_keycode(void *opaque, int keycode) static int adb_kbd_poll(ADBDevice *d, uint8_t *obuf) { - static int ext_keycode; KBDState *s = ADB_KEYBOARD(d); - int adb_keycode, keycode; + int keycode; int olen; olen = 0; - for(;;) { - if (s->count == 0) - break; - keycode = s->data[s->rptr]; - if (++s->rptr == sizeof(s->data)) - s->rptr = 0; - s->count--; - - if (keycode == 0xe0) { - ext_keycode = 1; - } else { - if (ext_keycode) - adb_keycode = pc_to_adb_keycode[keycode | 0x80]; - else - adb_keycode = pc_to_adb_keycode[keycode & 0x7f]; - obuf[0] = adb_keycode | (keycode & 0x80); - /* NOTE: could put a second keycode if needed */ - obuf[1] = 0xff; - olen = 2; - ext_keycode = 0; - break; - } + if (s->count == 0) { + return 0; + } + keycode = s->data[s->rptr]; + s->rptr++; + if (s->rptr == sizeof(s->data)) { + s->rptr = 0; } + s->count--; + /* + * The power key is the only two byte value key, so it is a special case. + * Since 0x7f is not a used keycode for ADB we overload it to indicate the + * power button when we're storing keycodes in our internal buffer, and + * expand it out to two bytes when we send to the guest. + */ + if (keycode == 0x7f) { + obuf[0] = 0x7f; + obuf[1] = 0x7f; + olen = 2; + } else { + obuf[0] = keycode; + /* NOTE: the power key key-up is the two byte sequence 0xff 0xff; + * otherwise we could in theory send a second keycode in the second + * byte, but choose not to bother. + */ + obuf[1] = 0xff; + olen = 2; + } + return olen; } @@ -313,6 +434,26 @@ static int adb_kbd_request(ADBDevice *d, uint8_t *obuf, return olen; } +/* This is where keyboard events enter this file */ +static void adb_keyboard_event(DeviceState *dev, QemuConsole *src, + InputEvent *evt) +{ + KBDState *s = (KBDState *)dev; + int qcode, keycode; + + qcode = qemu_input_key_value_to_qcode(evt->u.key.data->key); + if (qcode >= ARRAY_SIZE(qcode_to_adb_keycode)) { + return; + } + keycode = qcode_to_adb_keycode[qcode]; + + if (evt->u.key.data->down == false) { /* if key release event */ + keycode = keycode | 0x80; /* create keyboard break code */ + } + + adb_kbd_put_keycode(s, keycode); +} + static const VMStateDescription vmstate_adb_kbd = { .name = "adb_kbd", .version_id = 2, @@ -340,14 +481,17 @@ static void adb_kbd_reset(DeviceState *dev) s->count = 0; } +static QemuInputHandler adb_keyboard_handler = { + .name = "QEMU ADB Keyboard", + .mask = INPUT_EVENT_MASK_KEY, + .event = adb_keyboard_event, +}; + static void adb_kbd_realizefn(DeviceState *dev, Error **errp) { - ADBDevice *d = ADB_DEVICE(dev); ADBKeyboardClass *akc = ADB_KEYBOARD_GET_CLASS(dev); - akc->parent_realize(dev, errp); - - qemu_add_kbd_event_handler(adb_kbd_put_keycode, d); + qemu_input_handler_register(dev, &adb_keyboard_handler); } static void adb_kbd_initfn(Object *obj) From 25c01db74b58d62cc4a2239ffe9badd5227c3538 Mon Sep 17 00:00:00 2001 From: John Arbuckle Date: Wed, 17 Aug 2016 22:27:49 -0400 Subject: [PATCH 194/723] adb.c: correct several key assignments The original pc_to_adb_keycode mapping did have several keys that were incorrectly mapped. This patch fixes these mappings. Signed-off-by: John Arbuckle Signed-off-by: David Gibson --- hw/input/adb.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hw/input/adb.c b/hw/input/adb.c index 18c220bae8f..12c6333219e 100644 --- a/hw/input/adb.c +++ b/hw/input/adb.c @@ -196,7 +196,7 @@ int qcode_to_adb_keycode[] = { [Q_KEY_CODE_SHIFT_R] = ADB_KEY_RIGHT_SHIFT, [Q_KEY_CODE_ALT] = ADB_KEY_LEFT_OPTION, [Q_KEY_CODE_ALT_R] = ADB_KEY_RIGHT_OPTION, - [Q_KEY_CODE_ALTGR] = 0, + [Q_KEY_CODE_ALTGR] = ADB_KEY_RIGHT_OPTION, [Q_KEY_CODE_CTRL] = ADB_KEY_LEFT_CONTROL, [Q_KEY_CODE_CTRL_R] = ADB_KEY_RIGHT_CONTROL, [Q_KEY_CODE_META_L] = ADB_KEY_COMMAND, @@ -269,13 +269,13 @@ int qcode_to_adb_keycode[] = { [Q_KEY_CODE_F10] = ADB_KEY_F10, [Q_KEY_CODE_F11] = ADB_KEY_F11, [Q_KEY_CODE_F12] = ADB_KEY_F12, - [Q_KEY_CODE_PRINT] = 0, - [Q_KEY_CODE_SYSRQ] = 0, + [Q_KEY_CODE_PRINT] = ADB_KEY_F13, + [Q_KEY_CODE_SYSRQ] = ADB_KEY_F13, [Q_KEY_CODE_SCROLL_LOCK] = ADB_KEY_F14, - [Q_KEY_CODE_PAUSE] = 0, + [Q_KEY_CODE_PAUSE] = ADB_KEY_F15, [Q_KEY_CODE_NUM_LOCK] = ADB_KEY_KP_CLEAR, - [Q_KEY_CODE_KP_EQUALS] = 0, + [Q_KEY_CODE_KP_EQUALS] = ADB_KEY_KP_EQUAL, [Q_KEY_CODE_KP_DIVIDE] = ADB_KEY_KP_DIVIDE, [Q_KEY_CODE_KP_MULTIPLY] = ADB_KEY_KP_MULTIPLY, [Q_KEY_CODE_KP_SUBTRACT] = ADB_KEY_KP_SUBTRACT, @@ -298,7 +298,7 @@ int qcode_to_adb_keycode[] = { [Q_KEY_CODE_LEFT] = ADB_KEY_LEFT, [Q_KEY_CODE_RIGHT] = ADB_KEY_RIGHT, - [Q_KEY_CODE_HELP] = 0, + [Q_KEY_CODE_HELP] = ADB_KEY_HELP, [Q_KEY_CODE_INSERT] = ADB_KEY_HELP, [Q_KEY_CODE_DELETE] = ADB_KEY_FORWARD_DELETE, [Q_KEY_CODE_HOME] = ADB_KEY_HOME, From f366e729f9231e7176e96dba16ddfb6b4b3ab1a8 Mon Sep 17 00:00:00 2001 From: John Arbuckle Date: Wed, 17 Aug 2016 22:27:50 -0400 Subject: [PATCH 195/723] adb.c: prevent NO_KEY value from going to guest The NO_KEY value should not be sent to the guest. This patch drops that value. Signed-off-by: John Arbuckle Signed-off-by: David Gibson --- hw/input/adb.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/hw/input/adb.c b/hw/input/adb.c index 12c6333219e..3d393689092 100644 --- a/hw/input/adb.c +++ b/hw/input/adb.c @@ -62,6 +62,9 @@ do { printf("ADB: " fmt , ## __VA_ARGS__); } while (0) /* error codes */ #define ADB_RET_NOTPRESENT (-2) +/* The adb keyboard doesn't have every key imaginable */ +#define NO_KEY 0xff + static void adb_device_reset(ADBDevice *d) { qdev_reset_all(DEVICE(d)); @@ -191,6 +194,8 @@ typedef struct ADBKeyboardClass { } ADBKeyboardClass; int qcode_to_adb_keycode[] = { + /* Make sure future additions are automatically set to NO_KEY */ + [0 ... 0xff] = NO_KEY, [Q_KEY_CODE_SHIFT] = ADB_KEY_LEFT_SHIFT, [Q_KEY_CODE_SHIFT_R] = ADB_KEY_RIGHT_SHIFT, @@ -306,19 +311,6 @@ int qcode_to_adb_keycode[] = { [Q_KEY_CODE_PGUP] = ADB_KEY_PAGE_UP, [Q_KEY_CODE_PGDN] = ADB_KEY_PAGE_DOWN, - [Q_KEY_CODE_LESS] = 0xa, - [Q_KEY_CODE_STOP] = 0, - [Q_KEY_CODE_AGAIN] = 0, - [Q_KEY_CODE_PROPS] = 0, - [Q_KEY_CODE_UNDO] = 0, - [Q_KEY_CODE_FRONT] = 0, - [Q_KEY_CODE_COPY] = 0, - [Q_KEY_CODE_OPEN] = 0, - [Q_KEY_CODE_PASTE] = 0, - [Q_KEY_CODE_FIND] = 0, - [Q_KEY_CODE_CUT] = 0, - [Q_KEY_CODE_LF] = 0, - [Q_KEY_CODE_COMPOSE] = 0, [Q_KEY_CODE_POWER] = ADB_KEY_POWER }; @@ -446,7 +438,10 @@ static void adb_keyboard_event(DeviceState *dev, QemuConsole *src, return; } keycode = qcode_to_adb_keycode[qcode]; - + if (keycode == NO_KEY) { /* We don't want to send this to the guest */ + ADB_DPRINTF("Ignoring NO_KEY\n"); + return; + } if (evt->u.key.data->down == false) { /* if key release event */ keycode = keycode | 0x80; /* create keyboard break code */ } From 24ac7755d751ed01ae53f7537b2ec90fe016d599 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Wed, 14 Sep 2016 20:48:23 +0200 Subject: [PATCH 196/723] spapr_drc: convert to trace framework instead of DPRINTF Signed-off-by: Laurent Vivier Reviewed-by: Eric Blake Signed-off-by: David Gibson --- hw/ppc/spapr_drc.c | 54 +++++++++++++++++---------------------------- hw/ppc/trace-events | 21 ++++++++++++++++++ 2 files changed, 41 insertions(+), 34 deletions(-) diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c index 4b1a943b8e4..6e54fd47433 100644 --- a/hw/ppc/spapr_drc.c +++ b/hw/ppc/spapr_drc.c @@ -20,20 +20,7 @@ #include "qapi/visitor.h" #include "qemu/error-report.h" #include "hw/ppc/spapr.h" /* for RTAS return codes */ - -/* #define DEBUG_SPAPR_DRC */ - -#ifdef DEBUG_SPAPR_DRC -#define DPRINTF(fmt, ...) \ - do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) -#define DPRINTFN(fmt, ...) \ - do { DPRINTF(fmt, ## __VA_ARGS__); fprintf(stderr, "\n"); } while (0) -#else -#define DPRINTF(fmt, ...) \ - do { } while (0) -#define DPRINTFN(fmt, ...) \ - do { } while (0) -#endif +#include "trace.h" #define DRC_CONTAINER_PATH "/dr-connector" #define DRC_INDEX_TYPE_SHIFT 28 @@ -69,7 +56,7 @@ static uint32_t set_isolation_state(sPAPRDRConnector *drc, { sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); - DPRINTFN("drc: %x, set_isolation_state: %x", get_index(drc), state); + trace_spapr_drc_set_isolation_state(get_index(drc), state); if (state == SPAPR_DR_ISOLATION_STATE_UNISOLATED) { /* cannot unisolate a non-existant resource, and, or resources @@ -94,11 +81,11 @@ static uint32_t set_isolation_state(sPAPRDRConnector *drc, */ if (drc->awaiting_release) { if (drc->configured) { - DPRINTFN("finalizing device removal"); + trace_spapr_drc_set_isolation_state_finalizing(get_index(drc)); drck->detach(drc, DEVICE(drc->dev), drc->detach_cb, drc->detach_cb_opaque, NULL); } else { - DPRINTFN("deferring device removal on unconfigured device\n"); + trace_spapr_drc_set_isolation_state_deferring(get_index(drc)); } } drc->configured = false; @@ -110,7 +97,7 @@ static uint32_t set_isolation_state(sPAPRDRConnector *drc, static uint32_t set_indicator_state(sPAPRDRConnector *drc, sPAPRDRIndicatorState state) { - DPRINTFN("drc: %x, set_indicator_state: %x", get_index(drc), state); + trace_spapr_drc_set_indicator_state(get_index(drc), state); drc->indicator_state = state; return RTAS_OUT_SUCCESS; } @@ -120,7 +107,7 @@ static uint32_t set_allocation_state(sPAPRDRConnector *drc, { sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); - DPRINTFN("drc: %x, set_allocation_state: %x", get_index(drc), state); + trace_spapr_drc_set_allocation_state(get_index(drc), state); if (state == SPAPR_DR_ALLOCATION_STATE_USABLE) { /* if there's no resource/device associated with the DRC, there's @@ -137,7 +124,7 @@ static uint32_t set_allocation_state(sPAPRDRConnector *drc, drc->allocation_state = state; if (drc->awaiting_release && drc->allocation_state == SPAPR_DR_ALLOCATION_STATE_UNUSABLE) { - DPRINTFN("finalizing device removal"); + trace_spapr_drc_set_allocation_state_finalizing(get_index(drc)); drck->detach(drc, DEVICE(drc->dev), drc->detach_cb, drc->detach_cb_opaque, NULL); } else if (drc->allocation_state == SPAPR_DR_ALLOCATION_STATE_USABLE) { @@ -167,12 +154,11 @@ static const void *get_fdt(sPAPRDRConnector *drc, int *fdt_start_offset) static void set_configured(sPAPRDRConnector *drc) { - DPRINTFN("drc: %x, set_configured", get_index(drc)); + trace_spapr_drc_set_configured(get_index(drc)); if (drc->isolation_state != SPAPR_DR_ISOLATION_STATE_UNISOLATED) { /* guest should be not configuring an isolated device */ - DPRINTFN("drc: %x, set_configured: skipping isolated device", - get_index(drc)); + trace_spapr_drc_set_configured_skipping(get_index(drc)); return; } drc->configured = true; @@ -222,7 +208,7 @@ static uint32_t entity_sense(sPAPRDRConnector *drc, sPAPRDREntitySense *state) } } - DPRINTFN("drc: %x, entity_sense: %x", get_index(drc), state); + trace_spapr_drc_entity_sense(get_index(drc), *state); return RTAS_OUT_SUCCESS; } @@ -336,7 +322,7 @@ static void prop_get_fdt(Object *obj, Visitor *v, const char *name, static void attach(sPAPRDRConnector *drc, DeviceState *d, void *fdt, int fdt_start_offset, bool coldplug, Error **errp) { - DPRINTFN("drc: %x, attach", get_index(drc)); + trace_spapr_drc_attach(get_index(drc)); if (drc->isolation_state != SPAPR_DR_ISOLATION_STATE_ISOLATED) { error_setg(errp, "an attached device is still awaiting release"); @@ -389,7 +375,7 @@ static void detach(sPAPRDRConnector *drc, DeviceState *d, spapr_drc_detach_cb *detach_cb, void *detach_cb_opaque, Error **errp) { - DPRINTFN("drc: %x, detach", get_index(drc)); + trace_spapr_drc_detach(get_index(drc)); drc->detach_cb = detach_cb; drc->detach_cb_opaque = detach_cb_opaque; @@ -415,21 +401,21 @@ static void detach(sPAPRDRConnector *drc, DeviceState *d, } if (drc->isolation_state != SPAPR_DR_ISOLATION_STATE_ISOLATED) { - DPRINTFN("awaiting transition to isolated state before removal"); + trace_spapr_drc_awaiting_isolated(get_index(drc)); drc->awaiting_release = true; return; } if (drc->type != SPAPR_DR_CONNECTOR_TYPE_PCI && drc->allocation_state != SPAPR_DR_ALLOCATION_STATE_UNUSABLE) { - DPRINTFN("awaiting transition to unusable state before removal"); + trace_spapr_drc_awaiting_unusable(get_index(drc)); drc->awaiting_release = true; return; } if (drc->awaiting_allocation) { drc->awaiting_release = true; - DPRINTFN("awaiting allocation to complete before removal"); + trace_spapr_drc_awaiting_allocation(get_index(drc)); return; } @@ -460,7 +446,7 @@ static void reset(DeviceState *d) sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); sPAPRDREntitySense state; - DPRINTFN("drc reset: %x", drck->get_index(drc)); + trace_spapr_drc_reset(drck->get_index(drc)); /* immediately upon reset we can safely assume DRCs whose devices * are pending removal can be safely removed, and that they will * subsequently be left in an ISOLATED state. move the DRC to this @@ -502,7 +488,7 @@ static void realize(DeviceState *d, Error **errp) gchar *child_name; Error *err = NULL; - DPRINTFN("drc realize: %x", drck->get_index(drc)); + trace_spapr_drc_realize(drck->get_index(drc)); /* NOTE: we do this as part of realize/unrealize due to the fact * that the guest will communicate with the DRC via RTAS calls * referencing the global DRC index. By unlinking the DRC @@ -513,7 +499,7 @@ static void realize(DeviceState *d, Error **errp) root_container = container_get(object_get_root(), DRC_CONTAINER_PATH); snprintf(link_name, sizeof(link_name), "%x", drck->get_index(drc)); child_name = object_get_canonical_path_component(OBJECT(drc)); - DPRINTFN("drc child name: %s", child_name); + trace_spapr_drc_realize_child(drck->get_index(drc), child_name); object_property_add_alias(root_container, link_name, drc->owner, child_name, &err); if (err) { @@ -521,7 +507,7 @@ static void realize(DeviceState *d, Error **errp) object_unref(OBJECT(drc)); } g_free(child_name); - DPRINTFN("drc realize complete"); + trace_spapr_drc_realize_complete(drck->get_index(drc)); } static void unrealize(DeviceState *d, Error **errp) @@ -532,7 +518,7 @@ static void unrealize(DeviceState *d, Error **errp) char name[256]; Error *err = NULL; - DPRINTFN("drc unrealize: %x", drck->get_index(drc)); + trace_spapr_drc_unrealize(drck->get_index(drc)); root_container = container_get(object_get_root(), DRC_CONTAINER_PATH); snprintf(name, sizeof(name), "%x", drck->get_index(drc)); object_property_del(root_container, name, &err); diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events index dfeab930899..59caffdbab1 100644 --- a/hw/ppc/trace-events +++ b/hw/ppc/trace-events @@ -35,6 +35,27 @@ spapr_iommu_ddw_create(uint64_t buid, uint32_t cfgaddr, uint64_t pg_size, uint64 spapr_iommu_ddw_remove(uint32_t liobn) "liobn=%"PRIx32 spapr_iommu_ddw_reset(uint64_t buid, uint32_t cfgaddr) "buid=%"PRIx64" addr=%"PRIx32 +# hw/ppc/spapr_drc.c +spapr_drc_set_isolation_state(uint32_t index, int state) "drc: 0x%"PRIx32", state: %"PRIx32 +spapr_drc_set_isolation_state_finalizing(uint32_t index) "drc: 0x%"PRIx32 +spapr_drc_set_isolation_state_deferring(uint32_t index) "drc: 0x%"PRIx32 +spapr_drc_set_indicator_state(uint32_t index, int state) "drc: 0x%"PRIx32", state: 0x%x" +spapr_drc_set_allocation_state(uint32_t index, int state) "drc: 0x%"PRIx32", state: 0x%x" +spapr_drc_set_allocation_state_finalizing(uint32_t index) "drc: 0x%"PRIx32 +spapr_drc_set_configured(uint32_t index) "drc: 0x%"PRIx32 +spapr_drc_set_configured_skipping(uint32_t index) "drc: 0x%"PRIx32", isolated device" +spapr_drc_entity_sense(uint32_t index, int state) "drc: 0x%"PRIx32", state: 0x%x" +spapr_drc_attach(uint32_t index) "drc: 0x%"PRIx32 +spapr_drc_detach(uint32_t index) "drc: 0x%"PRIx32 +spapr_drc_awaiting_isolated(uint32_t index) "drc: 0x%"PRIx32 +spapr_drc_awaiting_unusable(uint32_t index) "drc: 0x%"PRIx32 +spapr_drc_awaiting_allocation(uint32_t index) "drc: 0x%"PRIx32 +spapr_drc_reset(uint32_t index) "drc: 0x%"PRIx32 +spapr_drc_realize(uint32_t index) "drc: 0x%"PRIx32 +spapr_drc_realize_child(uint32_t index, char *childname) "drc: 0x%"PRIx32", child name: %s" +spapr_drc_realize_complete(uint32_t index) "drc: 0x%"PRIx32 +spapr_drc_unrealize(uint32_t index) "drc: 0x%"PRIx32 + # hw/ppc/ppc.c ppc_tb_adjust(uint64_t offs1, uint64_t offs2, int64_t diff, int64_t seconds) "adjusted from 0x%"PRIx64" to 0x%"PRIx64", diff %"PRId64" (%"PRId64"s)" From 028ec3cee3872fca661a5339b5b75b965f593597 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Wed, 14 Sep 2016 20:48:24 +0200 Subject: [PATCH 197/723] spapr_rtas: convert to trace framework instead of DPRINTF Signed-off-by: Laurent Vivier Reviewed-by: Eric Blake Signed-off-by: David Gibson --- hw/ppc/spapr_rtas.c | 30 ++++++++---------------------- hw/ppc/trace-events | 8 ++++++++ 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c index b80c1db0c67..add910ce845 100644 --- a/hw/ppc/spapr_rtas.c +++ b/hw/ppc/spapr_rtas.c @@ -45,16 +45,7 @@ #include #include "hw/ppc/spapr_drc.h" #include "qemu/cutils.h" - -/* #define DEBUG_SPAPR */ - -#ifdef DEBUG_SPAPR -#define DPRINTF(fmt, ...) \ - do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) \ - do { } while (0) -#endif +#include "trace.h" static sPAPRConfigureConnectorState *spapr_ccs_find(sPAPRMachineState *spapr, uint32_t drc_index) @@ -436,8 +427,7 @@ static void rtas_set_indicator(PowerPCCPU *cpu, sPAPRMachineState *spapr, /* if this is a DR sensor we can assume sensor_index == drc_index */ drc = spapr_dr_connector_by_index(sensor_index); if (!drc) { - DPRINTF("rtas_set_indicator: invalid sensor/DRC index: %xh\n", - sensor_index); + trace_spapr_rtas_set_indicator_invalid(sensor_index); ret = RTAS_OUT_PARAM_ERROR; goto out; } @@ -476,8 +466,7 @@ static void rtas_set_indicator(PowerPCCPU *cpu, sPAPRMachineState *spapr, out_unimplemented: /* currently only DR-related sensors are implemented */ - DPRINTF("rtas_set_indicator: sensor/indicator not implemented: %d\n", - sensor_type); + trace_spapr_rtas_set_indicator_not_supported(sensor_index, sensor_type); rtas_st(rets, 0, RTAS_OUT_NOT_SUPPORTED); } @@ -503,16 +492,15 @@ static void rtas_get_sensor_state(PowerPCCPU *cpu, sPAPRMachineState *spapr, if (sensor_type != RTAS_SENSOR_TYPE_ENTITY_SENSE) { /* currently only DR-related sensors are implemented */ - DPRINTF("rtas_get_sensor_state: sensor/indicator not implemented: %d\n", - sensor_type); + trace_spapr_rtas_get_sensor_state_not_supported(sensor_index, + sensor_type); ret = RTAS_OUT_NOT_SUPPORTED; goto out; } drc = spapr_dr_connector_by_index(sensor_index); if (!drc) { - DPRINTF("rtas_get_sensor_state: invalid sensor/DRC index: %xh\n", - sensor_index); + trace_spapr_rtas_get_sensor_state_invalid(sensor_index); ret = RTAS_OUT_PARAM_ERROR; goto out; } @@ -569,8 +557,7 @@ static void rtas_ibm_configure_connector(PowerPCCPU *cpu, drc_index = rtas_ld(wa_addr, 0); drc = spapr_dr_connector_by_index(drc_index); if (!drc) { - DPRINTF("rtas_ibm_configure_connector: invalid DRC index: %xh\n", - drc_index); + trace_spapr_rtas_ibm_configure_connector_invalid(drc_index); rc = RTAS_OUT_PARAM_ERROR; goto out; } @@ -578,8 +565,7 @@ static void rtas_ibm_configure_connector(PowerPCCPU *cpu, drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); fdt = drck->get_fdt(drc, NULL); if (!fdt) { - DPRINTF("rtas_ibm_configure_connector: Missing FDT for DRC index: %xh\n", - drc_index); + trace_spapr_rtas_ibm_configure_connector_missing_fdt(drc_index); rc = SPAPR_DR_CC_RESPONSE_NOT_CONFIGURABLE; goto out; } diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events index 59caffdbab1..34b5ec35788 100644 --- a/hw/ppc/trace-events +++ b/hw/ppc/trace-events @@ -56,6 +56,14 @@ spapr_drc_realize_child(uint32_t index, char *childname) "drc: 0x%"PRIx32", chil spapr_drc_realize_complete(uint32_t index) "drc: 0x%"PRIx32 spapr_drc_unrealize(uint32_t index) "drc: 0x%"PRIx32 +# hw/ppc/spapr_rtas.c +spapr_rtas_set_indicator_invalid(uint32_t index) "sensor index: 0x%"PRIx32 +spapr_rtas_set_indicator_not_supported(uint32_t index, uint32_t type) "sensor index: 0x%"PRIx32", type: %"PRIu32 +spapr_rtas_get_sensor_state_not_supported(uint32_t index, uint32_t type) "sensor index: 0x%"PRIx32", type: %"PRIu32 +spapr_rtas_get_sensor_state_invalid(uint32_t index) "sensor index: 0x%"PRIx32 +spapr_rtas_ibm_configure_connector_invalid(uint32_t index) "DRC index: 0x%"PRIx32 +spapr_rtas_ibm_configure_connector_missing_fdt(uint32_t index) "DRC index: 0x%"PRIx32 + # hw/ppc/ppc.c ppc_tb_adjust(uint64_t offs1, uint64_t offs2, int64_t diff, int64_t seconds) "adjusted from 0x%"PRIx64" to 0x%"PRIx64", diff %"PRId64" (%"PRId64"s)" From 7ab6a501c6c14c608043f918a680af9faaa38939 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Wed, 14 Sep 2016 20:48:25 +0200 Subject: [PATCH 198/723] spapr_vio: convert to trace framework instead of DPRINTF Signed-off-by: Laurent Vivier Reviewed-by: Eric Blake Signed-off-by: David Gibson --- hw/ppc/spapr_vio.c | 17 +++-------------- hw/ppc/trace-events | 4 ++++ 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c index 497028f075e..d68dd35679b 100644 --- a/hw/ppc/spapr_vio.c +++ b/hw/ppc/spapr_vio.c @@ -36,19 +36,10 @@ #include "hw/ppc/spapr.h" #include "hw/ppc/spapr_vio.h" #include "hw/ppc/xics.h" +#include "trace.h" #include -/* #define DEBUG_SPAPR */ - -#ifdef DEBUG_SPAPR -#define DPRINTF(fmt, ...) \ - do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) \ - do { } while (0) -#endif - static Property spapr_vio_props[] = { DEFINE_PROP_UINT32("irq", VIOsPAPRDevice, irq, 0), \ DEFINE_PROP_END_OF_LIST(), @@ -202,9 +193,7 @@ static target_ulong h_reg_crq(PowerPCCPU *cpu, sPAPRMachineState *spapr, dev->crq.qsize = queue_len; dev->crq.qnext = 0; - DPRINTF("CRQ for dev 0x" TARGET_FMT_lx " registered at 0x" - TARGET_FMT_lx "/0x" TARGET_FMT_lx "\n", - reg, queue_addr, queue_len); + trace_spapr_vio_h_reg_crq(reg, queue_addr, queue_len); return H_SUCCESS; } @@ -214,7 +203,7 @@ static target_ulong free_crq(VIOsPAPRDevice *dev) dev->crq.qsize = 0; dev->crq.qnext = 0; - DPRINTF("CRQ for dev 0x%" PRIx32 " freed\n", dev->reg); + trace_spapr_vio_free_crq(dev->reg); return H_SUCCESS; } diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events index 34b5ec35788..2297ead11ed 100644 --- a/hw/ppc/trace-events +++ b/hw/ppc/trace-events @@ -64,6 +64,10 @@ spapr_rtas_get_sensor_state_invalid(uint32_t index) "sensor index: 0x%"PRIx32 spapr_rtas_ibm_configure_connector_invalid(uint32_t index) "DRC index: 0x%"PRIx32 spapr_rtas_ibm_configure_connector_missing_fdt(uint32_t index) "DRC index: 0x%"PRIx32 +# hw/ppc/spapr_vio.c +spapr_vio_h_reg_crq(uint64_t reg, uint64_t queue_addr, uint64_t queue_len) "CRQ for dev 0x%" PRIx64 " registered at 0x%" PRIx64 "/0x%" PRIx64 +spapr_vio_free_crq(uint32_t reg) "CRQ for dev 0x%" PRIx32 " freed" + # hw/ppc/ppc.c ppc_tb_adjust(uint64_t offs1, uint64_t offs2, int64_t diff, int64_t seconds) "adjusted from 0x%"PRIx64" to 0x%"PRIx64", diff %"PRId64" (%"PRId64"s)" From e8bb33de42bdb17447a46e1b8448032b88b2cd54 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Wed, 14 Sep 2016 20:48:26 +0200 Subject: [PATCH 199/723] spapr_llan: convert to trace framework instead of DPRINTF Signed-off-by: Laurent Vivier Reviewed-by: Eric Blake Signed-off-by: David Gibson --- hw/net/spapr_llan.c | 61 +++++++++++++++++++-------------------------- hw/net/trace-events | 16 ++++++++++++ 2 files changed, 41 insertions(+), 36 deletions(-) diff --git a/hw/net/spapr_llan.c b/hw/net/spapr_llan.c index 4bb95a51ddd..01ecb027735 100644 --- a/hw/net/spapr_llan.c +++ b/hw/net/spapr_llan.c @@ -34,20 +34,13 @@ #include "hw/ppc/spapr.h" #include "hw/ppc/spapr_vio.h" #include "sysemu/sysemu.h" +#include "trace.h" #include #define ETH_ALEN 6 #define MAX_PACKET_SIZE 65536 -/*#define DEBUG*/ - -#ifdef DEBUG -#define DPRINTF(fmt...) do { fprintf(stderr, fmt); } while (0) -#else -#define DPRINTF(fmt...) -#endif - /* Compatibility flags for migration */ #define SPAPRVLAN_FLAG_RX_BUF_POOLS_BIT 0 #define SPAPRVLAN_FLAG_RX_BUF_POOLS (1 << SPAPRVLAN_FLAG_RX_BUF_POOLS_BIT) @@ -158,8 +151,10 @@ static vlan_bd_t spapr_vlan_get_rx_bd_from_pool(VIOsPAPRVLANDevice *dev, return 0; } - DPRINTF("Found buffer: pool=%d count=%d rxbufs=%d\n", pool, - dev->rx_pool[pool]->count, dev->rx_bufs); + + trace_spapr_vlan_get_rx_bd_from_pool_found(pool, + dev->rx_pool[pool]->count, + dev->rx_bufs); /* Remove the buffer from the pool */ dev->rx_pool[pool]->count--; @@ -186,8 +181,8 @@ static vlan_bd_t spapr_vlan_get_rx_bd_from_page(VIOsPAPRVLANDevice *dev, } bd = vio_ldq(&dev->sdev, dev->buf_list + buf_ptr); - DPRINTF("use_buf_ptr=%d bd=0x%016llx\n", - buf_ptr, (unsigned long long)bd); + + trace_spapr_vlan_get_rx_bd_from_page(buf_ptr, (uint64_t)bd); } while ((!(bd & VLAN_BD_VALID) || VLAN_BD_LEN(bd) < size + 8) && buf_ptr != dev->use_buf_ptr); @@ -200,7 +195,7 @@ static vlan_bd_t spapr_vlan_get_rx_bd_from_page(VIOsPAPRVLANDevice *dev, dev->use_buf_ptr = buf_ptr; vio_stq(&dev->sdev, dev->buf_list + dev->use_buf_ptr, 0); - DPRINTF("Found buffer: ptr=%d rxbufs=%d\n", dev->use_buf_ptr, dev->rx_bufs); + trace_spapr_vlan_get_rx_bd_from_page_found(dev->use_buf_ptr, dev->rx_bufs); return bd; } @@ -215,8 +210,7 @@ static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf, uint64_t handle; uint8_t control; - DPRINTF("spapr_vlan_receive() [%s] rx_bufs=%d\n", sdev->qdev.id, - dev->rx_bufs); + trace_spapr_vlan_receive(sdev->qdev.id, dev->rx_bufs); if (!dev->isopen) { return -1; @@ -244,7 +238,7 @@ static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf, return -1; } - DPRINTF("spapr_vlan_receive: DMA write completed\n"); + trace_spapr_vlan_receive_dma_completed(); /* Update the receive queue */ control = VLAN_RXQC_TOGGLE | VLAN_RXQC_VALID; @@ -258,12 +252,11 @@ static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf, vio_sth(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr + 2, 8); vio_stb(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr, control); - DPRINTF("wrote rxq entry (ptr=0x%llx): 0x%016llx 0x%016llx\n", - (unsigned long long)dev->rxq_ptr, - (unsigned long long)vio_ldq(sdev, VLAN_BD_ADDR(rxq_bd) + - dev->rxq_ptr), - (unsigned long long)vio_ldq(sdev, VLAN_BD_ADDR(rxq_bd) + - dev->rxq_ptr + 8)); + trace_spapr_vlan_receive_wrote(dev->rxq_ptr, + vio_ldq(sdev, VLAN_BD_ADDR(rxq_bd) + + dev->rxq_ptr), + vio_ldq(sdev, VLAN_BD_ADDR(rxq_bd) + + dev->rxq_ptr + 8)); dev->rxq_ptr += 16; if (dev->rxq_ptr >= VLAN_BD_LEN(rxq_bd)) { @@ -580,8 +573,8 @@ static target_long spapr_vlan_add_rxbuf_to_pool(VIOsPAPRVLANDevice *dev, qsort(dev->rx_pool, RX_MAX_POOLS, sizeof(dev->rx_pool[0]), rx_pool_size_compare); pool = spapr_vlan_get_rx_pool_id(dev, size); - DPRINTF("created RX pool %d for size %lld\n", pool, - VLAN_BD_LEN(buf)); + trace_spapr_vlan_add_rxbuf_to_pool_create(pool, + VLAN_BD_LEN(buf)); break; } } @@ -591,8 +584,8 @@ static target_long spapr_vlan_add_rxbuf_to_pool(VIOsPAPRVLANDevice *dev, return H_RESOURCE; } - DPRINTF("h_add_llan_buf(): Add buf using pool %i (size %lli, count=%i)\n", - pool, VLAN_BD_LEN(buf), dev->rx_pool[pool]->count); + trace_spapr_vlan_add_rxbuf_to_pool(pool, VLAN_BD_LEN(buf), + dev->rx_pool[pool]->count); dev->rx_pool[pool]->bds[dev->rx_pool[pool]->count++] = buf; @@ -623,8 +616,7 @@ static target_long spapr_vlan_add_rxbuf_to_page(VIOsPAPRVLANDevice *dev, vio_stq(&dev->sdev, dev->buf_list + dev->add_buf_ptr, buf); - DPRINTF("h_add_llan_buf(): Added buf ptr=%d rx_bufs=%d bd=0x%016llx\n", - dev->add_buf_ptr, dev->rx_bufs, (unsigned long long)buf); + trace_spapr_vlan_add_rxbuf_to_page(dev->add_buf_ptr, dev->rx_bufs, buf); return 0; } @@ -640,8 +632,7 @@ static target_ulong h_add_logical_lan_buffer(PowerPCCPU *cpu, VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev); target_long ret; - DPRINTF("H_ADD_LOGICAL_LAN_BUFFER(0x" TARGET_FMT_lx - ", 0x" TARGET_FMT_lx ")\n", reg, buf); + trace_spapr_vlan_h_add_logical_lan_buffer(reg, buf); if (!sdev) { hcall_dprintf("Bad device\n"); @@ -694,14 +685,13 @@ static target_ulong h_send_logical_lan(PowerPCCPU *cpu, int i, nbufs; int ret; - DPRINTF("H_SEND_LOGICAL_LAN(0x" TARGET_FMT_lx ", , 0x" - TARGET_FMT_lx ")\n", reg, continue_token); + trace_spapr_vlan_h_send_logical_lan(reg, continue_token); if (!sdev) { return H_PARAMETER; } - DPRINTF("rxbufs = %d\n", dev->rx_bufs); + trace_spapr_vlan_h_send_logical_lan_rxbufs(dev->rx_bufs); if (!dev->isopen) { return H_DROPPED; @@ -713,7 +703,7 @@ static target_ulong h_send_logical_lan(PowerPCCPU *cpu, total_len = 0; for (i = 0; i < 6; i++) { - DPRINTF(" buf desc: 0x" TARGET_FMT_lx "\n", bufs[i]); + trace_spapr_vlan_h_send_logical_lan_buf_desc(bufs[i]); if (!(bufs[i] & VLAN_BD_VALID)) { break; } @@ -721,8 +711,7 @@ static target_ulong h_send_logical_lan(PowerPCCPU *cpu, } nbufs = i; - DPRINTF("h_send_logical_lan() %d buffers, total length 0x%x\n", - nbufs, total_len); + trace_spapr_vlan_h_send_logical_lan_total(nbufs, total_len); if (total_len == 0) { return H_SUCCESS; diff --git a/hw/net/trace-events b/hw/net/trace-events index 8d38d7724d3..47ab14ac71f 100644 --- a/hw/net/trace-events +++ b/hw/net/trace-events @@ -270,3 +270,19 @@ e1000e_cfg_support_virtio(bool support) "Virtio header supported: %d" e1000e_vm_state_running(void) "VM state is running" e1000e_vm_state_stopped(void) "VM state is stopped" + +# hw/net/spapr_llan.c +spapr_vlan_get_rx_bd_from_pool_found(int pool, int32_t count, uint32_t rx_bufs) "pool=%d count=%"PRId32" rxbufs=%"PRIu32 +spapr_vlan_get_rx_bd_from_page(int buf_ptr, uint64_t bd) "use_buf_ptr=%d bd=0x%016"PRIx64 +spapr_vlan_get_rx_bd_from_page_found(uint32_t use_buf_ptr, uint32_t rx_bufs) "ptr=%"PRIu32" rxbufs=%"PRIu32 +spapr_vlan_receive(const char *id, uint32_t rx_bufs) "[%s] rx_bufs=%"PRIu32 +spapr_vlan_receive_dma_completed(void) "DMA write completed" +spapr_vlan_receive_wrote(uint64_t ptr, uint64_t hi, uint64_t lo) "rxq entry (ptr=0x%"PRIx64"): 0x%016"PRIx64" 0x%016"PRIx64 +spapr_vlan_add_rxbuf_to_pool_create(int pool, uint64_t len) "created RX pool %d for size %"PRIu64 +spapr_vlan_add_rxbuf_to_pool(int pool, uint64_t len, int32_t count) "add buf using pool %d (size %"PRIu64", count=%"PRId32")" +spapr_vlan_add_rxbuf_to_page(uint32_t ptr, uint32_t rx_bufs, uint64_t bd) "added buf ptr=%"PRIu32" rx_bufs=%"PRIu32" bd=0x%016"PRIx64 +spapr_vlan_h_add_logical_lan_buffer(uint64_t reg, uint64_t buf) "H_ADD_LOGICAL_LAN_BUFFER(0x%"PRIx64", 0x%"PRIx64")" +spapr_vlan_h_send_logical_lan(uint64_t reg, uint64_t continue_token) "H_SEND_LOGICAL_LAN(0x%"PRIx64", , 0x%"PRIx64")" +spapr_vlan_h_send_logical_lan_rxbufs(uint32_t rx_bufs) "rxbufs = %"PRIu32 +spapr_vlan_h_send_logical_lan_buf_desc(uint64_t buf) " buf desc: 0x%"PRIx64 +spapr_vlan_h_send_logical_lan_total(int nbufs, unsigned total_len) "%d buffers, total length 0x%x" From f19661c8b1f7f460c47ca7306a05eca22c6c5c68 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Fri, 16 Sep 2016 14:39:11 +0200 Subject: [PATCH 200/723] spapr_vscsi: convert to trace framework instead of DPRINTF Signed-off-by: Laurent Vivier Reviewed-by: Eric Blake Signed-off-by: David Gibson --- hw/scsi/spapr_vscsi.c | 88 ++++++++++++++++++------------------------- hw/scsi/trace-events | 27 +++++++++++++ 2 files changed, 63 insertions(+), 52 deletions(-) diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c index 8fbd50f6604..d8a2296b7ba 100644 --- a/hw/scsi/spapr_vscsi.c +++ b/hw/scsi/spapr_vscsi.c @@ -42,19 +42,10 @@ #include "hw/ppc/spapr.h" #include "hw/ppc/spapr_vio.h" #include "viosrp.h" +#include "trace.h" #include -/*#define DEBUG_VSCSI*/ - -#ifdef DEBUG_VSCSI -#define DPRINTF(fmt, ...) \ - do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) \ - do { } while (0) -#endif - /* * Virtual SCSI device */ @@ -237,8 +228,7 @@ static int vscsi_send_rsp(VSCSIState *s, vscsi_req *req, int total_len = sizeof(iu->srp.rsp); uint8_t sol_not = iu->srp.cmd.sol_not; - DPRINTF("VSCSI: Sending resp status: 0x%x, " - "res_in: %d, res_out: %d\n", status, res_in, res_out); + trace_spapr_vscsi_send_rsp(status, res_in, res_out); memset(iu, 0, sizeof(struct srp_rsp)); iu->srp.rsp.opcode = SRP_RSP; @@ -298,13 +288,13 @@ static int vscsi_fetch_desc(VSCSIState *s, struct vscsi_req *req, switch (req->dma_fmt) { case SRP_NO_DATA_DESC: { - DPRINTF("VSCSI: no data descriptor\n"); + trace_spapr_vscsi_fetch_desc_no_data(); return 0; } case SRP_DATA_DESC_DIRECT: { memcpy(ret, cmd->add_data + req->cdb_offset, sizeof(*ret)); assert(req->cur_desc_num == 0); - DPRINTF("VSCSI: direct segment\n"); + trace_spapr_vscsi_fetch_desc_direct(); break; } case SRP_DATA_DESC_INDIRECT: { @@ -312,30 +302,29 @@ static int vscsi_fetch_desc(VSCSIState *s, struct vscsi_req *req, (cmd->add_data + req->cdb_offset); if (n < req->local_desc) { *ret = tmp->desc_list[n]; - DPRINTF("VSCSI: indirect segment local tag=0x%x desc#%d/%d\n", - req->qtag, n, req->local_desc); - + trace_spapr_vscsi_fetch_desc_indirect(req->qtag, n, + req->local_desc); } else if (n < req->total_desc) { int rc; struct srp_direct_buf tbl_desc = vscsi_swap_desc(tmp->table_desc); unsigned desc_offset = n * sizeof(struct srp_direct_buf); if (desc_offset >= tbl_desc.len) { - DPRINTF("VSCSI: #%d is ouf of range (%d bytes)\n", - n, desc_offset); + trace_spapr_vscsi_fetch_desc_out_of_range(n, desc_offset); return -1; } rc = spapr_vio_dma_read(&s->vdev, tbl_desc.va + desc_offset, ret, sizeof(struct srp_direct_buf)); if (rc) { - DPRINTF("VSCSI: spapr_vio_dma_read -> %d reading ext_desc\n", - rc); + trace_spapr_vscsi_fetch_desc_dma_read_error(rc); return -1; } - DPRINTF("VSCSI: indirect segment ext. tag=0x%x desc#%d/%d { va=%"PRIx64" len=%x }\n", - req->qtag, n, req->total_desc, tbl_desc.va, tbl_desc.len); + trace_spapr_vscsi_fetch_desc_indirect_seg_ext(req->qtag, n, + req->total_desc, + tbl_desc.va, + tbl_desc.len); } else { - DPRINTF("VSCSI: Out of descriptors !\n"); + trace_spapr_vscsi_fetch_desc_out_of_desc(); return 0; } break; @@ -347,15 +336,16 @@ static int vscsi_fetch_desc(VSCSIState *s, struct vscsi_req *req, *ret = vscsi_swap_desc(*ret); if (buf_offset > ret->len) { - DPRINTF(" offset=%x is out of a descriptor #%d boundary=%x\n", - buf_offset, req->cur_desc_num, ret->len); + trace_spapr_vscsi_fetch_desc_out_of_desc_boundary(buf_offset, + req->cur_desc_num, + ret->len); return -1; } ret->va += buf_offset; ret->len -= buf_offset; - DPRINTF(" cur=%d offs=%x ret { va=%"PRIx64" len=%x }\n", - req->cur_desc_num, req->cur_desc_offset, ret->va, ret->len); + trace_spapr_vscsi_fetch_desc_done(req->cur_desc_num, req->cur_desc_offset, + ret->va, ret->len); return ret->len ? 1 : 0; } @@ -398,7 +388,7 @@ static int vscsi_srp_indirect_data(VSCSIState *s, vscsi_req *req, int rc = 0; uint32_t llen, total = 0; - DPRINTF("VSCSI: indirect segment 0x%x bytes\n", len); + trace_spapr_vscsi_srp_indirect_data(len); /* While we have data ... */ while (len) { @@ -417,11 +407,10 @@ static int vscsi_srp_indirect_data(VSCSIState *s, vscsi_req *req, rc = spapr_vio_dma_write(&s->vdev, md.va, buf, llen); } if (rc) { - DPRINTF("VSCSI: spapr_vio_dma_r/w(%d) -> %d\n", req->writing, rc); + trace_spapr_vscsi_srp_indirect_data_rw(req->writing, rc); break; } - DPRINTF("VSCSI: data: %02x %02x %02x %02x...\n", - buf[0], buf[1], buf[2], buf[3]); + trace_spapr_vscsi_srp_indirect_data_buf(buf[0], buf[1], buf[2], buf[3]); len -= llen; buf += llen; @@ -447,7 +436,7 @@ static int vscsi_srp_transfer_data(VSCSIState *s, vscsi_req *req, switch (req->dma_fmt) { case SRP_NO_DATA_DESC: - DPRINTF("VSCSI: no data desc transfer, skipping 0x%x bytes\n", len); + trace_spapr_vscsi_srp_transfer_data(len); break; case SRP_DATA_DESC_DIRECT: err = vscsi_srp_direct_data(s, req, buf, len); @@ -527,8 +516,7 @@ static void vscsi_transfer_data(SCSIRequest *sreq, uint32_t len) uint8_t *buf; int rc = 0; - DPRINTF("VSCSI: SCSI xfer complete tag=0x%x len=0x%x, req=%p\n", - sreq->tag, len, req); + trace_spapr_vscsi_transfer_data(sreq->tag, len, req); if (req == NULL) { fprintf(stderr, "VSCSI: Can't find request for tag 0x%x\n", sreq->tag); return; @@ -557,8 +545,7 @@ static void vscsi_command_complete(SCSIRequest *sreq, uint32_t status, size_t re vscsi_req *req = sreq->hba_private; int32_t res_in = 0, res_out = 0; - DPRINTF("VSCSI: SCSI cmd complete, tag=0x%x status=0x%x, req=%p\n", - sreq->tag, status, req); + trace_spapr_vscsi_command_complete(sreq->tag, status, req); if (req == NULL) { fprintf(stderr, "VSCSI: Can't find request for tag 0x%x\n", sreq->tag); return; @@ -567,16 +554,15 @@ static void vscsi_command_complete(SCSIRequest *sreq, uint32_t status, size_t re if (status == CHECK_CONDITION) { req->senselen = scsi_req_get_sense(req->sreq, req->sense, sizeof(req->sense)); - DPRINTF("VSCSI: Sense data, %d bytes:\n", req->senselen); - DPRINTF(" %02x %02x %02x %02x %02x %02x %02x %02x\n", + trace_spapr_vscsi_command_complete_sense_data1(req->senselen, req->sense[0], req->sense[1], req->sense[2], req->sense[3], req->sense[4], req->sense[5], req->sense[6], req->sense[7]); - DPRINTF(" %02x %02x %02x %02x %02x %02x %02x %02x\n", + trace_spapr_vscsi_command_complete_sense_data2( req->sense[8], req->sense[9], req->sense[10], req->sense[11], req->sense[12], req->sense[13], req->sense[14], req->sense[15]); } - DPRINTF("VSCSI: Command complete err=%d\n", status); + trace_spapr_vscsi_command_complete_status(status); if (status == 0) { /* We handle overflows, not underflows for normal commands, * but hopefully nobody cares @@ -635,8 +621,8 @@ static void vscsi_save_request(QEMUFile *f, SCSIRequest *sreq) vmstate_save_state(f, &vmstate_spapr_vscsi_req, req, NULL); - DPRINTF("VSCSI: saving tag=%u, current desc#%d, offset=%x\n", - req->qtag, req->cur_desc_num, req->cur_desc_offset); + trace_spapr_vscsi_save_request(req->qtag, req->cur_desc_num, + req->cur_desc_offset); } static void *vscsi_load_request(QEMUFile *f, SCSIRequest *sreq) @@ -660,8 +646,8 @@ static void *vscsi_load_request(QEMUFile *f, SCSIRequest *sreq) req->sreq = scsi_req_ref(sreq); - DPRINTF("VSCSI: restoring tag=%u, current desc#%d, offset=%x\n", - req->qtag, req->cur_desc_num, req->cur_desc_offset); + trace_spapr_vscsi_load_request(req->qtag, req->cur_desc_num, + req->cur_desc_offset); return req; } @@ -672,7 +658,7 @@ static void vscsi_process_login(VSCSIState *s, vscsi_req *req) struct srp_login_rsp *rsp = &iu->srp.login_rsp; uint64_t tag = iu->srp.rsp.tag; - DPRINTF("VSCSI: Got login, sendin response !\n"); + trace_spapr_vscsi__process_login(); /* TODO handle case that requested size is wrong and * buffer format is wrong @@ -795,8 +781,7 @@ static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req) sdev = vscsi_device_find(&s->bus, be64_to_cpu(srp->cmd.lun), &lun); if (!sdev) { - DPRINTF("VSCSI: Command for lun %08" PRIx64 " with no drive\n", - be64_to_cpu(srp->cmd.lun)); + trace_spapr_vscsi_queue_cmd_no_drive(be64_to_cpu(srp->cmd.lun)); if (srp->cmd.cdb[0] == INQUIRY) { vscsi_inquiry_no_target(s, req); } else { @@ -808,9 +793,8 @@ static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req) req->sreq = scsi_req_new(sdev, req->qtag, lun, srp->cmd.cdb, req); n = scsi_req_enqueue(req->sreq); - DPRINTF("VSCSI: Queued command tag 0x%x CMD 0x%x=%s LUN %d ret: %d\n", - req->qtag, srp->cmd.cdb[0], scsi_command_name(srp->cmd.cdb[0]), - lun, n); + trace_spapr_vscsi_queue_cmd(req->qtag, srp->cmd.cdb[0], + scsi_command_name(srp->cmd.cdb[0]), lun, n); if (n) { /* Transfer direction must be set before preprocessing the @@ -1141,7 +1125,7 @@ static int vscsi_do_crq(struct VIOsPAPRDevice *dev, uint8_t *crq_data) crq.s.IU_length = be16_to_cpu(crq.s.IU_length); crq.s.IU_data_ptr = be64_to_cpu(crq.s.IU_data_ptr); - DPRINTF("VSCSI: do_crq %02x %02x ...\n", crq.raw[0], crq.raw[1]); + trace_spapr_vscsi_do_crq(crq.raw[0], crq.raw[1]); switch (crq.s.valid) { case 0xc0: /* Init command/response */ diff --git a/hw/scsi/trace-events b/hw/scsi/trace-events index ed64858fe37..d1995b84f87 100644 --- a/hw/scsi/trace-events +++ b/hw/scsi/trace-events @@ -202,3 +202,30 @@ esp_pci_dma_abort(uint32_t val) "ABORT (%.8x)" esp_pci_dma_start(uint32_t val) "START (%.8x)" esp_pci_sbac_read(uint32_t reg) "sbac: 0x%8.8x" esp_pci_sbac_write(uint32_t reg, uint32_t val) "sbac: 0x%8.8x -> 0x%8.8x" + +# hw/scsi/spapr_vscsi.c +spapr_vscsi_send_rsp(uint8_t status, int32_t res_in, int32_t res_out) "status: 0x%x, res_in: %"PRId32", res_out: %"PRId32 +spapr_vscsi_fetch_desc_no_data(void) "no data descriptor" +spapr_vscsi_fetch_desc_direct(void) "direct segment" +spapr_vscsi_fetch_desc_indirect(uint32_t qtag, unsigned desc, unsigned local_desc) "indirect segment local tag=0x%"PRIx32" desc#%u/%u" +spapr_vscsi_fetch_desc_out_of_range(unsigned desc, unsigned desc_offset) "#%u is ouf of range (%u bytes)" +spapr_vscsi_fetch_desc_dma_read_error(int rc) "spapr_vio_dma_read -> %d reading ext_desc" +spapr_vscsi_fetch_desc_indirect_seg_ext(uint32_t qtag, unsigned n, unsigned desc, uint64_t va, uint32_t len) "indirect segment ext. tag=0x%"PRIx32" desc#%u/%u { va=0x%"PRIx64" len=0x%"PRIx32" }" +spapr_vscsi_fetch_desc_out_of_desc(void) "Out of descriptors !" +spapr_vscsi_fetch_desc_out_of_desc_boundary(unsigned offset, unsigned desc, uint32_t len) " offset=0x%x is out of a descriptor #%u boundary=%"PRIx32 +spapr_vscsi_fetch_desc_done(unsigned desc_num, unsigned desc_offset, uint64_t va, uint32_t len) " cur=%u offs=0x%x ret { va=0x%"PRIx64" len=0x%"PRIx32" }" +spapr_vscsi_srp_indirect_data(uint32_t len) "indirect segment 0x%"PRIx32" bytes" +spapr_vscsi_srp_indirect_data_rw(int writing, int rc) "spapr_vio_dma_r/w(%d) -> %d" +spapr_vscsi_srp_indirect_data_buf(unsigned a, unsigned b, unsigned c, unsigned d) " data: %02x %02x %02x %02x..." +spapr_vscsi_srp_transfer_data(uint32_t len) "no data desc transfer, skipping 0x%"PRIx32" bytes" +spapr_vscsi_transfer_data(uint32_t tag, uint32_t len, void *req) "SCSI xfer complete tag=0x%"PRIx32" len=0x%"PRIx32", req=%p" +spapr_vscsi_command_complete(uint32_t tag, uint32_t status, void *req) "SCSI cmd complete, tag=0x%"PRIx32" status=0x%"PRIx32", req=%p" +spapr_vscsi_command_complete_sense_data1(uint32_t len, unsigned s0, unsigned s1, unsigned s2, unsigned s3, unsigned s4, unsigned s5, unsigned s6, unsigned s7) "Sense data, %d bytes: %02x %02x %02x %02x %02x %02x %02x %02x" +spapr_vscsi_command_complete_sense_data2(unsigned s8, unsigned s9, unsigned s10, unsigned s11, unsigned s12, unsigned s13, unsigned s14, unsigned s15) " %02x %02x %02x %02x %02x %02x %02x %02x" +spapr_vscsi_command_complete_status(uint32_t status) "Command complete err=%"PRIu32 +spapr_vscsi_save_request(uint32_t qtag, unsigned desc, unsigned offset) "saving tag=%"PRIu32", current desc#%u, offset=0x%x" +spapr_vscsi_load_request(uint32_t qtag, unsigned desc, unsigned offset) "restoring tag=%"PRIu32", current desc#%u, offset=0x%x" +spapr_vscsi__process_login(void) "Got login, sending response !" +spapr_vscsi_queue_cmd_no_drive(uint64_t lun) "Command for lun %08" PRIx64 " with no drive" +spapr_vscsi_queue_cmd(uint32_t qtag, unsigned cdb, const char *cmd, int lun, int ret) "Queued command tag 0x%"PRIx32" CMD 0x%x=%s LUN %d ret: %d" +spapr_vscsi_do_crq(unsigned c0, unsigned c1) "crq: %02x %02x ..." From 09bfe50d57d1986f8b3d0fd01ce32e303204c283 Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Mon, 12 Sep 2016 12:11:30 +0530 Subject: [PATCH 201/723] target-ppc: consolidate load operations Implement macro to consolidate load operations using newer tcg_gen_qemu_ld functions. Signed-off-by: Nikunj A Dadhania Signed-off-by: David Gibson --- target-ppc/translate.c | 58 +++++++++++++++--------------------------- 1 file changed, 20 insertions(+), 38 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index a27f45593bc..66069691897 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -2462,50 +2462,32 @@ static inline void gen_align_no_le(DisasContext *ctx) } /*** Integer load ***/ -static inline void gen_qemu_ld8u(DisasContext *ctx, TCGv arg1, TCGv arg2) -{ - tcg_gen_qemu_ld8u(arg1, arg2, ctx->mem_idx); -} - -static inline void gen_qemu_ld16u(DisasContext *ctx, TCGv arg1, TCGv arg2) -{ - TCGMemOp op = MO_UW | ctx->default_tcg_memop_mask; - tcg_gen_qemu_ld_tl(arg1, arg2, ctx->mem_idx, op); -} - -static inline void gen_qemu_ld16s(DisasContext *ctx, TCGv arg1, TCGv arg2) -{ - TCGMemOp op = MO_SW | ctx->default_tcg_memop_mask; - tcg_gen_qemu_ld_tl(arg1, arg2, ctx->mem_idx, op); -} +#define DEF_MEMOP(op) ((op) | ctx->default_tcg_memop_mask) -static inline void gen_qemu_ld32u(DisasContext *ctx, TCGv arg1, TCGv arg2) -{ - TCGMemOp op = MO_UL | ctx->default_tcg_memop_mask; - tcg_gen_qemu_ld_tl(arg1, arg2, ctx->mem_idx, op); +#define GEN_QEMU_LOAD_TL(ldop, op) \ +static void glue(gen_qemu_, ldop)(DisasContext *ctx, \ + TCGv val, \ + TCGv addr) \ +{ \ + tcg_gen_qemu_ld_tl(val, addr, ctx->mem_idx, op); \ } -static void gen_qemu_ld32u_i64(DisasContext *ctx, TCGv_i64 val, TCGv addr) -{ - TCGv tmp = tcg_temp_new(); - gen_qemu_ld32u(ctx, tmp, addr); - tcg_gen_extu_tl_i64(val, tmp); - tcg_temp_free(tmp); -} +GEN_QEMU_LOAD_TL(ld8u, DEF_MEMOP(MO_UB)) +GEN_QEMU_LOAD_TL(ld16u, DEF_MEMOP(MO_UW)) +GEN_QEMU_LOAD_TL(ld16s, DEF_MEMOP(MO_SW)) +GEN_QEMU_LOAD_TL(ld32u, DEF_MEMOP(MO_UL)) +GEN_QEMU_LOAD_TL(ld32s, DEF_MEMOP(MO_SL)) -static inline void gen_qemu_ld32s(DisasContext *ctx, TCGv arg1, TCGv arg2) -{ - TCGMemOp op = MO_SL | ctx->default_tcg_memop_mask; - tcg_gen_qemu_ld_tl(arg1, arg2, ctx->mem_idx, op); +#define GEN_QEMU_LOAD_64(ldop, op) \ +static void glue(gen_qemu_, glue(ldop, _i64))(DisasContext *ctx, \ + TCGv_i64 val, \ + TCGv addr) \ +{ \ + tcg_gen_qemu_ld_i64(val, addr, ctx->mem_idx, op); \ } -static void gen_qemu_ld32s_i64(DisasContext *ctx, TCGv_i64 val, TCGv addr) -{ - TCGv tmp = tcg_temp_new(); - gen_qemu_ld32s(ctx, tmp, addr); - tcg_gen_ext_tl_i64(val, tmp); - tcg_temp_free(tmp); -} +GEN_QEMU_LOAD_64(ld32u, DEF_MEMOP(MO_UL)) +GEN_QEMU_LOAD_64(ld32s, DEF_MEMOP(MO_SL)) static inline void gen_qemu_ld64(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2) { From 4f364fe76f9288bd30b418ecfd007a08412c4456 Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Mon, 12 Sep 2016 12:11:31 +0530 Subject: [PATCH 202/723] target-ppc: convert ld64 to use new macro Use macro for ld64 as well, this changes the function signature from gen_qemu_ld64 => gen_qemu_ld64_i64. Replace this at all the call sites. Signed-off-by: Nikunj A Dadhania Signed-off-by: David Gibson --- target-ppc/translate.c | 39 ++++++++++++--------------- target-ppc/translate/fp-impl.inc.c | 42 ++++++++++++++--------------- target-ppc/translate/spe-impl.inc.c | 2 +- target-ppc/translate/vmx-impl.inc.c | 12 ++++----- target-ppc/translate/vsx-impl.inc.c | 8 +++--- 5 files changed, 49 insertions(+), 54 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 66069691897..d36d45e7b74 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -2488,12 +2488,7 @@ static void glue(gen_qemu_, glue(ldop, _i64))(DisasContext *ctx, \ GEN_QEMU_LOAD_64(ld32u, DEF_MEMOP(MO_UL)) GEN_QEMU_LOAD_64(ld32s, DEF_MEMOP(MO_SL)) - -static inline void gen_qemu_ld64(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2) -{ - TCGMemOp op = MO_Q | ctx->default_tcg_memop_mask; - tcg_gen_qemu_ld_i64(arg1, arg2, ctx->mem_idx, op); -} +GEN_QEMU_LOAD_64(ld64, DEF_MEMOP(MO_Q)) static inline void gen_qemu_st8(DisasContext *ctx, TCGv arg1, TCGv arg2) { @@ -2612,12 +2607,12 @@ GEN_LDUX(lwa, ld32s, 0x15, 0x0B, PPC_64B); /* lwax */ GEN_LDX(lwa, ld32s, 0x15, 0x0A, PPC_64B); /* ldux */ -GEN_LDUX(ld, ld64, 0x15, 0x01, PPC_64B); +GEN_LDUX(ld, ld64_i64, 0x15, 0x01, PPC_64B); /* ldx */ -GEN_LDX(ld, ld64, 0x15, 0x00, PPC_64B); +GEN_LDX(ld, ld64_i64, 0x15, 0x00, PPC_64B); /* CI load/store variants */ -GEN_LDX_HVRM(ldcix, ld64, 0x15, 0x1b, PPC_CILDST) +GEN_LDX_HVRM(ldcix, ld64_i64, 0x15, 0x1b, PPC_CILDST) GEN_LDX_HVRM(lwzcix, ld32u, 0x15, 0x15, PPC_CILDST) GEN_LDX_HVRM(lhzcix, ld16u, 0x15, 0x19, PPC_CILDST) GEN_LDX_HVRM(lbzcix, ld8u, 0x15, 0x1a, PPC_CILDST) @@ -2640,7 +2635,7 @@ static void gen_ld(DisasContext *ctx) gen_qemu_ld32s(ctx, cpu_gpr[rD(ctx->opcode)], EA); } else { /* ld - ldu */ - gen_qemu_ld64(ctx, cpu_gpr[rD(ctx->opcode)], EA); + gen_qemu_ld64_i64(ctx, cpu_gpr[rD(ctx->opcode)], EA); } if (Rc(ctx->opcode)) tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA); @@ -2677,16 +2672,16 @@ static void gen_lq(DisasContext *ctx) EA = tcg_temp_new(); gen_addr_imm_index(ctx, EA, 0x0F); - /* We only need to swap high and low halves. gen_qemu_ld64 does necessary - 64-bit byteswap already. */ + /* We only need to swap high and low halves. gen_qemu_ld64_i64 does + necessary 64-bit byteswap already. */ if (unlikely(ctx->le_mode)) { - gen_qemu_ld64(ctx, cpu_gpr[rd+1], EA); + gen_qemu_ld64_i64(ctx, cpu_gpr[rd + 1], EA); gen_addr_add(ctx, EA, EA, 8); - gen_qemu_ld64(ctx, cpu_gpr[rd], EA); + gen_qemu_ld64_i64(ctx, cpu_gpr[rd], EA); } else { - gen_qemu_ld64(ctx, cpu_gpr[rd], EA); + gen_qemu_ld64_i64(ctx, cpu_gpr[rd], EA); gen_addr_add(ctx, EA, EA, 8); - gen_qemu_ld64(ctx, cpu_gpr[rd+1], EA); + gen_qemu_ld64_i64(ctx, cpu_gpr[rd + 1], EA); } tcg_temp_free(EA); } @@ -3184,7 +3179,7 @@ STCX(stwcx_, 4); #if defined(TARGET_PPC64) /* ldarx */ -LARX(ldarx, 8, ld64); +LARX(ldarx, 8, ld64_i64); /* lqarx */ static void gen_lqarx(DisasContext *ctx) @@ -3210,11 +3205,11 @@ static void gen_lqarx(DisasContext *ctx) gpr1 = cpu_gpr[rd]; gpr2 = cpu_gpr[rd+1]; } - gen_qemu_ld64(ctx, gpr1, EA); + gen_qemu_ld64_i64(ctx, gpr1, EA); tcg_gen_mov_tl(cpu_reserve, EA); gen_addr_add(ctx, EA, EA, 8); - gen_qemu_ld64(ctx, gpr2, EA); + gen_qemu_ld64_i64(ctx, gpr2, EA); tcg_gen_st_tl(gpr1, cpu_env, offsetof(CPUPPCState, reserve_val)); tcg_gen_st_tl(gpr2, cpu_env, offsetof(CPUPPCState, reserve_val2)); @@ -6601,12 +6596,12 @@ GEN_LDS(lwz, ld32u, 0x00, PPC_INTEGER) #if defined(TARGET_PPC64) GEN_LDUX(lwa, ld32s, 0x15, 0x0B, PPC_64B) GEN_LDX(lwa, ld32s, 0x15, 0x0A, PPC_64B) -GEN_LDUX(ld, ld64, 0x15, 0x01, PPC_64B) -GEN_LDX(ld, ld64, 0x15, 0x00, PPC_64B) +GEN_LDUX(ld, ld64_i64, 0x15, 0x01, PPC_64B) +GEN_LDX(ld, ld64_i64, 0x15, 0x00, PPC_64B) GEN_LDX_E(ldbr, ld64ur, 0x14, 0x10, PPC_NONE, PPC2_DBRX, CHK_NONE) /* HV/P7 and later only */ -GEN_LDX_HVRM(ldcix, ld64, 0x15, 0x1b, PPC_CILDST) +GEN_LDX_HVRM(ldcix, ld64_i64, 0x15, 0x1b, PPC_CILDST) GEN_LDX_HVRM(lwzcix, ld32u, 0x15, 0x18, PPC_CILDST) GEN_LDX_HVRM(lhzcix, ld16u, 0x15, 0x19, PPC_CILDST) GEN_LDX_HVRM(lbzcix, ld8u, 0x15, 0x1a, PPC_CILDST) diff --git a/target-ppc/translate/fp-impl.inc.c b/target-ppc/translate/fp-impl.inc.c index 9ba92891570..53b7fc74454 100644 --- a/target-ppc/translate/fp-impl.inc.c +++ b/target-ppc/translate/fp-impl.inc.c @@ -672,7 +672,7 @@ static inline void gen_qemu_ld32fs(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2) } /* lfd lfdu lfdux lfdx */ -GEN_LDFS(lfd, ld64, 0x12, PPC_FLOAT); +GEN_LDFS(lfd, ld64_i64, 0x12, PPC_FLOAT); /* lfs lfsu lfsux lfsx */ GEN_LDFS(lfs, ld32fs, 0x10, PPC_FLOAT); @@ -687,16 +687,16 @@ static void gen_lfdp(DisasContext *ctx) gen_set_access_type(ctx, ACCESS_FLOAT); EA = tcg_temp_new(); gen_addr_imm_index(ctx, EA, 0); - /* We only need to swap high and low halves. gen_qemu_ld64 does necessary - 64-bit byteswap already. */ + /* We only need to swap high and low halves. gen_qemu_ld64_i64 does + necessary 64-bit byteswap already. */ if (unlikely(ctx->le_mode)) { - gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); + gen_qemu_ld64_i64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); tcg_gen_addi_tl(EA, EA, 8); - gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode)], EA); + gen_qemu_ld64_i64(ctx, cpu_fpr[rD(ctx->opcode)], EA); } else { - gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode)], EA); + gen_qemu_ld64_i64(ctx, cpu_fpr[rD(ctx->opcode)], EA); tcg_gen_addi_tl(EA, EA, 8); - gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); + gen_qemu_ld64_i64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); } tcg_temp_free(EA); } @@ -712,16 +712,16 @@ static void gen_lfdpx(DisasContext *ctx) gen_set_access_type(ctx, ACCESS_FLOAT); EA = tcg_temp_new(); gen_addr_reg_index(ctx, EA); - /* We only need to swap high and low halves. gen_qemu_ld64 does necessary - 64-bit byteswap already. */ + /* We only need to swap high and low halves. gen_qemu_ld64_i64 does + necessary 64-bit byteswap already. */ if (unlikely(ctx->le_mode)) { - gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); + gen_qemu_ld64_i64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); tcg_gen_addi_tl(EA, EA, 8); - gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode)], EA); + gen_qemu_ld64_i64(ctx, cpu_fpr[rD(ctx->opcode)], EA); } else { - gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode)], EA); + gen_qemu_ld64_i64(ctx, cpu_fpr[rD(ctx->opcode)], EA); tcg_gen_addi_tl(EA, EA, 8); - gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); + gen_qemu_ld64_i64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); } tcg_temp_free(EA); } @@ -924,9 +924,9 @@ static void gen_lfq(DisasContext *ctx) gen_set_access_type(ctx, ACCESS_FLOAT); t0 = tcg_temp_new(); gen_addr_imm_index(ctx, t0, 0); - gen_qemu_ld64(ctx, cpu_fpr[rd], t0); + gen_qemu_ld64_i64(ctx, cpu_fpr[rd], t0); gen_addr_add(ctx, t0, t0, 8); - gen_qemu_ld64(ctx, cpu_fpr[(rd + 1) % 32], t0); + gen_qemu_ld64_i64(ctx, cpu_fpr[(rd + 1) % 32], t0); tcg_temp_free(t0); } @@ -940,9 +940,9 @@ static void gen_lfqu(DisasContext *ctx) t0 = tcg_temp_new(); t1 = tcg_temp_new(); gen_addr_imm_index(ctx, t0, 0); - gen_qemu_ld64(ctx, cpu_fpr[rd], t0); + gen_qemu_ld64_i64(ctx, cpu_fpr[rd], t0); gen_addr_add(ctx, t1, t0, 8); - gen_qemu_ld64(ctx, cpu_fpr[(rd + 1) % 32], t1); + gen_qemu_ld64_i64(ctx, cpu_fpr[(rd + 1) % 32], t1); if (ra != 0) tcg_gen_mov_tl(cpu_gpr[ra], t0); tcg_temp_free(t0); @@ -958,10 +958,10 @@ static void gen_lfqux(DisasContext *ctx) TCGv t0, t1; t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); - gen_qemu_ld64(ctx, cpu_fpr[rd], t0); + gen_qemu_ld64_i64(ctx, cpu_fpr[rd], t0); t1 = tcg_temp_new(); gen_addr_add(ctx, t1, t0, 8); - gen_qemu_ld64(ctx, cpu_fpr[(rd + 1) % 32], t1); + gen_qemu_ld64_i64(ctx, cpu_fpr[(rd + 1) % 32], t1); tcg_temp_free(t1); if (ra != 0) tcg_gen_mov_tl(cpu_gpr[ra], t0); @@ -976,9 +976,9 @@ static void gen_lfqx(DisasContext *ctx) gen_set_access_type(ctx, ACCESS_FLOAT); t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); - gen_qemu_ld64(ctx, cpu_fpr[rd], t0); + gen_qemu_ld64_i64(ctx, cpu_fpr[rd], t0); gen_addr_add(ctx, t0, t0, 8); - gen_qemu_ld64(ctx, cpu_fpr[(rd + 1) % 32], t0); + gen_qemu_ld64_i64(ctx, cpu_fpr[(rd + 1) % 32], t0); tcg_temp_free(t0); } diff --git a/target-ppc/translate/spe-impl.inc.c b/target-ppc/translate/spe-impl.inc.c index 0ce403a8619..a969927e9b2 100644 --- a/target-ppc/translate/spe-impl.inc.c +++ b/target-ppc/translate/spe-impl.inc.c @@ -617,7 +617,7 @@ static inline void gen_addr_spe_imm_index(DisasContext *ctx, TCGv EA, int sh) static inline void gen_op_evldd(DisasContext *ctx, TCGv addr) { TCGv_i64 t0 = tcg_temp_new_i64(); - gen_qemu_ld64(ctx, t0, addr); + gen_qemu_ld64_i64(ctx, t0, addr); gen_store_gpr64(rD(ctx->opcode), t0); tcg_temp_free_i64(t0); } diff --git a/target-ppc/translate/vmx-impl.inc.c b/target-ppc/translate/vmx-impl.inc.c index 024faf76fef..eb3164bbb87 100644 --- a/target-ppc/translate/vmx-impl.inc.c +++ b/target-ppc/translate/vmx-impl.inc.c @@ -26,16 +26,16 @@ static void glue(gen_, name)(DisasContext *ctx) EA = tcg_temp_new(); \ gen_addr_reg_index(ctx, EA); \ tcg_gen_andi_tl(EA, EA, ~0xf); \ - /* We only need to swap high and low halves. gen_qemu_ld64 does necessary \ - 64-bit byteswap already. */ \ + /* We only need to swap high and low halves. gen_qemu_ld64_i64 does \ + necessary 64-bit byteswap already. */ \ if (ctx->le_mode) { \ - gen_qemu_ld64(ctx, cpu_avrl[rD(ctx->opcode)], EA); \ + gen_qemu_ld64_i64(ctx, cpu_avrl[rD(ctx->opcode)], EA); \ tcg_gen_addi_tl(EA, EA, 8); \ - gen_qemu_ld64(ctx, cpu_avrh[rD(ctx->opcode)], EA); \ + gen_qemu_ld64_i64(ctx, cpu_avrh[rD(ctx->opcode)], EA); \ } else { \ - gen_qemu_ld64(ctx, cpu_avrh[rD(ctx->opcode)], EA); \ + gen_qemu_ld64_i64(ctx, cpu_avrh[rD(ctx->opcode)], EA); \ tcg_gen_addi_tl(EA, EA, 8); \ - gen_qemu_ld64(ctx, cpu_avrl[rD(ctx->opcode)], EA); \ + gen_qemu_ld64_i64(ctx, cpu_avrl[rD(ctx->opcode)], EA); \ } \ tcg_temp_free(EA); \ } diff --git a/target-ppc/translate/vsx-impl.inc.c b/target-ppc/translate/vsx-impl.inc.c index 9f77b06bd8f..572579403f7 100644 --- a/target-ppc/translate/vsx-impl.inc.c +++ b/target-ppc/translate/vsx-impl.inc.c @@ -34,7 +34,7 @@ static void gen_##name(DisasContext *ctx) \ tcg_temp_free(EA); \ } -VSX_LOAD_SCALAR(lxsdx, ld64) +VSX_LOAD_SCALAR(lxsdx, ld64_i64) VSX_LOAD_SCALAR(lxsiwax, ld32s_i64) VSX_LOAD_SCALAR(lxsiwzx, ld32u_i64) VSX_LOAD_SCALAR(lxsspx, ld32fs) @@ -49,9 +49,9 @@ static void gen_lxvd2x(DisasContext *ctx) gen_set_access_type(ctx, ACCESS_INT); EA = tcg_temp_new(); gen_addr_reg_index(ctx, EA); - gen_qemu_ld64(ctx, cpu_vsrh(xT(ctx->opcode)), EA); + gen_qemu_ld64_i64(ctx, cpu_vsrh(xT(ctx->opcode)), EA); tcg_gen_addi_tl(EA, EA, 8); - gen_qemu_ld64(ctx, cpu_vsrl(xT(ctx->opcode)), EA); + gen_qemu_ld64_i64(ctx, cpu_vsrl(xT(ctx->opcode)), EA); tcg_temp_free(EA); } @@ -65,7 +65,7 @@ static void gen_lxvdsx(DisasContext *ctx) gen_set_access_type(ctx, ACCESS_INT); EA = tcg_temp_new(); gen_addr_reg_index(ctx, EA); - gen_qemu_ld64(ctx, cpu_vsrh(xT(ctx->opcode)), EA); + gen_qemu_ld64_i64(ctx, cpu_vsrh(xT(ctx->opcode)), EA); tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), cpu_vsrh(xT(ctx->opcode))); tcg_temp_free(EA); } From ff5f3981a291bdf37ba78bedb499af45cf04253b Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Mon, 12 Sep 2016 12:11:32 +0530 Subject: [PATCH 203/723] target-ppc: convert ld[16,32,64]ur to use new macro Make byte-swap routines use the common GEN_QEMU_LOAD macro Signed-off-by: Nikunj A Dadhania Signed-off-by: David Gibson --- target-ppc/translate.c | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index d36d45e7b74..0d27067843c 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -2463,6 +2463,7 @@ static inline void gen_align_no_le(DisasContext *ctx) /*** Integer load ***/ #define DEF_MEMOP(op) ((op) | ctx->default_tcg_memop_mask) +#define BSWAP_MEMOP(op) ((op) | (ctx->default_tcg_memop_mask ^ MO_BSWAP)) #define GEN_QEMU_LOAD_TL(ldop, op) \ static void glue(gen_qemu_, ldop)(DisasContext *ctx, \ @@ -2478,6 +2479,9 @@ GEN_QEMU_LOAD_TL(ld16s, DEF_MEMOP(MO_SW)) GEN_QEMU_LOAD_TL(ld32u, DEF_MEMOP(MO_UL)) GEN_QEMU_LOAD_TL(ld32s, DEF_MEMOP(MO_SL)) +GEN_QEMU_LOAD_TL(ld16ur, BSWAP_MEMOP(MO_UW)) +GEN_QEMU_LOAD_TL(ld32ur, BSWAP_MEMOP(MO_UL)) + #define GEN_QEMU_LOAD_64(ldop, op) \ static void glue(gen_qemu_, glue(ldop, _i64))(DisasContext *ctx, \ TCGv_i64 val, \ @@ -2490,6 +2494,10 @@ GEN_QEMU_LOAD_64(ld32u, DEF_MEMOP(MO_UL)) GEN_QEMU_LOAD_64(ld32s, DEF_MEMOP(MO_SL)) GEN_QEMU_LOAD_64(ld64, DEF_MEMOP(MO_Q)) +#if defined(TARGET_PPC64) +GEN_QEMU_LOAD_64(ld64ur, BSWAP_MEMOP(MO_Q)) +#endif + static inline void gen_qemu_st8(DisasContext *ctx, TCGv arg1, TCGv arg2) { tcg_gen_qemu_st8(arg1, arg2, ctx->mem_idx); @@ -2836,29 +2844,14 @@ static void gen_std(DisasContext *ctx) /*** Integer load and store with byte reverse ***/ /* lhbrx */ -static inline void gen_qemu_ld16ur(DisasContext *ctx, TCGv arg1, TCGv arg2) -{ - TCGMemOp op = MO_UW | (ctx->default_tcg_memop_mask ^ MO_BSWAP); - tcg_gen_qemu_ld_tl(arg1, arg2, ctx->mem_idx, op); -} GEN_LDX(lhbr, ld16ur, 0x16, 0x18, PPC_INTEGER); /* lwbrx */ -static inline void gen_qemu_ld32ur(DisasContext *ctx, TCGv arg1, TCGv arg2) -{ - TCGMemOp op = MO_UL | (ctx->default_tcg_memop_mask ^ MO_BSWAP); - tcg_gen_qemu_ld_tl(arg1, arg2, ctx->mem_idx, op); -} GEN_LDX(lwbr, ld32ur, 0x16, 0x10, PPC_INTEGER); #if defined(TARGET_PPC64) /* ldbrx */ -static inline void gen_qemu_ld64ur(DisasContext *ctx, TCGv arg1, TCGv arg2) -{ - TCGMemOp op = MO_Q | (ctx->default_tcg_memop_mask ^ MO_BSWAP); - tcg_gen_qemu_ld_i64(arg1, arg2, ctx->mem_idx, op); -} -GEN_LDX_E(ldbr, ld64ur, 0x14, 0x10, PPC_NONE, PPC2_DBRX, CHK_NONE); +GEN_LDX_E(ldbr, ld64ur_i64, 0x14, 0x10, PPC_NONE, PPC2_DBRX, CHK_NONE); #endif /* TARGET_PPC64 */ /* sthbrx */ @@ -6598,7 +6591,7 @@ GEN_LDUX(lwa, ld32s, 0x15, 0x0B, PPC_64B) GEN_LDX(lwa, ld32s, 0x15, 0x0A, PPC_64B) GEN_LDUX(ld, ld64_i64, 0x15, 0x01, PPC_64B) GEN_LDX(ld, ld64_i64, 0x15, 0x00, PPC_64B) -GEN_LDX_E(ldbr, ld64ur, 0x14, 0x10, PPC_NONE, PPC2_DBRX, CHK_NONE) +GEN_LDX_E(ldbr, ld64ur_i64, 0x14, 0x10, PPC_NONE, PPC2_DBRX, CHK_NONE) /* HV/P7 and later only */ GEN_LDX_HVRM(ldcix, ld64_i64, 0x15, 0x1b, PPC_CILDST) From 761a89c6419132e612f7c9f773ea42872134bb88 Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Mon, 12 Sep 2016 12:11:33 +0530 Subject: [PATCH 204/723] target-ppc: consolidate store operations Implement macro to consolidate store operations using newer tcg_gen_qemu_st function. Signed-off-by: Nikunj A Dadhania Signed-off-by: David Gibson --- target-ppc/translate.c | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 0d27067843c..f228ae0ff43 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -2498,30 +2498,27 @@ GEN_QEMU_LOAD_64(ld64, DEF_MEMOP(MO_Q)) GEN_QEMU_LOAD_64(ld64ur, BSWAP_MEMOP(MO_Q)) #endif -static inline void gen_qemu_st8(DisasContext *ctx, TCGv arg1, TCGv arg2) -{ - tcg_gen_qemu_st8(arg1, arg2, ctx->mem_idx); +#define GEN_QEMU_STORE_TL(stop, op) \ +static void glue(gen_qemu_, stop)(DisasContext *ctx, \ + TCGv val, \ + TCGv addr) \ +{ \ + tcg_gen_qemu_st_tl(val, addr, ctx->mem_idx, op); \ } -static inline void gen_qemu_st16(DisasContext *ctx, TCGv arg1, TCGv arg2) -{ - TCGMemOp op = MO_UW | ctx->default_tcg_memop_mask; - tcg_gen_qemu_st_tl(arg1, arg2, ctx->mem_idx, op); -} +GEN_QEMU_STORE_TL(st8, DEF_MEMOP(MO_UB)) +GEN_QEMU_STORE_TL(st16, DEF_MEMOP(MO_UW)) +GEN_QEMU_STORE_TL(st32, DEF_MEMOP(MO_UL)) -static inline void gen_qemu_st32(DisasContext *ctx, TCGv arg1, TCGv arg2) -{ - TCGMemOp op = MO_UL | ctx->default_tcg_memop_mask; - tcg_gen_qemu_st_tl(arg1, arg2, ctx->mem_idx, op); +#define GEN_QEMU_STORE_64(stop, op) \ +static void glue(gen_qemu_, glue(stop, _i64))(DisasContext *ctx, \ + TCGv_i64 val, \ + TCGv addr) \ +{ \ + tcg_gen_qemu_st_i64(val, addr, ctx->mem_idx, op); \ } -static void gen_qemu_st32_i64(DisasContext *ctx, TCGv_i64 val, TCGv addr) -{ - TCGv tmp = tcg_temp_new(); - tcg_gen_trunc_i64_tl(tmp, val); - gen_qemu_st32(ctx, tmp, addr); - tcg_temp_free(tmp); -} +GEN_QEMU_STORE_64(st32, DEF_MEMOP(MO_UL)) static inline void gen_qemu_st64(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2) { From 2468f23dcb5b74ef882f3a3a5dd0a00bf0a71bb7 Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Mon, 12 Sep 2016 12:11:34 +0530 Subject: [PATCH 205/723] target-ppc: convert st64 to use new macro Use macro for st64 as well, this changes the function signature from gen_qemu_st64 => gen_qemu_st64_i64. Replace this at all the call sites. Signed-off-by: Nikunj A Dadhania Signed-off-by: David Gibson --- target-ppc/translate.c | 37 +++++++++++-------------- target-ppc/translate/fp-impl.inc.c | 42 ++++++++++++++--------------- target-ppc/translate/fp-ops.inc.c | 2 +- target-ppc/translate/spe-impl.inc.c | 2 +- target-ppc/translate/vmx-impl.inc.c | 12 ++++----- target-ppc/translate/vsx-impl.inc.c | 6 ++--- 6 files changed, 48 insertions(+), 53 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index f228ae0ff43..254ad4092ea 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -2519,12 +2519,7 @@ static void glue(gen_qemu_, glue(stop, _i64))(DisasContext *ctx, \ } GEN_QEMU_STORE_64(st32, DEF_MEMOP(MO_UL)) - -static inline void gen_qemu_st64(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2) -{ - TCGMemOp op = MO_Q | ctx->default_tcg_memop_mask; - tcg_gen_qemu_st_i64(arg1, arg2, ctx->mem_idx, op); -} +GEN_QEMU_STORE_64(st64, DEF_MEMOP(MO_Q)) #define GEN_LD(name, ldop, opc, type) \ static void glue(gen_, name)(DisasContext *ctx) \ @@ -2769,9 +2764,9 @@ GEN_STS(sth, st16, 0x0C, PPC_INTEGER); /* stw stwu stwux stwx */ GEN_STS(stw, st32, 0x04, PPC_INTEGER); #if defined(TARGET_PPC64) -GEN_STUX(std, st64, 0x15, 0x05, PPC_64B); -GEN_STX(std, st64, 0x15, 0x04, PPC_64B); -GEN_STX_HVRM(stdcix, st64, 0x15, 0x1f, PPC_CILDST) +GEN_STUX(std, st64_i64, 0x15, 0x05, PPC_64B); +GEN_STX(std, st64_i64, 0x15, 0x04, PPC_64B); +GEN_STX_HVRM(stdcix, st64_i64, 0x15, 0x1f, PPC_CILDST) GEN_STX_HVRM(stwcix, st32, 0x15, 0x1c, PPC_CILDST) GEN_STX_HVRM(sthcix, st16, 0x15, 0x1d, PPC_CILDST) GEN_STX_HVRM(stbcix, st8, 0x15, 0x1e, PPC_CILDST) @@ -2808,16 +2803,16 @@ static void gen_std(DisasContext *ctx) EA = tcg_temp_new(); gen_addr_imm_index(ctx, EA, 0x03); - /* We only need to swap high and low halves. gen_qemu_st64 does + /* We only need to swap high and low halves. gen_qemu_st64_i64 does necessary 64-bit byteswap already. */ if (unlikely(ctx->le_mode)) { - gen_qemu_st64(ctx, cpu_gpr[rs+1], EA); + gen_qemu_st64_i64(ctx, cpu_gpr[rs + 1], EA); gen_addr_add(ctx, EA, EA, 8); - gen_qemu_st64(ctx, cpu_gpr[rs], EA); + gen_qemu_st64_i64(ctx, cpu_gpr[rs], EA); } else { - gen_qemu_st64(ctx, cpu_gpr[rs], EA); + gen_qemu_st64_i64(ctx, cpu_gpr[rs], EA); gen_addr_add(ctx, EA, EA, 8); - gen_qemu_st64(ctx, cpu_gpr[rs+1], EA); + gen_qemu_st64_i64(ctx, cpu_gpr[rs + 1], EA); } tcg_temp_free(EA); } else { @@ -2831,7 +2826,7 @@ static void gen_std(DisasContext *ctx) gen_set_access_type(ctx, ACCESS_INT); EA = tcg_temp_new(); gen_addr_imm_index(ctx, EA, 0x03); - gen_qemu_st64(ctx, cpu_gpr[rs], EA); + gen_qemu_st64_i64(ctx, cpu_gpr[rs], EA); if (Rc(ctx->opcode)) tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA); tcg_temp_free(EA); @@ -3113,7 +3108,7 @@ static void gen_conditional_store(DisasContext *ctx, TCGv EA, tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], 1 << CRF_EQ); #if defined(TARGET_PPC64) if (size == 8) { - gen_qemu_st64(ctx, cpu_gpr[reg], EA); + gen_qemu_st64_i64(ctx, cpu_gpr[reg], EA); } else #endif if (size == 4) { @@ -3130,10 +3125,10 @@ static void gen_conditional_store(DisasContext *ctx, TCGv EA, gpr1 = cpu_gpr[reg]; gpr2 = cpu_gpr[reg+1]; } - gen_qemu_st64(ctx, gpr1, EA); + gen_qemu_st64_i64(ctx, gpr1, EA); EA8 = tcg_temp_local_new(); gen_addr_add(ctx, EA8, EA, 8); - gen_qemu_st64(ctx, gpr2, EA8); + gen_qemu_st64_i64(ctx, gpr2, EA8); tcg_temp_free(EA8); #endif } else { @@ -6622,10 +6617,10 @@ GEN_STS(stb, st8, 0x06, PPC_INTEGER) GEN_STS(sth, st16, 0x0C, PPC_INTEGER) GEN_STS(stw, st32, 0x04, PPC_INTEGER) #if defined(TARGET_PPC64) -GEN_STUX(std, st64, 0x15, 0x05, PPC_64B) -GEN_STX(std, st64, 0x15, 0x04, PPC_64B) +GEN_STUX(std, st64_i64, 0x15, 0x05, PPC_64B) +GEN_STX(std, st64_i64, 0x15, 0x04, PPC_64B) GEN_STX_E(stdbr, st64r, 0x14, 0x14, PPC_NONE, PPC2_DBRX, CHK_NONE) -GEN_STX_HVRM(stdcix, st64, 0x15, 0x1f, PPC_CILDST) +GEN_STX_HVRM(stdcix, st64_i64, 0x15, 0x1f, PPC_CILDST) GEN_STX_HVRM(stwcix, st32, 0x15, 0x1c, PPC_CILDST) GEN_STX_HVRM(sthcix, st16, 0x15, 0x1d, PPC_CILDST) GEN_STX_HVRM(stbcix, st8, 0x15, 0x1e, PPC_CILDST) diff --git a/target-ppc/translate/fp-impl.inc.c b/target-ppc/translate/fp-impl.inc.c index 53b7fc74454..872af7b56f1 100644 --- a/target-ppc/translate/fp-impl.inc.c +++ b/target-ppc/translate/fp-impl.inc.c @@ -848,7 +848,7 @@ static inline void gen_qemu_st32fs(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2) } /* stfd stfdu stfdux stfdx */ -GEN_STFS(stfd, st64, 0x16, PPC_FLOAT); +GEN_STFS(stfd, st64_i64, 0x16, PPC_FLOAT); /* stfs stfsu stfsux stfsx */ GEN_STFS(stfs, st32fs, 0x14, PPC_FLOAT); @@ -863,16 +863,16 @@ static void gen_stfdp(DisasContext *ctx) gen_set_access_type(ctx, ACCESS_FLOAT); EA = tcg_temp_new(); gen_addr_imm_index(ctx, EA, 0); - /* We only need to swap high and low halves. gen_qemu_st64 does necessary - 64-bit byteswap already. */ + /* We only need to swap high and low halves. gen_qemu_st64_i64 does + necessary 64-bit byteswap already. */ if (unlikely(ctx->le_mode)) { - gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); + gen_qemu_st64_i64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); tcg_gen_addi_tl(EA, EA, 8); - gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode)], EA); + gen_qemu_st64_i64(ctx, cpu_fpr[rD(ctx->opcode)], EA); } else { - gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode)], EA); + gen_qemu_st64_i64(ctx, cpu_fpr[rD(ctx->opcode)], EA); tcg_gen_addi_tl(EA, EA, 8); - gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); + gen_qemu_st64_i64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); } tcg_temp_free(EA); } @@ -888,16 +888,16 @@ static void gen_stfdpx(DisasContext *ctx) gen_set_access_type(ctx, ACCESS_FLOAT); EA = tcg_temp_new(); gen_addr_reg_index(ctx, EA); - /* We only need to swap high and low halves. gen_qemu_st64 does necessary - 64-bit byteswap already. */ + /* We only need to swap high and low halves. gen_qemu_st64_i64 does + necessary 64-bit byteswap already. */ if (unlikely(ctx->le_mode)) { - gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); + gen_qemu_st64_i64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); tcg_gen_addi_tl(EA, EA, 8); - gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode)], EA); + gen_qemu_st64_i64(ctx, cpu_fpr[rD(ctx->opcode)], EA); } else { - gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode)], EA); + gen_qemu_st64_i64(ctx, cpu_fpr[rD(ctx->opcode)], EA); tcg_gen_addi_tl(EA, EA, 8); - gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); + gen_qemu_st64_i64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); } tcg_temp_free(EA); } @@ -990,9 +990,9 @@ static void gen_stfq(DisasContext *ctx) gen_set_access_type(ctx, ACCESS_FLOAT); t0 = tcg_temp_new(); gen_addr_imm_index(ctx, t0, 0); - gen_qemu_st64(ctx, cpu_fpr[rd], t0); + gen_qemu_st64_i64(ctx, cpu_fpr[rd], t0); gen_addr_add(ctx, t0, t0, 8); - gen_qemu_st64(ctx, cpu_fpr[(rd + 1) % 32], t0); + gen_qemu_st64_i64(ctx, cpu_fpr[(rd + 1) % 32], t0); tcg_temp_free(t0); } @@ -1005,10 +1005,10 @@ static void gen_stfqu(DisasContext *ctx) gen_set_access_type(ctx, ACCESS_FLOAT); t0 = tcg_temp_new(); gen_addr_imm_index(ctx, t0, 0); - gen_qemu_st64(ctx, cpu_fpr[rd], t0); + gen_qemu_st64_i64(ctx, cpu_fpr[rd], t0); t1 = tcg_temp_new(); gen_addr_add(ctx, t1, t0, 8); - gen_qemu_st64(ctx, cpu_fpr[(rd + 1) % 32], t1); + gen_qemu_st64_i64(ctx, cpu_fpr[(rd + 1) % 32], t1); tcg_temp_free(t1); if (ra != 0) tcg_gen_mov_tl(cpu_gpr[ra], t0); @@ -1024,10 +1024,10 @@ static void gen_stfqux(DisasContext *ctx) gen_set_access_type(ctx, ACCESS_FLOAT); t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); - gen_qemu_st64(ctx, cpu_fpr[rd], t0); + gen_qemu_st64_i64(ctx, cpu_fpr[rd], t0); t1 = tcg_temp_new(); gen_addr_add(ctx, t1, t0, 8); - gen_qemu_st64(ctx, cpu_fpr[(rd + 1) % 32], t1); + gen_qemu_st64_i64(ctx, cpu_fpr[(rd + 1) % 32], t1); tcg_temp_free(t1); if (ra != 0) tcg_gen_mov_tl(cpu_gpr[ra], t0); @@ -1042,9 +1042,9 @@ static void gen_stfqx(DisasContext *ctx) gen_set_access_type(ctx, ACCESS_FLOAT); t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); - gen_qemu_st64(ctx, cpu_fpr[rd], t0); + gen_qemu_st64_i64(ctx, cpu_fpr[rd], t0); gen_addr_add(ctx, t0, t0, 8); - gen_qemu_st64(ctx, cpu_fpr[(rd + 1) % 32], t0); + gen_qemu_st64_i64(ctx, cpu_fpr[(rd + 1) % 32], t0); tcg_temp_free(t0); } diff --git a/target-ppc/translate/fp-ops.inc.c b/target-ppc/translate/fp-ops.inc.c index 291a1e62d0c..d36ab4ecc30 100644 --- a/target-ppc/translate/fp-ops.inc.c +++ b/target-ppc/translate/fp-ops.inc.c @@ -85,7 +85,7 @@ GEN_STUF(name, stop, op | 0x21, type) \ GEN_STUXF(name, stop, op | 0x01, type) \ GEN_STXF(name, stop, 0x17, op | 0x00, type) -GEN_STFS(stfd, st64, 0x16, PPC_FLOAT) +GEN_STFS(stfd, st64_i64, 0x16, PPC_FLOAT) GEN_STFS(stfs, st32fs, 0x14, PPC_FLOAT) GEN_STXF(stfiw, st32fiw, 0x17, 0x1E, PPC_FLOAT_STFIWX) GEN_HANDLER_E(stfdp, 0x3D, 0xFF, 0xFF, 0x00200003, PPC_NONE, PPC2_ISA205), diff --git a/target-ppc/translate/spe-impl.inc.c b/target-ppc/translate/spe-impl.inc.c index a969927e9b2..8c1c16c63e8 100644 --- a/target-ppc/translate/spe-impl.inc.c +++ b/target-ppc/translate/spe-impl.inc.c @@ -725,7 +725,7 @@ static inline void gen_op_evstdd(DisasContext *ctx, TCGv addr) { TCGv_i64 t0 = tcg_temp_new_i64(); gen_load_gpr64(t0, rS(ctx->opcode)); - gen_qemu_st64(ctx, t0, addr); + gen_qemu_st64_i64(ctx, t0, addr); tcg_temp_free_i64(t0); } diff --git a/target-ppc/translate/vmx-impl.inc.c b/target-ppc/translate/vmx-impl.inc.c index eb3164bbb87..3ce374d8911 100644 --- a/target-ppc/translate/vmx-impl.inc.c +++ b/target-ppc/translate/vmx-impl.inc.c @@ -52,16 +52,16 @@ static void gen_st##name(DisasContext *ctx) \ EA = tcg_temp_new(); \ gen_addr_reg_index(ctx, EA); \ tcg_gen_andi_tl(EA, EA, ~0xf); \ - /* We only need to swap high and low halves. gen_qemu_st64 does necessary \ - 64-bit byteswap already. */ \ + /* We only need to swap high and low halves. gen_qemu_st64_i64 does \ + necessary 64-bit byteswap already. */ \ if (ctx->le_mode) { \ - gen_qemu_st64(ctx, cpu_avrl[rD(ctx->opcode)], EA); \ + gen_qemu_st64_i64(ctx, cpu_avrl[rD(ctx->opcode)], EA); \ tcg_gen_addi_tl(EA, EA, 8); \ - gen_qemu_st64(ctx, cpu_avrh[rD(ctx->opcode)], EA); \ + gen_qemu_st64_i64(ctx, cpu_avrh[rD(ctx->opcode)], EA); \ } else { \ - gen_qemu_st64(ctx, cpu_avrh[rD(ctx->opcode)], EA); \ + gen_qemu_st64_i64(ctx, cpu_avrh[rD(ctx->opcode)], EA); \ tcg_gen_addi_tl(EA, EA, 8); \ - gen_qemu_st64(ctx, cpu_avrl[rD(ctx->opcode)], EA); \ + gen_qemu_st64_i64(ctx, cpu_avrl[rD(ctx->opcode)], EA); \ } \ tcg_temp_free(EA); \ } diff --git a/target-ppc/translate/vsx-impl.inc.c b/target-ppc/translate/vsx-impl.inc.c index 572579403f7..99cabb2f115 100644 --- a/target-ppc/translate/vsx-impl.inc.c +++ b/target-ppc/translate/vsx-impl.inc.c @@ -115,7 +115,7 @@ static void gen_##name(DisasContext *ctx) \ tcg_temp_free(EA); \ } -VSX_STORE_SCALAR(stxsdx, st64) +VSX_STORE_SCALAR(stxsdx, st64_i64) VSX_STORE_SCALAR(stxsiwx, st32_i64) VSX_STORE_SCALAR(stxsspx, st32fs) @@ -129,9 +129,9 @@ static void gen_stxvd2x(DisasContext *ctx) gen_set_access_type(ctx, ACCESS_INT); EA = tcg_temp_new(); gen_addr_reg_index(ctx, EA); - gen_qemu_st64(ctx, cpu_vsrh(xS(ctx->opcode)), EA); + gen_qemu_st64_i64(ctx, cpu_vsrh(xS(ctx->opcode)), EA); tcg_gen_addi_tl(EA, EA, 8); - gen_qemu_st64(ctx, cpu_vsrl(xS(ctx->opcode)), EA); + gen_qemu_st64_i64(ctx, cpu_vsrl(xS(ctx->opcode)), EA); tcg_temp_free(EA); } From 804108aaf9aa2256534c6ef8e6736934a2ec79c8 Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Mon, 12 Sep 2016 12:11:35 +0530 Subject: [PATCH 206/723] target-ppc: convert st[16,32,64]r to use new macro Make byte-swap routines use the common GEN_QEMU_STORE macro Signed-off-by: Nikunj A Dadhania Signed-off-by: David Gibson --- target-ppc/translate.c | 32 ++++++++++---------------------- 1 file changed, 10 insertions(+), 22 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 254ad4092ea..60668c2d779 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -2510,6 +2510,9 @@ GEN_QEMU_STORE_TL(st8, DEF_MEMOP(MO_UB)) GEN_QEMU_STORE_TL(st16, DEF_MEMOP(MO_UW)) GEN_QEMU_STORE_TL(st32, DEF_MEMOP(MO_UL)) +GEN_QEMU_STORE_TL(st16r, BSWAP_MEMOP(MO_UW)) +GEN_QEMU_STORE_TL(st32r, BSWAP_MEMOP(MO_UL)) + #define GEN_QEMU_STORE_64(stop, op) \ static void glue(gen_qemu_, glue(stop, _i64))(DisasContext *ctx, \ TCGv_i64 val, \ @@ -2521,6 +2524,10 @@ static void glue(gen_qemu_, glue(stop, _i64))(DisasContext *ctx, \ GEN_QEMU_STORE_64(st32, DEF_MEMOP(MO_UL)) GEN_QEMU_STORE_64(st64, DEF_MEMOP(MO_Q)) +#if defined(TARGET_PPC64) +GEN_QEMU_STORE_64(st64r, BSWAP_MEMOP(MO_Q)) +#endif + #define GEN_LD(name, ldop, opc, type) \ static void glue(gen_, name)(DisasContext *ctx) \ { \ @@ -2844,34 +2851,15 @@ GEN_LDX(lwbr, ld32ur, 0x16, 0x10, PPC_INTEGER); #if defined(TARGET_PPC64) /* ldbrx */ GEN_LDX_E(ldbr, ld64ur_i64, 0x14, 0x10, PPC_NONE, PPC2_DBRX, CHK_NONE); +/* stdbrx */ +GEN_STX_E(stdbr, st64r_i64, 0x14, 0x14, PPC_NONE, PPC2_DBRX, CHK_NONE); #endif /* TARGET_PPC64 */ /* sthbrx */ -static inline void gen_qemu_st16r(DisasContext *ctx, TCGv arg1, TCGv arg2) -{ - TCGMemOp op = MO_UW | (ctx->default_tcg_memop_mask ^ MO_BSWAP); - tcg_gen_qemu_st_tl(arg1, arg2, ctx->mem_idx, op); -} GEN_STX(sthbr, st16r, 0x16, 0x1C, PPC_INTEGER); - /* stwbrx */ -static inline void gen_qemu_st32r(DisasContext *ctx, TCGv arg1, TCGv arg2) -{ - TCGMemOp op = MO_UL | (ctx->default_tcg_memop_mask ^ MO_BSWAP); - tcg_gen_qemu_st_tl(arg1, arg2, ctx->mem_idx, op); -} GEN_STX(stwbr, st32r, 0x16, 0x14, PPC_INTEGER); -#if defined(TARGET_PPC64) -/* stdbrx */ -static inline void gen_qemu_st64r(DisasContext *ctx, TCGv arg1, TCGv arg2) -{ - TCGMemOp op = MO_Q | (ctx->default_tcg_memop_mask ^ MO_BSWAP); - tcg_gen_qemu_st_i64(arg1, arg2, ctx->mem_idx, op); -} -GEN_STX_E(stdbr, st64r, 0x14, 0x14, PPC_NONE, PPC2_DBRX, CHK_NONE); -#endif /* TARGET_PPC64 */ - /*** Integer load and store multiple ***/ /* lmw */ @@ -6619,7 +6607,7 @@ GEN_STS(stw, st32, 0x04, PPC_INTEGER) #if defined(TARGET_PPC64) GEN_STUX(std, st64_i64, 0x15, 0x05, PPC_64B) GEN_STX(std, st64_i64, 0x15, 0x04, PPC_64B) -GEN_STX_E(stdbr, st64r, 0x14, 0x14, PPC_NONE, PPC2_DBRX, CHK_NONE) +GEN_STX_E(stdbr, st64r_i64, 0x14, 0x14, PPC_NONE, PPC2_DBRX, CHK_NONE) GEN_STX_HVRM(stdcix, st64_i64, 0x15, 0x1f, PPC_CILDST) GEN_STX_HVRM(stwcix, st32, 0x15, 0x1c, PPC_CILDST) GEN_STX_HVRM(sthcix, st16, 0x15, 0x1d, PPC_CILDST) From 48793c95c963c3def3b6f3ecdbf89ec098d5e494 Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Mon, 12 Sep 2016 12:11:36 +0530 Subject: [PATCH 207/723] target-ppc: consolidate load with reservation Use tcg_gen_qemu_ld in the load with reservation instructions. Signed-off-by: Nikunj A Dadhania Signed-off-by: David Gibson --- target-ppc/translate.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 60668c2d779..72e78ff8ef7 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -3049,28 +3049,30 @@ static void gen_isync(DisasContext *ctx) gen_stop_exception(ctx); } -#define LARX(name, len, loadop) \ +#define MEMOP_GET_SIZE(x) (1 << ((x) & MO_SIZE)) + +#define LARX(name, memop) \ static void gen_##name(DisasContext *ctx) \ { \ TCGv t0; \ TCGv gpr = cpu_gpr[rD(ctx->opcode)]; \ + int len = MEMOP_GET_SIZE(memop); \ gen_set_access_type(ctx, ACCESS_RES); \ t0 = tcg_temp_local_new(); \ gen_addr_reg_index(ctx, t0); \ if ((len) > 1) { \ gen_check_align(ctx, t0, (len)-1); \ } \ - gen_qemu_##loadop(ctx, gpr, t0); \ + tcg_gen_qemu_ld_tl(gpr, t0, ctx->mem_idx, memop); \ tcg_gen_mov_tl(cpu_reserve, t0); \ tcg_gen_st_tl(gpr, cpu_env, offsetof(CPUPPCState, reserve_val)); \ tcg_temp_free(t0); \ } /* lwarx */ -LARX(lbarx, 1, ld8u); -LARX(lharx, 2, ld16u); -LARX(lwarx, 4, ld32u); - +LARX(lbarx, DEF_MEMOP(MO_UB)) +LARX(lharx, DEF_MEMOP(MO_UW)) +LARX(lwarx, DEF_MEMOP(MO_UL)) #if defined(CONFIG_USER_ONLY) static void gen_conditional_store(DisasContext *ctx, TCGv EA, @@ -3152,7 +3154,7 @@ STCX(stwcx_, 4); #if defined(TARGET_PPC64) /* ldarx */ -LARX(ldarx, 8, ld64_i64); +LARX(ldarx, DEF_MEMOP(MO_Q)) /* lqarx */ static void gen_lqarx(DisasContext *ctx) @@ -3178,15 +3180,13 @@ static void gen_lqarx(DisasContext *ctx) gpr1 = cpu_gpr[rd]; gpr2 = cpu_gpr[rd+1]; } - gen_qemu_ld64_i64(ctx, gpr1, EA); + tcg_gen_qemu_ld_i64(gpr1, EA, ctx->mem_idx, DEF_MEMOP(MO_Q)); tcg_gen_mov_tl(cpu_reserve, EA); - gen_addr_add(ctx, EA, EA, 8); - gen_qemu_ld64_i64(ctx, gpr2, EA); + tcg_gen_qemu_ld_i64(gpr2, EA, ctx->mem_idx, DEF_MEMOP(MO_Q)); tcg_gen_st_tl(gpr1, cpu_env, offsetof(CPUPPCState, reserve_val)); tcg_gen_st_tl(gpr2, cpu_env, offsetof(CPUPPCState, reserve_val2)); - tcg_temp_free(EA); } From aa2008af0c1cd26f6a7c522825438f8d1d3de272 Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Mon, 12 Sep 2016 12:11:37 +0530 Subject: [PATCH 208/723] target-ppc: move out stqcx impementation Being a 16byte operation, qemu_ld/st still does not support this. Move this out so other store operation can use qemu_ld/st in the following patch. Also, convert it to two MO_Q operations for stqcx. Signed-off-by: Nikunj A Dadhania Signed-off-by: David Gibson --- target-ppc/translate.c | 69 ++++++++++++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 22 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 72e78ff8ef7..618fe43da72 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -3105,22 +3105,6 @@ static void gen_conditional_store(DisasContext *ctx, TCGv EA, gen_qemu_st32(ctx, cpu_gpr[reg], EA); } else if (size == 2) { gen_qemu_st16(ctx, cpu_gpr[reg], EA); -#if defined(TARGET_PPC64) - } else if (size == 16) { - TCGv gpr1, gpr2 , EA8; - if (unlikely(ctx->le_mode)) { - gpr1 = cpu_gpr[reg+1]; - gpr2 = cpu_gpr[reg]; - } else { - gpr1 = cpu_gpr[reg]; - gpr2 = cpu_gpr[reg+1]; - } - gen_qemu_st64_i64(ctx, gpr1, EA); - EA8 = tcg_temp_local_new(); - gen_addr_add(ctx, EA8, EA, 8); - gen_qemu_st64_i64(ctx, gpr2, EA8); - tcg_temp_free(EA8); -#endif } else { gen_qemu_st8(ctx, cpu_gpr[reg], EA); } @@ -3133,11 +3117,6 @@ static void gen_conditional_store(DisasContext *ctx, TCGv EA, static void gen_##name(DisasContext *ctx) \ { \ TCGv t0; \ - if (unlikely((len == 16) && (rD(ctx->opcode) & 1))) { \ - gen_inval_exception(ctx, \ - POWERPC_EXCP_INVAL_INVAL); \ - return; \ - } \ gen_set_access_type(ctx, ACCESS_RES); \ t0 = tcg_temp_local_new(); \ gen_addr_reg_index(ctx, t0); \ @@ -3190,9 +3169,55 @@ static void gen_lqarx(DisasContext *ctx) tcg_temp_free(EA); } +/* stqcx. */ +static void gen_stqcx_(DisasContext *ctx) +{ + TCGv EA; + int reg = rS(ctx->opcode); + int len = 16; +#if !defined(CONFIG_USER_ONLY) + TCGLabel *l1; + TCGv gpr1, gpr2; +#endif + + if (unlikely((rD(ctx->opcode) & 1))) { + gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); + return; + } + gen_set_access_type(ctx, ACCESS_RES); + EA = tcg_temp_local_new(); + gen_addr_reg_index(ctx, EA); + if (len > 1) { + gen_check_align(ctx, EA, (len) - 1); + } + +#if defined(CONFIG_USER_ONLY) + gen_conditional_store(ctx, EA, reg, 16); +#else + tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_so); + l1 = gen_new_label(); + tcg_gen_brcond_tl(TCG_COND_NE, EA, cpu_reserve, l1); + tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], 1 << CRF_EQ); + + if (unlikely(ctx->le_mode)) { + gpr1 = cpu_gpr[reg + 1]; + gpr2 = cpu_gpr[reg]; + } else { + gpr1 = cpu_gpr[reg]; + gpr2 = cpu_gpr[reg + 1]; + } + tcg_gen_qemu_st_tl(gpr1, EA, ctx->mem_idx, DEF_MEMOP(MO_Q)); + gen_addr_add(ctx, EA, EA, 8); + tcg_gen_qemu_st_tl(gpr2, EA, ctx->mem_idx, DEF_MEMOP(MO_Q)); + + gen_set_label(l1); + tcg_gen_movi_tl(cpu_reserve, -1); +#endif + tcg_temp_free(EA); +} + /* stdcx. */ STCX(stdcx_, 8); -STCX(stqcx_, 16); #endif /* defined(TARGET_PPC64) */ /* sync */ From 2391b3577365bfa16009268a16dc7df9a71460c7 Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Mon, 12 Sep 2016 12:11:38 +0530 Subject: [PATCH 209/723] target-ppc: consolidate store conditional Use tcg_gen_qemu_st store conditional instructions. Signed-off-by: Nikunj A Dadhania Signed-off-by: David Gibson --- target-ppc/translate.c | 58 +++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 34 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 618fe43da72..ecc167482d3 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -3076,19 +3076,19 @@ LARX(lwarx, DEF_MEMOP(MO_UL)) #if defined(CONFIG_USER_ONLY) static void gen_conditional_store(DisasContext *ctx, TCGv EA, - int reg, int size) + int reg, int memop) { TCGv t0 = tcg_temp_new(); tcg_gen_st_tl(EA, cpu_env, offsetof(CPUPPCState, reserve_ea)); - tcg_gen_movi_tl(t0, (size << 5) | reg); + tcg_gen_movi_tl(t0, (MEMOP_GET_SIZE(memop) << 5) | reg); tcg_gen_st_tl(t0, cpu_env, offsetof(CPUPPCState, reserve_info)); tcg_temp_free(t0); gen_exception_err(ctx, POWERPC_EXCP_STCX, 0); } #else static void gen_conditional_store(DisasContext *ctx, TCGv EA, - int reg, int size) + int reg, int memop) { TCGLabel *l1; @@ -3096,44 +3096,36 @@ static void gen_conditional_store(DisasContext *ctx, TCGv EA, l1 = gen_new_label(); tcg_gen_brcond_tl(TCG_COND_NE, EA, cpu_reserve, l1); tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], 1 << CRF_EQ); -#if defined(TARGET_PPC64) - if (size == 8) { - gen_qemu_st64_i64(ctx, cpu_gpr[reg], EA); - } else -#endif - if (size == 4) { - gen_qemu_st32(ctx, cpu_gpr[reg], EA); - } else if (size == 2) { - gen_qemu_st16(ctx, cpu_gpr[reg], EA); - } else { - gen_qemu_st8(ctx, cpu_gpr[reg], EA); - } + tcg_gen_qemu_st_tl(cpu_gpr[reg], EA, ctx->mem_idx, memop); gen_set_label(l1); tcg_gen_movi_tl(cpu_reserve, -1); } #endif -#define STCX(name, len) \ -static void gen_##name(DisasContext *ctx) \ -{ \ - TCGv t0; \ - gen_set_access_type(ctx, ACCESS_RES); \ - t0 = tcg_temp_local_new(); \ - gen_addr_reg_index(ctx, t0); \ - if (len > 1) { \ - gen_check_align(ctx, t0, (len)-1); \ - } \ - gen_conditional_store(ctx, t0, rS(ctx->opcode), len); \ - tcg_temp_free(t0); \ -} - -STCX(stbcx_, 1); -STCX(sthcx_, 2); -STCX(stwcx_, 4); +#define STCX(name, memop) \ +static void gen_##name(DisasContext *ctx) \ +{ \ + TCGv t0; \ + int len = MEMOP_GET_SIZE(memop); \ + gen_set_access_type(ctx, ACCESS_RES); \ + t0 = tcg_temp_local_new(); \ + gen_addr_reg_index(ctx, t0); \ + if (len > 1) { \ + gen_check_align(ctx, t0, (len) - 1); \ + } \ + gen_conditional_store(ctx, t0, rS(ctx->opcode), memop); \ + tcg_temp_free(t0); \ +} + +STCX(stbcx_, DEF_MEMOP(MO_UB)) +STCX(sthcx_, DEF_MEMOP(MO_UW)) +STCX(stwcx_, DEF_MEMOP(MO_UL)) #if defined(TARGET_PPC64) /* ldarx */ LARX(ldarx, DEF_MEMOP(MO_Q)) +/* stdcx. */ +STCX(stdcx_, DEF_MEMOP(MO_Q)) /* lqarx */ static void gen_lqarx(DisasContext *ctx) @@ -3216,8 +3208,6 @@ static void gen_stqcx_(DisasContext *ctx) tcg_temp_free(EA); } -/* stdcx. */ -STCX(stdcx_, 8); #endif /* defined(TARGET_PPC64) */ /* sync */ From f113283525a46c16ee078caeefbc82b26aada86a Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Mon, 12 Sep 2016 12:11:39 +0530 Subject: [PATCH 210/723] target-ppc: add xxspltib instruction xxspltib: VSX Vector Splat Immediate Byte Copy the immediate byte in each byte of target VSR Signed-off-by: Nikunj A Dadhania Signed-off-by: David Gibson --- target-ppc/translate.c | 2 ++ target-ppc/translate/vsx-impl.inc.c | 20 ++++++++++++++++++++ target-ppc/translate/vsx-ops.inc.c | 5 +++++ 3 files changed, 27 insertions(+) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index ecc167482d3..133c53133c8 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -591,6 +591,8 @@ EXTRACT_HELPER(DM, 8, 2); EXTRACT_HELPER(UIM, 16, 2); EXTRACT_HELPER(SHW, 8, 2); EXTRACT_HELPER(SP, 19, 2); +EXTRACT_HELPER(IMM8, 11, 8); + /*****************************************************************************/ /* PowerPC instructions table */ diff --git a/target-ppc/translate/vsx-impl.inc.c b/target-ppc/translate/vsx-impl.inc.c index 99cabb2f115..67f5621e630 100644 --- a/target-ppc/translate/vsx-impl.inc.c +++ b/target-ppc/translate/vsx-impl.inc.c @@ -647,6 +647,26 @@ static void gen_xxspltw(DisasContext *ctx) tcg_temp_free_i64(b2); } +#define pattern(x) (((x) & 0xff) * (~(uint64_t)0 / 0xff)) + +static void gen_xxspltib(DisasContext *ctx) +{ + unsigned char uim8 = IMM8(ctx->opcode); + if (xS(ctx->opcode) < 32) { + if (unlikely(!ctx->altivec_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VPU); + return; + } + } else { + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + } + tcg_gen_movi_i64(cpu_vsrh(xT(ctx->opcode)), pattern(uim8)); + tcg_gen_movi_i64(cpu_vsrl(xT(ctx->opcode)), pattern(uim8)); +} + static void gen_xxsldwi(DisasContext *ctx) { TCGv_i64 xth, xtl; diff --git a/target-ppc/translate/vsx-ops.inc.c b/target-ppc/translate/vsx-ops.inc.c index 8b9da654440..62a62516e6f 100644 --- a/target-ppc/translate/vsx-ops.inc.c +++ b/target-ppc/translate/vsx-ops.inc.c @@ -20,6 +20,10 @@ GEN_HANDLER_E(mfvsrd, 0x1F, 0x13, 0x01, 0x0000F800, PPC_NONE, PPC2_VSX207), GEN_HANDLER_E(mtvsrd, 0x1F, 0x13, 0x05, 0x0000F800, PPC_NONE, PPC2_VSX207), #endif +#define GEN_XX1FORM(name, opc2, opc3, fl2) \ +GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0, opc3, 0, PPC_NONE, fl2), \ +GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 1, opc3, 0, PPC_NONE, fl2) + #define GEN_XX2FORM(name, opc2, opc3, fl2) \ GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0, opc3, 0, PPC_NONE, fl2), \ GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 1, opc3, 0, PPC_NONE, fl2) @@ -222,6 +226,7 @@ VSX_LOGICAL(xxlorc, 0x8, 0x15, PPC2_VSX207), GEN_XX3FORM(xxmrghw, 0x08, 0x02, PPC2_VSX), GEN_XX3FORM(xxmrglw, 0x08, 0x06, PPC2_VSX), GEN_XX2FORM(xxspltw, 0x08, 0x0A, PPC2_VSX), +GEN_XX1FORM(xxspltib, 0x08, 0x0B, PPC2_ISA300), GEN_XX3FORM_DM(xxsldwi, 0x08, 0x00), #define GEN_XXSEL_ROW(opc3) \ From 740ae9a27f97be6f9139905700d949b4184a5df7 Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Mon, 12 Sep 2016 12:11:41 +0530 Subject: [PATCH 211/723] target-ppc: add lxsi[bw]zx instruction lxsibzx - Load VSX Scalar as Integer Byte & Zero Indexed lxsihzx - Load VSX Scalar as Integer Halfword & Zero Indexed Signed-off-by: Nikunj A Dadhania Signed-off-by: David Gibson --- target-ppc/translate.c | 2 ++ target-ppc/translate/vsx-impl.inc.c | 2 ++ target-ppc/translate/vsx-ops.inc.c | 2 ++ 3 files changed, 6 insertions(+) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 133c53133c8..0af517ad036 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -2492,6 +2492,8 @@ static void glue(gen_qemu_, glue(ldop, _i64))(DisasContext *ctx, \ tcg_gen_qemu_ld_i64(val, addr, ctx->mem_idx, op); \ } +GEN_QEMU_LOAD_64(ld8u, DEF_MEMOP(MO_UB)) +GEN_QEMU_LOAD_64(ld16u, DEF_MEMOP(MO_UW)) GEN_QEMU_LOAD_64(ld32u, DEF_MEMOP(MO_UL)) GEN_QEMU_LOAD_64(ld32s, DEF_MEMOP(MO_SL)) GEN_QEMU_LOAD_64(ld64, DEF_MEMOP(MO_Q)) diff --git a/target-ppc/translate/vsx-impl.inc.c b/target-ppc/translate/vsx-impl.inc.c index 67f5621e630..888f2e4e136 100644 --- a/target-ppc/translate/vsx-impl.inc.c +++ b/target-ppc/translate/vsx-impl.inc.c @@ -36,6 +36,8 @@ static void gen_##name(DisasContext *ctx) \ VSX_LOAD_SCALAR(lxsdx, ld64_i64) VSX_LOAD_SCALAR(lxsiwax, ld32s_i64) +VSX_LOAD_SCALAR(lxsibzx, ld8u_i64) +VSX_LOAD_SCALAR(lxsihzx, ld16u_i64) VSX_LOAD_SCALAR(lxsiwzx, ld32u_i64) VSX_LOAD_SCALAR(lxsspx, ld32fs) diff --git a/target-ppc/translate/vsx-ops.inc.c b/target-ppc/translate/vsx-ops.inc.c index 62a62516e6f..4cd742c7ea1 100644 --- a/target-ppc/translate/vsx-ops.inc.c +++ b/target-ppc/translate/vsx-ops.inc.c @@ -1,6 +1,8 @@ GEN_HANDLER_E(lxsdx, 0x1F, 0x0C, 0x12, 0, PPC_NONE, PPC2_VSX), GEN_HANDLER_E(lxsiwax, 0x1F, 0x0C, 0x02, 0, PPC_NONE, PPC2_VSX207), GEN_HANDLER_E(lxsiwzx, 0x1F, 0x0C, 0x00, 0, PPC_NONE, PPC2_VSX207), +GEN_HANDLER_E(lxsibzx, 0x1F, 0x0D, 0x18, 0, PPC_NONE, PPC2_ISA300), +GEN_HANDLER_E(lxsihzx, 0x1F, 0x0D, 0x19, 0, PPC_NONE, PPC2_ISA300), GEN_HANDLER_E(lxsspx, 0x1F, 0x0C, 0x10, 0, PPC_NONE, PPC2_VSX207), GEN_HANDLER_E(lxvd2x, 0x1F, 0x0C, 0x1A, 0, PPC_NONE, PPC2_VSX), GEN_HANDLER_E(lxvdsx, 0x1F, 0x0C, 0x0A, 0, PPC_NONE, PPC2_VSX), From ddb9ac50ae999c8970fc5b145b0830b61d4da3f4 Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Mon, 12 Sep 2016 12:11:42 +0530 Subject: [PATCH 212/723] target-ppc: add stxsi[bh]x instruction stxsibx - Store VSX Scalar as Integer Byte Indexed stxsihx - Store VSX Scalar as Integer Halfword Indexed Signed-off-by: Nikunj A Dadhania Signed-off-by: David Gibson --- target-ppc/translate.c | 2 ++ target-ppc/translate/vsx-impl.inc.c | 3 +++ target-ppc/translate/vsx-ops.inc.c | 2 ++ 3 files changed, 7 insertions(+) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 0af517ad036..e747c1f71ce 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -2525,6 +2525,8 @@ static void glue(gen_qemu_, glue(stop, _i64))(DisasContext *ctx, \ tcg_gen_qemu_st_i64(val, addr, ctx->mem_idx, op); \ } +GEN_QEMU_STORE_64(st8, DEF_MEMOP(MO_UB)) +GEN_QEMU_STORE_64(st16, DEF_MEMOP(MO_UW)) GEN_QEMU_STORE_64(st32, DEF_MEMOP(MO_UL)) GEN_QEMU_STORE_64(st64, DEF_MEMOP(MO_Q)) diff --git a/target-ppc/translate/vsx-impl.inc.c b/target-ppc/translate/vsx-impl.inc.c index 888f2e4e136..eee6052d038 100644 --- a/target-ppc/translate/vsx-impl.inc.c +++ b/target-ppc/translate/vsx-impl.inc.c @@ -118,6 +118,9 @@ static void gen_##name(DisasContext *ctx) \ } VSX_STORE_SCALAR(stxsdx, st64_i64) + +VSX_STORE_SCALAR(stxsibx, st8_i64) +VSX_STORE_SCALAR(stxsihx, st16_i64) VSX_STORE_SCALAR(stxsiwx, st32_i64) VSX_STORE_SCALAR(stxsspx, st32fs) diff --git a/target-ppc/translate/vsx-ops.inc.c b/target-ppc/translate/vsx-ops.inc.c index 4cd742c7ea1..414b73bd104 100644 --- a/target-ppc/translate/vsx-ops.inc.c +++ b/target-ppc/translate/vsx-ops.inc.c @@ -9,6 +9,8 @@ GEN_HANDLER_E(lxvdsx, 0x1F, 0x0C, 0x0A, 0, PPC_NONE, PPC2_VSX), GEN_HANDLER_E(lxvw4x, 0x1F, 0x0C, 0x18, 0, PPC_NONE, PPC2_VSX), GEN_HANDLER_E(stxsdx, 0x1F, 0xC, 0x16, 0, PPC_NONE, PPC2_VSX), +GEN_HANDLER_E(stxsibx, 0x1F, 0xD, 0x1C, 0, PPC_NONE, PPC2_ISA300), +GEN_HANDLER_E(stxsihx, 0x1F, 0xD, 0x1D, 0, PPC_NONE, PPC2_ISA300), GEN_HANDLER_E(stxsiwx, 0x1F, 0xC, 0x04, 0, PPC_NONE, PPC2_VSX207), GEN_HANDLER_E(stxsspx, 0x1F, 0xC, 0x14, 0, PPC_NONE, PPC2_VSX207), GEN_HANDLER_E(stxvd2x, 0x1F, 0xC, 0x1E, 0, PPC_NONE, PPC2_VSX), From fec5c62a6434bc306906972e276c5a6f2cafdd9a Mon Sep 17 00:00:00 2001 From: Ravi Bangoria Date: Fri, 16 Sep 2016 16:21:47 +0530 Subject: [PATCH 213/723] target-ppc: implement darn instruction darn: Deliver A Random Number Currently return invalid random number for all the case. This needs proper algorithm to provide cryptographically suitable random data. Reading from /dev/random can block and that is not an expected behaviour while the cpu instruction is getting executed. Moreover, /dev/random would only work for linux-user Signed-off-by: Ravi Bangoria Signed-off-by: Nikunj A Dadhania [dwg: Added minor clang warning fix for ppc32 target] Signed-off-by: David Gibson --- target-ppc/helper.h | 2 ++ target-ppc/int_helper.c | 16 ++++++++++++++++ target-ppc/translate.c | 20 ++++++++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/target-ppc/helper.h b/target-ppc/helper.h index e75d0701c0e..966f2ce841e 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -50,6 +50,8 @@ DEF_HELPER_FLAGS_1(cnttzd, TCG_CALL_NO_RWG_SE, tl, tl) DEF_HELPER_FLAGS_1(popcntd, TCG_CALL_NO_RWG_SE, tl, tl) DEF_HELPER_FLAGS_2(bpermd, TCG_CALL_NO_RWG_SE, i64, i64, i64) DEF_HELPER_3(srad, tl, env, tl, tl) +DEF_HELPER_0(darn32, tl) +DEF_HELPER_0(darn64, tl) #endif DEF_HELPER_FLAGS_1(cntlsw32, TCG_CALL_NO_RWG_SE, i32, i32) diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c index 291fba03f65..51a9ac51827 100644 --- a/target-ppc/int_helper.c +++ b/target-ppc/int_helper.c @@ -182,6 +182,22 @@ target_ulong helper_cnttzd(target_ulong t) { return ctz64(t); } + +/* Return invalid random number. + * + * FIXME: Add rng backend or other mechanism to get cryptographically suitable + * random number + */ +target_ulong helper_darn32(void) +{ + return -1; +} + +target_ulong helper_darn64(void) +{ + return -1; +} + #endif #if defined(TARGET_PPC64) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index e747c1f71ce..4f33915bdef 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -528,6 +528,10 @@ EXTRACT_HELPER(FPW, 16, 1); /* addpcis */ EXTRACT_HELPER_DXFORM(DX, 10, 6, 6, 5, 16, 1, 1, 0, 0) +#if defined(TARGET_PPC64) +/* darn */ +EXTRACT_HELPER(L, 16, 2); +#endif /*** Jump target decoding ***/ /* Immediate address */ @@ -1895,6 +1899,21 @@ static void gen_cnttzd(DisasContext *ctx) gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); } } + +/* darn */ +static void gen_darn(DisasContext *ctx) +{ + int l = L(ctx->opcode); + + if (l == 0) { + gen_helper_darn32(cpu_gpr[rD(ctx->opcode)]); + } else if (l <= 2) { + /* Return 64-bit random for both CRN and RRN */ + gen_helper_darn64(cpu_gpr[rD(ctx->opcode)]); + } else { + tcg_gen_movi_i64(cpu_gpr[rD(ctx->opcode)], -1); + } +} #endif /*** Integer rotate ***/ @@ -6216,6 +6235,7 @@ GEN_HANDLER_E(prtyw, 0x1F, 0x1A, 0x04, 0x0000F801, PPC_NONE, PPC2_ISA205), GEN_HANDLER(popcntd, 0x1F, 0x1A, 0x0F, 0x0000F801, PPC_POPCNTWD), GEN_HANDLER(cntlzd, 0x1F, 0x1A, 0x01, 0x00000000, PPC_64B), GEN_HANDLER_E(cnttzd, 0x1F, 0x1A, 0x11, 0x00000000, PPC_NONE, PPC2_ISA300), +GEN_HANDLER_E(darn, 0x1F, 0x13, 0x17, 0x001CF801, PPC_NONE, PPC2_ISA300), GEN_HANDLER_E(prtyd, 0x1F, 0x1A, 0x05, 0x0000F801, PPC_NONE, PPC2_ISA205), GEN_HANDLER_E(bpermd, 0x1F, 0x1C, 0x07, 0x00000001, PPC_NONE, PPC2_PERM_ISA206), #endif From 7ebaf7955603cc50988e0eafd5e6074320fefc70 Mon Sep 17 00:00:00 2001 From: Bharata B Rao Date: Mon, 12 Sep 2016 13:27:20 +0530 Subject: [PATCH 214/723] spapr: Introduce sPAPRCPUCoreClass Each spapr cpu core type defines an instance_init routine which just populates the CPU class name. This can be done in the class_init commonly for all core types which simplifies the registration. This is inspired by how PowerNV core types are registered. Certain types of spapr cpu cores ('host' and generic type based on host CPU) are initialized in target-ppc/kvm.c. To convert these type registrations to use class_init, we need to expose spapr_cpu_core_class_init() outside of spapr_cpu_core.c. Commit d11b268e1765 added a generic sPAPR CPU core family type to support cases like POWER8 CPU type on POWER8E host CPU. Switching to class_init would fix such scenarios to use the right CPU thread type instead of defaulting to host-powerpc64-cpu. In an unrelated cleanup, fix a typo in .get_hotplug_handler routine. Signed-off-by: Bharata B Rao Signed-off-by: David Gibson --- hw/ppc/spapr.c | 6 +- hw/ppc/spapr_cpu_core.c | 104 ++++++++++++-------------------- include/hw/ppc/spapr_cpu_core.h | 11 +++- target-ppc/kvm.c | 22 ++----- 4 files changed, 57 insertions(+), 86 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index ca77bb0dea4..79d36b377cd 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -2312,8 +2312,8 @@ static void spapr_machine_device_pre_plug(HotplugHandler *hotplug_dev, } } -static HotplugHandler *spapr_get_hotpug_handler(MachineState *machine, - DeviceState *dev) +static HotplugHandler *spapr_get_hotplug_handler(MachineState *machine, + DeviceState *dev) { if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) || object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) { @@ -2385,7 +2385,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) mc->kvm_type = spapr_kvm_type; mc->has_dynamic_sysbus = true; mc->pci_allow_0_address = true; - mc->get_hotplug_handler = spapr_get_hotpug_handler; + mc->get_hotplug_handler = spapr_get_hotplug_handler; hc->pre_plug = spapr_machine_device_pre_plug; hc->plug = spapr_machine_device_plug; hc->unplug = spapr_machine_device_unplug; diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index bcb483dbe69..6f0533c3425 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -112,7 +112,8 @@ char *spapr_get_cpu_core_type(const char *model) static void spapr_core_release(DeviceState *dev, void *opaque) { sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev)); - const char *typename = object_class_get_name(sc->cpu_class); + sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(OBJECT(dev)); + const char *typename = object_class_get_name(scc->cpu_class); size_t size = object_type_get_instance_size(typename); sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); CPUCore *cc = CPU_CORE(dev); @@ -287,8 +288,9 @@ static void spapr_cpu_core_realize_child(Object *child, Error **errp) static void spapr_cpu_core_realize(DeviceState *dev, Error **errp) { sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev)); + sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(OBJECT(dev)); CPUCore *cc = CPU_CORE(OBJECT(dev)); - const char *typename = object_class_get_name(sc->cpu_class); + const char *typename = object_class_get_name(scc->cpu_class); size_t size = object_type_get_instance_size(typename); Error *local_err = NULL; void *obj; @@ -331,83 +333,43 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp) error_propagate(errp, local_err); } -static void spapr_cpu_core_class_init(ObjectClass *oc, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - dc->realize = spapr_cpu_core_realize; -} - -/* - * instance_init routines from different flavours of sPAPR CPU cores. - */ -#define SPAPR_CPU_CORE_INITFN(_type, _fname) \ -static void glue(glue(spapr_cpu_core_, _fname), _initfn(Object *obj)) \ -{ \ - sPAPRCPUCore *core = SPAPR_CPU_CORE(obj); \ - char *name = g_strdup_printf("%s-" TYPE_POWERPC_CPU, stringify(_type)); \ - ObjectClass *oc = object_class_by_name(name); \ - g_assert(oc); \ - g_free((void *)name); \ - core->cpu_class = oc; \ -} - -SPAPR_CPU_CORE_INITFN(970mp_v1.0, 970MP_v10); -SPAPR_CPU_CORE_INITFN(970mp_v1.1, 970MP_v11); -SPAPR_CPU_CORE_INITFN(970_v2.2, 970); -SPAPR_CPU_CORE_INITFN(POWER5+_v2.1, POWER5plus); -SPAPR_CPU_CORE_INITFN(POWER7_v2.3, POWER7); -SPAPR_CPU_CORE_INITFN(POWER7+_v2.1, POWER7plus); -SPAPR_CPU_CORE_INITFN(POWER8_v2.0, POWER8); -SPAPR_CPU_CORE_INITFN(POWER8E_v2.1, POWER8E); -SPAPR_CPU_CORE_INITFN(POWER8NVL_v1.0, POWER8NVL); - -typedef struct SPAPRCoreInfo { - const char *name; - void (*initfn)(Object *obj); -} SPAPRCoreInfo; - -static const SPAPRCoreInfo spapr_cores[] = { +static const char *spapr_core_models[] = { /* 970 */ - { .name = "970_v2.2", .initfn = spapr_cpu_core_970_initfn }, + "970_v2.2", /* 970MP variants */ - { .name = "970MP_v1.0", .initfn = spapr_cpu_core_970MP_v10_initfn }, - { .name = "970mp_v1.0", .initfn = spapr_cpu_core_970MP_v10_initfn }, - { .name = "970MP_v1.1", .initfn = spapr_cpu_core_970MP_v11_initfn }, - { .name = "970mp_v1.1", .initfn = spapr_cpu_core_970MP_v11_initfn }, + "970MP_v1.0", + "970mp_v1.0", + "970MP_v1.1", + "970mp_v1.1", /* POWER5+ */ - { .name = "POWER5+_v2.1", .initfn = spapr_cpu_core_POWER5plus_initfn }, + "POWER5+_v2.1", /* POWER7 */ - { .name = "POWER7_v2.3", .initfn = spapr_cpu_core_POWER7_initfn }, + "POWER7_v2.3", /* POWER7+ */ - { .name = "POWER7+_v2.1", .initfn = spapr_cpu_core_POWER7plus_initfn }, + "POWER7+_v2.1", /* POWER8 */ - { .name = "POWER8_v2.0", .initfn = spapr_cpu_core_POWER8_initfn }, + "POWER8_v2.0", /* POWER8E */ - { .name = "POWER8E_v2.1", .initfn = spapr_cpu_core_POWER8E_initfn }, + "POWER8E_v2.1", /* POWER8NVL */ - { .name = "POWER8NVL_v1.0", .initfn = spapr_cpu_core_POWER8NVL_initfn }, - - { .name = NULL } + "POWER8NVL_v1.0", }; -static void spapr_cpu_core_register(const SPAPRCoreInfo *info) +void spapr_cpu_core_class_init(ObjectClass *oc, void *data) { - TypeInfo type_info = { - .parent = TYPE_SPAPR_CPU_CORE, - .instance_size = sizeof(sPAPRCPUCore), - .instance_init = info->initfn, - }; - - type_info.name = g_strdup_printf("%s-" TYPE_SPAPR_CPU_CORE, info->name); - type_register(&type_info); - g_free((void *)type_info.name); + DeviceClass *dc = DEVICE_CLASS(oc); + sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_CLASS(oc); + + dc->realize = spapr_cpu_core_realize; + scc->cpu_class = cpu_class_by_name(TYPE_POWERPC_CPU, data); + g_assert(scc->cpu_class); } static const TypeInfo spapr_cpu_core_type_info = { @@ -415,17 +377,27 @@ static const TypeInfo spapr_cpu_core_type_info = { .parent = TYPE_CPU_CORE, .abstract = true, .instance_size = sizeof(sPAPRCPUCore), - .class_init = spapr_cpu_core_class_init, + .class_size = sizeof(sPAPRCPUCoreClass), }; static void spapr_cpu_core_register_types(void) { - const SPAPRCoreInfo *info = spapr_cores; + int i; type_register_static(&spapr_cpu_core_type_info); - while (info->name) { - spapr_cpu_core_register(info); - info++; + + for (i = 0; i < ARRAY_SIZE(spapr_core_models); i++) { + TypeInfo type_info = { + .parent = TYPE_SPAPR_CPU_CORE, + .instance_size = sizeof(sPAPRCPUCore), + .class_init = spapr_cpu_core_class_init, + .class_data = (void *) spapr_core_models[i], + }; + + type_info.name = g_strdup_printf("%s-" TYPE_SPAPR_CPU_CORE, + spapr_core_models[i]); + type_register(&type_info); + g_free((void *)type_info.name); } } diff --git a/include/hw/ppc/spapr_cpu_core.h b/include/hw/ppc/spapr_cpu_core.h index 1c9b3195cce..283969bafbf 100644 --- a/include/hw/ppc/spapr_cpu_core.h +++ b/include/hw/ppc/spapr_cpu_core.h @@ -16,6 +16,10 @@ #define TYPE_SPAPR_CPU_CORE "spapr-cpu-core" #define SPAPR_CPU_CORE(obj) \ OBJECT_CHECK(sPAPRCPUCore, (obj), TYPE_SPAPR_CPU_CORE) +#define SPAPR_CPU_CORE_CLASS(klass) \ + OBJECT_CLASS_CHECK(sPAPRCPUCoreClass, (klass), TYPE_SPAPR_CPU_CORE) +#define SPAPR_CPU_CORE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(sPAPRCPUCoreClass, (obj), TYPE_SPAPR_CPU_CORE) typedef struct sPAPRCPUCore { /*< private >*/ @@ -23,9 +27,13 @@ typedef struct sPAPRCPUCore { /*< public >*/ void *threads; - ObjectClass *cpu_class; } sPAPRCPUCore; +typedef struct sPAPRCPUCoreClass { + DeviceClass parent_class; + ObjectClass *cpu_class; +} sPAPRCPUCoreClass; + void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp); char *spapr_get_cpu_core_type(const char *model); @@ -33,4 +41,5 @@ void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp); void spapr_core_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp); +void spapr_cpu_core_class_init(ObjectClass *oc, void *data); #endif diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index dcb68b90812..445733788d8 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -36,6 +36,7 @@ #include "hw/sysbus.h" #include "hw/ppc/spapr.h" #include "hw/ppc/spapr_vio.h" +#include "hw/ppc/spapr_cpu_core.h" #include "hw/ppc/ppc.h" #include "sysemu/watchdog.h" #include "trace.h" @@ -2364,19 +2365,6 @@ PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void) return pvr_pcc; } -#if defined(TARGET_PPC64) -static void spapr_cpu_core_host_initfn(Object *obj) -{ - sPAPRCPUCore *core = SPAPR_CPU_CORE(obj); - char *name = g_strdup_printf("%s-" TYPE_POWERPC_CPU, "host"); - ObjectClass *oc = object_class_by_name(name); - - g_assert(oc); - g_free((void *)name); - core->cpu_class = oc; -} -#endif - static int kvm_ppc_register_host_cpu_type(void) { TypeInfo type_info = { @@ -2404,14 +2392,16 @@ static int kvm_ppc_register_host_cpu_type(void) #if defined(TARGET_PPC64) type_info.name = g_strdup_printf("%s-"TYPE_SPAPR_CPU_CORE, "host"); type_info.parent = TYPE_SPAPR_CPU_CORE, - type_info.instance_size = sizeof(sPAPRCPUCore), - type_info.instance_init = spapr_cpu_core_host_initfn, - type_info.class_init = NULL; + type_info.instance_size = sizeof(sPAPRCPUCore); + type_info.instance_init = NULL; + type_info.class_init = spapr_cpu_core_class_init; + type_info.class_data = (void *) "host"; type_register(&type_info); g_free((void *)type_info.name); /* Register generic spapr CPU family class for current host CPU type */ type_info.name = g_strdup_printf("%s-"TYPE_SPAPR_CPU_CORE, dc->desc); + type_info.class_data = (void *) dc->desc; type_register(&type_info); g_free((void *)type_info.name); #endif From a8a6d53e3626e96d5a37b9eb6dc6ce759714502e Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Tue, 20 Sep 2016 22:04:59 +0530 Subject: [PATCH 215/723] target-ppc: add TLB_NEED_LOCAL_FLUSH flag Introduces bit-flag in CPUPPCState::tlb_need_flush: TLB_NEED_LOCAL_FLUSH (0x1) - Flush local tlb This would indicate a pending local tlb flush (isync instructions, interrupts, ...) Signed-off-by: Nikunj A Dadhania Reviewed-by: David Gibson Signed-off-by: David Gibson --- target-ppc/cpu.h | 1 + target-ppc/helper_regs.h | 4 ++-- target-ppc/mmu-hash64.c | 4 ++-- target-ppc/mmu_helper.c | 6 +++--- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 96174811969..96d2deffce6 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1009,6 +1009,7 @@ struct CPUPPCState { bool tlb_dirty; /* Set to non-zero when modifying TLB */ bool kvm_sw_tlb; /* non-zero if KVM SW TLB API is active */ uint32_t tlb_need_flush; /* Delayed flush needed */ +#define TLB_NEED_LOCAL_FLUSH 0x1 #endif /* Other registers */ diff --git a/target-ppc/helper_regs.h b/target-ppc/helper_regs.h index 3d279f1d8aa..69204a5645f 100644 --- a/target-ppc/helper_regs.h +++ b/target-ppc/helper_regs.h @@ -157,9 +157,9 @@ static inline int hreg_store_msr(CPUPPCState *env, target_ulong value, static inline void check_tlb_flush(CPUPPCState *env) { CPUState *cs = CPU(ppc_env_get_cpu(env)); - if (env->tlb_need_flush) { - env->tlb_need_flush = 0; + if (env->tlb_need_flush & TLB_NEED_LOCAL_FLUSH) { tlb_flush(cs, 1); + env->tlb_need_flush &= ~TLB_NEED_LOCAL_FLUSH; } } #else diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c index 81181438747..1f52b648c62 100644 --- a/target-ppc/mmu-hash64.c +++ b/target-ppc/mmu-hash64.c @@ -110,7 +110,7 @@ void helper_slbia(CPUPPCState *env) * and we still don't have a tlb_flush_mask(env, n, mask) * in QEMU, we just invalidate all TLBs */ - env->tlb_need_flush = 1; + env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH; } } } @@ -132,7 +132,7 @@ void helper_slbie(CPUPPCState *env, target_ulong addr) * and we still don't have a tlb_flush_mask(env, n, mask) * in QEMU, we just invalidate all TLBs */ - env->tlb_need_flush = 1; + env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH; } } diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c index 696bb03ab5f..d59d2f83d29 100644 --- a/target-ppc/mmu_helper.c +++ b/target-ppc/mmu_helper.c @@ -1965,7 +1965,7 @@ void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr) * we just mark the TLB to be flushed later (context synchronizing * event or sync instruction on 32-bit). */ - env->tlb_need_flush = 1; + env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH; break; #if defined(TARGET_PPC64) case POWERPC_MMU_64B: @@ -1979,7 +1979,7 @@ void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr) * and we still don't have a tlb_flush_mask(env, n, mask) in QEMU, * we just invalidate all TLBs */ - env->tlb_need_flush = 1; + env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH; break; #endif /* defined(TARGET_PPC64) */ default: @@ -2065,7 +2065,7 @@ void helper_store_sr(CPUPPCState *env, target_ulong srnum, target_ulong value) } } #else - env->tlb_need_flush = 1; + env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH; #endif } } From e3cffe6fad29e07d401eabb913a6d88501d5c143 Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Tue, 20 Sep 2016 22:05:00 +0530 Subject: [PATCH 216/723] target-ppc: add flag in check_tlb_flush() We flush the qemu TLB lazily. check_tlb_flush is called whenever we hit a context synchronizing event or instruction that requires a pending flush to be performed. However, we fail to handle broadcast TLB flush operations. In order to fix that efficiently, we want to differentiate whether check_tlb_flush() needs to only apply pending local flushes (isync instructions, interrupts, ...) or also global pending flush operations. The latter is only needed when executing instructions that are defined architecturally as synchronizing global TLB flush operations. This in our case is ptesync on BookS and tlbsync on BookE along with the paravirtualized hypervisor calls. Signed-off-by: Nikunj A Dadhania [dwg: Changed gen_check_tlb_flush() to also take a bool, and fixed some spelling errors in commit message] Signed-off-by: David Gibson --- hw/ppc/spapr_hcall.c | 4 ++-- target-ppc/excp_helper.c | 4 ++-- target-ppc/helper.h | 3 ++- target-ppc/helper_regs.h | 4 ++-- target-ppc/mmu_helper.c | 9 +++++++-- target-ppc/translate.c | 23 +++++++++++++---------- 6 files changed, 28 insertions(+), 19 deletions(-) diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 73af112e1d3..0884e3e8a89 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -201,7 +201,7 @@ static target_ulong h_remove(PowerPCCPU *cpu, sPAPRMachineState *spapr, switch (ret) { case REMOVE_SUCCESS: - check_tlb_flush(env); + check_tlb_flush(env, true); return H_SUCCESS; case REMOVE_NOT_FOUND: @@ -282,7 +282,7 @@ static target_ulong h_bulk_remove(PowerPCCPU *cpu, sPAPRMachineState *spapr, } } exit: - check_tlb_flush(env); + check_tlb_flush(env, true); return rc; } diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c index 04ed4da1f46..921c39d33f2 100644 --- a/target-ppc/excp_helper.c +++ b/target-ppc/excp_helper.c @@ -711,7 +711,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) /* Any interrupt is context synchronizing, check if TCG TLB * needs a delayed flush on ppc64 */ - check_tlb_flush(env); + check_tlb_flush(env, false); } void ppc_cpu_do_interrupt(CPUState *cs) @@ -973,7 +973,7 @@ static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr) cs->interrupt_request |= CPU_INTERRUPT_EXITTB; /* Context synchronizing: check if TCG TLB needs flush */ - check_tlb_flush(env); + check_tlb_flush(env, false); } void helper_rfi(CPUPPCState *env) diff --git a/target-ppc/helper.h b/target-ppc/helper.h index 966f2ce841e..a1c29628bd7 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -18,7 +18,8 @@ DEF_HELPER_1(rfid, void, env) DEF_HELPER_1(hrfid, void, env) DEF_HELPER_2(store_lpcr, void, env, tl) #endif -DEF_HELPER_1(check_tlb_flush, void, env) +DEF_HELPER_1(check_tlb_flush_local, void, env) +DEF_HELPER_1(check_tlb_flush_global, void, env) #endif DEF_HELPER_3(lmw, void, env, tl, i32) diff --git a/target-ppc/helper_regs.h b/target-ppc/helper_regs.h index 69204a5645f..dd85fc5cd0b 100644 --- a/target-ppc/helper_regs.h +++ b/target-ppc/helper_regs.h @@ -154,7 +154,7 @@ static inline int hreg_store_msr(CPUPPCState *env, target_ulong value, } #if !defined(CONFIG_USER_ONLY) -static inline void check_tlb_flush(CPUPPCState *env) +static inline void check_tlb_flush(CPUPPCState *env, bool global) { CPUState *cs = CPU(ppc_env_get_cpu(env)); if (env->tlb_need_flush & TLB_NEED_LOCAL_FLUSH) { @@ -163,7 +163,7 @@ static inline void check_tlb_flush(CPUPPCState *env) } } #else -static inline void check_tlb_flush(CPUPPCState *env) { } +static inline void check_tlb_flush(CPUPPCState *env, bool global) { } #endif #endif /* HELPER_REGS_H */ diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c index d59d2f83d29..0124150a7d9 100644 --- a/target-ppc/mmu_helper.c +++ b/target-ppc/mmu_helper.c @@ -2867,9 +2867,14 @@ void helper_booke206_tlbflush(CPUPPCState *env, target_ulong type) } -void helper_check_tlb_flush(CPUPPCState *env) +void helper_check_tlb_flush_local(CPUPPCState *env) { - check_tlb_flush(env); + check_tlb_flush(env, false); +} + +void helper_check_tlb_flush_global(CPUPPCState *env) +{ + check_tlb_flush(env, true); } /*****************************************************************************/ diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 4f33915bdef..3514f1dc21f 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -3041,7 +3041,7 @@ static void gen_eieio(DisasContext *ctx) } #if !defined(CONFIG_USER_ONLY) -static inline void gen_check_tlb_flush(DisasContext *ctx) +static inline void gen_check_tlb_flush(DisasContext *ctx, bool global) { TCGv_i32 t; TCGLabel *l; @@ -3053,12 +3053,16 @@ static inline void gen_check_tlb_flush(DisasContext *ctx) t = tcg_temp_new_i32(); tcg_gen_ld_i32(t, cpu_env, offsetof(CPUPPCState, tlb_need_flush)); tcg_gen_brcondi_i32(TCG_COND_EQ, t, 0, l); - gen_helper_check_tlb_flush(cpu_env); + if (global) { + gen_helper_check_tlb_flush_global(cpu_env); + } else { + gen_helper_check_tlb_flush_local(cpu_env); + } gen_set_label(l); tcg_temp_free_i32(t); } #else -static inline void gen_check_tlb_flush(DisasContext *ctx) { } +static inline void gen_check_tlb_flush(DisasContext *ctx, bool global) { } #endif /* isync */ @@ -3069,7 +3073,7 @@ static void gen_isync(DisasContext *ctx) * kernel mode however so check MSR_PR */ if (!ctx->pr) { - gen_check_tlb_flush(ctx); + gen_check_tlb_flush(ctx, false); } gen_stop_exception(ctx); } @@ -3249,7 +3253,7 @@ static void gen_sync(DisasContext *ctx) * check MSR_PR as well. */ if (((l == 2) || !(ctx->insns_flags & PPC_64B)) && !ctx->pr) { - gen_check_tlb_flush(ctx); + gen_check_tlb_flush(ctx, true); } } @@ -4458,11 +4462,10 @@ static void gen_tlbsync(DisasContext *ctx) #else CHK_HV; - /* tlbsync is a nop for server, ptesync handles delayed tlb flush, - * embedded however needs to deal with tlbsync. We don't try to be - * fancy and swallow the overhead of checking for both. - */ - gen_check_tlb_flush(ctx); + /* BookS does both ptesync and tlbsync make tlbsync a nop for server */ + if (ctx->insns_flags & PPC_BOOKE) { + gen_check_tlb_flush(ctx, true); + } #endif /* defined(CONFIG_USER_ONLY) */ } From d76ab5e1c7db5f064700b9c3cb0924ccfd9017e5 Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Tue, 20 Sep 2016 22:05:01 +0530 Subject: [PATCH 217/723] target-ppc: tlbie/tlbivax should have global effect tlbie (BookS) and tlbivax (BookE) plus the H_CALLs(pseries) should have a global effect. Introduces TLB_NEED_GLOBAL_FLUSH flag. During lazy tlb flush, after taking care of pending local flushes, check broadcast flush(at context synchronizing event ptesync/tlbsync, etc) is needed. Depending on the bitmask state of the tlb_need_flush, tlb is flushed from other cpus if needed and the flags are cleared. Suggested-by: Benjamin Herrenschmidt Signed-off-by: Nikunj A Dadhania Reviewed-by: David Gibson [dwg: Use 'true' instead of '1' for call to check_tlb_flush()] Signed-off-by: David Gibson --- hw/ppc/spapr_hcall.c | 2 ++ target-ppc/cpu.h | 1 + target-ppc/helper_regs.h | 17 +++++++++++++++++ target-ppc/mmu-hash64.c | 2 +- target-ppc/mmu_helper.c | 10 +++++++--- target-ppc/translate.c | 6 ++++++ 6 files changed, 34 insertions(+), 4 deletions(-) diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 0884e3e8a89..290a7122d40 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -319,6 +319,8 @@ static target_ulong h_protect(PowerPCCPU *cpu, sPAPRMachineState *spapr, ppc_hash64_store_hpte(cpu, pte_index, (v & ~HPTE64_V_VALID) | HPTE64_V_HPTE_DIRTY, 0); ppc_hash64_tlb_flush_hpte(cpu, pte_index, v, r); + /* Flush the tlb */ + check_tlb_flush(env, true); /* Don't need a memory barrier, due to qemu's global lock */ ppc_hash64_store_hpte(cpu, pte_index, v | HPTE64_V_HPTE_DIRTY, r); return H_SUCCESS; diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 96d2deffce6..1c90adb5d7b 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1010,6 +1010,7 @@ struct CPUPPCState { bool kvm_sw_tlb; /* non-zero if KVM SW TLB API is active */ uint32_t tlb_need_flush; /* Delayed flush needed */ #define TLB_NEED_LOCAL_FLUSH 0x1 +#define TLB_NEED_GLOBAL_FLUSH 0x2 #endif /* Other registers */ diff --git a/target-ppc/helper_regs.h b/target-ppc/helper_regs.h index dd85fc5cd0b..bb9ce60436a 100644 --- a/target-ppc/helper_regs.h +++ b/target-ppc/helper_regs.h @@ -161,6 +161,23 @@ static inline void check_tlb_flush(CPUPPCState *env, bool global) tlb_flush(cs, 1); env->tlb_need_flush &= ~TLB_NEED_LOCAL_FLUSH; } + + /* Propagate TLB invalidations to other CPUs when the guest uses broadcast + * TLB invalidation instructions. + */ + if (global && (env->tlb_need_flush & TLB_NEED_GLOBAL_FLUSH)) { + CPUState *other_cs; + CPU_FOREACH(other_cs) { + if (other_cs != cs) { + PowerPCCPU *cpu = POWERPC_CPU(other_cs); + CPUPPCState *other_env = &cpu->env; + + other_env->tlb_need_flush &= ~TLB_NEED_LOCAL_FLUSH; + tlb_flush(other_cs, 1); + } + } + env->tlb_need_flush &= ~TLB_NEED_GLOBAL_FLUSH; + } } #else static inline void check_tlb_flush(CPUPPCState *env, bool global) { } diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c index 1f52b648c62..fdb7a787bf3 100644 --- a/target-ppc/mmu-hash64.c +++ b/target-ppc/mmu-hash64.c @@ -912,7 +912,7 @@ void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu, * invalidate, and we still don't have a tlb_flush_mask(env, n, * mask) in QEMU, we just invalidate all TLBs */ - tlb_flush(CPU(cpu), 1); + cpu->env.tlb_need_flush = TLB_NEED_GLOBAL_FLUSH | TLB_NEED_LOCAL_FLUSH; } void ppc_hash64_update_rmls(CPUPPCState *env) diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c index 0124150a7d9..d09fc0a85fd 100644 --- a/target-ppc/mmu_helper.c +++ b/target-ppc/mmu_helper.c @@ -2757,7 +2757,7 @@ static inline void booke206_invalidate_ea_tlb(CPUPPCState *env, int tlbn, void helper_booke206_tlbivax(CPUPPCState *env, target_ulong address) { - PowerPCCPU *cpu = ppc_env_get_cpu(env); + CPUState *cs; if (address & 0x4) { /* flush all entries */ @@ -2774,11 +2774,15 @@ void helper_booke206_tlbivax(CPUPPCState *env, target_ulong address) if (address & 0x8) { /* flush TLB1 entries */ booke206_invalidate_ea_tlb(env, 1, address); - tlb_flush(CPU(cpu), 1); + CPU_FOREACH(cs) { + tlb_flush(cs, 1); + } } else { /* flush TLB0 entries */ booke206_invalidate_ea_tlb(env, 0, address); - tlb_flush_page(CPU(cpu), address & MAS2_EPN_MASK); + CPU_FOREACH(cs) { + tlb_flush_page(cs, address & MAS2_EPN_MASK); + } } } diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 3514f1dc21f..8eefd8231dd 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -4441,6 +4441,7 @@ static void gen_tlbie(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) GEN_PRIV; #else + TCGv_i32 t1; CHK_HV; if (NARROW_MODE(ctx)) { @@ -4451,6 +4452,11 @@ static void gen_tlbie(DisasContext *ctx) } else { gen_helper_tlbie(cpu_env, cpu_gpr[rB(ctx->opcode)]); } + t1 = tcg_temp_new_i32(); + tcg_gen_ld_i32(t1, cpu_env, offsetof(CPUPPCState, tlb_need_flush)); + tcg_gen_ori_i32(t1, t1, TLB_NEED_GLOBAL_FLUSH); + tcg_gen_st_i32(t1, cpu_env, offsetof(CPUPPCState, tlb_need_flush)); + tcg_temp_free_i32(t1); #endif /* defined(CONFIG_USER_ONLY) */ } From 5145ad4fad099983887c6e6caa2354376005226f Mon Sep 17 00:00:00 2001 From: Nathan Whitehorn Date: Tue, 30 Aug 2016 01:02:47 +0000 Subject: [PATCH 218/723] Enable H_CLEAR_MOD and H_CLEAR_REF hypercalls on KVM/PPC64. These are mandatory per PAPR and available on Linux 4.3 and newer kernels. The calls in question are required to run FreeBSD guests with reasonable performance, so enable them if possible. Signed-off-by: Nathan Whitehorn [dwg: Added a stub to fix compile without KVM (e.g. on x86 host)] Signed-off-by: David Gibson --- hw/ppc/spapr.c | 3 +++ target-ppc/kvm.c | 6 ++++++ target-ppc/kvm_ppc.h | 5 +++++ 3 files changed, 14 insertions(+) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 79d36b377cd..e1769d07473 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1814,6 +1814,9 @@ static void ppc_spapr_init(MachineState *machine) /* Enable H_LOGICAL_CI_* so SLOF can talk to in-kernel devices */ kvmppc_enable_logical_ci_hcalls(); kvmppc_enable_set_mode_hcall(); + + /* H_CLEAR_MOD/_REF are mandatory in PAPR, but off by default */ + kvmppc_enable_clear_ref_mod_hcalls(); } /* allocate RAM */ diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 445733788d8..c89991c78d5 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -2056,6 +2056,12 @@ void kvmppc_enable_set_mode_hcall(void) kvmppc_enable_hcall(kvm_state, H_SET_MODE); } +void kvmppc_enable_clear_ref_mod_hcalls(void) +{ + kvmppc_enable_hcall(kvm_state, H_CLEAR_REF); + kvmppc_enable_hcall(kvm_state, H_CLEAR_MOD); +} + void kvmppc_set_papr(PowerPCCPU *cpu) { CPUState *cs = CPU(cpu); diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index 5461d1082c1..a778184567d 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -24,6 +24,7 @@ int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len); int kvmppc_set_interrupt(PowerPCCPU *cpu, int irq, int level); void kvmppc_enable_logical_ci_hcalls(void); void kvmppc_enable_set_mode_hcall(void); +void kvmppc_enable_clear_ref_mod_hcalls(void); void kvmppc_set_papr(PowerPCCPU *cpu); int kvmppc_set_compat(PowerPCCPU *cpu, uint32_t cpu_version); void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy); @@ -113,6 +114,10 @@ static inline void kvmppc_enable_set_mode_hcall(void) { } +static inline void kvmppc_enable_clear_ref_mod_hcalls(void) +{ +} + static inline void kvmppc_set_papr(PowerPCCPU *cpu) { } From 056b977521a907e9b84c0ad0017a082ff56e69f3 Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Mon, 19 Sep 2016 11:59:29 +0530 Subject: [PATCH 219/723] ppc/xics: account correct irq status Fix inconsistent irq status, because of this in the trace logs, for e.g. LSI status was 0x7, i.e. XICS_STATUS_ASSERTED, XICS_STATUS_SENT and XICS_STATUS_REJECTED all set, which did not make sense. So the REJECTED would have been set in earlier interrupt cycle, and then asserted and sent in this current one. Signed-off-by: Nikunj A Dadhania Signed-off-by: David Gibson --- hw/intc/xics.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/hw/intc/xics.c b/hw/intc/xics.c index cd48f42046f..69162f0328f 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -505,8 +505,11 @@ static void ics_reject(ICSState *ics, int nr) ICSIRQState *irq = ics->irqs + nr - ics->offset; trace_xics_ics_reject(nr, nr - ics->offset); - irq->status |= XICS_STATUS_REJECTED; /* Irrelevant but harmless for LSI */ - irq->status &= ~XICS_STATUS_SENT; /* Irrelevant but harmless for MSI */ + if (irq->flags & XICS_FLAGS_IRQ_MSI) { + irq->status |= XICS_STATUS_REJECTED; + } else if (irq->flags & XICS_FLAGS_IRQ_LSI) { + irq->status &= ~XICS_STATUS_SENT; + } } static void ics_resend(ICSState *ics) From 15ed653fa49a7ddda2034db5d722fd6c2d439dd8 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 19 Sep 2016 11:59:32 +0530 Subject: [PATCH 220/723] ppc/xics: An ICS with offset 0 is assumed to be uninitialized This will make life easier for dealing with dynamically configured ICSes such as PHB3 Signed-off-by: Benjamin Herrenschmidt Reviewed-by: David Gibson Signed-off-by: Nikunj A Dadhania Signed-off-by: David Gibson --- include/hw/ppc/xics.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/hw/ppc/xics.h b/include/hw/ppc/xics.h index 2db9f938d3e..5aac67ad89b 100644 --- a/include/hw/ppc/xics.h +++ b/include/hw/ppc/xics.h @@ -149,7 +149,7 @@ struct ICSState { static inline bool ics_valid_irq(ICSState *ics, uint32_t nr) { - return (nr >= ics->offset) + return (ics->offset != 0) && (nr >= ics->offset) && (nr < (ics->offset + ics->nr_irqs)); } From 0d594f5565837fe2886a8aa307ef8abb65eab8f7 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 21 Sep 2016 11:42:15 +0200 Subject: [PATCH 221/723] ppc/kvm: Mark 64kB page size support as disabled if not available QEMU currently refuses to start with KVM-PR and only prints out qemu: fatal: Unknown MMU model 851972 when being started there. This is because commit 4322e8ced5aaac719 ("ppc: Fix 64K pages support in full emulation") introduced a new POWERPC_MMU_64K bit to indicate support for this page size, but it never gets cleared on KVM-PR if the host kernel does not support this. Thus we've got to turn off this bit in the mmu_model for KVM-PR. Signed-off-by: Thomas Huth Signed-off-by: David Gibson --- target-ppc/kvm.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index c89991c78d5..a18d4d5654b 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -428,6 +428,7 @@ static void kvm_fixup_page_sizes(PowerPCCPU *cpu) CPUPPCState *env = &cpu->env; long rampagesize; int iq, ik, jq, jk; + bool has_64k_pages = false; /* We only handle page sizes for 64-bit server guests for now */ if (!(env->mmu_model & POWERPC_MMU_64)) { @@ -471,6 +472,9 @@ static void kvm_fixup_page_sizes(PowerPCCPU *cpu) ksps->enc[jk].page_shift)) { continue; } + if (ksps->enc[jk].page_shift == 16) { + has_64k_pages = true; + } qsps->enc[jq].page_shift = ksps->enc[jk].page_shift; qsps->enc[jq].pte_enc = ksps->enc[jk].pte_enc; if (++jq >= PPC_PAGE_SIZES_MAX_SZ) { @@ -485,6 +489,9 @@ static void kvm_fixup_page_sizes(PowerPCCPU *cpu) if (!(smmu_info.flags & KVM_PPC_1T_SEGMENTS)) { env->mmu_model &= ~POWERPC_MMU_1TSEG; } + if (!has_64k_pages) { + env->mmu_model &= ~POWERPC_MMU_64K; + } } #else /* defined (TARGET_PPC64) */ From 58eb53083ccac82bc9c8e4b5f0800dcc47d22927 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Wed, 21 Sep 2016 11:57:05 +0200 Subject: [PATCH 222/723] linux-user: ppc64: fix ARCH_206 bit in AT_HWCAP Only the POWER[789] CPUs should have the ARCH_206 bit set. This is what the linux kernel does. I guess this was also the intention of commit 0e019746. We have to make sure all *206 bits are set. Before this patch, the flags check in the GET_FEATURES2 macro returned true if _any_ bit was set. This worked well as long as there was only one bit set in the 'flag' parameter. But as explained before, we have to make sure all bits in the 'flag' parameter are set. Signed-off-by: Michael Walle Signed-off-by: David Gibson --- linux-user/elfload.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 3d751f85239..816272aa327 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -741,8 +741,12 @@ static uint32_t get_elf_hwcap(void) Altivec/FP/SPE support. Anything else is just a bonus. */ #define GET_FEATURE(flag, feature) \ do { if (cpu->env.insns_flags & flag) { features |= feature; } } while (0) -#define GET_FEATURE2(flag, feature) \ - do { if (cpu->env.insns_flags2 & flag) { features |= feature; } } while (0) +#define GET_FEATURE2(flags, feature) \ + do { \ + if ((cpu->env.insns_flags2 & flags) == flags) { \ + features |= feature; \ + } \ + } while (0) GET_FEATURE(PPC_64B, QEMU_PPC_FEATURE_64); GET_FEATURE(PPC_FLOAT, QEMU_PPC_FEATURE_HAS_FPU); GET_FEATURE(PPC_ALTIVEC, QEMU_PPC_FEATURE_HAS_ALTIVEC); From 27a83f8e7ed63ced7e36c47a42f46ab44ee02bd8 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 21 Sep 2016 15:29:26 +1000 Subject: [PATCH 223/723] monitor: fix crash for platforms without a CPU 0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that we allow CPU hot unplug on a few platforms, we can end up in a situation where we don't have a CPU with index 0. Or at least we could, if we didn't have code to explicitly prohibit unplug of CPU 0. Longer term we want to allow CPU 0 unplug, this patch is an early step in allowing this, by removing an assumption in the monitor code that CPU 0 always exists. Signed-off-by: Cédric Le Goater [dwg: Rewrote commit message to better explain background] Reviewed-by: Igor Mammedov Reviewed-by: Eduardo Habkost Reviewed-by: Luiz Capitulino Signed-off-by: David Gibson --- monitor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monitor.c b/monitor.c index 8bb8bbfd151..83c4edfce08 100644 --- a/monitor.c +++ b/monitor.c @@ -1025,7 +1025,7 @@ int monitor_set_cpu(int cpu_index) CPUState *mon_get_cpu(void) { if (!cur_mon->mon_cpu) { - monitor_set_cpu(0); + monitor_set_cpu(first_cpu->cpu_index); } cpu_synchronize_state(cur_mon->mon_cpu); return cur_mon->mon_cpu; From 4814401fa01271235df2ac60fafc831bd3d624f3 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Wed, 27 Jul 2016 18:03:38 +1000 Subject: [PATCH 224/723] spapr_pci: Add numa node id This adds a numa id property to a PHB to allow linking passed PCI device to CPU/memory. It is up to the management stack to do CPU/memory pinning to the node with the actual PCI device. Signed-off-by: Alexey Kardashevskiy [dwg: Renamed property from "node" to "numa_node" to match the similar one in the pxb device] Signed-off-by: David Gibson --- hw/ppc/spapr_pci.c | 13 +++++++++++++ include/hw/pci-host/spapr.h | 2 ++ 2 files changed, 15 insertions(+) diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 949c44fec8f..4f008654d67 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -47,6 +47,7 @@ #include "sysemu/device_tree.h" #include "sysemu/kvm.h" #include "sysemu/hostmem.h" +#include "sysemu/numa.h" #include "hw/vfio/vfio.h" @@ -1544,6 +1545,7 @@ static Property spapr_phb_properties[] = { DEFINE_PROP_BOOL("ddw", sPAPRPHBState, ddw_enabled, true), DEFINE_PROP_UINT64("pgsz", sPAPRPHBState, page_size_mask, (1ULL << 12) | (1ULL << 16)), + DEFINE_PROP_UINT32("numa_node", sPAPRPHBState, numa_node, -1), DEFINE_PROP_END_OF_LIST(), }; @@ -1805,6 +1807,11 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb, cpu_to_be32(1), cpu_to_be32(RTAS_IBM_RESET_PE_DMA_WINDOW) }; + uint32_t associativity[] = {cpu_to_be32(0x4), + cpu_to_be32(0x0), + cpu_to_be32(0x0), + cpu_to_be32(0x0), + cpu_to_be32(phb->numa_node)}; sPAPRTCETable *tcet; PCIBus *bus = PCI_HOST_BRIDGE(phb)->bus; sPAPRFDT s_fdt; @@ -1837,6 +1844,12 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb, &ddw_extensions, sizeof(ddw_extensions))); } + /* Advertise NUMA via ibm,associativity */ + if (nb_numa_nodes > 1) { + _FDT(fdt_setprop(fdt, bus_off, "ibm,associativity", associativity, + sizeof(associativity))); + } + /* Build the interrupt-map, this must matches what is done * in pci_spapr_map_irq */ diff --git a/include/hw/pci-host/spapr.h b/include/hw/pci-host/spapr.h index 1a2b11b322d..30dbd461d49 100644 --- a/include/hw/pci-host/spapr.h +++ b/include/hw/pci-host/spapr.h @@ -75,6 +75,8 @@ struct sPAPRPHBState { bool ddw_enabled; uint64_t page_size_mask; uint64_t dma64_win_addr; + + uint32_t numa_node; }; #define SPAPR_PCI_MAX_INDEX 255 From 0679f98b4035c6c3125fc6720a961bb25f916a7a Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Tue, 20 Sep 2016 08:05:59 -0300 Subject: [PATCH 225/723] docker: Handle exceptions when looking for docker command When trying to run docker tests on a host without the docker command, we get the following Python backtrace: $ make docker-test-quick@centos6 V=1 .../qemu/tests/docker/docker.py build qemu:centos6 .../qemu/tests/docker/dockerfiles/centos6.docker Traceback (most recent call last): File ".../qemu/tests/docker/docker.py", line 339, in sys.exit(main()) File ".../qemu/tests/docker/docker.py", line 336, in main return args.cmdobj.run(args, argv) File ".../qemu/tests/docker/docker.py", line 231, in run dkr = Docker() File ".../qemu/tests/docker/docker.py", line 98, in __init__ self._command = _guess_docker_command() File ".../qemu/tests/docker/docker.py", line 41, in _guess_docker_command stdout=DEVNULL, stderr=DEVNULL) == 0: File "/usr/lib64/python2.7/subprocess.py", line 523, in call return Popen(*popenargs, **kwargs).wait() File "/usr/lib64/python2.7/subprocess.py", line 711, in __init__ errread, errwrite) File "/usr/lib64/python2.7/subprocess.py", line 1343, in _execute_child raise child_exception OSError: [Errno 2] No such file or directory .../qemu/tests/docker/Makefile.include:47: recipe for target 'docker-image-centos6' failed make: *** [docker-image-centos6] Error 1 Change _guess_docker_command() to handle OSError exceptions raised by subprocess.call(), so we will keep looking for other commands and print a better error message. New output will be: $ make docker-test-quick@centos6 V=1 .../qemu/tests/docker/docker.py build qemu:centos6 .../qemu/tests/docker/dockerfiles/centos6.docker Traceback (most recent call last): File ".../qemu/tests/docker/docker.py", line 343, in sys.exit(main()) File ".../qemu/tests/docker/docker.py", line 340, in main return args.cmdobj.run(args, argv) File ".../qemu/tests/docker/docker.py", line 235, in run dkr = Docker() File ".../qemu/tests/docker/docker.py", line 102, in __init__ self._command = _guess_docker_command() File ".../qemu/tests/docker/docker.py", line 49, in _guess_docker_command commands_txt) Exception: Cannot find working docker command. Tried: docker sudo -n docker .../qemu/tests/docker/Makefile.include:47: recipe for target 'docker-image-centos6' failed make: *** [docker-image-centos6] Error 1 Signed-off-by: Eduardo Habkost Message-Id: <1474369559-16903-1-git-send-email-ehabkost@redhat.com> [exceptions.OSError -> OSError and drop the import. - Fam] Signed-off-by: Fam Zheng --- tests/docker/docker.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/docker/docker.py b/tests/docker/docker.py index b85c165130d..71b0d27e18e 100755 --- a/tests/docker/docker.py +++ b/tests/docker/docker.py @@ -37,9 +37,12 @@ def _guess_docker_command(): """ Guess a working docker command or raise exception if not found""" commands = [["docker"], ["sudo", "-n", "docker"]] for cmd in commands: - if subprocess.call(cmd + ["images"], - stdout=DEVNULL, stderr=DEVNULL) == 0: - return cmd + try: + if subprocess.call(cmd + ["images"], + stdout=DEVNULL, stderr=DEVNULL) == 0: + return cmd + except OSError: + pass commands_txt = "\n".join([" " + " ".join(x) for x in commands]) raise Exception("Cannot find working docker command. Tried:\n%s" % \ commands_txt) From cea25275a3590cdee774a1230f4b99f6c5c0eaa8 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 21 Sep 2016 12:27:14 +0800 Subject: [PATCH 226/723] util: Add UUID API A number of different places across the code base use CONFIG_UUID. Some of them are soft dependency, some are not built if libuuid is not available, some come with dummy fallback, some throws runtime error. It is hard to maintain, and hard to reason for users. Since UUID is a simple standard with only a small number of operations, it is cleaner to have a central support in libqemuutil. This patch adds qemu_uuid_* functions that all uuid users in the code base can rely on. Except for qemu_uuid_generate which is new code, all other functions are just copy from existing fallbacks from other files. Note that qemu_uuid_parse is moved without updating the function signature to use QemuUUID, to keep this patch simple. Signed-off-by: Fam Zheng Reviewed-by: Eric Blake Reviewed-by: Jeff Cody Message-Id: <1474432046-325-2-git-send-email-famz@redhat.com> --- arch_init.c | 19 --------- block/iscsi.c | 2 +- hw/smbios/smbios.c | 1 + include/qemu/uuid.h | 59 ++++++++++++++++++++++++++ include/sysemu/sysemu.h | 4 -- qmp.c | 1 + stubs/uuid.c | 2 +- util/Makefile.objs | 1 + util/uuid.c | 91 +++++++++++++++++++++++++++++++++++++++++ vl.c | 1 + 10 files changed, 156 insertions(+), 25 deletions(-) create mode 100644 include/qemu/uuid.h create mode 100644 util/uuid.c diff --git a/arch_init.c b/arch_init.c index fa059731ed3..5cc58b2c350 100644 --- a/arch_init.c +++ b/arch_init.c @@ -235,25 +235,6 @@ void audio_init(void) } } -int qemu_uuid_parse(const char *str, uint8_t *uuid) -{ - int ret; - - if (strlen(str) != 36) { - return -1; - } - - ret = sscanf(str, UUID_FMT, &uuid[0], &uuid[1], &uuid[2], &uuid[3], - &uuid[4], &uuid[5], &uuid[6], &uuid[7], &uuid[8], &uuid[9], - &uuid[10], &uuid[11], &uuid[12], &uuid[13], &uuid[14], - &uuid[15]); - - if (ret != 16) { - return -1; - } - return 0; -} - void do_acpitable_option(const QemuOpts *opts) { #ifdef TARGET_I386 diff --git a/block/iscsi.c b/block/iscsi.c index c4a09374192..40f88a24901 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -36,7 +36,7 @@ #include "block/block_int.h" #include "block/scsi.h" #include "qemu/iov.h" -#include "sysemu/sysemu.h" +#include "qemu/uuid.h" #include "qmp-commands.h" #include "qapi/qmp/qstring.h" #include "crypto/secret.h" diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c index 74c71029294..0705eb1dbde 100644 --- a/hw/smbios/smbios.c +++ b/hw/smbios/smbios.c @@ -20,6 +20,7 @@ #include "qemu/config-file.h" #include "qemu/error-report.h" #include "sysemu/sysemu.h" +#include "qemu/uuid.h" #include "sysemu/cpus.h" #include "hw/smbios/smbios.h" #include "hw/loader.h" diff --git a/include/qemu/uuid.h b/include/qemu/uuid.h new file mode 100644 index 00000000000..bc0601e65bf --- /dev/null +++ b/include/qemu/uuid.h @@ -0,0 +1,59 @@ +/* + * QEMU UUID functions + * + * Copyright 2016 Red Hat, Inc. + * + * Authors: + * Fam Zheng + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ + +#ifndef QEMU_UUID_H +#define QEMU_UUID_H + +#include "qemu-common.h" + +/* Version 4 UUID (pseudo random numbers), RFC4122 4.4. */ + +typedef struct { + union { + unsigned char data[16]; + struct { + /* Generated in BE endian, can be swapped with qemu_uuid_bswap. */ + uint32_t time_low; + uint16_t time_mid; + uint16_t time_high_and_version; + uint8_t clock_seq_and_reserved; + uint8_t clock_seq_low; + uint8_t node[6]; + } fields; + }; +} QemuUUID; + +#define UUID_FMT "%02hhx%02hhx%02hhx%02hhx-" \ + "%02hhx%02hhx-%02hhx%02hhx-" \ + "%02hhx%02hhx-" \ + "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx" + +#define UUID_FMT_LEN 36 + +#define UUID_NONE "00000000-0000-0000-0000-000000000000" + +void qemu_uuid_generate(QemuUUID *out); + +int qemu_uuid_is_null(const QemuUUID *uu); + +void qemu_uuid_unparse(const QemuUUID *uuid, char *out); + +char *qemu_uuid_unparse_strdup(const QemuUUID *uuid); + +int qemu_uuid_parse(const char *str, uint8_t *uuid); + +void qemu_uuid_bswap(QemuUUID *uuid); + +#endif diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index ee7c7608e07..6111950d512 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -18,10 +18,6 @@ extern const char *bios_name; extern const char *qemu_name; extern uint8_t qemu_uuid[]; extern bool qemu_uuid_set; -int qemu_uuid_parse(const char *str, uint8_t *uuid); - -#define UUID_FMT "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx" -#define UUID_NONE "00000000-0000-0000-0000-000000000000" bool runstate_check(RunState state); void runstate_set(RunState new_state); diff --git a/qmp.c b/qmp.c index 6733463fa23..524da629f85 100644 --- a/qmp.c +++ b/qmp.c @@ -18,6 +18,7 @@ #include "qemu/cutils.h" #include "monitor/monitor.h" #include "sysemu/sysemu.h" +#include "qemu/uuid.h" #include "qmp-commands.h" #include "sysemu/char.h" #include "ui/qemu-spice.h" diff --git a/stubs/uuid.c b/stubs/uuid.c index 92ad7178310..a880de8d61d 100644 --- a/stubs/uuid.c +++ b/stubs/uuid.c @@ -1,6 +1,6 @@ #include "qemu/osdep.h" #include "qemu-common.h" -#include "sysemu/sysemu.h" +#include "qemu/uuid.h" #include "qmp-commands.h" UuidInfo *qmp_query_uuid(Error **errp) diff --git a/util/Makefile.objs b/util/Makefile.objs index ffca8f30026..36c7dcc1fa1 100644 --- a/util/Makefile.objs +++ b/util/Makefile.objs @@ -21,6 +21,7 @@ util-obj-y += iov.o qemu-config.o qemu-sockets.o uri.o notify.o util-obj-y += qemu-option.o qemu-progress.o util-obj-y += hexdump.o util-obj-y += crc32c.o +util-obj-y += uuid.o util-obj-y += throttle.o util-obj-y += getauxval.o util-obj-y += readline.o diff --git a/util/uuid.c b/util/uuid.c new file mode 100644 index 00000000000..68159044356 --- /dev/null +++ b/util/uuid.c @@ -0,0 +1,91 @@ +/* + * QEMU UUID functions + * + * Copyright 2016 Red Hat, Inc. + * + * Authors: + * Fam Zheng + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "qemu/uuid.h" +#include "qemu/bswap.h" + +void qemu_uuid_generate(QemuUUID *uuid) +{ + int i; + uint32_t tmp[4]; + + QEMU_BUILD_BUG_ON(sizeof(QemuUUID) != 16); + + for (i = 0; i < 4; ++i) { + tmp[i] = g_random_int(); + } + memcpy(uuid, tmp, sizeof(tmp)); + /* Set the two most significant bits (bits 6 and 7) of the + clock_seq_hi_and_reserved to zero and one, respectively. */ + uuid->data[8] = (uuid->data[8] & 0x3f) | 0x80; + /* Set the four most significant bits (bits 12 through 15) of the + time_hi_and_version field to the 4-bit version number. + */ + uuid->data[6] = (uuid->data[6] & 0xf) | 0x40; +} + +int qemu_uuid_is_null(const QemuUUID *uu) +{ + QemuUUID null_uuid = { 0 }; + return memcmp(uu, &null_uuid, sizeof(QemuUUID)) == 0; +} + +void qemu_uuid_unparse(const QemuUUID *uuid, char *out) +{ + const unsigned char *uu = &uuid->data[0]; + snprintf(out, UUID_FMT_LEN + 1, UUID_FMT, + uu[0], uu[1], uu[2], uu[3], uu[4], uu[5], uu[6], uu[7], + uu[8], uu[9], uu[10], uu[11], uu[12], uu[13], uu[14], uu[15]); +} + +char *qemu_uuid_unparse_strdup(const QemuUUID *uuid) +{ + const unsigned char *uu = &uuid->data[0]; + return g_strdup_printf(UUID_FMT, + uu[0], uu[1], uu[2], uu[3], uu[4], uu[5], uu[6], + uu[7], uu[8], uu[9], uu[10], uu[11], uu[12], + uu[13], uu[14], uu[15]); +} + +int qemu_uuid_parse(const char *str, uint8_t *uuid) +{ + int ret; + + if (strlen(str) != 36) { + return -1; + } + + ret = sscanf(str, UUID_FMT, &uuid[0], &uuid[1], &uuid[2], &uuid[3], + &uuid[4], &uuid[5], &uuid[6], &uuid[7], &uuid[8], &uuid[9], + &uuid[10], &uuid[11], &uuid[12], &uuid[13], &uuid[14], + &uuid[15]); + + if (ret != 16) { + return -1; + } + return 0; +} + +/* Swap from UUID format endian (BE) to the opposite or vice versa. + */ +void qemu_uuid_bswap(QemuUUID *uuid) +{ + assert(QEMU_PTR_IS_ALIGNED(uuid, sizeof(uint32_t))); + bswap32s(&uuid->fields.time_low); + bswap16s(&uuid->fields.time_mid); + bswap16s(&uuid->fields.time_high_and_version); +} diff --git a/vl.c b/vl.c index fd321e2fd44..38395019f12 100644 --- a/vl.c +++ b/vl.c @@ -25,6 +25,7 @@ #include "qemu-version.h" #include "qemu/cutils.h" #include "qemu/help_option.h" +#include "qemu/uuid.h" #ifdef CONFIG_SECCOMP #include "sysemu/seccomp.h" From 3630be75d8eda7811f5783d1dc50f4d8682fdaec Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 21 Sep 2016 12:27:15 +0800 Subject: [PATCH 227/723] uuid: Make null_uuid static So that it doesn't have to be zeroed at each call. Suggested-by: Eric Blake Signed-off-by: Fam Zheng Reviewed-by: Jeff Cody Message-Id: <1474432046-325-3-git-send-email-famz@redhat.com> --- util/uuid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/uuid.c b/util/uuid.c index 68159044356..f0c1eeb527b 100644 --- a/util/uuid.c +++ b/util/uuid.c @@ -40,7 +40,7 @@ void qemu_uuid_generate(QemuUUID *uuid) int qemu_uuid_is_null(const QemuUUID *uu) { - QemuUUID null_uuid = { 0 }; + static QemuUUID null_uuid; return memcmp(uu, &null_uuid, sizeof(QemuUUID)) == 0; } From cb6414dfec8a308e68529b0fd2a454403c05bbb3 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 21 Sep 2016 12:27:16 +0800 Subject: [PATCH 228/723] vhdx: Use QEMU UUID API This removes our dependency to libuuid, so that the driver can always be built. Similar to how we handled data plane configure options, --enable-vhdx and --disable-vhdx are also changed to a nop with a message saying it's obsolete. Signed-off-by: Fam Zheng Reviewed-by: Eric Blake Reviewed-by: Jeff Cody Message-Id: <1474432046-325-4-git-send-email-famz@redhat.com> --- block/Makefile.objs | 2 +- block/vhdx-endian.c | 3 --- block/vhdx.c | 9 ++++----- configure | 27 +++------------------------ 4 files changed, 8 insertions(+), 33 deletions(-) diff --git a/block/Makefile.objs b/block/Makefile.objs index cb158e9275f..7d4031dae5c 100644 --- a/block/Makefile.objs +++ b/block/Makefile.objs @@ -2,7 +2,7 @@ block-obj-y += raw_bsd.o qcow.o vdi.o vmdk.o cloop.o bochs.o vpc.o vvfat.o dmg.o block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o block-obj-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o block-obj-y += qed-check.o -block-obj-$(CONFIG_VHDX) += vhdx.o vhdx-endian.o vhdx-log.o +block-obj-y += vhdx.o vhdx-endian.o vhdx-log.o block-obj-y += quorum.o block-obj-y += parallels.o blkdebug.o blkverify.o blkreplay.o block-obj-y += block-backend.o snapshot.o qapi.o diff --git a/block/vhdx-endian.c b/block/vhdx-endian.c index c306b90d544..429d7556bdf 100644 --- a/block/vhdx-endian.c +++ b/block/vhdx-endian.c @@ -21,9 +21,6 @@ #include "qemu/bswap.h" #include "block/vhdx.h" -#include - - /* * All the VHDX formats on disk are little endian - the following * are helper import/export functions to correctly convert diff --git a/block/vhdx.c b/block/vhdx.c index 75ef2b1c2d7..0ba2f0a2f9d 100644 --- a/block/vhdx.c +++ b/block/vhdx.c @@ -25,8 +25,7 @@ #include "qemu/bswap.h" #include "block/vhdx.h" #include "migration/migration.h" - -#include +#include "qemu/uuid.h" /* Options for VHDX creation */ @@ -213,11 +212,11 @@ bool vhdx_checksum_is_valid(uint8_t *buf, size_t size, int crc_offset) */ void vhdx_guid_generate(MSGUID *guid) { - uuid_t uuid; + QemuUUID uuid; assert(guid != NULL); - uuid_generate(uuid); - memcpy(guid, uuid, sizeof(MSGUID)); + qemu_uuid_generate(&uuid); + memcpy(guid, &uuid, sizeof(MSGUID)); } /* Check for region overlaps inside the VHDX image */ diff --git a/configure b/configure index 2efc3382e15..e4f70f150c2 100755 --- a/configure +++ b/configure @@ -317,7 +317,6 @@ vte="" virglrenderer="" tpm="yes" libssh2="" -vhdx="" numa="" tcmalloc="no" jemalloc="no" @@ -1103,6 +1102,9 @@ for opt do --disable-virtio-blk-data-plane|--enable-virtio-blk-data-plane) echo "$0: $opt is obsolete, virtio-blk data-plane is always on" >&2 ;; + --enable-vhdx|--disable-vhdx) + echo "$0: $opt is obsolete, VHDX driver is always built" >&2 + ;; --disable-gtk) gtk="no" ;; --enable-gtk) gtk="yes" @@ -1143,10 +1145,6 @@ for opt do ;; --enable-libssh2) libssh2="yes" ;; - --enable-vhdx) vhdx="yes" - ;; - --disable-vhdx) vhdx="no" - ;; --disable-numa) numa="no" ;; --enable-numa) numa="yes" @@ -1389,7 +1387,6 @@ disabled with --disable-FEATURE, default is enabled if available: archipelago Archipelago backend tpm TPM support libssh2 ssh block device support - vhdx support for the Microsoft VHDX image format numa libnuma support tcmalloc tcmalloc support jemalloc jemalloc support @@ -2690,19 +2687,6 @@ EOF fi fi -if test "$vhdx" = "yes" ; then - if test "$uuid" = "no" ; then - error_exit "uuid required for VHDX support" - fi -elif test "$vhdx" != "no" ; then - if test "$uuid" = "yes" ; then - vhdx=yes - else - vhdx=no - fi -fi - -########################################## # xfsctl() probe, used for raw-posix if test "$xfs" != "no" ; then cat > $TMPC << EOF @@ -4917,7 +4901,6 @@ echo "TPM support $tpm" echo "libssh2 support $libssh2" echo "TPM passthrough $tpm_passthrough" echo "QOM debugging $qom_cast_debug" -echo "vhdx $vhdx" echo "lzo support $lzo" echo "snappy support $snappy" echo "bzip2 support $bzip2" @@ -5443,10 +5426,6 @@ if test "$libssh2" = "yes" ; then echo "LIBSSH2_LIBS=$libssh2_libs" >> $config_host_mak fi -if test "$vhdx" = "yes" ; then - echo "CONFIG_VHDX=y" >> $config_host_mak -fi - # USB host support if test "$libusb" = "yes"; then echo "HOST_USB=libusb legacy" >> $config_host_mak From 7c6f55b69714a0cb9fdf5a80f0c23e87127e01a8 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 21 Sep 2016 12:27:17 +0800 Subject: [PATCH 229/723] vdi: Use QEMU UUID API The UUID operations we need from libuuid are fully supported by QEMU UUID implementation. Use it, and remove the unused code. Signed-off-by: Fam Zheng Reviewed-by: Eric Blake Reviewed-by: Jeff Cody Message-Id: <1474432046-325-5-git-send-email-famz@redhat.com> --- block/vdi.c | 73 +++++++++++++---------------------------------------- 1 file changed, 17 insertions(+), 56 deletions(-) diff --git a/block/vdi.c b/block/vdi.c index 8a1cf979288..96b78d5a43f 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -58,14 +58,7 @@ #include "migration/migration.h" #include "qemu/coroutine.h" #include "qemu/cutils.h" - -#if defined(CONFIG_UUID) -#include -#else -/* TODO: move uuid emulation to some central place in QEMU. */ -#include "sysemu/sysemu.h" /* UUID_FMT */ -typedef unsigned char uuid_t[16]; -#endif +#include "qemu/uuid.h" /* Code configuration options. */ @@ -140,28 +133,6 @@ typedef unsigned char uuid_t[16]; #define VDI_DISK_SIZE_MAX ((uint64_t)VDI_BLOCKS_IN_IMAGE_MAX * \ (uint64_t)DEFAULT_CLUSTER_SIZE) -#if !defined(CONFIG_UUID) -static inline void uuid_generate(uuid_t out) -{ - memset(out, 0, sizeof(uuid_t)); -} - -static inline int uuid_is_null(const uuid_t uu) -{ - uuid_t null_uuid = { 0 }; - return memcmp(uu, null_uuid, sizeof(uuid_t)) == 0; -} - -# if defined(CONFIG_VDI_DEBUG) -static inline void uuid_unparse(const uuid_t uu, char *out) -{ - snprintf(out, 37, UUID_FMT, - uu[0], uu[1], uu[2], uu[3], uu[4], uu[5], uu[6], uu[7], - uu[8], uu[9], uu[10], uu[11], uu[12], uu[13], uu[14], uu[15]); -} -# endif -#endif - typedef struct { char text[0x40]; uint32_t signature; @@ -182,10 +153,10 @@ typedef struct { uint32_t block_extra; /* unused here */ uint32_t blocks_in_image; uint32_t blocks_allocated; - uuid_t uuid_image; - uuid_t uuid_last_snap; - uuid_t uuid_link; - uuid_t uuid_parent; + QemuUUID uuid_image; + QemuUUID uuid_last_snap; + QemuUUID uuid_link; + QemuUUID uuid_parent; uint64_t unused2[7]; } QEMU_PACKED VdiHeader; @@ -206,16 +177,6 @@ typedef struct { Error *migration_blocker; } BDRVVdiState; -/* Change UUID from little endian (IPRT = VirtualBox format) to big endian - * format (network byte order, standard, see RFC 4122) and vice versa. - */ -static void uuid_convert(uuid_t uuid) -{ - bswap32s((uint32_t *)&uuid[0]); - bswap16s((uint16_t *)&uuid[4]); - bswap16s((uint16_t *)&uuid[6]); -} - static void vdi_header_to_cpu(VdiHeader *header) { le32_to_cpus(&header->signature); @@ -234,10 +195,10 @@ static void vdi_header_to_cpu(VdiHeader *header) le32_to_cpus(&header->block_extra); le32_to_cpus(&header->blocks_in_image); le32_to_cpus(&header->blocks_allocated); - uuid_convert(header->uuid_image); - uuid_convert(header->uuid_last_snap); - uuid_convert(header->uuid_link); - uuid_convert(header->uuid_parent); + qemu_uuid_bswap(&header->uuid_image); + qemu_uuid_bswap(&header->uuid_last_snap); + qemu_uuid_bswap(&header->uuid_link); + qemu_uuid_bswap(&header->uuid_parent); } static void vdi_header_to_le(VdiHeader *header) @@ -258,10 +219,10 @@ static void vdi_header_to_le(VdiHeader *header) cpu_to_le32s(&header->block_extra); cpu_to_le32s(&header->blocks_in_image); cpu_to_le32s(&header->blocks_allocated); - uuid_convert(header->uuid_image); - uuid_convert(header->uuid_last_snap); - uuid_convert(header->uuid_link); - uuid_convert(header->uuid_parent); + qemu_uuid_bswap(&header->uuid_image); + qemu_uuid_bswap(&header->uuid_last_snap); + qemu_uuid_bswap(&header->uuid_link); + qemu_uuid_bswap(&header->uuid_parent); } #if defined(CONFIG_VDI_DEBUG) @@ -469,11 +430,11 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags, (uint64_t)header.blocks_in_image * header.block_size); ret = -ENOTSUP; goto fail; - } else if (!uuid_is_null(header.uuid_link)) { + } else if (!qemu_uuid_is_null(&header.uuid_link)) { error_setg(errp, "unsupported VDI image (non-NULL link UUID)"); ret = -ENOTSUP; goto fail; - } else if (!uuid_is_null(header.uuid_parent)) { + } else if (!qemu_uuid_is_null(&header.uuid_parent)) { error_setg(errp, "unsupported VDI image (non-NULL parent UUID)"); ret = -ENOTSUP; goto fail; @@ -821,8 +782,8 @@ static int vdi_create(const char *filename, QemuOpts *opts, Error **errp) if (image_type == VDI_TYPE_STATIC) { header.blocks_allocated = blocks; } - uuid_generate(header.uuid_image); - uuid_generate(header.uuid_last_snap); + qemu_uuid_generate(&header.uuid_image); + qemu_uuid_generate(&header.uuid_last_snap); /* There is no need to set header.uuid_link or header.uuid_parent here. */ #if defined(CONFIG_VDI_DEBUG) vdi_header_print(&header); From 38440a21fa662767e58db0d5f8b71a0e1f00dc46 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 21 Sep 2016 12:27:18 +0800 Subject: [PATCH 230/723] vpc: Use QEMU UUID API Previously we conditionally generated footer->uuid, when libuuid was available. Now that we have a built-in implementation, we can switch to it. Signed-off-by: Fam Zheng Reviewed-by: Eric Blake Reviewed-by: Jeff Cody Message-Id: <1474432046-325-6-git-send-email-famz@redhat.com> --- block/vpc.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/block/vpc.c b/block/vpc.c index 43707ed22cd..8d5886f003e 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -30,9 +30,7 @@ #include "qemu/module.h" #include "migration/migration.h" #include "qemu/bswap.h" -#if defined(CONFIG_UUID) -#include -#endif +#include "qemu/uuid.h" /**************************************************************/ @@ -89,7 +87,7 @@ typedef struct vhd_footer { uint32_t checksum; /* UUID used to identify a parent hard disk (backing file) */ - uint8_t uuid[16]; + QemuUUID uuid; uint8_t in_saved_state; } QEMU_PACKED VHDFooter; @@ -980,9 +978,7 @@ static int vpc_create(const char *filename, QemuOpts *opts, Error **errp) footer->type = cpu_to_be32(disk_type); -#if defined(CONFIG_UUID) - uuid_generate(footer->uuid); -#endif + qemu_uuid_generate(&footer->uuid); footer->checksum = cpu_to_be32(vpc_checksum(buf, HEADER_SIZE)); From 2ef950f91d1c439da0aad6629521825523578dce Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 21 Sep 2016 12:27:19 +0800 Subject: [PATCH 231/723] crypto: Switch to QEMU UUID API The uuid generation doesn't return error, so update the function signature and calling code accordingly. Signed-off-by: Fam Zheng Reviewed-by: Eric Blake Reviewed-by: Jeff Cody Message-Id: <1474432046-325-7-git-send-email-famz@redhat.com> Reviewed-by: Daniel P. Berrange --- crypto/block-luks.c | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/crypto/block-luks.c b/crypto/block-luks.c index a848232034d..4530f8241c0 100644 --- a/crypto/block-luks.c +++ b/crypto/block-luks.c @@ -29,10 +29,7 @@ #include "crypto/pbkdf.h" #include "crypto/secret.h" #include "crypto/random.h" - -#ifdef CONFIG_UUID -#include -#endif +#include "qemu/uuid.h" #include "qemu/coroutine.h" @@ -877,18 +874,12 @@ qcrypto_block_luks_open(QCryptoBlock *block, } -static int -qcrypto_block_luks_uuid_gen(uint8_t *uuidstr, Error **errp) +static void +qcrypto_block_luks_uuid_gen(uint8_t *uuidstr) { -#ifdef CONFIG_UUID - uuid_t uuid; - uuid_generate(uuid); - uuid_unparse(uuid, (char *)uuidstr); - return 0; -#else - error_setg(errp, "Unable to generate uuids on this platform"); - return -1; -#endif + QemuUUID uuid; + qemu_uuid_generate(&uuid); + qemu_uuid_unparse(&uuid, (char *)uuidstr); } static int @@ -965,10 +956,7 @@ qcrypto_block_luks_create(QCryptoBlock *block, * it out to disk */ luks->header.version = QCRYPTO_BLOCK_LUKS_VERSION; - if (qcrypto_block_luks_uuid_gen(luks->header.uuid, - errp) < 0) { - goto error; - } + qcrypto_block_luks_uuid_gen(luks->header.uuid); cipher_alg = qcrypto_block_luks_cipher_alg_lookup(luks_opts.cipher_alg, errp); From 586d15ff873585ec9c229217eaec76f858f8f45a Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 21 Sep 2016 12:27:20 +0800 Subject: [PATCH 232/723] tests: No longer dependent on CONFIG_UUID crypto now uses built-in uuid implementation, so this check is not needed. Signed-off-by: Fam Zheng Reviewed-by: Eric Blake Reviewed-by: Jeff Cody Message-Id: <1474432046-325-8-git-send-email-famz@redhat.com> Reviewed-by: Daniel P. Berrange --- tests/test-crypto-block.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test-crypto-block.c b/tests/test-crypto-block.c index a38110d3ffb..1957a867431 100644 --- a/tests/test-crypto-block.c +++ b/tests/test-crypto-block.c @@ -28,7 +28,7 @@ #include #endif -#if defined(CONFIG_UUID) && (defined(_WIN32) || defined RUSAGE_THREAD) +#if (defined(_WIN32) || defined RUSAGE_THREAD) #define TEST_LUKS #else #undef TEST_LUKS From 315d3184525c90865bf5e1ec4db5e633f1d8c7e8 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 21 Sep 2016 12:27:21 +0800 Subject: [PATCH 233/723] configure: Remove detection code for UUID All code now uses built-in UUID implementation. Remove the code of libuuid and make --enable-uuid and --disable-uuid only print a message. Signed-off-by: Fam Zheng Reviewed-by: Eric Blake Reviewed-by: Jeff Cody Message-Id: <1474432046-325-9-git-send-email-famz@redhat.com> --- configure | 43 ++++--------------------------------------- 1 file changed, 4 insertions(+), 39 deletions(-) diff --git a/configure b/configure index e4f70f150c2..8fa62ade57b 100755 --- a/configure +++ b/configure @@ -212,7 +212,6 @@ sdlabi="" virtfs="" vnc="yes" sparse="no" -uuid="" vde="" vnc_sasl="" vnc_jpeg="" @@ -886,10 +885,6 @@ for opt do ;; --disable-slirp) slirp="no" ;; - --disable-uuid) uuid="no" - ;; - --enable-uuid) uuid="yes" - ;; --disable-vde) vde="no" ;; --enable-vde) vde="yes" @@ -1105,6 +1100,9 @@ for opt do --enable-vhdx|--disable-vhdx) echo "$0: $opt is obsolete, VHDX driver is always built" >&2 ;; + --enable-uuid|--disable-uuid) + echo "$0: $opt is obsolete, UUID support is always built" >&2 + ;; --disable-gtk) gtk="no" ;; --enable-gtk) gtk="yes" @@ -1363,7 +1361,6 @@ disabled with --disable-FEATURE, default is enabled if available: bluez bluez stack connectivity kvm KVM acceleration support rdma RDMA-based migration support - uuid uuid support vde support for vde network netmap support for netmap network linux-aio Linux AIO support @@ -2659,34 +2656,6 @@ if compile_prog "" "" ; then fi ########################################## -# uuid_generate() probe, used for vdi block driver -# Note that on some systems (notably MacOSX) no extra library -# need be linked to get the uuid functions. -if test "$uuid" != "no" ; then - uuid_libs="-luuid" - cat > $TMPC << EOF -#include -int main(void) -{ - uuid_t my_uuid; - uuid_generate(my_uuid); - return 0; -} -EOF - if compile_prog "" "" ; then - uuid="yes" - elif compile_prog "" "$uuid_libs" ; then - uuid="yes" - libs_softmmu="$uuid_libs $libs_softmmu" - libs_tools="$uuid_libs $libs_tools" - else - if test "$uuid" = "yes" ; then - feature_not_found "uuid" "Install libuuid devel" - fi - uuid=no - fi -fi - # xfsctl() probe, used for raw-posix if test "$xfs" != "no" ; then cat > $TMPC << EOF @@ -4059,7 +4028,7 @@ EOF if compile_prog "$vss_win32_include" "" ; then guest_agent_with_vss="yes" QEMU_CFLAGS="$QEMU_CFLAGS $vss_win32_include" - libs_qga="-lole32 -loleaut32 -lshlwapi -luuid -lstdc++ -Wl,--enable-stdcall-fixup $libs_qga" + libs_qga="-lole32 -loleaut32 -lshlwapi -lstdc++ -Wl,--enable-stdcall-fixup $libs_qga" qga_vss_provider="qga/vss-win32/qga-vss.dll qga/vss-win32/qga-vss.tlb" else if test "$vss_win32_sdk" != "" ; then @@ -4867,7 +4836,6 @@ echo "preadv support $preadv" echo "fdatasync $fdatasync" echo "madvise $madvise" echo "posix_madvise $posix_madvise" -echo "uuid support $uuid" echo "libcap-ng support $cap_ng" echo "vhost-net support $vhost_net" echo "vhost-scsi support $vhost_scsi" @@ -5057,9 +5025,6 @@ fi if test "$fnmatch" = "yes" ; then echo "CONFIG_FNMATCH=y" >> $config_host_mak fi -if test "$uuid" = "yes" ; then - echo "CONFIG_UUID=y" >> $config_host_mak -fi if test "$xfs" = "yes" ; then echo "CONFIG_XFS=y" >> $config_host_mak fi From 9c5ce8db2e5c2769ed2fd3d91928dd1853b5ce7c Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 21 Sep 2016 12:27:22 +0800 Subject: [PATCH 234/723] vl: Switch qemu_uuid to QemuUUID Update all qemu_uuid users as well, especially get rid of the duplicated low level g_strdup_printf, sscanf and snprintf calls with QEMU UUID API. Since qemu_uuid_parse is quite tangled with qemu_uuid, its switching to QemuUUID is done here too to keep everything in sync and avoid code churn. Signed-off-by: Fam Zheng Reviewed-by: Eric Blake Reviewed-by: Jeff Cody Message-Id: <1474432046-325-10-git-send-email-famz@redhat.com> --- hw/ipmi/ipmi_bmc_sim.c | 2 +- hw/nvram/fw_cfg.c | 2 +- hw/ppc/spapr.c | 7 +------ hw/ppc/spapr_rtas.c | 3 ++- hw/smbios/smbios.c | 12 ++++++------ hw/xenpv/xen_domainbuild.c | 6 +----- include/qemu/uuid.h | 2 +- include/sysemu/sysemu.h | 3 ++- qmp.c | 10 ++-------- ui/spice-core.c | 2 +- util/uuid.c | 11 ++++++----- vl.c | 6 +++--- 12 files changed, 27 insertions(+), 39 deletions(-) diff --git a/hw/ipmi/ipmi_bmc_sim.c b/hw/ipmi/ipmi_bmc_sim.c index dc9c14cd293..17c7c0ea074 100644 --- a/hw/ipmi/ipmi_bmc_sim.c +++ b/hw/ipmi/ipmi_bmc_sim.c @@ -1773,7 +1773,7 @@ static void ipmi_sim_realize(DeviceState *dev, Error **errp) ibs->acpi_power_state[1] = 0; if (qemu_uuid_set) { - memcpy(&ibs->uuid, qemu_uuid, 16); + memcpy(&ibs->uuid, &qemu_uuid, 16); } else { memset(&ibs->uuid, 0, 16); } diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c index 1776b1b3c46..92aa5639294 100644 --- a/hw/nvram/fw_cfg.c +++ b/hw/nvram/fw_cfg.c @@ -883,7 +883,7 @@ static void fw_cfg_init1(DeviceState *dev) qdev_init_nofail(dev); fw_cfg_add_bytes(s, FW_CFG_SIGNATURE, (char *)"QEMU", 4); - fw_cfg_add_bytes(s, FW_CFG_UUID, qemu_uuid, 16); + fw_cfg_add_bytes(s, FW_CFG_UUID, &qemu_uuid, 16); fw_cfg_add_i16(s, FW_CFG_NOGRAPHIC, (uint16_t)!machine->enable_graphics); fw_cfg_add_i16(s, FW_CFG_NB_CPUS, (uint16_t)smp_cpus); fw_cfg_add_i16(s, FW_CFG_BOOT_MENU, (uint16_t)boot_menu); diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index ca77bb0dea4..bdb689c552a 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -332,12 +332,7 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base, g_free(buf); } - buf = g_strdup_printf(UUID_FMT, qemu_uuid[0], qemu_uuid[1], - qemu_uuid[2], qemu_uuid[3], qemu_uuid[4], - qemu_uuid[5], qemu_uuid[6], qemu_uuid[7], - qemu_uuid[8], qemu_uuid[9], qemu_uuid[10], - qemu_uuid[11], qemu_uuid[12], qemu_uuid[13], - qemu_uuid[14], qemu_uuid[15]); + buf = qemu_uuid_unparse_strdup(&qemu_uuid); _FDT((fdt_property_string(fdt, "vm,uuid", buf))); if (qemu_uuid_set) { diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c index 27b5ad4bc43..02ce27314a1 100644 --- a/hw/ppc/spapr_rtas.c +++ b/hw/ppc/spapr_rtas.c @@ -303,7 +303,8 @@ static void rtas_ibm_get_system_parameter(PowerPCCPU *cpu, break; } case RTAS_SYSPARM_UUID: - ret = sysparm_st(buffer, length, qemu_uuid, (qemu_uuid_set ? 16 : 0)); + ret = sysparm_st(buffer, length, (unsigned char *)&qemu_uuid, + (qemu_uuid_set ? 16 : 0)); break; default: ret = RTAS_OUT_NOT_SUPPORTED; diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c index 0705eb1dbde..9a6552aa602 100644 --- a/hw/smbios/smbios.c +++ b/hw/smbios/smbios.c @@ -80,7 +80,7 @@ static struct { static struct { const char *manufacturer, *product, *version, *serial, *sku, *family; - /* uuid is in qemu_uuid[] */ + /* uuid is in qemu_uuid */ } type1; static struct { @@ -409,7 +409,7 @@ static void smbios_build_type_1_fields(void) * BIOS. */ smbios_add_field(1, offsetof(struct smbios_type_1, uuid), - qemu_uuid, 16); + &qemu_uuid, 16); } } @@ -484,9 +484,9 @@ static void smbios_build_type_0_table(void) /* Encode UUID from the big endian encoding described on RFC4122 to the wire * format specified by SMBIOS version 2.6. */ -static void smbios_encode_uuid(struct smbios_uuid *uuid, const uint8_t *buf) +static void smbios_encode_uuid(struct smbios_uuid *uuid, QemuUUID *in) { - memcpy(uuid, buf, 16); + memcpy(uuid, &in, 16); if (smbios_uuid_encoded) { uuid->time_low = bswap32(uuid->time_low); uuid->time_mid = bswap16(uuid->time_mid); @@ -503,7 +503,7 @@ static void smbios_build_type_1_table(void) SMBIOS_TABLE_SET_STR(1, version_str, type1.version); SMBIOS_TABLE_SET_STR(1, serial_number_str, type1.serial); if (qemu_uuid_set) { - smbios_encode_uuid(&t->uuid, qemu_uuid); + smbios_encode_uuid(&t->uuid, &qemu_uuid); } else { memset(&t->uuid, 0, 16); } @@ -1002,7 +1002,7 @@ void smbios_entry_add(QemuOpts *opts) val = qemu_opt_get(opts, "uuid"); if (val) { - if (qemu_uuid_parse(val, qemu_uuid) != 0) { + if (qemu_uuid_parse(val, &qemu_uuid) != 0) { error_report("Invalid UUID"); exit(1); } diff --git a/hw/xenpv/xen_domainbuild.c b/hw/xenpv/xen_domainbuild.c index 5a9f5ac8064..b439b0ed5d7 100644 --- a/hw/xenpv/xen_domainbuild.c +++ b/hw/xenpv/xen_domainbuild.c @@ -53,11 +53,7 @@ int xenstore_domain_init1(const char *kernel, const char *ramdisk, char *dom, uuid_string[42], vm[256], path[256]; int i; - snprintf(uuid_string, sizeof(uuid_string), UUID_FMT, - qemu_uuid[0], qemu_uuid[1], qemu_uuid[2], qemu_uuid[3], - qemu_uuid[4], qemu_uuid[5], qemu_uuid[6], qemu_uuid[7], - qemu_uuid[8], qemu_uuid[9], qemu_uuid[10], qemu_uuid[11], - qemu_uuid[12], qemu_uuid[13], qemu_uuid[14], qemu_uuid[15]); + qemu_uuid_unparse(&qemu_uuid, uuid_string); dom = xs_get_domain_path(xenstore, xen_domid); snprintf(vm, sizeof(vm), "/vm/%s", uuid_string); diff --git a/include/qemu/uuid.h b/include/qemu/uuid.h index bc0601e65bf..afe48402969 100644 --- a/include/qemu/uuid.h +++ b/include/qemu/uuid.h @@ -52,7 +52,7 @@ void qemu_uuid_unparse(const QemuUUID *uuid, char *out); char *qemu_uuid_unparse_strdup(const QemuUUID *uuid); -int qemu_uuid_parse(const char *str, uint8_t *uuid); +int qemu_uuid_parse(const char *str, QemuUUID *uuid); void qemu_uuid_bswap(QemuUUID *uuid); diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index 6111950d512..ef2c50bb04e 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -9,6 +9,7 @@ #include "qemu/notify.h" #include "qemu/main-loop.h" #include "qemu/bitmap.h" +#include "qemu/uuid.h" #include "qom/object.h" /* vl.c */ @@ -16,7 +17,7 @@ extern const char *bios_name; extern const char *qemu_name; -extern uint8_t qemu_uuid[]; +extern QemuUUID qemu_uuid; extern bool qemu_uuid_set; bool runstate_check(RunState state); diff --git a/qmp.c b/qmp.c index 524da629f85..71f0c8b4390 100644 --- a/qmp.c +++ b/qmp.c @@ -36,6 +36,7 @@ #include "qom/object_interfaces.h" #include "hw/mem/pc-dimm.h" #include "hw/acpi/acpi_dev_interface.h" +#include "qemu/uuid.h" NameInfo *qmp_query_name(Error **errp) { @@ -75,15 +76,8 @@ KvmInfo *qmp_query_kvm(Error **errp) UuidInfo *qmp_query_uuid(Error **errp) { UuidInfo *info = g_malloc0(sizeof(*info)); - char uuid[64]; - - snprintf(uuid, sizeof(uuid), UUID_FMT, qemu_uuid[0], qemu_uuid[1], - qemu_uuid[2], qemu_uuid[3], qemu_uuid[4], qemu_uuid[5], - qemu_uuid[6], qemu_uuid[7], qemu_uuid[8], qemu_uuid[9], - qemu_uuid[10], qemu_uuid[11], qemu_uuid[12], qemu_uuid[13], - qemu_uuid[14], qemu_uuid[15]); - info->UUID = g_strdup(uuid); + info->UUID = qemu_uuid_unparse_strdup(&qemu_uuid); return info; } diff --git a/ui/spice-core.c b/ui/spice-core.c index da0505434a0..1452e77fd15 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -796,7 +796,7 @@ void qemu_spice_init(void) qemu_opt_foreach(opts, add_channel, &tls_port, NULL); spice_server_set_name(spice_server, qemu_name); - spice_server_set_uuid(spice_server, qemu_uuid); + spice_server_set_uuid(spice_server, (unsigned char *)&qemu_uuid); seamless_migration = qemu_opt_get_bool(opts, "seamless-migration", 0); spice_server_set_seamless_migration(spice_server, seamless_migration); diff --git a/util/uuid.c b/util/uuid.c index f0c1eeb527b..47019035bff 100644 --- a/util/uuid.c +++ b/util/uuid.c @@ -61,18 +61,19 @@ char *qemu_uuid_unparse_strdup(const QemuUUID *uuid) uu[13], uu[14], uu[15]); } -int qemu_uuid_parse(const char *str, uint8_t *uuid) +int qemu_uuid_parse(const char *str, QemuUUID *uuid) { + unsigned char *uu = &uuid->data[0]; int ret; if (strlen(str) != 36) { return -1; } - ret = sscanf(str, UUID_FMT, &uuid[0], &uuid[1], &uuid[2], &uuid[3], - &uuid[4], &uuid[5], &uuid[6], &uuid[7], &uuid[8], &uuid[9], - &uuid[10], &uuid[11], &uuid[12], &uuid[13], &uuid[14], - &uuid[15]); + ret = sscanf(str, UUID_FMT, &uu[0], &uu[1], &uu[2], &uu[3], + &uu[4], &uu[5], &uu[6], &uu[7], &uu[8], &uu[9], + &uu[10], &uu[11], &uu[12], &uu[13], &uu[14], + &uu[15]); if (ret != 16) { return -1; diff --git a/vl.c b/vl.c index 38395019f12..215a6f9c7a0 100644 --- a/vl.c +++ b/vl.c @@ -183,10 +183,10 @@ uint8_t qemu_extra_params_fw[2]; int icount_align_option; -/* The bytes in qemu_uuid[] are in the order specified by RFC4122, _not_ in the +/* The bytes in qemu_uuid are in the order specified by RFC4122, _not_ in the * little-endian "wire format" described in the SMBIOS 2.6 specification. */ -uint8_t qemu_uuid[16]; +QemuUUID qemu_uuid; bool qemu_uuid_set; static NotifierList exit_notifiers = @@ -3780,7 +3780,7 @@ int main(int argc, char **argv, char **envp) cursor_hide = 0; break; case QEMU_OPTION_uuid: - if(qemu_uuid_parse(optarg, qemu_uuid) < 0) { + if (qemu_uuid_parse(optarg, &qemu_uuid) < 0) { error_report("failed to parse UUID string: wrong format"); exit(1); } From 0d6ae94783b35a5c42d88872d1adb523f5fcc6f3 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 21 Sep 2016 12:27:23 +0800 Subject: [PATCH 235/723] uuid: Tighten uuid parse sscanf is relatively loose (tolerate) on some invalid formats that we should fail instead of generating a wrong uuid structure, like with whitespaces and short strings. Add and use a helper function to first check the format. Signed-off-by: Fam Zheng Reviewed-by: Eric Blake Reviewed-by: Jeff Cody Message-Id: <1474432046-325-11-git-send-email-famz@redhat.com> --- util/uuid.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/util/uuid.c b/util/uuid.c index 47019035bff..dd6b5fdf058 100644 --- a/util/uuid.c +++ b/util/uuid.c @@ -61,12 +61,34 @@ char *qemu_uuid_unparse_strdup(const QemuUUID *uuid) uu[13], uu[14], uu[15]); } +static bool qemu_uuid_is_valid(const char *str) +{ + int i; + + for (i = 0; i < strlen(str); i++) { + const char c = str[i]; + if (i == 8 || i == 13 || i == 18 || i == 23) { + if (str[i] != '-') { + return false; + } + } else { + if ((c >= '0' && c <= '9') || + (c >= 'A' && c <= 'F') || + (c >= 'a' && c <= 'f')) { + continue; + } + return false; + } + } + return i == 36; +} + int qemu_uuid_parse(const char *str, QemuUUID *uuid) { unsigned char *uu = &uuid->data[0]; int ret; - if (strlen(str) != 36) { + if (!qemu_uuid_is_valid(str)) { return -1; } From c739cdddeb61d57470b3a7ecf6cea45064828269 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 21 Sep 2016 12:27:24 +0800 Subject: [PATCH 236/723] tests: Add uuid tests Signed-off-by: Fam Zheng Reviewed-by: Jeff Cody Message-Id: <1474432046-325-12-git-send-email-famz@redhat.com> --- tests/Makefile.include | 2 + tests/test-uuid.c | 177 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 179 insertions(+) create mode 100644 tests/test-uuid.c diff --git a/tests/Makefile.include b/tests/Makefile.include index 6052a3828f6..7dcd5d25a18 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -115,6 +115,7 @@ check-unit-y += tests/test-logging$(EXESUF) check-unit-$(CONFIG_REPLICATION) += tests/test-replication$(EXESUF) check-unit-y += tests/test-bufferiszero$(EXESUF) gcov-files-check-bufferiszero-y = util/bufferiszero.c +check-unit-y += tests/test-uuid$(EXESUF) check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh @@ -658,6 +659,7 @@ tests/test-filter-mirror$(EXESUF): tests/test-filter-mirror.o $(qtest-obj-y) tests/test-filter-redirector$(EXESUF): tests/test-filter-redirector.o $(qtest-obj-y) tests/ivshmem-test$(EXESUF): tests/ivshmem-test.o contrib/ivshmem-server/ivshmem-server.o $(libqos-pc-obj-y) tests/vhost-user-bridge$(EXESUF): tests/vhost-user-bridge.o +tests/test-uuid$(EXESUF): tests/test-uuid.o $(test-util-obj-y) tests/migration/stress$(EXESUF): tests/migration/stress.o $(call quiet-command, $(LINKPROG) -static -O3 $(PTHREAD_LIB) -o $@ $< ," LINK $(TARGET_DIR)$@") diff --git a/tests/test-uuid.c b/tests/test-uuid.c new file mode 100644 index 00000000000..77dcdc4b55d --- /dev/null +++ b/tests/test-uuid.c @@ -0,0 +1,177 @@ +/* + * QEMU UUID Library + * + * Copyright (c) 2016 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + */ + +#include "qemu/osdep.h" +#include "qemu/uuid.h" + +struct { + const char *uuidstr; + QemuUUID uuid; + bool uuidstr_is_valid; + bool check_unparse; +} uuid_test_data[] = { + { /* Normal */ + "586ece27-7f09-41e0-9e74-e901317e9d42", + { { { + 0x58, 0x6e, 0xce, 0x27, 0x7f, 0x09, 0x41, 0xe0, + 0x9e, 0x74, 0xe9, 0x01, 0x31, 0x7e, 0x9d, 0x42, + } } }, + true, true, + }, { /* NULL */ + "00000000-0000-0000-0000-000000000000", + { }, + true, true, + }, { /* Upper case */ + "0CC6C752-3961-4028-A286-C05CC616D396", + { { { + 0x0c, 0xc6, 0xc7, 0x52, 0x39, 0x61, 0x40, 0x28, + 0xa2, 0x86, 0xc0, 0x5c, 0xc6, 0x16, 0xd3, 0x96, + } } }, + true, false, + }, { /* Mixed case */ + "0CC6C752-3961-4028-a286-c05cc616D396", + { { { + 0x0c, 0xc6, 0xc7, 0x52, 0x39, 0x61, 0x40, 0x28, + 0xa2, 0x86, 0xc0, 0x5c, 0xc6, 0x16, 0xd3, 0x96, + } } }, + true, false, + }, { /* Empty */ + "" + }, { /* Too short */ + "abc", + }, { /* Non-hex */ + "abcdefgh-0000-0000-0000-000000000000", + }, { /* No '-' */ + "0cc6c75239614028a286c05cc616d396", + }, { /* '-' in wrong position */ + "0cc6c-7523961-4028-a286-c05cc616d396", + }, { /* Double '-' */ + "0cc6c752--3961-4028-a286-c05cc616d396", + }, { /* Too long */ + "0000000000000000000000000000000000000000000000", + }, { /* Invalid char in the beginning */ + ")cc6c752-3961-4028-a286-c05cc616d396", + }, { /* Invalid char in the beginning, in extra */ + ")0cc6c752-3961-4028-a286-c05cc616d396", + }, { /* Invalid char in the middle */ + "0cc6c752-39*1-4028-a286-c05cc616d396", + }, { /* Invalid char in the middle, in extra */ + "0cc6c752-39*61-4028-a286-c05cc616d396", + }, { /* Invalid char in the end */ + "0cc6c752-3961-4028-a286-c05cc616d39&", + }, { /* Invalid char in the end, in extra */ + "0cc6c752-3961-4028-a286-c05cc616d396&", + }, { /* Short end and trailing space */ + "0cc6c752-3961-4028-a286-c05cc616d39 ", + }, { /* Leading space and short end */ + " 0cc6c752-3961-4028-a286-c05cc616d39", + }, +}; + +static inline bool uuid_is_valid(QemuUUID *uuid) +{ + return qemu_uuid_is_null(uuid) || + ((uuid->data[6] & 0xf0) == 0x40 && (uuid->data[8] & 0xc0) == 0x80); +} + +static void test_uuid_generate(void) +{ + QemuUUID uuid; + int i; + + for (i = 0; i < 100; ++i) { + qemu_uuid_generate(&uuid); + g_assert(uuid_is_valid(&uuid)); + } +} + +static void test_uuid_is_null(void) +{ + QemuUUID uuid_null = { }; + QemuUUID uuid_not_null = { { { + 0x58, 0x6e, 0xce, 0x27, 0x7f, 0x09, 0x41, 0xe0, + 0x9e, 0x74, 0xe9, 0x01, 0x31, 0x7e, 0x9d, 0x42 + } } }; + QemuUUID uuid_not_null_2 = { { { 1 } } }; + + g_assert(qemu_uuid_is_null(&uuid_null)); + g_assert_false(qemu_uuid_is_null(&uuid_not_null)); + g_assert_false(qemu_uuid_is_null(&uuid_not_null_2)); +} + +static void test_uuid_parse(void) +{ + int i, r; + + for (i = 0; i < ARRAY_SIZE(uuid_test_data); i++) { + QemuUUID uuid; + bool is_valid = uuid_test_data[i].uuidstr_is_valid; + + r = qemu_uuid_parse(uuid_test_data[i].uuidstr, &uuid); + g_assert_cmpint(!r, ==, is_valid); + if (is_valid) { + g_assert_cmpint(is_valid, ==, uuid_is_valid(&uuid)); + g_assert_cmpmem(&uuid_test_data[i].uuid, sizeof(uuid), + &uuid, sizeof(uuid)); + } + } +} + +static void test_uuid_unparse(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(uuid_test_data); i++) { + char out[37]; + + if (!uuid_test_data[i].check_unparse) { + continue; + } + qemu_uuid_unparse(&uuid_test_data[i].uuid, out); + g_assert_cmpstr(uuid_test_data[i].uuidstr, ==, out); + } +} + +static void test_uuid_unparse_strdup(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(uuid_test_data); i++) { + char *out; + + if (!uuid_test_data[i].check_unparse) { + continue; + } + out = qemu_uuid_unparse_strdup(&uuid_test_data[i].uuid); + g_assert_cmpstr(uuid_test_data[i].uuidstr, ==, out); + } +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + g_test_add_func("/uuid/generate", test_uuid_generate); + g_test_add_func("/uuid/is_null", test_uuid_is_null); + g_test_add_func("/uuid/parse", test_uuid_parse); + g_test_add_func("/uuid/unparse", test_uuid_unparse); + g_test_add_func("/uuid/unparse_strdup", test_uuid_unparse_strdup); + + return g_test_run(); +} From 080d7aac31006092c8b85a784cfc4e3b525d9d33 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 21 Sep 2016 12:27:25 +0800 Subject: [PATCH 237/723] Add UUID files to MAINTAINERS I understand that we've been keeping eyes on the uncovered files. Since I'm adding some more files I volunteer to look after them in the futuer. Signed-off-by: Fam Zheng Reviewed-by: Jeff Cody Message-Id: <1474432046-325-13-git-send-email-famz@redhat.com> --- MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 09d13bf1c0f..bc4466399fc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1342,6 +1342,13 @@ F: include/qemu/throttle.h F: util/throttle.c L: qemu-block@nongnu.org +UUID +M: Fam Zheng +S: Supported +F: util/uuid.c +F: include/qemu/uuid.h +F: tests/test-uuid.c + Usermode Emulation ------------------ Overall From 65a03dd6c6b89223154e48193044577387e05dc2 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 21 Sep 2016 12:27:26 +0800 Subject: [PATCH 238/723] tests: Ignore test-uuid Signed-off-by: Fam Zheng Message-Id: <1474432046-325-14-git-send-email-famz@redhat.com> Reviewed-by: Jeff Cody Reviewed-by: Daniel P. Berrange --- tests/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/.gitignore b/tests/.gitignore index b4a9cfc8c40..24ac6cfa77a 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -70,6 +70,7 @@ test-string-output-visitor test-thread-pool test-throttle test-timed-average +test-uuid test-visitor-serialization test-vmstate test-write-threshold From a34ac8d472a36582e8aaf93688cee62b4cac4201 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 21 Sep 2016 11:49:20 +0800 Subject: [PATCH 239/723] docker: Generate /packages.txt in centos6 image Put the list of package names in an environment, and output their package names to the target file in the end. Signed-off-by: Fam Zheng Message-Id: <1474429768-25027-2-git-send-email-famz@redhat.com> Reviewed-by: Daniel P. Berrange --- tests/docker/dockerfiles/centos6.docker | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/docker/dockerfiles/centos6.docker b/tests/docker/dockerfiles/centos6.docker index 8f4fe463793..34e0d3b91e8 100644 --- a/tests/docker/dockerfiles/centos6.docker +++ b/tests/docker/dockerfiles/centos6.docker @@ -1,6 +1,8 @@ FROM centos:6 -RUN yum install -y \ +RUN yum install -y epel-release +ENV PACKAGES libfdt-devel ccache \ tar git make gcc g++ \ zlib-devel glib2-devel SDL-devel pixman-devel \ epel-release -RUN yum install -y libfdt-devel ccache +RUN yum install -y $PACKAGES +RUN rpm -q $PACKAGES | sort > /packages.txt From 28a0cccd544983273c0178e4b198e781cb01e074 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 21 Sep 2016 11:49:21 +0800 Subject: [PATCH 240/723] docker: Generate /packages.txt in fedora image Put the list of package names in an environment, and output their package names to the target file in the end. Signed-off-by: Fam Zheng Message-Id: <1474429768-25027-3-git-send-email-famz@redhat.com> Reviewed-by: Daniel P. Berrange --- tests/docker/dockerfiles/fedora.docker | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker index 1d26a8e98a4..b414e88dd15 100644 --- a/tests/docker/dockerfiles/fedora.docker +++ b/tests/docker/dockerfiles/fedora.docker @@ -1,7 +1,17 @@ FROM fedora:23 -RUN dnf install -y \ +ENV PACKAGES \ ccache git tar PyYAML sparse flex bison \ glib2-devel pixman-devel zlib-devel SDL-devel libfdt-devel \ gcc gcc-c++ clang make perl which bc findutils \ - mingw{32,64}-{pixman,glib2,gmp,SDL,pkg-config,gtk2,gtk3,gnutls,nettle,libtasn1,libjpeg-turbo,libpng,curl,libssh2,bzip2} + mingw32-pixman mingw32-glib2 mingw32-gmp mingw32-SDL mingw32-pkg-config \ + mingw32-gtk2 mingw32-gtk3 mingw32-gnutls mingw32-nettle mingw32-libtasn1 \ + mingw32-libjpeg-turbo mingw32-libpng mingw32-curl mingw32-libssh2 \ + mingw32-bzip2 \ + mingw64-pixman mingw64-glib2 mingw64-gmp mingw64-SDL mingw64-pkg-config \ + mingw64-gtk2 mingw64-gtk3 mingw64-gnutls mingw64-nettle mingw64-libtasn1 \ + mingw64-libjpeg-turbo mingw64-libpng mingw64-curl mingw64-libssh2 \ + mingw64-bzip2 + +RUN dnf install -y $PACKAGES +RUN rpm -q $PACKAGES | sort > /packages.txt ENV FEATURES mingw clang pyyaml From 5008fc787b9d923f937c71d3dbe0d8ef88875c91 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 21 Sep 2016 11:49:22 +0800 Subject: [PATCH 241/723] docker: Generate /packages.txt in ubuntu image Put the list of package names in an environment, and output their package names to the target file in the end. Signed-off-by: Fam Zheng Message-Id: <1474429768-25027-4-git-send-email-famz@redhat.com> Reviewed-by: Daniel. P. Berrange --- tests/docker/dockerfiles/ubuntu.docker | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/docker/dockerfiles/ubuntu.docker b/tests/docker/dockerfiles/ubuntu.docker index a8b88c318c6..a360a050a2f 100644 --- a/tests/docker/dockerfiles/ubuntu.docker +++ b/tests/docker/dockerfiles/ubuntu.docker @@ -2,10 +2,12 @@ FROM ubuntu:14.04 RUN echo "deb http://archive.ubuntu.com/ubuntu/ trusty universe multiverse" >> \ /etc/apt/sources.list RUN apt-get update -RUN apt-get -y install flex bison \ +ENV PACKAGES flex bison \ libusb-1.0-0-dev libiscsi-dev librados-dev libncurses5-dev \ libseccomp-dev libgnutls-dev libssh2-1-dev libspice-server-dev \ libspice-protocol-dev libnss3-dev libfdt-dev \ libgtk-3-dev libvte-2.90-dev libsdl1.2-dev libpng12-dev libpixman-1-dev \ git make ccache python-yaml gcc clang sparse +RUN apt-get -y install $PACKAGES +RUN dpkg -l $PACKAGES | sort > /packages.txt ENV FEATURES clang pyyaml From a2bd7252fe8b43367d2f7d054154ffc56d6dd377 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 21 Sep 2016 11:49:23 +0800 Subject: [PATCH 242/723] docker: Update fedora image to latest Now that 23 is becoming an "old" release with 24 available. Fedora has a quick release cycle, so use latest to follow more closely. Signed-off-by: Fam Zheng Message-Id: <1474429768-25027-5-git-send-email-famz@redhat.com> Reviewed-by: Daniel P. Berrange --- tests/docker/dockerfiles/fedora.docker | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker index b414e88dd15..478163b8d83 100644 --- a/tests/docker/dockerfiles/fedora.docker +++ b/tests/docker/dockerfiles/fedora.docker @@ -1,4 +1,4 @@ -FROM fedora:23 +FROM fedora:latest ENV PACKAGES \ ccache git tar PyYAML sparse flex bison \ glib2-devel pixman-devel zlib-devel SDL-devel libfdt-devel \ From 3d3a6eb60d259a503ed771c878f777e2715d83db Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 21 Sep 2016 11:49:24 +0800 Subject: [PATCH 243/723] docker: Flatten default target list in test-quick Previously it is expanded to a whitespace separated list which is not the most appropriate format. Since it's only two items, flatten it. Signed-off-by: Fam Zheng Message-Id: <1474429768-25027-6-git-send-email-famz@redhat.com> Reviewed-by: Daniel P. Berrange --- tests/docker/test-quick | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/docker/test-quick b/tests/docker/test-quick index 07cdc59a106..7885dfafdbe 100755 --- a/tests/docker/test-quick +++ b/tests/docker/test-quick @@ -13,7 +13,7 @@ . common.rc -DEF_TARGET_LIST="$(echo {x86_64,aarch64}-softmmu)" +DEF_TARGET_LIST="x86_64-softmmu,aarch64-softmmu" TARGET_LIST=${TARGET_LIST:-$DEF_TARGET_LIST} \ build_qemu make check $MAKEFLAGS From 9445c28ec3753470554790debc6ac12609c3b733 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 21 Sep 2016 11:49:25 +0800 Subject: [PATCH 244/723] docker: Print used options before doing configure This makes the configure command more obvious which usually has useful information. Signed-off-by: Fam Zheng Message-Id: <1474429768-25027-7-git-send-email-famz@redhat.com> Reviewed-by: Daniel P. Berrange --- tests/docker/common.rc | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tests/docker/common.rc b/tests/docker/common.rc index 0c6d8d5ecea..510a3ad3f44 100755 --- a/tests/docker/common.rc +++ b/tests/docker/common.rc @@ -23,11 +23,13 @@ requires() build_qemu() { - $QEMU_SRC/configure \ - --enable-werror \ - ${TARGET_LIST:+"--target-list=${TARGET_LIST}"} \ - --prefix="$PWD/install" \ - $EXTRA_CONFIGURE_OPTS \ - "$@" + config_opts="--enable-werror \ + ${TARGET_LIST:+--target-list=${TARGET_LIST}} \ + --prefix=$PWD/install \ + $EXTRA_CONFIGURE_OPTS \ + $@" + echo "Configure options:" + echo $config_opts + $QEMU_SRC/configure $config_opts make $MAKEFLAGS } From ec960b9a73f48b8b0bc7d5d31a173e90bd38a290 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 21 Sep 2016 11:49:26 +0800 Subject: [PATCH 245/723] docker: Support showing environment information Add a make variable SHOW_ENV. When it's set to non empty, print the package information and environment variables. Signed-off-by: Fam Zheng Message-Id: <1474429768-25027-8-git-send-email-famz@redhat.com> Reviewed-by: Daniel P. Berrange --- tests/docker/Makefile.include | 2 +- tests/docker/run | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include index 19d4cc7077a..2fcc3c64187 100644 --- a/tests/docker/Makefile.include +++ b/tests/docker/Makefile.include @@ -117,7 +117,7 @@ docker-run-%: docker-qemu-src $(if $(DEBUG),-i,--net=none) \ -e TARGET_LIST=$(TARGET_LIST) \ -e EXTRA_CONFIGURE_OPTS=$(EXTRA_CONFIGURE_OPTS) \ - -e V=$V -e J=$J -e DEBUG=$(DEBUG)\ + -e V=$V -e J=$J -e DEBUG=$(DEBUG) -e SHOW_ENV=$(SHOW_ENV)\ -e CCACHE_DIR=/var/tmp/ccache \ -v $$(readlink -e $(DOCKER_SRC_COPY)):/var/tmp/qemu:z$(COMMA)ro \ -v $(DOCKER_CCACHE_DIR):/var/tmp/ccache:z \ diff --git a/tests/docker/run b/tests/docker/run index d85d49afc13..ed7dd312f81 100755 --- a/tests/docker/run +++ b/tests/docker/run @@ -40,6 +40,17 @@ for p in dtc pixman; do fi done +if test -n "$SHOW_ENV"; then + if test -f /packages.txt; then + echo "Packages installed:" + cat /packages.txt + echo + fi + echo "Environment variables:" + env + echo +fi + export QEMU_SRC="$TEST_DIR/src" cd "$QEMU_SRC/tests/docker" From 97cba1a1d1e62ea3e2718ad22188d10f2aa5478d Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 21 Sep 2016 11:49:27 +0800 Subject: [PATCH 246/723] docker: Terminate instances at SIGTERM and SIGHUP Signed-off-by: Fam Zheng Message-Id: <1474429768-25027-9-git-send-email-famz@redhat.com> Reviewed-by: Daniel P. Berrange --- tests/docker/docker.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/docker/docker.py b/tests/docker/docker.py index 71b0d27e18e..37d83199e7c 100755 --- a/tests/docker/docker.py +++ b/tests/docker/docker.py @@ -21,6 +21,7 @@ import argparse import tempfile import re +import signal from tarfile import TarFile, TarInfo from StringIO import StringIO from shutil import copy, rmtree @@ -101,6 +102,8 @@ def __init__(self): self._command = _guess_docker_command() self._instances = [] atexit.register(self._kill_instances) + signal.signal(signal.SIGTERM, self._kill_instances) + signal.signal(signal.SIGHUP, self._kill_instances) def _do(self, cmd, quiet=True, infile=None, **kwargs): if quiet: @@ -133,7 +136,7 @@ def clean(self): self._do_kill_instances(False, False) return 0 - def _kill_instances(self): + def _kill_instances(self, *args, **kwargs): return self._do_kill_instances(True) def _output(self, cmd, **kwargs): From 9b77336d83b73f7585cc2dbc565d377940905191 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 21 Sep 2016 11:49:28 +0800 Subject: [PATCH 247/723] docker: exec $CMD This is the last command to run (unless DEBUG), make it 'exec' to simplify the process tree. Signed-off-by: Fam Zheng Message-Id: <1474429768-25027-10-git-send-email-famz@redhat.com> Reviewed-by: Daniel P. Berrange --- tests/docker/run | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/tests/docker/run b/tests/docker/run index ed7dd312f81..c1e4513bcee 100755 --- a/tests/docker/run +++ b/tests/docker/run @@ -57,14 +57,17 @@ cd "$QEMU_SRC/tests/docker" CMD="$QEMU_SRC/tests/docker/$@" -if test -n "$DEBUG"; then - echo "* Prepared to run command:" - echo " $CMD" - echo "* Hit Ctrl-D to continue, or type 'exit 1' to abort" - echo - $SHELL +if test -z "$DEBUG"; then + exec $CMD fi +# DEBUG workflow +echo "* Prepared to run command:" +echo " $CMD" +echo "* Hit Ctrl-D to continue, or type 'exit 1' to abort" +echo +$SHELL + if "$CMD"; then exit 0 elif test -n "$DEBUG"; then From e9deaad8a58c899dc32e9fdeff9e533070e79dca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Draszik?= Date: Tue, 26 Jul 2016 00:42:45 +0100 Subject: [PATCH 248/723] target-mips: add 24KEc CPU definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Define a new CPU definition supporting 24KEc cores, similar to the existing 24Kc, but with added support for DSP instructions and MIPS16e (and without FPU). Signed-off-by: André Draszik Signed-off-by: Leon Alrae --- target-mips/translate_init.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index 39ed5c4c1b1..6ae23e476f7 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -255,6 +255,28 @@ static const mips_def_t mips_defs[] = .insn_flags = CPU_MIPS32R2 | ASE_MIPS16, .mmu_type = MMU_TYPE_R4000, }, + { + .name = "24KEc", + .CP0_PRid = 0x00019600, + .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) | + (MMU_TYPE_R4000 << CP0C0_MT), + .CP0_Config1 = MIPS_CONFIG1 | (15 << CP0C1_MMU) | + (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) | + (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA) | + (1 << CP0C1_CA), + .CP0_Config2 = MIPS_CONFIG2, + .CP0_Config3 = MIPS_CONFIG3 | (1 << CP0C3_DSPP) | (0 << CP0C3_VInt), + .CP0_LLAddr_rw_bitmask = 0, + .CP0_LLAddr_shift = 4, + .SYNCI_Step = 32, + .CCRes = 2, + /* we have a DSP, but no FPU */ + .CP0_Status_rw_bitmask = 0x1378FF1F, + .SEGBITS = 32, + .PABITS = 32, + .insn_flags = CPU_MIPS32R2 | ASE_MIPS16 | ASE_DSP, + .mmu_type = MMU_TYPE_R4000, + }, { .name = "24Kf", .CP0_PRid = 0x00019300, From d208ac0c2e4cb43b74153bd584fc63c7b8a93ed6 Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Thu, 8 Sep 2016 11:01:01 +0100 Subject: [PATCH 249/723] target-mips: generate fences Make use of memory barrier TCG opcode in MIPS front end. Signed-off-by: Leon Alrae Reviewed-by: Richard Henderson --- target-mips/translate.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index bab52cb2549..55c2ca0c7b4 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -13109,6 +13109,34 @@ static void gen_ldst_pair (DisasContext *ctx, uint32_t opc, int rd, tcg_temp_free(t1); } +static void gen_sync(int stype) +{ + TCGBar tcg_mo = TCG_BAR_SC; + + switch (stype) { + case 0x4: /* SYNC_WMB */ + tcg_mo |= TCG_MO_ST_ST; + break; + case 0x10: /* SYNC_MB */ + tcg_mo |= TCG_MO_ALL; + break; + case 0x11: /* SYNC_ACQUIRE */ + tcg_mo |= TCG_MO_LD_LD | TCG_MO_LD_ST; + break; + case 0x12: /* SYNC_RELEASE */ + tcg_mo |= TCG_MO_ST_ST | TCG_MO_LD_ST; + break; + case 0x13: /* SYNC_RMB */ + tcg_mo |= TCG_MO_LD_LD; + break; + default: + tcg_mo |= TCG_MO_ALL; + break; + } + + tcg_gen_mb(tcg_mo); +} + static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs) { int extension = (ctx->opcode >> 6) & 0x3f; @@ -13384,7 +13412,7 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs) case 0x2d: switch (minor) { case SYNC: - /* NOP */ + gen_sync(extract32(ctx->opcode, 16, 5)); break; case SYSCALL: generate_exception_end(ctx, EXCP_SYSCALL); @@ -17201,7 +17229,7 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx) break; case OPC_SYNC: check_insn(ctx, ISA_MIPS2); - /* Treat as NOP. */ + gen_sync(extract32(ctx->opcode, 6, 5)); break; #if defined(TARGET_MIPS64) From e1be160691e1d64591c48c16b9a6f3901cee6cbf Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Mon, 19 Sep 2016 13:44:38 +0200 Subject: [PATCH 250/723] linux-user: Fix TARGET_SIOCATMARK definition for Mips This patch fixes wrong definition of TARGET_SIOCATMARK for mips, alpha, and sh4. The current definition is: #define SIOCATMARK 0x8905 while the correct definition is: #define SIOCATMARK TARGET_IOR('s', 7, int) See Linux kernel source file arch/mips/include/uapi/asm/sockios.h#L19 for reference. This patch also a fixes LTP test failure for test sockioctl01, for mips, alpha, and sh4. Signed-off-by: Aleksandar Rikalo Signed-off-by: Aleksandar Markovic Reviewed-by: Laurent Vivier Reviewed-by: Leon Alrae Acked-by: Riku Voipio Signed-off-by: Leon Alrae --- linux-user/syscall_defs.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 5c19c5ca192..d50878b58f8 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -898,7 +898,11 @@ struct target_pollfd { #define TARGET_KDSETLED 0x4B32 /* set led state [lights, not flags] */ #define TARGET_KDSIGACCEPT 0x4B4E +#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_SH4) +#define TARGET_SIOCATMARK TARGET_IOR('s', 7, int) +#else #define TARGET_SIOCATMARK 0x8905 +#endif /* Networking ioctls */ #define TARGET_SIOCADDRT 0x890B /* add routing table entry */ From 3a87a954c84d036b1f6ceb95abbdc80cdc5d5b68 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Mon, 19 Sep 2016 13:44:39 +0200 Subject: [PATCH 251/723] linux-user: Fix TARGET_F_GETOWN definition for Mips For some reason, Qemu's TARGET_F_GETOWN constant for Mips does not match the correct value of correspondent F_GETOWN. This patch fixes this problem. For reference, see Mips' F_GETOWN definition in Linux kernel at arch/mips/include/uapi/asm/fcntl.h#L44. This patch also fixes some fcntl()-related LTP tests for Qemu user mode for Mips. Signed-off-by: Miodrag Dinic Signed-off-by: Aleksandar Markovic Reviewed-by: Laurent Vivier Reviewed-by: Leon Alrae Acked-by: Riku Voipio Signed-off-by: Leon Alrae --- linux-user/syscall_defs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index d50878b58f8..925feda6a6d 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -2164,7 +2164,7 @@ struct target_statfs64 { #define TARGET_F_SETLK 6 #define TARGET_F_SETLKW 7 #define TARGET_F_SETOWN 24 /* for sockets. */ -#define TARGET_F_GETOWN 25 /* for sockets. */ +#define TARGET_F_GETOWN 23 /* for sockets. */ #else #define TARGET_F_GETLK 5 #define TARGET_F_SETLK 6 From 8a8001b14728baacaa3491f7f723b92a7376e421 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Mon, 19 Sep 2016 13:44:40 +0200 Subject: [PATCH 252/723] linux-user: Fix structure target_flock definition for Mips Structure flock is defined for Mips in a way different from any other platform. For reference, see Linux kernel source code files: arch/mips/include/uapi/asm/fcntl.h, line 63 (for Mips) include/uapi/asm-generic/fcntl.h, line 195 (for all other platforms) This patch fix this problem, by amending structure target_flock, for Mips only. Besides, this patch fixes LTP tests fcntl11, fcntl17, fcntl19, fcntl20, and fcntl21, which are currently failing, if executed in Qemu user mode for Mips platforms. Signed-off-by: Aleksandar Markovic Reviewed-by: Laurent Vivier Reviewed-by: Leon Alrae Acked-by: Riku Voipio Signed-off-by: Leon Alrae --- linux-user/syscall_defs.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 925feda6a6d..9fdbe865dc4 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -2333,7 +2333,13 @@ struct target_flock { short l_whence; abi_long l_start; abi_long l_len; +#if defined(TARGET_MIPS) + abi_long l_sysid; +#endif int l_pid; +#if defined(TARGET_MIPS) + abi_long pad[4]; +#endif }; struct target_flock64 { From 2ef4186964653671ef899016c05d44e7b71cf4a6 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Mon, 19 Sep 2016 13:44:41 +0200 Subject: [PATCH 253/723] linux-user: Fix structure target_semid64_ds definition for Mips This patch corrects target_semid64_ds structure definition for Mips. See, for example definition of semid64_ds for Mips in Linux kernel: arch/mips/include/uapi/asm/sembuf.h#L13. This patch will also fix certain semaphore-related LTP tests for Mips, if they are executed in Qemu user mode for any Mips platform. Signed-off-by: Miodrag Dinic Signed-off-by: Aleksandar Markovic Reviewed-by: Peter Maydell Reviewed-by: Laurent Vivier Reviewed-by: Leon Alrae Acked-by: Riku Voipio Signed-off-by: Leon Alrae --- linux-user/mips/target_structs.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/linux-user/mips/target_structs.h b/linux-user/mips/target_structs.h index fbd995581ea..909ba897089 100644 --- a/linux-user/mips/target_structs.h +++ b/linux-user/mips/target_structs.h @@ -45,4 +45,20 @@ struct target_shmid_ds { abi_ulong __unused2; }; +#define TARGET_SEMID64_DS + +/* + * The semid64_ds structure for the MIPS architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + */ +struct target_semid64_ds { + struct target_ipc_perm sem_perm; + abi_ulong sem_otime; + abi_ulong sem_ctime; + abi_ulong sem_nsems; + abi_ulong __unused1; + abi_ulong __unused2; +}; + #endif From d7779acb30489729431436e71afb1fd36ef1966d Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Mon, 19 Sep 2016 13:44:42 +0200 Subject: [PATCH 254/723] linux-user: Fix certain argument alignment cases for Mips64 The function that is changed in this patch is supposed to indicate that there was certain argument rearrangement related to 64-bit arguments on 32-bit platforms. The background on such rearrangements can be found, for example, in the man page for syscall(2). However, for 64-bit Mips architectures there is no such rearrangement, and this patch reflects it. Signed-off-by: Aleksandar Rikalo Signed-off-by: Aleksandar Markovic Reviewed-by: Laurent Vivier Reviewed-by: Leon Alrae Acked-by: Riku Voipio Signed-off-by: Leon Alrae --- linux-user/syscall.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 7aa2c1d7206..116e4635688 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -658,7 +658,7 @@ static inline int next_free_host_timer(void) static inline int regpairs_aligned(void *cpu_env) { return ((((CPUARMState *)cpu_env)->eabi) == 1) ; } -#elif defined(TARGET_MIPS) +#elif defined(TARGET_MIPS) && (TARGET_ABI_BITS == 32) static inline int regpairs_aligned(void *cpu_env) { return 1; } #elif defined(TARGET_PPC) && !defined(TARGET_PPC64) /* SysV AVI for PPC32 expects 64bit parameters to be passed on odd/even pairs From 0444a3b7935f6e09dfddf00411840e70f6fd933e Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Mon, 19 Sep 2016 13:44:43 +0200 Subject: [PATCH 255/723] linux-user: Add missing TARGET_EDQUOT error code for Mips EDQUOT is defined for Mips platform in Linux kernel in such a way that it has different value than on most other platforms. However, correspondent TARGET_EDQUOT for Mips is missing in Qemu code. Moreover, TARGET_EDQUOT is missing from the table for conversion of error codes from host to target. This patch fixes these problems. Without this patch, syscalls add_key(), keyctl(), link(), mkdir(), mknod(), open(), rename(), request_key(), setxattr(), symlink(), and write() will not be able to return the right error code in some scenarios on Mips platform. (Some of these syscalls are not yet supported in Qemu, but once they are supported, they will need correct EDQUOT handling.) Signed-off-by: Aleksandar Markovic Reviewed-by: Laurent Vivier Acked-by: Riku Voipio Signed-off-by: Leon Alrae --- linux-user/mips/target_syscall.h | 2 ++ linux-user/mips64/target_syscall.h | 2 ++ linux-user/syscall.c | 1 + 3 files changed, 5 insertions(+) diff --git a/linux-user/mips/target_syscall.h b/linux-user/mips/target_syscall.h index 6c666dcb730..0b64b73714d 100644 --- a/linux-user/mips/target_syscall.h +++ b/linux-user/mips/target_syscall.h @@ -221,6 +221,8 @@ struct target_pt_regs { #undef TARGET_ENOTRECOVERABLE #define TARGET_ENOTRECOVERABLE 166 /* State not recoverable */ +#undef TARGET_EDQUOT +#define TARGET_EDQUOT 1133 /* Quota exceeded */ #define UNAME_MACHINE "mips" #define UNAME_MINIMUM_RELEASE "2.6.32" diff --git a/linux-user/mips64/target_syscall.h b/linux-user/mips64/target_syscall.h index a9c17f7edfb..6692917e2e5 100644 --- a/linux-user/mips64/target_syscall.h +++ b/linux-user/mips64/target_syscall.h @@ -218,6 +218,8 @@ struct target_pt_regs { #undef TARGET_ENOTRECOVERABLE #define TARGET_ENOTRECOVERABLE 166 /* State not recoverable */ +#undef TARGET_EDQUOT +#define TARGET_EDQUOT 1133 /* Quota exceeded */ #define UNAME_MACHINE "mips64" #define UNAME_MINIMUM_RELEASE "2.6.32" diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 116e4635688..0815f309654 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -757,6 +757,7 @@ static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = { [ENAVAIL] = TARGET_ENAVAIL, [EISNAM] = TARGET_EISNAM, [EREMOTEIO] = TARGET_EREMOTEIO, + [EDQUOT] = TARGET_EDQUOT, [ESHUTDOWN] = TARGET_ESHUTDOWN, [ETOOMANYREFS] = TARGET_ETOOMANYREFS, [ETIMEDOUT] = TARGET_ETIMEDOUT, From fea55615b2f924128e115ceb2265069561b03ef8 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Mon, 19 Sep 2016 13:44:44 +0200 Subject: [PATCH 256/723] linux-user: Add missing Mips syscalls items in strace.list Without this patch, a number of Mips syscalls will be logged in the following way (in this example, this is an invocation of accept4()): 86906 Unknown syscall 4334 This patch provides standard Qemu's strace output for such cases, like this: 95861 accept4(3,1996486000,1996486016,128,0,0) = 5 Such output may be further improved by providing strace-related functions that handle only particular syscalls, but this is beyond the scope of this patch. Signed-off-by: Aleksandar Markovic Reviewed-by: Laurent Vivier Acked-by: Riku Voipio Signed-off-by: Leon Alrae --- linux-user/strace.list | 114 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/linux-user/strace.list b/linux-user/strace.list index aa967a24754..608f7e09323 100644 --- a/linux-user/strace.list +++ b/linux-user/strace.list @@ -6,6 +6,9 @@ #ifdef TARGET_NR_accept { TARGET_NR_accept, "accept" , NULL, print_accept, NULL }, #endif +#ifdef TARGET_NR_accept4 +{ TARGET_NR_accept4, "accept4" , NULL, NULL, NULL }, +#endif #ifdef TARGET_NR_access { TARGET_NR_access, "access" , NULL, print_access, NULL }, #endif @@ -39,6 +42,9 @@ #ifdef TARGET_NR_bind { TARGET_NR_bind, "bind" , NULL, NULL, NULL }, #endif +#ifdef TARGET_NR_bpf +{ TARGET_NR_bpf, "bpf" , NULL, NULL, NULL }, +#endif #ifdef TARGET_NR_break { TARGET_NR_break, "break" , NULL, NULL, NULL }, #endif @@ -123,18 +129,30 @@ #ifdef TARGET_NR_epoll_ctl_old { TARGET_NR_epoll_ctl_old, "epoll_ctl_old" , NULL, NULL, NULL }, #endif +#ifdef TARGET_NR_epoll_pwait +{ TARGET_NR_epoll_pwait, "epoll_pwait" , NULL, NULL, NULL }, +#endif #ifdef TARGET_NR_epoll_wait { TARGET_NR_epoll_wait, "epoll_wait" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_epoll_wait_old { TARGET_NR_epoll_wait_old, "epoll_wait_old" , NULL, NULL, NULL }, #endif +#ifdef TARGET_NR_eventfd +{ TARGET_NR_eventfd, "eventfd" , NULL, NULL, NULL }, +#endif +#ifdef TARGET_NR_eventfd2 +{ TARGET_NR_eventfd2, "eventfd2" , NULL, NULL, NULL }, +#endif #ifdef TARGET_NR_execv { TARGET_NR_execv, "execv" , NULL, print_execv, NULL }, #endif #ifdef TARGET_NR_execve { TARGET_NR_execve, "execve" , NULL, print_execve, NULL }, #endif +#ifdef TARGET_NR_execveat +{ TARGET_NR_execveat, "execveat" , NULL, NULL, NULL }, +#endif #ifdef TARGET_NR_exec_with_loader { TARGET_NR_exec_with_loader, "exec_with_loader" , NULL, NULL, NULL }, #endif @@ -156,6 +174,15 @@ #ifdef TARGET_NR_fadvise64_64 { TARGET_NR_fadvise64_64, "fadvise64_64" , NULL, NULL, NULL }, #endif +#ifdef TARGET_NR_fallocate +{ TARGET_NR_fallocate, "fallocate" , NULL, NULL, NULL }, +#endif +#ifdef TARGET_NR_fanotify_init +{ TARGET_NR_fanotify_init, "fanotify_init" , NULL, NULL, NULL }, +#endif +#ifdef TARGET_NR_fanotify_mark +{ TARGET_NR_fanotify_mark, "fanotify_mark" , NULL, NULL, NULL }, +#endif #ifdef TARGET_NR_fchdir { TARGET_NR_fchdir, "fchdir" , NULL, NULL, NULL }, #endif @@ -186,6 +213,9 @@ #ifdef TARGET_NR_fgetxattr { TARGET_NR_fgetxattr, "fgetxattr" , NULL, NULL, NULL }, #endif +#ifdef TARGET_NR_finit_module +{ TARGET_NR_finit_module, "finit_module" , NULL, NULL, NULL }, +#endif #ifdef TARGET_NR_flistxattr { TARGET_NR_flistxattr, "flistxattr" , NULL, NULL, NULL }, #endif @@ -231,6 +261,9 @@ #ifdef TARGET_NR_futimesat { TARGET_NR_futimesat, "futimesat" , NULL, print_futimesat, NULL }, #endif +#ifdef TARGET_NR_getcpu +{ TARGET_NR_getcpu, "getcpu" , "%s(%p,%d)", NULL, NULL }, +#endif #ifdef TARGET_NR_getcwd { TARGET_NR_getcwd, "getcwd" , "%s(%p,%d)", NULL, NULL }, #endif @@ -306,6 +339,9 @@ #ifdef TARGET_NR_getpriority { TARGET_NR_getpriority, "getpriority", "%s(%#x,%#x)", NULL, NULL }, #endif +#ifdef TARGET_NR_getrandom +{ TARGET_NR_getrandom, "getrandom", NULL, NULL, NULL }, +#endif #ifdef TARGET_NR_getresgid { TARGET_NR_getresgid, "getresgid" , NULL, NULL, NULL }, #endif @@ -379,6 +415,9 @@ #ifdef TARGET_NR_inotify_init { TARGET_NR_inotify_init, "inotify_init" , NULL, NULL, NULL }, #endif +#ifdef TARGET_NR_inotify_init1 +{ TARGET_NR_inotify_init1, "inotify_init1" , NULL, NULL, NULL }, +#endif #ifdef TARGET_NR_inotify_rm_watch { TARGET_NR_inotify_rm_watch, "inotify_rm_watch" , NULL, NULL, NULL }, #endif @@ -415,6 +454,9 @@ #ifdef TARGET_NR_ipc { TARGET_NR_ipc, "ipc" , NULL, print_ipc, NULL }, #endif +#ifdef TARGET_NR_kcmp +{ TARGET_NR_kcmp, "kcmp" , NULL, NULL, NULL }, +#endif #ifdef TARGET_NR_kexec_load { TARGET_NR_kexec_load, "kexec_load" , NULL, NULL, NULL }, #endif @@ -484,6 +526,12 @@ #ifdef TARGET_NR_mbind { TARGET_NR_mbind, "mbind" , NULL, NULL, NULL }, #endif +#ifdef TARGET_NR_membarrier +{ TARGET_NR_membarrier, "membarrier" , NULL, NULL, NULL }, +#endif +#ifdef TARGET_NR_memfd_create +{ TARGET_NR_memfd_create, "memfd_create" , NULL, NULL, NULL }, +#endif #ifdef TARGET_NR_memory_ordering { TARGET_NR_memory_ordering, "memory_ordering" , NULL, NULL, NULL }, #endif @@ -511,6 +559,9 @@ #ifdef TARGET_NR_mlock { TARGET_NR_mlock, "mlock" , NULL, NULL, NULL }, #endif +#ifdef TARGET_NR_mlock2 +{ TARGET_NR_mlock2, "mlock2" , NULL, NULL, NULL }, +#endif #ifdef TARGET_NR_mlockall { TARGET_NR_mlockall, "mlockall" , NULL, NULL, NULL }, #endif @@ -583,6 +634,9 @@ #ifdef TARGET_NR_munmap { TARGET_NR_munmap, "munmap" , NULL, print_munmap, NULL }, #endif +#ifdef TARGET_NR_name_to_handle_at +{ TARGET_NR_name_to_handle_at, "name_to_handle_at" , NULL, NULL, NULL }, +#endif #ifdef TARGET_NR_nanosleep { TARGET_NR_nanosleep, "nanosleep" , NULL, NULL, NULL }, #endif @@ -952,6 +1006,9 @@ #ifdef TARGET_NR_pciconfig_write { TARGET_NR_pciconfig_write, "pciconfig_write" , NULL, NULL, NULL }, #endif +#ifdef TARGET_NR_perf_event_open +{ TARGET_NR_perf_event_open, "perf_event_open" , NULL, NULL, NULL }, +#endif #ifdef TARGET_NR_perfctr { TARGET_NR_perfctr, "perfctr" , NULL, NULL, NULL }, #endif @@ -976,6 +1033,18 @@ #ifdef TARGET_NR_pread64 { TARGET_NR_pread64, "pread64" , NULL, NULL, NULL }, #endif +#ifdef TARGET_NR_preadv +{ TARGET_NR_preadv, "preadv" , NULL, NULL, NULL }, +#endif +#ifdef TARGET_NR_prlimit64 +{ TARGET_NR_prlimit64, "prlimit64" , NULL, NULL, NULL }, +#endif +#ifdef TARGET_NR_process_vm_readv +{ TARGET_NR_process_vm_readv, "process_vm_readv" , NULL, NULL, NULL }, +#endif +#ifdef TARGET_NR_process_vm_writev +{ TARGET_NR_process_vm_writev, "process_vm_writev" , NULL, NULL, NULL }, +#endif #ifdef TARGET_NR_prof { TARGET_NR_prof, "prof" , NULL, NULL, NULL }, #endif @@ -994,6 +1063,9 @@ #ifdef TARGET_NR_pwrite64 { TARGET_NR_pwrite64, "pwrite64" , NULL, NULL, NULL }, #endif +#ifdef TARGET_NR_pwritev +{ TARGET_NR_pwritev, "pwritev" , NULL, NULL, NULL }, +#endif #ifdef TARGET_NR_query_module { TARGET_NR_query_module, "query_module" , NULL, NULL, NULL }, #endif @@ -1027,6 +1099,9 @@ #ifdef TARGET_NR_recvfrom { TARGET_NR_recvfrom, "recvfrom" , NULL, NULL, NULL }, #endif +#ifdef TARGET_NR_recvmmsg +{ TARGET_NR_recvmmsg, "recvmmsg" , NULL, NULL, NULL }, +#endif #ifdef TARGET_NR_recvmsg { TARGET_NR_recvmsg, "recvmsg" , NULL, NULL, NULL }, #endif @@ -1042,9 +1117,18 @@ #ifdef TARGET_NR_renameat { TARGET_NR_renameat, "renameat" , NULL, print_renameat, NULL }, #endif +#ifdef TARGET_NR_renameat2 +{ TARGET_NR_renameat2, "renameat2" , NULL, NULL, NULL }, +#endif #ifdef TARGET_NR_request_key { TARGET_NR_request_key, "request_key" , NULL, NULL, NULL }, #endif +#ifdef TARGET_NR_reserved177 +{ TARGET_NR_reserved177, "reserved177" , NULL, NULL, NULL }, +#endif +#ifdef TARGET_NR_reserved193 +{ TARGET_NR_reserved193, "reserved193" , NULL, NULL, NULL }, +#endif #ifdef TARGET_NR_reserved221 { TARGET_NR_reserved221, "reserved221" , NULL, NULL, NULL }, #endif @@ -1078,12 +1162,18 @@ #ifdef TARGET_NR_rt_sigtimedwait { TARGET_NR_rt_sigtimedwait, "rt_sigtimedwait" , NULL, NULL, NULL }, #endif +#ifdef TARGET_NR_rt_tgsigqueueinfo +{ TARGET_NR_rt_tgsigqueueinfo, "rt_tgsigqueueinfo" , NULL, NULL, NULL }, +#endif #ifdef TARGET_NR_sched_getaffinity { TARGET_NR_sched_getaffinity, "sched_getaffinity" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_sched_get_affinity { TARGET_NR_sched_get_affinity, "sched_get_affinity" , NULL, NULL, NULL }, #endif +#ifdef TARGET_NR_sched_getattr +{ TARGET_NR_sched_getattr, "sched_getattr" , NULL, NULL, NULL }, +#endif #ifdef TARGET_NR_sched_getparam { TARGET_NR_sched_getparam, "sched_getparam" , NULL, NULL, NULL }, #endif @@ -1102,6 +1192,9 @@ #ifdef TARGET_NR_sched_setaffinity { TARGET_NR_sched_setaffinity, "sched_setaffinity" , NULL, NULL, NULL }, #endif +#ifdef TARGET_NR_sched_setatt +{ TARGET_NR_sched_setatt, "sched_setatt" , NULL, NULL, NULL }, +#endif #ifdef TARGET_NR_sched_set_affinity { TARGET_NR_sched_set_affinity, "sched_set_affinity" , NULL, NULL, NULL }, #endif @@ -1114,6 +1207,9 @@ #ifdef TARGET_NR_sched_yield { TARGET_NR_sched_yield, "sched_yield" , NULL, NULL, NULL }, #endif +#ifdef TARGET_NR_seccomp +{ TARGET_NR_seccomp, "seccomp" , NULL, NULL, NULL }, +#endif #ifdef TARGET_NR_security { TARGET_NR_security, "security" , NULL, NULL, NULL }, #endif @@ -1141,6 +1237,9 @@ #ifdef TARGET_NR_sendfile64 { TARGET_NR_sendfile64, "sendfile64" , NULL, NULL, NULL }, #endif +#ifdef TARGET_NR_sendmmsg +{ TARGET_NR_sendmmsg, "sendmmsg" , NULL, NULL, NULL }, +#endif #ifdef TARGET_NR_sendmsg { TARGET_NR_sendmsg, "sendmsg" , NULL, NULL, NULL }, #endif @@ -1280,6 +1379,12 @@ #ifdef TARGET_NR_signal { TARGET_NR_signal, "signal" , NULL, NULL, NULL }, #endif +#ifdef TARGET_NR_signalfd +{ TARGET_NR_signalfd, "signalfd" , NULL, NULL, NULL }, +#endif +#ifdef TARGET_NR_signalfd4 +{ TARGET_NR_signalfd4, "signalfd4" , NULL, NULL, NULL }, +#endif #ifdef TARGET_NR_sigpending { TARGET_NR_sigpending, "sigpending" , NULL, NULL, NULL }, #endif @@ -1352,6 +1457,9 @@ #ifdef TARGET_NR_sync_file_range { TARGET_NR_sync_file_range, "sync_file_range" , NULL, NULL, NULL }, #endif +#ifdef TARGET_NR_syncfs +{ TARGET_NR_syncfs, "syncfs" , NULL, NULL, NULL }, +#endif #ifdef TARGET_NR_syscall { TARGET_NR_syscall, "syscall" , NULL, NULL, NULL }, #endif @@ -1409,6 +1517,9 @@ #ifdef TARGET_NR_timer_settime { TARGET_NR_timer_settime, "timer_settime" , NULL, NULL, NULL }, #endif +#ifdef TARGET_NR_timerfd +{ TARGET_NR_timerfd, "timerfd" , NULL, NULL, NULL }, +#endif #ifdef TARGET_NR_timerfd_create { TARGET_NR_timerfd_create, "timerfd_create" , NULL, NULL, NULL }, #endif @@ -1460,6 +1571,9 @@ #ifdef TARGET_NR_unshare { TARGET_NR_unshare, "unshare" , NULL, NULL, NULL }, #endif +#ifdef TARGET_NR_userfaultfd +{ TARGET_NR_userfaultfd, "userfaultfd" , NULL, NULL, NULL }, +#endif #ifdef TARGET_NR_unused109 { TARGET_NR_unused109, "unused109" , NULL, NULL, NULL }, #endif From bb9f8dd0e15a9744b8d09d06ecb6a18ca3dcc173 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Tue, 6 Sep 2016 15:26:37 +0100 Subject: [PATCH 257/723] qcow2: fix encryption during cow of sectors Broken in previous commit: commit aaa4d20b4972bb1a811ce929502e6741835d584e Author: Kevin Wolf Date: Wed Jun 1 15:21:05 2016 +0200 qcow2: Make copy_sectors() byte based The copy_sectors() code was originally using the 'sector' parameter for encryption, which was passed in by the caller from the QCowL2Meta.offset field (aka the guest logical offset). After the change, the code is using 'cluster_offset' which was passed in from QCow2L2Meta.alloc_offset field (aka the host physical offset). This would cause the data to be encrypted using an incorrect initialization vector which will in turn cause later reads to return garbage. Although current qcow2 built-in encryption is blocked from usage in the emulator, one could still hit this if writing to the file via qemu-{img,io,nbd} commands. Cc: qemu-stable@nongnu.org Signed-off-by: Daniel P. Berrange Signed-off-by: Kevin Wolf --- block/qcow2-cluster.c | 2 +- tests/qemu-iotests/158 | 80 ++++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/158.out | 36 +++++++++++++++++ tests/qemu-iotests/group | 1 + 4 files changed, 118 insertions(+), 1 deletion(-) create mode 100755 tests/qemu-iotests/158 create mode 100644 tests/qemu-iotests/158.out diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 9ab445dd172..61d1ffd2235 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -429,7 +429,7 @@ static int coroutine_fn do_perform_cow(BlockDriverState *bs, if (bs->encrypted) { Error *err = NULL; - int64_t sector = (cluster_offset + offset_in_cluster) + int64_t sector = (src_cluster_offset + offset_in_cluster) >> BDRV_SECTOR_BITS; assert(s->cipher); assert((offset_in_cluster & ~BDRV_SECTOR_MASK) == 0); diff --git a/tests/qemu-iotests/158 b/tests/qemu-iotests/158 new file mode 100755 index 00000000000..a6cdd6d8cfa --- /dev/null +++ b/tests/qemu-iotests/158 @@ -0,0 +1,80 @@ +#!/bin/bash +# +# Test encrypted read/write using backing files +# +# Copyright (C) 2015 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +# creator +owner=berrange@redhat.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_supported_fmt qcow2 +_supported_proto generic +_supported_os Linux + + +size=128M +TEST_IMG_BASE=$TEST_IMG.base + +TEST_IMG_SAVE=$TEST_IMG +TEST_IMG=$TEST_IMG_BASE +echo "== create base ==" +IMGOPTS="encryption=on" _make_test_img $size +TEST_IMG=$TEST_IMG_SAVE + +echo +echo "== writing whole image ==" +echo "astrochicken" | $QEMU_IO -c "write -P 0xa 0 $size" "$TEST_IMG_BASE" | _filter_qemu_io | _filter_testdir + +echo +echo "== verify pattern ==" +echo "astrochicken" | $QEMU_IO -c "read -P 0xa 0 $size" "$TEST_IMG_BASE" | _filter_qemu_io | _filter_testdir + +echo "== create overlay ==" +IMGOPTS="encryption=on" _make_test_img -b "$TEST_IMG_BASE" $size + +echo +echo "== writing part of a cluster ==" +echo "astrochicken" | $QEMU_IO -c "write -P 0xe 0 1024" "$TEST_IMG" | _filter_qemu_io | _filter_testdir + +echo +echo "== verify pattern ==" +echo "astrochicken" | $QEMU_IO -c "read -P 0xe 0 1024" "$TEST_IMG" | _filter_qemu_io | _filter_testdir +echo +echo "== verify pattern ==" +echo "astrochicken" | $QEMU_IO -c "read -P 0xa 1024 64512" "$TEST_IMG" | _filter_qemu_io | _filter_testdir + + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/158.out b/tests/qemu-iotests/158.out new file mode 100644 index 00000000000..b3f37e28eff --- /dev/null +++ b/tests/qemu-iotests/158.out @@ -0,0 +1,36 @@ +QA output created by 158 +== create base == +Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728 encryption=on + +== writing whole image == +Disk image 'TEST_DIR/t.qcow2.base' is encrypted. +password: +wrote 134217728/134217728 bytes at offset 0 +128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== verify pattern == +Disk image 'TEST_DIR/t.qcow2.base' is encrypted. +password: +read 134217728/134217728 bytes at offset 0 +128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +== create overlay == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base encryption=on + +== writing part of a cluster == +Disk image 'TEST_DIR/t.qcow2' is encrypted. +password: +wrote 1024/1024 bytes at offset 0 +1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== verify pattern == +Disk image 'TEST_DIR/t.qcow2' is encrypted. +password: +read 1024/1024 bytes at offset 0 +1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== verify pattern == +Disk image 'TEST_DIR/t.qcow2' is encrypted. +password: +read 64512/64512 bytes at offset 1024 +63 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +*** done diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index a57fc9218f5..7eb17707a2b 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -157,6 +157,7 @@ 155 rw auto 156 rw auto quick 157 auto +158 rw auto quick 159 rw auto quick 160 rw auto quick 162 auto quick From 1813d33015f0a6780609739999f3962f2dc56921 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 15 Sep 2016 17:44:16 +0200 Subject: [PATCH 258/723] hmp: Remove dead code in hmp_qemu_io() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit blk can never be NULL, drop the check. This fixes a Coverity warning. Signed-off-by: Kevin Wolf Reviewed-by: Marc-André Lureau --- hmp.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/hmp.c b/hmp.c index ad33b442d2b..0a16aefc2ac 100644 --- a/hmp.c +++ b/hmp.c @@ -1924,6 +1924,7 @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict) { BlockBackend *blk; BlockBackend *local_blk = NULL; + AioContext *aio_context; const char* device = qdict_get_str(qdict, "device"); const char* command = qdict_get_str(qdict, "command"); Error *err = NULL; @@ -1939,17 +1940,12 @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict) } } - if (blk) { - AioContext *aio_context = blk_get_aio_context(blk); - aio_context_acquire(aio_context); + aio_context = blk_get_aio_context(blk); + aio_context_acquire(aio_context); - qemuio_command(blk, command); + qemuio_command(blk, command); - aio_context_release(aio_context); - } else { - error_set(&err, ERROR_CLASS_DEVICE_NOT_FOUND, - "Device '%s' not found", device); - } + aio_context_release(aio_context); fail: blk_unref(local_blk); From c2519009b428fb19a9fdbc707e786b1cebd4994f Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 15 Sep 2016 19:42:49 +0300 Subject: [PATCH 259/723] tests: allow to specify list of formats to test for check-block.sh This would make code better and allow to test specific format. Signed-off-by: Denis V. Lunev CC: Stefan Hajnoczi CC: Kevin Wolf CC: Paolo Bonzini Signed-off-by: Kevin Wolf --- tests/check-block.sh | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/tests/check-block.sh b/tests/check-block.sh index a37797a494b..c3de3789c48 100755 --- a/tests/check-block.sh +++ b/tests/check-block.sh @@ -1,5 +1,10 @@ #!/bin/sh +FORMAT_LIST="raw qcow2 qed vmdk vpc" +if [ "$#" -ne 0 ]; then + FORMAT_LIST="$@" +fi + export QEMU_PROG="$(pwd)/x86_64-softmmu/qemu-system-x86_64" export QEMU_IMG_PROG="$(pwd)/qemu-img" export QEMU_IO_PROG="$(pwd)/qemu-io" @@ -12,10 +17,8 @@ fi cd tests/qemu-iotests ret=0 -./check -T -nocache -raw || ret=1 -./check -T -nocache -qcow2 || ret=1 -./check -T -nocache -qed|| ret=1 -./check -T -nocache -vmdk|| ret=1 -./check -T -nocache -vpc || ret=1 +for FMT in $FORMAT_LIST ; do + ./check -T -nocache -$FMT || ret=1 +done exit $ret From 38b5e4c3dc6d713eae340341ee139c12d5c1a21e Mon Sep 17 00:00:00 2001 From: Alberto Garcia Date: Thu, 15 Sep 2016 17:52:59 +0300 Subject: [PATCH 260/723] block: Remove bdrv_is_snapshot This is unnecessary and has been unused since 5433c24f0f9306c82ad9bcc. Signed-off-by: Alberto Garcia Reviewed-by: Kevin Wolf Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block.c | 5 ----- include/block/block.h | 1 - 2 files changed, 6 deletions(-) diff --git a/block.c b/block.c index afaff93423d..d4485209516 100644 --- a/block.c +++ b/block.c @@ -3013,11 +3013,6 @@ bool bdrv_debug_is_suspended(BlockDriverState *bs, const char *tag) return false; } -int bdrv_is_snapshot(BlockDriverState *bs) -{ - return !!(bs->open_flags & BDRV_O_SNAPSHOT); -} - /* backing_file can either be relative, or absolute, or a protocol. If it is * relative, it must be relative to the chain. So, passing in bs->filename * from a BDS as backing_file should not be done, as that may be relative to diff --git a/include/block/block.h b/include/block/block.h index ffecebfb3a7..f374e1a7251 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -414,7 +414,6 @@ void bdrv_get_full_backing_filename_from_filename(const char *backed, const char *backing, char *dest, size_t sz, Error **errp); -int bdrv_is_snapshot(BlockDriverState *bs); int path_has_protocol(const char *path); int path_is_absolute(const char *path); From 14499ea5413be45bbb3934dd6fd8fa27c54c1dd4 Mon Sep 17 00:00:00 2001 From: Alberto Garcia Date: Thu, 15 Sep 2016 17:53:00 +0300 Subject: [PATCH 261/723] block: Set BDRV_O_ALLOW_RDWR and snapshot_options before storing the flags If an image is opened with snapshot=on, its flags are modified by bdrv_backing_options() and then bs->open_flags is updated accordingly. This last step is unnecessary if we calculate the new flags before setting bs->open_flags. Soon we'll introduce the "read-only" option, and then we'll need to be able to modify its value in the QDict when snapshot=on. This is more cumbersome if bs->options is already set. This patch simplifies that. Other than that, there are no semantic changes. Although it might seem that bs->options can have a different value now because it is stored after calling bdrv_backing_options(), this call doesn't actually modify them in this scenario. The code that sets BDRV_O_ALLOW_RDWR is also moved for the same reason. Signed-off-by: Alberto Garcia Signed-off-by: Kevin Wolf --- block.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/block.c b/block.c index d4485209516..324dbe702b5 100644 --- a/block.c +++ b/block.c @@ -1675,6 +1675,17 @@ static BlockDriverState *bdrv_open_inherit(const char *filename, goto fail; } + if (flags & BDRV_O_RDWR) { + flags |= BDRV_O_ALLOW_RDWR; + } + + if (flags & BDRV_O_SNAPSHOT) { + snapshot_options = qdict_new(); + bdrv_temp_snapshot_options(&snapshot_flags, snapshot_options, + flags, options); + bdrv_backing_options(&flags, options, flags, options); + } + bs->open_flags = flags; bs->options = options; options = qdict_clone_shallow(options); @@ -1699,18 +1710,6 @@ static BlockDriverState *bdrv_open_inherit(const char *filename, /* Open image file without format layer */ if ((flags & BDRV_O_PROTOCOL) == 0) { - if (flags & BDRV_O_RDWR) { - flags |= BDRV_O_ALLOW_RDWR; - } - if (flags & BDRV_O_SNAPSHOT) { - snapshot_options = qdict_new(); - bdrv_temp_snapshot_options(&snapshot_flags, snapshot_options, - flags, options); - bdrv_backing_options(&flags, options, flags, options); - } - - bs->open_flags = flags; - file = bdrv_open_child(filename, options, "file", bs, &child_file, true, &local_err); if (local_err) { From 9b7e8691670fab57c387b6955dc14a09696ae034 Mon Sep 17 00:00:00 2001 From: Alberto Garcia Date: Thu, 15 Sep 2016 17:53:01 +0300 Subject: [PATCH 262/723] block: Update bs->open_flags earlier in bdrv_open_common() We're only doing this immediately before opening the image, but bs->open_flags is used earlier in the function. At the moment this is not causing problems because none of the checked flags are modified by update_flags_from_options(), but this will change when we introduce the "read-only" option. This patch calls update_flags_from_options() at the beginning of the function, immediately after creating the QemuOpts. Signed-off-by: Alberto Garcia Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- block.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/block.c b/block.c index 324dbe702b5..a98b75e4df0 100644 --- a/block.c +++ b/block.c @@ -961,6 +961,8 @@ static int bdrv_open_common(BlockDriverState *bs, BdrvChild *file, goto fail_opts; } + update_flags_from_options(&bs->open_flags, opts); + driver_name = qemu_opt_get(opts, "driver"); drv = bdrv_find_format(driver_name); assert(drv != NULL); @@ -1022,9 +1024,6 @@ static int bdrv_open_common(BlockDriverState *bs, BdrvChild *file, bs->drv = drv; bs->opaque = g_malloc0(drv->instance_size); - /* Apply cache mode options */ - update_flags_from_options(&bs->open_flags, opts); - /* Open the image, either directly or using a protocol */ open_flags = bdrv_open_flags(bs, bs->open_flags); if (drv->bdrv_file_open) { From f87a0e29a9814a7ab6ee92b238989fed6186c4f3 Mon Sep 17 00:00:00 2001 From: Alberto Garcia Date: Thu, 15 Sep 2016 17:53:02 +0300 Subject: [PATCH 263/723] block: Add "read-only" to the options QDict This adds the "read-only" option to the QDict. One important effect of this change is that when a child inherits options from its parent, the existing "read-only" mode can be preserved if it was explicitly set previously. This addresses scenarios like this: [E] <- [D] <- [C] <- [B] <- [A] In this case, if we reopen [D] with read-only=off, and later reopen [B], then [D] will not inherit read-only=on from its parent during the bdrv_reopen_queue_child() stage. The BDRV_O_RDWR flag is not removed yet, but its keep in sync with the value of the "read-only" option. Signed-off-by: Alberto Garcia Signed-off-by: Kevin Wolf --- block.c | 38 +++++++++++++++++++++++++++++++++++--- block/vvfat.c | 3 ++- blockdev.c | 16 +++++++--------- include/block/block.h | 1 + 4 files changed, 45 insertions(+), 13 deletions(-) diff --git a/block.c b/block.c index a98b75e4df0..b724adacfcb 100644 --- a/block.c +++ b/block.c @@ -733,6 +733,9 @@ static void bdrv_temp_snapshot_options(int *child_flags, QDict *child_options, qdict_set_default_str(child_options, BDRV_OPT_CACHE_DIRECT, "off"); qdict_set_default_str(child_options, BDRV_OPT_CACHE_NO_FLUSH, "on"); + /* Copy the read-only option from the parent */ + qdict_copy_default(child_options, parent_options, BDRV_OPT_READ_ONLY); + /* aio=native doesn't work for cache.direct=off, so disable it for the * temporary snapshot */ *child_flags &= ~BDRV_O_NATIVE_AIO; @@ -755,6 +758,9 @@ static void bdrv_inherited_options(int *child_flags, QDict *child_options, qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_DIRECT); qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_NO_FLUSH); + /* Inherit the read-only option from the parent if it's not set */ + qdict_copy_default(child_options, parent_options, BDRV_OPT_READ_ONLY); + /* Our block drivers take care to send flushes and respect unmap policy, * so we can default to enable both on lower layers regardless of the * corresponding parent options. */ @@ -808,7 +814,8 @@ static void bdrv_backing_options(int *child_flags, QDict *child_options, qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_NO_FLUSH); /* backing files always opened read-only */ - flags &= ~(BDRV_O_RDWR | BDRV_O_COPY_ON_READ); + qdict_set_default_str(child_options, BDRV_OPT_READ_ONLY, "on"); + flags &= ~BDRV_O_COPY_ON_READ; /* snapshot=on is handled on the top layer */ flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_TEMPORARY); @@ -855,6 +862,14 @@ static void update_flags_from_options(int *flags, QemuOpts *opts) if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_DIRECT, false)) { *flags |= BDRV_O_NOCACHE; } + + *flags &= ~BDRV_O_RDWR; + + assert(qemu_opt_find(opts, BDRV_OPT_READ_ONLY)); + if (!qemu_opt_get_bool(opts, BDRV_OPT_READ_ONLY, false)) { + *flags |= BDRV_O_RDWR; + } + } static void update_options_from_flags(QDict *options, int flags) @@ -867,6 +882,10 @@ static void update_options_from_flags(QDict *options, int flags) qdict_put(options, BDRV_OPT_CACHE_NO_FLUSH, qbool_from_bool(flags & BDRV_O_NO_FLUSH)); } + if (!qdict_haskey(options, BDRV_OPT_READ_ONLY)) { + qdict_put(options, BDRV_OPT_READ_ONLY, + qbool_from_bool(!(flags & BDRV_O_RDWR))); + } } static void bdrv_assign_node_name(BlockDriverState *bs, @@ -930,6 +949,11 @@ static QemuOptsList bdrv_runtime_opts = { .type = QEMU_OPT_BOOL, .help = "Ignore flush requests", }, + { + .name = BDRV_OPT_READ_ONLY, + .type = QEMU_OPT_BOOL, + .help = "Node is opened in read-only mode", + }, { /* end of list */ } }, }; @@ -1674,14 +1698,22 @@ static BlockDriverState *bdrv_open_inherit(const char *filename, goto fail; } - if (flags & BDRV_O_RDWR) { - flags |= BDRV_O_ALLOW_RDWR; + /* Set the BDRV_O_RDWR and BDRV_O_ALLOW_RDWR flags. + * FIXME: we're parsing the QDict to avoid having to create a + * QemuOpts just for this, but neither option is optimal. */ + if (g_strcmp0(qdict_get_try_str(options, BDRV_OPT_READ_ONLY), "on") && + !qdict_get_try_bool(options, BDRV_OPT_READ_ONLY, false)) { + flags |= (BDRV_O_RDWR | BDRV_O_ALLOW_RDWR); + } else { + flags &= ~BDRV_O_RDWR; } if (flags & BDRV_O_SNAPSHOT) { snapshot_options = qdict_new(); bdrv_temp_snapshot_options(&snapshot_flags, snapshot_options, flags, options); + /* Let bdrv_backing_options() override "read-only" */ + qdict_del(options, BDRV_OPT_READ_ONLY); bdrv_backing_options(&flags, options, flags, options); } diff --git a/block/vvfat.c b/block/vvfat.c index ba2620f3c20..ded21092eef 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -2971,7 +2971,8 @@ static BlockDriver vvfat_write_target = { static void vvfat_qcow_options(int *child_flags, QDict *child_options, int parent_flags, QDict *parent_options) { - *child_flags = BDRV_O_RDWR | BDRV_O_NO_FLUSH; + qdict_set_default_str(child_options, BDRV_OPT_READ_ONLY, "off"); + *child_flags = BDRV_O_NO_FLUSH; } static const BdrvChildRole child_vvfat_qcow = { diff --git a/blockdev.c b/blockdev.c index 301039392c2..c3f8da4700f 100644 --- a/blockdev.c +++ b/blockdev.c @@ -360,9 +360,6 @@ static void extract_common_blockdev_options(QemuOpts *opts, int *bdrv_flags, const char *aio; if (bdrv_flags) { - if (!qemu_opt_get_bool(opts, "read-only", false)) { - *bdrv_flags |= BDRV_O_RDWR; - } if (qemu_opt_get_bool(opts, "copy-on-read", false)) { *bdrv_flags |= BDRV_O_COPY_ON_READ; } @@ -471,7 +468,7 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, int bdrv_flags = 0; int on_read_error, on_write_error; bool account_invalid, account_failed; - bool writethrough; + bool writethrough, read_only; BlockBackend *blk; BlockDriverState *bs; ThrottleConfig cfg; @@ -567,6 +564,8 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, bdrv_flags |= BDRV_O_SNAPSHOT; } + read_only = qemu_opt_get_bool(opts, BDRV_OPT_READ_ONLY, false); + /* init */ if ((!file || !*file) && !qdict_size(bs_opts)) { BlockBackendRootState *blk_rs; @@ -574,7 +573,7 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, blk = blk_new(); blk_rs = blk_get_root_state(blk); blk_rs->open_flags = bdrv_flags; - blk_rs->read_only = !(bdrv_flags & BDRV_O_RDWR); + blk_rs->read_only = read_only; blk_rs->detect_zeroes = detect_zeroes; QDECREF(bs_opts); @@ -588,6 +587,8 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, * Apply the defaults here instead. */ qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_DIRECT, "off"); qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_NO_FLUSH, "off"); + qdict_set_default_str(bs_opts, BDRV_OPT_READ_ONLY, + read_only ? "on" : "off"); assert((bdrv_flags & BDRV_O_CACHE_MASK) == 0); if (runstate_check(RUN_STATE_INMIGRATE)) { @@ -682,6 +683,7 @@ static BlockDriverState *bds_tree_init(QDict *bs_opts, Error **errp) * Apply the defaults here instead. */ qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_DIRECT, "off"); qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_NO_FLUSH, "off"); + qdict_set_default_str(bs_opts, BDRV_OPT_READ_ONLY, "off"); if (runstate_check(RUN_STATE_INMIGRATE)) { bdrv_flags |= BDRV_O_INACTIVE; @@ -4158,10 +4160,6 @@ static QemuOptsList qemu_root_bds_opts = { .name = "aio", .type = QEMU_OPT_STRING, .help = "host AIO implementation (threads, native)", - },{ - .name = "read-only", - .type = QEMU_OPT_BOOL, - .help = "open drive file as read-only", },{ .name = "copy-on-read", .type = QEMU_OPT_BOOL, diff --git a/include/block/block.h b/include/block/block.h index f374e1a7251..e18233afe0e 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -107,6 +107,7 @@ typedef struct HDGeometry { #define BDRV_OPT_CACHE_WB "cache.writeback" #define BDRV_OPT_CACHE_DIRECT "cache.direct" #define BDRV_OPT_CACHE_NO_FLUSH "cache.no-flush" +#define BDRV_OPT_READ_ONLY "read-only" #define BDRV_SECTOR_BITS 9 From 5b7ba05fe7313b03712e129a86fa70c2c215e908 Mon Sep 17 00:00:00 2001 From: Alberto Garcia Date: Thu, 15 Sep 2016 17:53:03 +0300 Subject: [PATCH 264/723] block: Don't queue the same BDS twice in bdrv_reopen_queue_child() bdrv_reopen_queue_child() assumes that a BlockDriverState is never added twice to BlockReopenQueue. That's however not the case: commit_start() adds 'base' (and its children) to a new reopen queue, and then 'overlay_bs' (and its children, which include 'base') to the same queue. The effect of this is that the first set of options is ignored and overriden by the second. We fixed this by swapping the order in which both BDSs were added to the queue in 3db2bd5508c86a1605258bc77c9672d93b5c350e. This patch checks if a BDS is already in the reopen queue and keeps its options. Signed-off-by: Alberto Garcia Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- block.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/block.c b/block.c index b724adacfcb..493ecf3137f 100644 --- a/block.c +++ b/block.c @@ -1925,6 +1925,13 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, options = qdict_new(); } + /* Check if this BlockDriverState is already in the queue */ + QSIMPLEQ_FOREACH(bs_entry, bs_queue, entry) { + if (bs == bs_entry->state.bs) { + break; + } + } + /* * Precedence of options: * 1. Explicitly passed in options (highest) @@ -1945,7 +1952,11 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, } /* Old explicitly set values (don't overwrite by inherited value) */ - old_options = qdict_clone_shallow(bs->explicit_options); + if (bs_entry) { + old_options = qdict_clone_shallow(bs_entry->state.explicit_options); + } else { + old_options = qdict_clone_shallow(bs->explicit_options); + } bdrv_join_options(bs, options, old_options); QDECREF(old_options); @@ -1984,8 +1995,13 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, child->role, options, flags); } - bs_entry = g_new0(BlockReopenQueueEntry, 1); - QSIMPLEQ_INSERT_TAIL(bs_queue, bs_entry, entry); + if (!bs_entry) { + bs_entry = g_new0(BlockReopenQueueEntry, 1); + QSIMPLEQ_INSERT_TAIL(bs_queue, bs_entry, entry); + } else { + QDECREF(bs_entry->state.options); + QDECREF(bs_entry->state.explicit_options); + } bs_entry->state.bs = bs; bs_entry->state.options = options; From 0fe282bb4b29ad51adefc2e500bcecfb3c499e10 Mon Sep 17 00:00:00 2001 From: Alberto Garcia Date: Thu, 15 Sep 2016 17:53:04 +0300 Subject: [PATCH 265/723] commit: Add 'base' to the reopen queue before 'overlay_bs' Now that we're checking for duplicates in the reopen queue, there's no need to force a specific order in which the queue is constructed so we can revert 3db2bd5508c86a1605258bc77c9672d93b5c350e. Since both ways of constructing the queue are now valid, this patch doesn't have any effect on the behavior of QEMU and is not strictly necessary. However it can help us check that the fix for the reopen queue is robust: if it stops working properly at some point, iotest 040 will break. Signed-off-by: Alberto Garcia Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- block/commit.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/block/commit.c b/block/commit.c index a02539bacc1..9f67a8b1215 100644 --- a/block/commit.c +++ b/block/commit.c @@ -242,14 +242,14 @@ void commit_start(const char *job_id, BlockDriverState *bs, orig_overlay_flags = bdrv_get_flags(overlay_bs); /* convert base & overlay_bs to r/w, if necessary */ - if (!(orig_overlay_flags & BDRV_O_RDWR)) { - reopen_queue = bdrv_reopen_queue(reopen_queue, overlay_bs, NULL, - orig_overlay_flags | BDRV_O_RDWR); - } if (!(orig_base_flags & BDRV_O_RDWR)) { reopen_queue = bdrv_reopen_queue(reopen_queue, base, NULL, orig_base_flags | BDRV_O_RDWR); } + if (!(orig_overlay_flags & BDRV_O_RDWR)) { + reopen_queue = bdrv_reopen_queue(reopen_queue, overlay_bs, NULL, + orig_overlay_flags | BDRV_O_RDWR); + } if (reopen_queue) { bdrv_reopen_multiple(reopen_queue, &local_err); if (local_err != NULL) { From 4e200cf8e64cc37abf00c53b299a794c80276360 Mon Sep 17 00:00:00 2001 From: Alberto Garcia Date: Thu, 15 Sep 2016 17:53:05 +0300 Subject: [PATCH 266/723] block: rename "read-only" to BDRV_OPT_READ_ONLY There were a few instances left. After this patch we're using the macro in all places. Signed-off-by: Alberto Garcia Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- blockdev.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/blockdev.c b/blockdev.c index c3f8da4700f..fb207cd4c10 100644 --- a/blockdev.c +++ b/blockdev.c @@ -807,7 +807,7 @@ QemuOptsList qemu_legacy_drive_opts = { /* Options that are passed on, but have special semantics with -drive */ { - .name = "read-only", + .name = BDRV_OPT_READ_ONLY, .type = QEMU_OPT_BOOL, .help = "open drive file as read-only", },{ @@ -873,7 +873,7 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type) { "group", "throttling.group" }, - { "readonly", "read-only" }, + { "readonly", BDRV_OPT_READ_ONLY }, }; for (i = 0; i < ARRAY_SIZE(opt_renames); i++) { @@ -945,7 +945,7 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type) } /* copy-on-read is disabled with a warning for read-only devices */ - read_only |= qemu_opt_get_bool(legacy_opts, "read-only", false); + read_only |= qemu_opt_get_bool(legacy_opts, BDRV_OPT_READ_ONLY, false); copy_on_read = qemu_opt_get_bool(legacy_opts, "copy-on-read", false); if (read_only && copy_on_read) { @@ -953,7 +953,7 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type) copy_on_read = false; } - qdict_put(bs_opts, "read-only", + qdict_put(bs_opts, BDRV_OPT_READ_ONLY, qstring_from_str(read_only ? "on" : "off")); qdict_put(bs_opts, "copy-on-read", qstring_from_str(copy_on_read ? "on" :"off")); @@ -4042,7 +4042,7 @@ QemuOptsList qemu_common_drive_opts = { .type = QEMU_OPT_STRING, .help = "write error action", },{ - .name = "read-only", + .name = BDRV_OPT_READ_ONLY, .type = QEMU_OPT_BOOL, .help = "open drive file as read-only", },{ From 6bed02805666035a59daa6a46935074f6f6d507d Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 16 Sep 2016 17:42:25 +0200 Subject: [PATCH 267/723] block: Fix 'since' for compressed Drive/BlockdevBackup These patches missed 2.7, update the QAPI documentation. Reported-by: Eric Blake Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake --- qapi/block-core.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qapi/block-core.json b/qapi/block-core.json index 24223fd08ad..eb0a7d5aab6 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -900,7 +900,7 @@ # otherwise. (Since 2.4) # # @compress: #optional true to compress data, if the target format supports it. -# (default: false) (since 2.7) +# (default: false) (since 2.8) # # @on-source-error: #optional the action to take on an error on the source, # default 'report'. 'stop' and 'enospc' can only be used @@ -941,7 +941,7 @@ # for unlimited. # # @compress: #optional true to compress data, if the target format supports it. -# (default: false) (since 2.7) +# (default: false) (since 2.8) # # @on-source-error: #optional the action to take on an error on the source, # default 'report'. 'stop' and 'enospc' can only be used From 1c89e1fa2fb1414f4485a01924032ad9cdb9073d Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 20 Sep 2016 13:38:40 +0200 Subject: [PATCH 268/723] block: Add blk_by_dev() This finds a BlockBackend given the device model that is attached to it. Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake --- block/block-backend.c | 19 +++++++++++++++++++ include/sysemu/block-backend.h | 1 + 2 files changed, 20 insertions(+) diff --git a/block/block-backend.c b/block/block-backend.c index d1349d90e5c..0bd19abdfb9 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -559,6 +559,25 @@ void *blk_get_attached_dev(BlockBackend *blk) return blk->dev; } +/* + * Return the BlockBackend which has the device model @dev attached if it + * exists, else null. + * + * @dev must not be null. + */ +BlockBackend *blk_by_dev(void *dev) +{ + BlockBackend *blk = NULL; + + assert(dev != NULL); + while ((blk = blk_all_next(blk)) != NULL) { + if (blk->dev == dev) { + return blk; + } + } + return NULL; +} + /* * Set @blk's device model callbacks to @ops. * @opaque is the opaque argument to pass to the callbacks. diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h index 4808a9621a3..410eb68145a 100644 --- a/include/sysemu/block-backend.h +++ b/include/sysemu/block-backend.h @@ -111,6 +111,7 @@ int blk_attach_dev(BlockBackend *blk, void *dev); void blk_attach_dev_nofail(BlockBackend *blk, void *dev); void blk_detach_dev(BlockBackend *blk, void *dev); void *blk_get_attached_dev(BlockBackend *blk); +BlockBackend *blk_by_dev(void *dev); void blk_set_dev_ops(BlockBackend *blk, const BlockDevOps *ops, void *opaque); int blk_pread_unthrottled(BlockBackend *blk, int64_t offset, uint8_t *buf, int count); From 6c1db528b0e1a68c342d49d032af1c707e9de87c Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 20 Sep 2016 13:38:41 +0200 Subject: [PATCH 269/723] qdev-monitor: Factor out find_device_state() Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake --- qdev-monitor.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/qdev-monitor.c b/qdev-monitor.c index e19617fa8b3..bc0213f5e38 100644 --- a/qdev-monitor.c +++ b/qdev-monitor.c @@ -801,7 +801,7 @@ void qmp_device_add(QDict *qdict, QObject **ret_data, Error **errp) object_unref(OBJECT(dev)); } -void qmp_device_del(const char *id, Error **errp) +static DeviceState *find_device_state(const char *id, Error **errp) { Object *obj; @@ -819,15 +819,23 @@ void qmp_device_del(const char *id, Error **errp) if (!obj) { error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, "Device '%s' not found", id); - return; + return NULL; } if (!object_dynamic_cast(obj, TYPE_DEVICE)) { error_setg(errp, "%s is not a hotpluggable device", id); - return; + return NULL; } - qdev_unplug(DEVICE(obj), errp); + return DEVICE(obj); +} + +void qmp_device_del(const char *id, Error **errp) +{ + DeviceState *dev = find_device_state(id, errp); + if (dev != NULL) { + qdev_unplug(dev, errp); + } } void qdev_machine_init(void) From 9680caee0fa530726809bc72d44e127ae676e251 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 20 Sep 2016 13:38:42 +0200 Subject: [PATCH 270/723] qdev-monitor: Add blk_by_qdev_id() This finds the BlockBackend attached to the device model identified by its qdev ID. Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake --- include/sysemu/block-backend.h | 1 + qdev-monitor.c | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h index 410eb68145a..3b29317349b 100644 --- a/include/sysemu/block-backend.h +++ b/include/sysemu/block-backend.h @@ -112,6 +112,7 @@ void blk_attach_dev_nofail(BlockBackend *blk, void *dev); void blk_detach_dev(BlockBackend *blk, void *dev); void *blk_get_attached_dev(BlockBackend *blk); BlockBackend *blk_by_dev(void *dev); +BlockBackend *blk_by_qdev_id(const char *id, Error **errp); void blk_set_dev_ops(BlockBackend *blk, const BlockDevOps *ops, void *opaque); int blk_pread_unthrottled(BlockBackend *blk, int64_t offset, uint8_t *buf, int count); diff --git a/qdev-monitor.c b/qdev-monitor.c index bc0213f5e38..4f78ecb091c 100644 --- a/qdev-monitor.c +++ b/qdev-monitor.c @@ -28,6 +28,7 @@ #include "qemu/config-file.h" #include "qemu/error-report.h" #include "qemu/help_option.h" +#include "sysemu/block-backend.h" /* * Aliases were a bad idea from the start. Let's keep them @@ -838,6 +839,23 @@ void qmp_device_del(const char *id, Error **errp) } } +BlockBackend *blk_by_qdev_id(const char *id, Error **errp) +{ + DeviceState *dev; + BlockBackend *blk; + + dev = find_device_state(id, errp); + if (dev == NULL) { + return NULL; + } + + blk = blk_by_dev(dev); + if (!blk) { + error_setg(errp, "Device does not have a block device backend"); + } + return blk; +} + void qdev_machine_init(void) { qdev_get_peripheral_anon(); From b33945cfffcc3f847122dbf5db00fff28161c593 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 20 Sep 2016 13:38:43 +0200 Subject: [PATCH 271/723] block: Accept device model name for blockdev-open/close-tray In order to remove the need for BlockBackend names in the external API, we want to allow qdev device names in all device related commands. This converts blockdev-open/close-tray to accept a qdev device name. Signed-off-by: Kevin Wolf --- blockdev.c | 61 ++++++++++++++++++++++++++++++++----------- docs/qmp-commands.txt | 12 ++++++--- qapi/block-core.json | 14 +++++++--- 3 files changed, 64 insertions(+), 23 deletions(-) diff --git a/blockdev.c b/blockdev.c index fb207cd4c10..046f9c6cd49 100644 --- a/blockdev.c +++ b/blockdev.c @@ -56,7 +56,8 @@ static QTAILQ_HEAD(, BlockDriverState) monitor_bdrv_states = QTAILQ_HEAD_INITIALIZER(monitor_bdrv_states); -static int do_open_tray(const char *device, bool force, Error **errp); +static int do_open_tray(const char *blk_name, const char *qdev_id, + bool force, Error **errp); static const char *const if_name[IF_COUNT] = { [IF_NONE] = "none", @@ -1198,6 +1199,29 @@ static BlockDriverState *qmp_get_root_bs(const char *name, Error **errp) return bs; } +static BlockBackend *qmp_get_blk(const char *blk_name, const char *qdev_id, + Error **errp) +{ + BlockBackend *blk; + + if (!blk_name == !qdev_id) { + error_setg(errp, "Need exactly one of 'device' and 'id'"); + return NULL; + } + + if (qdev_id) { + blk = blk_by_qdev_id(qdev_id, errp); + } else { + blk = blk_by_name(blk_name); + if (blk == NULL) { + error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, + "Device '%s' not found", blk_name); + } + } + + return blk; +} + void hmp_commit(Monitor *mon, const QDict *qdict) { const char *device = qdict_get_str(qdict, "device"); @@ -2250,7 +2274,7 @@ void qmp_eject(const char *device, bool has_force, bool force, Error **errp) force = false; } - rc = do_open_tray(device, force, &local_err); + rc = do_open_tray(device, NULL, force, &local_err); if (rc && rc != -ENOSYS) { error_propagate(errp, local_err); return; @@ -2295,15 +2319,15 @@ void qmp_block_passwd(bool has_device, const char *device, * If the guest was asked to open the tray, return -EINPROGRESS. * Else, return 0. */ -static int do_open_tray(const char *device, bool force, Error **errp) +static int do_open_tray(const char *blk_name, const char *qdev_id, + bool force, Error **errp) { BlockBackend *blk; + const char *device = qdev_id ?: blk_name; bool locked; - blk = blk_by_name(device); + blk = qmp_get_blk(blk_name, qdev_id, errp); if (!blk) { - error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, - "Device '%s' not found", device); return -ENODEV; } @@ -2339,7 +2363,9 @@ static int do_open_tray(const char *device, bool force, Error **errp) return 0; } -void qmp_blockdev_open_tray(const char *device, bool has_force, bool force, +void qmp_blockdev_open_tray(bool has_device, const char *device, + bool has_id, const char *id, + bool has_force, bool force, Error **errp) { Error *local_err = NULL; @@ -2348,7 +2374,9 @@ void qmp_blockdev_open_tray(const char *device, bool has_force, bool force, if (!has_force) { force = false; } - rc = do_open_tray(device, force, &local_err); + rc = do_open_tray(has_device ? device : NULL, + has_id ? id : NULL, + force, &local_err); if (rc && rc != -ENOSYS && rc != -EINPROGRESS) { error_propagate(errp, local_err); return; @@ -2356,19 +2384,22 @@ void qmp_blockdev_open_tray(const char *device, bool has_force, bool force, error_free(local_err); } -void qmp_blockdev_close_tray(const char *device, Error **errp) +void qmp_blockdev_close_tray(bool has_device, const char *device, + bool has_id, const char *id, + Error **errp) { BlockBackend *blk; - blk = blk_by_name(device); + device = has_device ? device : NULL; + id = has_id ? id : NULL; + + blk = qmp_get_blk(device, id, errp); if (!blk) { - error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, - "Device '%s' not found", device); return; } if (!blk_dev_has_removable_media(blk)) { - error_setg(errp, "Device '%s' is not removable", device); + error_setg(errp, "Device '%s' is not removable", device ?: id); return; } @@ -2564,7 +2595,7 @@ void qmp_blockdev_change_medium(const char *device, const char *filename, goto fail; } - rc = do_open_tray(device, false, &err); + rc = do_open_tray(device, NULL, false, &err); if (rc && rc != -ENOSYS) { error_propagate(errp, err); goto fail; @@ -2586,7 +2617,7 @@ void qmp_blockdev_change_medium(const char *device, const char *filename, blk_apply_root_state(blk, medium_bs); - qmp_blockdev_close_tray(device, errp); + qmp_blockdev_close_tray(true, device, false, NULL, errp); fail: /* If the medium has been inserted, the device has its own reference, so diff --git a/docs/qmp-commands.txt b/docs/qmp-commands.txt index acebeb3954a..9e230f51f79 100644 --- a/docs/qmp-commands.txt +++ b/docs/qmp-commands.txt @@ -3228,7 +3228,9 @@ which no such event will be generated, these include: Arguments: -- "device": block device name (json-string) +- "device": block device name (deprecated, use @id instead) + (json-string, optional) +- "id": the name or QOM path of the guest device (json-string, optional) - "force": if false (the default), an eject request will be sent to the guest if it has locked the tray (and the tray will not be opened immediately); if true, the tray will be opened regardless of whether it is locked @@ -3237,7 +3239,7 @@ Arguments: Example: -> { "execute": "blockdev-open-tray", - "arguments": { "device": "ide1-cd0" } } + "arguments": { "id": "ide0-1-0" } } <- { "timestamp": { "seconds": 1418751016, "microseconds": 716996 }, @@ -3258,12 +3260,14 @@ If the tray was already closed before, this will be a no-op. Arguments: -- "device": block device name (json-string) +- "device": block device name (deprecated, use @id instead) + (json-string, optional) +- "id": the name or QOM path of the guest device (json-string, optional) Example: -> { "execute": "blockdev-close-tray", - "arguments": { "device": "ide1-cd0" } } + "arguments": { "id": "ide0-1-0" } } <- { "timestamp": { "seconds": 1418751345, "microseconds": 272147 }, diff --git a/qapi/block-core.json b/qapi/block-core.json index eb0a7d5aab6..cd7b38aa53e 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -2363,7 +2363,9 @@ # to it # - if the guest device does not have an actual tray # -# @device: block device name +# @device: #optional Block device name (deprecated, use @id instead) +# +# @id: #optional The name or QOM path of the guest device (since: 2.8) # # @force: #optional if false (the default), an eject request will be sent to # the guest if it has locked the tray (and the tray will not be opened @@ -2373,7 +2375,8 @@ # Since: 2.5 ## { 'command': 'blockdev-open-tray', - 'data': { 'device': 'str', + 'data': { '*device': 'str', + '*id': 'str', '*force': 'bool' } } ## @@ -2385,12 +2388,15 @@ # # If the tray was already closed before, this will be a no-op. # -# @device: block device name +# @device: #optional Block device name (deprecated, use @id instead) +# +# @id: #optional The name or QOM path of the guest device (since: 2.8) # # Since: 2.5 ## { 'command': 'blockdev-close-tray', - 'data': { 'device': 'str' } } + 'data': { '*device': 'str', + '*id': 'str' } } ## # @x-blockdev-remove-medium: From 716df21707b9c95d61c86e1df9105d0cefe59a97 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 20 Sep 2016 13:38:44 +0200 Subject: [PATCH 272/723] block: Accept device model name for x-blockdev-insert-medium In order to remove the need for BlockBackend names in the external API, we want to allow qdev device names in all device related commands. This converts x-blockdev-insert-medium to accept a qdev device name. As the command is experimental, we can still remove the 'device' option that uses the BlockBackend name. This requires some test case changes and is left for another series. Signed-off-by: Kevin Wolf --- blockdev.c | 33 +++++++++++++++++---------------- docs/qmp-commands.txt | 6 ++++-- qapi/block-core.json | 7 +++++-- 3 files changed, 26 insertions(+), 20 deletions(-) diff --git a/blockdev.c b/blockdev.c index 046f9c6cd49..0eb173d8199 100644 --- a/blockdev.c +++ b/blockdev.c @@ -2468,34 +2468,26 @@ void qmp_x_blockdev_remove_medium(const char *device, Error **errp) aio_context_release(aio_context); } -static void qmp_blockdev_insert_anon_medium(const char *device, +static void qmp_blockdev_insert_anon_medium(BlockBackend *blk, BlockDriverState *bs, Error **errp) { - BlockBackend *blk; bool has_device; - blk = blk_by_name(device); - if (!blk) { - error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, - "Device '%s' not found", device); - return; - } - /* For BBs without a device, we can exchange the BDS tree at will */ has_device = blk_get_attached_dev(blk); if (has_device && !blk_dev_has_removable_media(blk)) { - error_setg(errp, "Device '%s' is not removable", device); + error_setg(errp, "Device is not removable"); return; } if (has_device && blk_dev_has_tray(blk) && !blk_dev_is_tray_open(blk)) { - error_setg(errp, "Tray of device '%s' is not open", device); + error_setg(errp, "Tray of the device is not open"); return; } if (blk_bs(blk)) { - error_setg(errp, "There already is a medium in device '%s'", device); + error_setg(errp, "There already is a medium in the device"); return; } @@ -2511,11 +2503,20 @@ static void qmp_blockdev_insert_anon_medium(const char *device, } } -void qmp_x_blockdev_insert_medium(const char *device, const char *node_name, - Error **errp) +void qmp_x_blockdev_insert_medium(bool has_device, const char *device, + bool has_id, const char *id, + const char *node_name, Error **errp) { + BlockBackend *blk; BlockDriverState *bs; + blk = qmp_get_blk(has_device ? device : NULL, + has_id ? id : NULL, + errp); + if (!blk) { + return; + } + bs = bdrv_find_node(node_name); if (!bs) { error_setg(errp, "Node '%s' not found", node_name); @@ -2528,7 +2529,7 @@ void qmp_x_blockdev_insert_medium(const char *device, const char *node_name, return; } - qmp_blockdev_insert_anon_medium(device, bs, errp); + qmp_blockdev_insert_anon_medium(blk, bs, errp); } void qmp_blockdev_change_medium(const char *device, const char *filename, @@ -2609,7 +2610,7 @@ void qmp_blockdev_change_medium(const char *device, const char *filename, goto fail; } - qmp_blockdev_insert_anon_medium(device, medium_bs, &err); + qmp_blockdev_insert_anon_medium(blk, medium_bs, &err); if (err) { error_propagate(errp, err); goto fail; diff --git a/docs/qmp-commands.txt b/docs/qmp-commands.txt index 9e230f51f79..ebb65e0ad88 100644 --- a/docs/qmp-commands.txt +++ b/docs/qmp-commands.txt @@ -3328,7 +3328,9 @@ Stay away from it unless you want to help with its development. Arguments: -- "device": block device name (json-string) +- "device": block device name (deprecated, use @id instead) + (json-string, optional) +- "id": the name or QOM path of the guest device (json-string, optional) - "node-name": root node of the BDS tree to insert into the block device Example: @@ -3342,7 +3344,7 @@ Example: <- { "return": {} } -> { "execute": "x-blockdev-insert-medium", - "arguments": { "device": "ide1-cd0", + "arguments": { "id": "ide0-1-0", "node-name": "node0" } } <- { "return": {} } diff --git a/qapi/block-core.json b/qapi/block-core.json index cd7b38aa53e..6ac680966f3 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -2427,14 +2427,17 @@ # This command is still a work in progress and is considered experimental. # Stay away from it unless you want to help with its development. # -# @device: block device name +# @device: #optional Block device name (deprecated, use @id instead) +# +# @id: #optional The name or QOM path of the guest device (since: 2.8) # # @node-name: name of a node in the block driver state graph # # Since: 2.5 ## { 'command': 'x-blockdev-insert-medium', - 'data': { 'device': 'str', + 'data': { '*device': 'str', + '*id': 'str', 'node-name': 'str'} } From 00949babe90c528df1ffb79439d632c7bd4f6c42 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 20 Sep 2016 13:38:45 +0200 Subject: [PATCH 273/723] block: Accept device model name for x-blockdev-remove-medium In order to remove the need for BlockBackend names in the external API, we want to allow qdev device names in all device related commands. This converts x-blockdev-remove-medium to accept a qdev device name. As the command is experimental, we can still remove the 'device' option that uses the BlockBackend name. This requires some test case changes and is left for another series. Signed-off-by: Kevin Wolf --- blockdev.c | 28 ++++++++++++++++------------ docs/qmp-commands.txt | 12 +++++++----- qapi/block-core.json | 7 +++++-- 3 files changed, 28 insertions(+), 19 deletions(-) diff --git a/blockdev.c b/blockdev.c index 0eb173d8199..a007b22f804 100644 --- a/blockdev.c +++ b/blockdev.c @@ -2281,7 +2281,7 @@ void qmp_eject(const char *device, bool has_force, bool force, Error **errp) } error_free(local_err); - qmp_x_blockdev_remove_medium(device, errp); + qmp_x_blockdev_remove_medium(true, device, false, NULL, errp); } void qmp_block_passwd(bool has_device, const char *device, @@ -2415,30 +2415,34 @@ void qmp_blockdev_close_tray(bool has_device, const char *device, blk_dev_change_media_cb(blk, true); } -void qmp_x_blockdev_remove_medium(const char *device, Error **errp) +void qmp_x_blockdev_remove_medium(bool has_device, const char *device, + bool has_id, const char *id, Error **errp) { BlockBackend *blk; BlockDriverState *bs; AioContext *aio_context; - bool has_device; + bool has_attached_device; - blk = blk_by_name(device); + device = has_device ? device : NULL; + id = has_id ? id : NULL; + + blk = qmp_get_blk(device, id, errp); if (!blk) { - error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, - "Device '%s' not found", device); return; } /* For BBs without a device, we can exchange the BDS tree at will */ - has_device = blk_get_attached_dev(blk); + has_attached_device = blk_get_attached_dev(blk); - if (has_device && !blk_dev_has_removable_media(blk)) { - error_setg(errp, "Device '%s' is not removable", device); + if (has_attached_device && !blk_dev_has_removable_media(blk)) { + error_setg(errp, "Device '%s' is not removable", device ?: id); return; } - if (has_device && blk_dev_has_tray(blk) && !blk_dev_is_tray_open(blk)) { - error_setg(errp, "Tray of device '%s' is not open", device); + if (has_attached_device && blk_dev_has_tray(blk) && + !blk_dev_is_tray_open(blk)) + { + error_setg(errp, "Tray of device '%s' is not open", device ?: id); return; } @@ -2604,7 +2608,7 @@ void qmp_blockdev_change_medium(const char *device, const char *filename, error_free(err); err = NULL; - qmp_x_blockdev_remove_medium(device, &err); + qmp_x_blockdev_remove_medium(true, device, false, NULL, errp); if (err) { error_propagate(errp, err); goto fail; diff --git a/docs/qmp-commands.txt b/docs/qmp-commands.txt index ebb65e0ad88..e77bf2f1dd0 100644 --- a/docs/qmp-commands.txt +++ b/docs/qmp-commands.txt @@ -3290,18 +3290,20 @@ Stay away from it unless you want to help with its development. Arguments: -- "device": block device name (json-string) +- "device": block device name (deprecated, use @id instead) + (json-string, optional) +- "id": the name or QOM path of the guest device (json-string, optional) Example: -> { "execute": "x-blockdev-remove-medium", - "arguments": { "device": "ide1-cd0" } } + "arguments": { "id": "ide0-1-0" } } <- { "error": { "class": "GenericError", - "desc": "Tray of device 'ide1-cd0' is not open" } } + "desc": "Tray of device 'ide0-1-0' is not open" } } -> { "execute": "blockdev-open-tray", - "arguments": { "device": "ide1-cd0" } } + "arguments": { "id": "ide0-1-0" } } <- { "timestamp": { "seconds": 1418751627, "microseconds": 549958 }, @@ -3312,7 +3314,7 @@ Example: <- { "return": {} } -> { "execute": "x-blockdev-remove-medium", - "arguments": { "device": "ide1-cd0" } } + "arguments": { "device": "ide0-1-0" } } <- { "return": {} } diff --git a/qapi/block-core.json b/qapi/block-core.json index 6ac680966f3..e3703667863 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -2410,12 +2410,15 @@ # This command is still a work in progress and is considered experimental. # Stay away from it unless you want to help with its development. # -# @device: block device name +# @device: #optional Block device name (deprecated, use @id instead) +# +# @id: #optional The name or QOM path of the guest device (since: 2.8) # # Since: 2.5 ## { 'command': 'x-blockdev-remove-medium', - 'data': { 'device': 'str' } } + 'data': { '*device': 'str', + '*id': 'str' } } ## # @x-blockdev-insert-medium: From fbe2d8163e8900fe22c67f55bd09ebc6f322f430 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 20 Sep 2016 13:38:46 +0200 Subject: [PATCH 274/723] block: Accept device model name for eject In order to remove the need for BlockBackend names in the external API, we want to allow qdev device names in all device related commands. This converts eject to accept a qdev device name. Signed-off-by: Kevin Wolf --- blockdev.c | 10 +++++++--- docs/qmp-commands.txt | 8 +++++--- hmp.c | 2 +- qapi/block.json | 9 +++++++-- ui/cocoa.m | 3 ++- 5 files changed, 22 insertions(+), 10 deletions(-) diff --git a/blockdev.c b/blockdev.c index a007b22f804..3d92724d0f5 100644 --- a/blockdev.c +++ b/blockdev.c @@ -2265,7 +2265,9 @@ void qmp_transaction(TransactionActionList *dev_list, block_job_txn_unref(block_job_txn); } -void qmp_eject(const char *device, bool has_force, bool force, Error **errp) +void qmp_eject(bool has_device, const char *device, + bool has_id, const char *id, + bool has_force, bool force, Error **errp) { Error *local_err = NULL; int rc; @@ -2274,14 +2276,16 @@ void qmp_eject(const char *device, bool has_force, bool force, Error **errp) force = false; } - rc = do_open_tray(device, NULL, force, &local_err); + rc = do_open_tray(has_device ? device : NULL, + has_id ? id : NULL, + force, &local_err); if (rc && rc != -ENOSYS) { error_propagate(errp, local_err); return; } error_free(local_err); - qmp_x_blockdev_remove_medium(true, device, false, NULL, errp); + qmp_x_blockdev_remove_medium(has_device, device, has_id, id, errp); } void qmp_block_passwd(bool has_device, const char *device, diff --git a/docs/qmp-commands.txt b/docs/qmp-commands.txt index e77bf2f1dd0..9024ef28238 100644 --- a/docs/qmp-commands.txt +++ b/docs/qmp-commands.txt @@ -72,12 +72,14 @@ Eject a removable medium. Arguments: -- force: force ejection (json-bool, optional) -- device: device name (json-string) +- "force": force ejection (json-bool, optional) +- "device": block device name (deprecated, use @id instead) + (json-string, optional) +- "id": the name or QOM path of the guest device (json-string, optional) Example: --> { "execute": "eject", "arguments": { "device": "ide1-cd0" } } +-> { "execute": "eject", "arguments": { "id": "ide0-1-0" } } <- { "return": {} } Note: The "force" argument defaults to false. diff --git a/hmp.c b/hmp.c index 0a16aefc2ac..09827b3ec40 100644 --- a/hmp.c +++ b/hmp.c @@ -1376,7 +1376,7 @@ void hmp_eject(Monitor *mon, const QDict *qdict) const char *device = qdict_get_str(qdict, "device"); Error *err = NULL; - qmp_eject(device, true, force, &err); + qmp_eject(true, device, false, NULL, true, force, &err); hmp_handle_error(mon, &err); } diff --git a/qapi/block.json b/qapi/block.json index 8b08bd2fd0b..c896bd1d3bb 100644 --- a/qapi/block.json +++ b/qapi/block.json @@ -125,7 +125,9 @@ # # Ejects a device from a removable drive. # -# @device: The name of the device +# @device: #optional Block device name (deprecated, use @id instead) +# +# @id: #optional The name or QOM path of the guest device (since: 2.8) # # @force: @optional If true, eject regardless of whether the drive is locked. # If not specified, the default value is false. @@ -137,7 +139,10 @@ # # Since: 0.14.0 ## -{ 'command': 'eject', 'data': {'device': 'str', '*force': 'bool'} } +{ 'command': 'eject', + 'data': { '*device': 'str', + '*id': 'str', + '*force': 'bool' } } ## # @nbd-server-start: diff --git a/ui/cocoa.m b/ui/cocoa.m index 52d9c54b6de..a847737b686 100644 --- a/ui/cocoa.m +++ b/ui/cocoa.m @@ -1085,7 +1085,8 @@ - (void)ejectDeviceMedia:(id)sender } Error *err = NULL; - qmp_eject([drive cStringUsingEncoding: NSASCIIStringEncoding], false, false, &err); + qmp_eject(true, [drive cStringUsingEncoding: NSASCIIStringEncoding], + false, NULL, false, false, &err); handleAnyDeviceErrors(err); } From 70e2cb3bd75fc7aa988f81eae854001e8fcbffe1 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 20 Sep 2016 13:38:47 +0200 Subject: [PATCH 275/723] block: Accept device model name for blockdev-change-medium In order to remove the need for BlockBackend names in the external API, we want to allow qdev device names in all device related commands. This converts blockdev-change-medium to accept a qdev device name. Signed-off-by: Kevin Wolf --- blockdev.c | 18 +++++++++++------- docs/qmp-commands.txt | 10 ++++++---- hmp.c | 5 +++-- qapi/block-core.json | 8 ++++++-- qmp.c | 4 ++-- ui/cocoa.m | 4 +++- 6 files changed, 31 insertions(+), 18 deletions(-) diff --git a/blockdev.c b/blockdev.c index 3d92724d0f5..8c8fcd67504 100644 --- a/blockdev.c +++ b/blockdev.c @@ -2540,7 +2540,9 @@ void qmp_x_blockdev_insert_medium(bool has_device, const char *device, qmp_blockdev_insert_anon_medium(blk, bs, errp); } -void qmp_blockdev_change_medium(const char *device, const char *filename, +void qmp_blockdev_change_medium(bool has_device, const char *device, + bool has_id, const char *id, + const char *filename, bool has_format, const char *format, bool has_read_only, BlockdevChangeReadOnlyMode read_only, @@ -2553,10 +2555,10 @@ void qmp_blockdev_change_medium(const char *device, const char *filename, QDict *options = NULL; Error *err = NULL; - blk = blk_by_name(device); + blk = qmp_get_blk(has_device ? device : NULL, + has_id ? id : NULL, + errp); if (!blk) { - error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, - "Device '%s' not found", device); goto fail; } @@ -2604,7 +2606,9 @@ void qmp_blockdev_change_medium(const char *device, const char *filename, goto fail; } - rc = do_open_tray(device, NULL, false, &err); + rc = do_open_tray(has_device ? device : NULL, + has_id ? id : NULL, + false, &err); if (rc && rc != -ENOSYS) { error_propagate(errp, err); goto fail; @@ -2612,7 +2616,7 @@ void qmp_blockdev_change_medium(const char *device, const char *filename, error_free(err); err = NULL; - qmp_x_blockdev_remove_medium(true, device, false, NULL, errp); + qmp_x_blockdev_remove_medium(has_device, device, has_id, id, errp); if (err) { error_propagate(errp, err); goto fail; @@ -2626,7 +2630,7 @@ void qmp_blockdev_change_medium(const char *device, const char *filename, blk_apply_root_state(blk, medium_bs); - qmp_blockdev_close_tray(true, device, false, NULL, errp); + qmp_blockdev_close_tray(has_device, device, has_id, id, errp); fail: /* If the medium has been inserted, the device has its own reference, so diff --git a/docs/qmp-commands.txt b/docs/qmp-commands.txt index 9024ef28238..8b2a0ea1765 100644 --- a/docs/qmp-commands.txt +++ b/docs/qmp-commands.txt @@ -3458,7 +3458,9 @@ and loading a new image file which is inserted as the new medium. Arguments: -- "device": device name (json-string) +- "device": block device name (deprecated, use @id instead) + (json-string, optional) +- "id": the name or QOM path of the guest device (json-string, optional) - "filename": filename of the new image (json-string) - "format": format of the new image (json-string, optional) - "read-only-mode": new read-only mode (json-string, optional) @@ -3469,7 +3471,7 @@ Examples: 1. Change a removable medium -> { "execute": "blockdev-change-medium", - "arguments": { "device": "ide1-cd0", + "arguments": { "id": "ide0-1-0", "filename": "/srv/images/Fedora-12-x86_64-DVD.iso", "format": "raw" } } <- { "return": {} } @@ -3477,7 +3479,7 @@ Examples: 2. Load a read-only medium into a writable drive -> { "execute": "blockdev-change-medium", - "arguments": { "device": "isa-fd0", + "arguments": { "id": "floppyA", "filename": "/srv/images/ro.img", "format": "raw", "read-only-mode": "retain" } } @@ -3487,7 +3489,7 @@ Examples: "desc": "Could not open '/srv/images/ro.img': Permission denied" } } -> { "execute": "blockdev-change-medium", - "arguments": { "device": "isa-fd0", + "arguments": { "id": "floppyA", "filename": "/srv/images/ro.img", "format": "raw", "read-only-mode": "read-only" } } diff --git a/hmp.c b/hmp.c index 09827b3ec40..336e7bf0769 100644 --- a/hmp.c +++ b/hmp.c @@ -1422,8 +1422,9 @@ void hmp_change(Monitor *mon, const QDict *qdict) } } - qmp_blockdev_change_medium(device, target, !!arg, arg, - !!read_only, read_only_mode, &err); + qmp_blockdev_change_medium(true, device, false, NULL, target, + !!arg, arg, !!read_only, read_only_mode, + &err); if (err && error_get_class(err) == ERROR_CLASS_DEVICE_ENCRYPTED) { error_free(err); diff --git a/qapi/block-core.json b/qapi/block-core.json index e3703667863..1d7d4cc8a05 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -2470,7 +2470,10 @@ # combines blockdev-open-tray, x-blockdev-remove-medium, # x-blockdev-insert-medium and blockdev-close-tray). # -# @device: block device name +# @device: #optional Block device name (deprecated, use @id instead) +# +# @id: #optional The name or QOM path of the guest device +# (since: 2.8) # # @filename: filename of the new image to be loaded # @@ -2483,7 +2486,8 @@ # Since: 2.5 ## { 'command': 'blockdev-change-medium', - 'data': { 'device': 'str', + 'data': { '*device': 'str', + '*id': 'str', 'filename': 'str', '*format': 'str', '*read-only-mode': 'BlockdevChangeReadOnlyMode' } } diff --git a/qmp.c b/qmp.c index 6733463fa23..8b4bc980f16 100644 --- a/qmp.c +++ b/qmp.c @@ -436,8 +436,8 @@ void qmp_change(const char *device, const char *target, if (strcmp(device, "vnc") == 0) { qmp_change_vnc(target, has_arg, arg, errp); } else { - qmp_blockdev_change_medium(device, target, has_arg, arg, false, 0, - errp); + qmp_blockdev_change_medium(true, device, false, NULL, target, + has_arg, arg, false, 0, errp); } } diff --git a/ui/cocoa.m b/ui/cocoa.m index a847737b686..ba0e98a297f 100644 --- a/ui/cocoa.m +++ b/ui/cocoa.m @@ -1119,8 +1119,10 @@ - (void)changeDeviceMedia:(id)sender } Error *err = NULL; - qmp_blockdev_change_medium([drive cStringUsingEncoding: + qmp_blockdev_change_medium(true, + [drive cStringUsingEncoding: NSASCIIStringEncoding], + false, NULL, [file cStringUsingEncoding: NSASCIIStringEncoding], true, "raw", From 7a9877a0263561f11bae116a7639eec53a625807 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 20 Sep 2016 13:38:48 +0200 Subject: [PATCH 276/723] block: Accept device model name for block_set_io_throttle In order to remove the need for BlockBackend names in the external API, we want to allow qdev device names in all device related commands. This converts block_set_io_throttle to accept a qdev device name. Signed-off-by: Kevin Wolf --- blockdev.c | 12 +++++++----- docs/qmp-commands.txt | 6 ++++-- qapi/block-core.json | 8 +++++--- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/blockdev.c b/blockdev.c index 8c8fcd67504..405145ae95f 100644 --- a/blockdev.c +++ b/blockdev.c @@ -2647,10 +2647,10 @@ void qmp_block_set_io_throttle(BlockIOThrottle *arg, Error **errp) BlockBackend *blk; AioContext *aio_context; - blk = blk_by_name(arg->device); + blk = qmp_get_blk(arg->has_device ? arg->device : NULL, + arg->has_id ? arg->id : NULL, + errp); if (!blk) { - error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, - "Device '%s' not found", arg->device); return; } @@ -2659,7 +2659,7 @@ void qmp_block_set_io_throttle(BlockIOThrottle *arg, Error **errp) bs = blk_bs(blk); if (!bs) { - error_setg(errp, "Device '%s' has no medium", arg->device); + error_setg(errp, "Device has no medium"); goto out; } @@ -2723,7 +2723,9 @@ void qmp_block_set_io_throttle(BlockIOThrottle *arg, Error **errp) * just update the throttling group. */ if (!blk_get_public(blk)->throttle_state) { blk_io_limits_enable(blk, - arg->has_group ? arg->group : arg->device); + arg->has_group ? arg->group : + arg->has_device ? arg->device : + arg->id); } else if (arg->has_group) { blk_io_limits_update_group(blk, arg->group); } diff --git a/docs/qmp-commands.txt b/docs/qmp-commands.txt index 8b2a0ea1765..41f56981af9 100644 --- a/docs/qmp-commands.txt +++ b/docs/qmp-commands.txt @@ -1459,7 +1459,9 @@ Change I/O throttle limits for a block drive. Arguments: -- "device": device name (json-string) +- "device": block device name (deprecated, use @id instead) + (json-string, optional) +- "id": the name or QOM path of the guest device (json-string, optional) - "bps": total throughput limit in bytes per second (json-int) - "bps_rd": read throughput limit in bytes per second (json-int) - "bps_wr": write throughput limit in bytes per second (json-int) @@ -1483,7 +1485,7 @@ Arguments: Example: --> { "execute": "block_set_io_throttle", "arguments": { "device": "virtio0", +-> { "execute": "block_set_io_throttle", "arguments": { "id": "ide0-1-0", "bps": 1000000, "bps_rd": 0, "bps_wr": 0, diff --git a/qapi/block-core.json b/qapi/block-core.json index 1d7d4cc8a05..5f04dab0275 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -1377,7 +1377,9 @@ # # A set of parameters describing block throttling. # -# @device: The name of the device +# @device: #optional Block device name (deprecated, use @id instead) +# +# @id: #optional The name or QOM path of the guest device (since: 2.8) # # @bps: total throughput limit in bytes per second # @@ -1446,8 +1448,8 @@ # Since: 1.1 ## { 'struct': 'BlockIOThrottle', - 'data': { 'device': 'str', 'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int', - 'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int', + 'data': { '*device': 'str', '*id': 'str', 'bps': 'int', 'bps_rd': 'int', + 'bps_wr': 'int', 'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int', '*bps_max': 'int', '*bps_rd_max': 'int', '*bps_wr_max': 'int', '*iops_max': 'int', '*iops_rd_max': 'int', '*iops_wr_max': 'int', From 486b88bdc87eb70d26428624a1669824e093c861 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 20 Sep 2016 13:38:49 +0200 Subject: [PATCH 277/723] qemu-iotests/118: Test media change with qdev name We just added the option to use qdev device names in all device related block QMP commands. This patch converts some of the test cases in 118 to use qdev device names instead of BlockBackend names to cover the new way. It converts cases for each of the media change commands, but only for CD-ROM and not everywhere, so that the old way is still tested, too. Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake --- tests/qemu-iotests/118 | 85 ++++++++++++++++++++++++++++------- tests/qemu-iotests/iotests.py | 5 +++ 2 files changed, 73 insertions(+), 17 deletions(-) diff --git a/tests/qemu-iotests/118 b/tests/qemu-iotests/118 index 9e5951f645b..0380069ef68 100755 --- a/tests/qemu-iotests/118 +++ b/tests/qemu-iotests/118 @@ -62,6 +62,9 @@ class ChangeBaseClass(iotests.QMPTestCase): self.fail('Timeout while waiting for the tray to close') class GeneralChangeTestsBaseClass(ChangeBaseClass): + + device_name = None + def test_change(self): result = self.vm.qmp('change', device='drive0', target=new_img, arg=iotests.imgfmt) @@ -76,9 +79,15 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass): self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img) def test_blockdev_change_medium(self): - result = self.vm.qmp('blockdev-change-medium', device='drive0', - filename=new_img, - format=iotests.imgfmt) + if self.device_name is not None: + result = self.vm.qmp('blockdev-change-medium', + id=self.device_name, filename=new_img, + format=iotests.imgfmt) + else: + result = self.vm.qmp('blockdev-change-medium', + device='drive0', filename=new_img, + format=iotests.imgfmt) + self.assert_qmp(result, 'return', {}) self.wait_for_open() @@ -90,7 +99,10 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass): self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img) def test_eject(self): - result = self.vm.qmp('eject', device='drive0', force=True) + if self.device_name is not None: + result = self.vm.qmp('eject', id=self.device_name, force=True) + else: + result = self.vm.qmp('eject', device='drive0', force=True) self.assert_qmp(result, 'return', {}) self.wait_for_open() @@ -101,7 +113,10 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass): self.assert_qmp_absent(result, 'return[0]/inserted') def test_tray_eject_change(self): - result = self.vm.qmp('eject', device='drive0', force=True) + if self.device_name is not None: + result = self.vm.qmp('eject', id=self.device_name, force=True) + else: + result = self.vm.qmp('eject', device='drive0', force=True) self.assert_qmp(result, 'return', {}) self.wait_for_open() @@ -111,9 +126,12 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass): self.assert_qmp(result, 'return[0]/tray_open', True) self.assert_qmp_absent(result, 'return[0]/inserted') - result = self.vm.qmp('blockdev-change-medium', device='drive0', - filename=new_img, - format=iotests.imgfmt) + if self.device_name is not None: + result = self.vm.qmp('blockdev-change-medium', id=self.device_name, + filename=new_img, format=iotests.imgfmt) + else: + result = self.vm.qmp('blockdev-change-medium', device='drive0', + filename=new_img, format=iotests.imgfmt) self.assert_qmp(result, 'return', {}) self.wait_for_close() @@ -124,7 +142,12 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass): self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img) def test_tray_open_close(self): - result = self.vm.qmp('blockdev-open-tray', device='drive0', force=True) + if self.device_name is not None: + result = self.vm.qmp('blockdev-open-tray', + id=self.device_name, force=True) + else: + result = self.vm.qmp('blockdev-open-tray', + device='drive0', force=True) self.assert_qmp(result, 'return', {}) self.wait_for_open() @@ -137,7 +160,10 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass): else: self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img) - result = self.vm.qmp('blockdev-close-tray', device='drive0') + if self.device_name is not None: + result = self.vm.qmp('blockdev-close-tray', id=self.device_name) + else: + result = self.vm.qmp('blockdev-close-tray', device='drive0') self.assert_qmp(result, 'return', {}) if self.has_real_tray or not self.was_empty: @@ -162,7 +188,10 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass): self.assert_qmp(result, 'return[0]/tray_open', True) self.assert_qmp_absent(result, 'return[0]/inserted') - result = self.vm.qmp('blockdev-close-tray', device='drive0') + if self.device_name is not None: + result = self.vm.qmp('blockdev-close-tray', id=self.device_name) + else: + result = self.vm.qmp('blockdev-close-tray', device='drive0') self.assert_qmp(result, 'return', {}) self.wait_for_close() @@ -206,7 +235,12 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass): 'driver': 'file'}}) self.assert_qmp(result, 'return', {}) - result = self.vm.qmp('blockdev-open-tray', device='drive0', force=True) + if self.device_name is not None: + result = self.vm.qmp('blockdev-open-tray', + id=self.device_name, force=True) + else: + result = self.vm.qmp('blockdev-open-tray', + device='drive0', force=True) self.assert_qmp(result, 'return', {}) self.wait_for_open() @@ -219,7 +253,11 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass): else: self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img) - result = self.vm.qmp('x-blockdev-remove-medium', device='drive0') + if self.device_name is not None: + result = self.vm.qmp('x-blockdev-remove-medium', + id=self.device_name) + else: + result = self.vm.qmp('x-blockdev-remove-medium', device='drive0') self.assert_qmp(result, 'return', {}) result = self.vm.qmp('query-block') @@ -227,8 +265,12 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass): self.assert_qmp(result, 'return[0]/tray_open', True) self.assert_qmp_absent(result, 'return[0]/inserted') - result = self.vm.qmp('x-blockdev-insert-medium', device='drive0', - node_name='new') + if self.device_name is not None: + result = self.vm.qmp('x-blockdev-insert-medium', + id=self.device_name, node_name='new') + else: + result = self.vm.qmp('x-blockdev-insert-medium', + device='drive0', node_name='new') self.assert_qmp(result, 'return', {}) result = self.vm.qmp('query-block') @@ -236,7 +278,10 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass): self.assert_qmp(result, 'return[0]/tray_open', True) self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img) - result = self.vm.qmp('blockdev-close-tray', device='drive0') + if self.device_name is not None: + result = self.vm.qmp('blockdev-close-tray', id=self.device_name) + else: + result = self.vm.qmp('blockdev-close-tray', device='drive0') self.assert_qmp(result, 'return', {}) self.wait_for_close() @@ -280,7 +325,13 @@ class TestInitiallyFilled(GeneralChangeTestsBaseClass): def setUp(self, media, interface): qemu_img('create', '-f', iotests.imgfmt, old_img, '1440k') qemu_img('create', '-f', iotests.imgfmt, new_img, '1440k') - self.vm = iotests.VM().add_drive(old_img, 'media=%s' % media, interface) + self.vm = iotests.VM() + if interface == 'ide': + self.device_name = 'qdev0' + self.vm.add_drive(old_img, 'media=%s' % media, 'none') + self.vm.add_device('ide-cd,drive=drive0,id=%s' % self.device_name) + else: + self.vm.add_drive(old_img, 'media=%s' % media, interface) self.vm.launch() def tearDown(self): diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index f1f36d7fc76..3329bc1721a 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -139,6 +139,11 @@ def __init__(self): self._debug = True self._num_drives = 0 + def add_device(self, opts): + self._args.append('-device') + self._args.append(opts) + return self + def add_drive_raw(self, opts): self._args.append('-drive') self._args.append(opts) From 476fb028bf21cd44f5e3a72c856147a00e74f670 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Wed, 21 Sep 2016 14:56:00 +0200 Subject: [PATCH 278/723] qemu-iotests/041: Avoid blockdev-add with id We want to remove the 'id' option for blockdev-add. This removes one user of the option and makes it use only node names. Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake --- tests/qemu-iotests/041 | 71 +++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 39 deletions(-) diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041 index 80939c0d0de..d1e1ad8bd27 100755 --- a/tests/qemu-iotests/041 +++ b/tests/qemu-iotests/041 @@ -782,7 +782,7 @@ class TestRepairQuorum(iotests.QMPTestCase): self.vm.launch() #assemble the quorum block device from the individual files - args = { "options" : { "driver": "quorum", "id": "quorum0", + args = { "options" : { "driver": "quorum", "node-name": "quorum0", "vote-threshold": 2, "children": [ "img0", "img1", "img2" ] } } if self.has_quorum(): result = self.vm.qmp("blockdev-add", **args) @@ -804,13 +804,12 @@ class TestRepairQuorum(iotests.QMPTestCase): self.assert_no_active_block_jobs() - result = self.vm.qmp('drive-mirror', device='quorum0', sync='full', - node_name="repair0", - replaces="img1", + result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0', + sync='full', node_name="repair0", replaces="img1", target=quorum_repair_img, format=iotests.imgfmt) self.assert_qmp(result, 'return', {}) - self.complete_and_wait(drive="quorum0") + self.complete_and_wait(drive="job0") self.assert_has_block_node("repair0", quorum_repair_img) # TODO: a better test requiring some QEMU infrastructure will be added # to check that this file is really driven by quorum @@ -824,13 +823,12 @@ class TestRepairQuorum(iotests.QMPTestCase): self.assert_no_active_block_jobs() - result = self.vm.qmp('drive-mirror', device='quorum0', sync='full', - node_name="repair0", - replaces="img1", + result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0', + sync='full', node_name="repair0", replaces="img1", target=quorum_repair_img, format=iotests.imgfmt) self.assert_qmp(result, 'return', {}) - self.cancel_and_wait(drive="quorum0", force=True) + self.cancel_and_wait(drive="job0", force=True) # here we check that the last registered quorum file has not been # swapped out and unref self.assert_has_block_node(None, quorum_img3) @@ -842,13 +840,12 @@ class TestRepairQuorum(iotests.QMPTestCase): self.assert_no_active_block_jobs() - result = self.vm.qmp('drive-mirror', device='quorum0', sync='full', - node_name="repair0", - replaces="img1", + result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0', + sync='full', node_name="repair0", replaces="img1", target=quorum_repair_img, format=iotests.imgfmt) self.assert_qmp(result, 'return', {}) - self.wait_ready_and_cancel(drive="quorum0") + self.wait_ready_and_cancel(drive="job0") # here we check that the last registered quorum file has not been # swapped out and unref self.assert_has_block_node(None, quorum_img3) @@ -862,13 +859,12 @@ class TestRepairQuorum(iotests.QMPTestCase): self.assert_no_active_block_jobs() - result = self.vm.qmp('drive-mirror', device='quorum0', sync='full', - node_name="repair0", - replaces="img1", + result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0', + sync='full', node_name="repair0", replaces="img1", target=quorum_repair_img, format=iotests.imgfmt) self.assert_qmp(result, 'return', {}) - result = self.vm.qmp('block-job-pause', device='quorum0') + result = self.vm.qmp('block-job-pause', device='job0') self.assert_qmp(result, 'return', {}) time.sleep(1) @@ -879,10 +875,10 @@ class TestRepairQuorum(iotests.QMPTestCase): result = self.vm.qmp('query-block-jobs') self.assert_qmp(result, 'return[0]/offset', offset) - result = self.vm.qmp('block-job-resume', device='quorum0') + result = self.vm.qmp('block-job-resume', device='job0') self.assert_qmp(result, 'return', {}) - self.complete_and_wait(drive="quorum0") + self.complete_and_wait(drive="job0") self.vm.shutdown() self.assertTrue(iotests.compare_images(quorum_img2, quorum_repair_img), 'target image does not match source after mirroring') @@ -894,7 +890,7 @@ class TestRepairQuorum(iotests.QMPTestCase): if iotests.qemu_default_machine != 'pc': return - result = self.vm.qmp('drive-mirror', device='drive0', # CD-ROM + result = self.vm.qmp('drive-mirror', job_id='job0', device='drive0', # CD-ROM sync='full', node_name='repair0', replaces='img1', @@ -905,18 +901,18 @@ class TestRepairQuorum(iotests.QMPTestCase): if not self.has_quorum(): return - result = self.vm.qmp('drive-mirror', device='quorum0', sync='full', - node_name='repair0', - replaces='img1', - mode='existing', - target=quorum_repair_img, format=iotests.imgfmt) + result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0', + sync='full', node_name='repair0', replaces='img1', + mode='existing', target=quorum_repair_img, + format=iotests.imgfmt) self.assert_qmp(result, 'error/class', 'GenericError') def test_device_not_found(self): if not self.has_quorum(): return - result = self.vm.qmp('drive-mirror', device='nonexistent', sync='full', + result = self.vm.qmp('drive-mirror', job_id='job0', + device='nonexistent', sync='full', node_name='repair0', replaces='img1', target=quorum_repair_img, format=iotests.imgfmt) @@ -926,7 +922,7 @@ class TestRepairQuorum(iotests.QMPTestCase): if not self.has_quorum(): return - result = self.vm.qmp('drive-mirror', device='quorum0', + result = self.vm.qmp('drive-mirror', device='quorum0', job_id='job0', node_name='repair0', replaces='img1', target=quorum_repair_img, format=iotests.imgfmt) @@ -936,8 +932,8 @@ class TestRepairQuorum(iotests.QMPTestCase): if not self.has_quorum(): return - result = self.vm.qmp('drive-mirror', device='quorum0', sync='full', - replaces='img1', + result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0', + sync='full', replaces='img1', target=quorum_repair_img, format=iotests.imgfmt) self.assert_qmp(result, 'error/class', 'GenericError') @@ -945,9 +941,8 @@ class TestRepairQuorum(iotests.QMPTestCase): if not self.has_quorum(): return - result = self.vm.qmp('drive-mirror', device='quorum0', sync='full', - node_name='repair0', - replaces='img77', + result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0', + sync='full', node_name='repair0', replaces='img77', target=quorum_repair_img, format=iotests.imgfmt) self.assert_qmp(result, 'error/class', 'GenericError') @@ -959,19 +954,17 @@ class TestRepairQuorum(iotests.QMPTestCase): snapshot_file=quorum_snapshot_file, snapshot_node_name="snap1"); - result = self.vm.qmp('drive-mirror', device='quorum0', sync='full', - node_name='repair0', - replaces="img1", + result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0', + sync='full', node_name='repair0', replaces="img1", target=quorum_repair_img, format=iotests.imgfmt) self.assert_qmp(result, 'error/class', 'GenericError') - result = self.vm.qmp('drive-mirror', device='quorum0', sync='full', - node_name='repair0', - replaces="snap1", + result = self.vm.qmp('drive-mirror', job_id='job0', device='quorum0', + sync='full', node_name='repair0', replaces="snap1", target=quorum_repair_img, format=iotests.imgfmt) self.assert_qmp(result, 'return', {}) - self.complete_and_wait(drive="quorum0") + self.complete_and_wait('job0') self.assert_has_block_node("repair0", quorum_repair_img) # TODO: a better test requiring some QEMU infrastructure will be added # to check that this file is really driven by quorum From 522ce4ecd4e93f77ba4cd399b25db1fd5405c7e9 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Wed, 21 Sep 2016 14:56:01 +0200 Subject: [PATCH 279/723] qemu-iotests/067: Avoid blockdev-add with id We want to remove the 'id' option for blockdev-add. This removes one user of the option and makes it use only node names. In order to keep the test meaningful, some instances of query-block that want to check whether the node still exists and would now turn up empty must be converted to query-named-block-nodes (which also return the protocol level node, but that shouldn't hurt). Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake --- tests/qemu-iotests/067 | 6 +- tests/qemu-iotests/067.out | 211 ++++++++++++++++++++++--------------- 2 files changed, 131 insertions(+), 86 deletions(-) diff --git a/tests/qemu-iotests/067 b/tests/qemu-iotests/067 index c1df48eded5..a12125bd46a 100755 --- a/tests/qemu-iotests/067 +++ b/tests/qemu-iotests/067 @@ -121,7 +121,7 @@ run_qemu < Date: Wed, 21 Sep 2016 14:56:02 +0200 Subject: [PATCH 280/723] qemu-iotests/071: Avoid blockdev-add with id We want to remove the 'id' option for blockdev-add. This removes one user of the option and makes it use only node names. Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake --- tests/qemu-iotests/071 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/qemu-iotests/071 b/tests/qemu-iotests/071 index bdfd91fef17..6d0864cff6d 100755 --- a/tests/qemu-iotests/071 +++ b/tests/qemu-iotests/071 @@ -118,7 +118,7 @@ run_qemu < Date: Wed, 21 Sep 2016 14:56:03 +0200 Subject: [PATCH 281/723] qemu-iotests/081: Avoid blockdev-add with id We want to remove the 'id' option for blockdev-add. This removes one user of the option and makes it use only node names. Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake --- tests/qemu-iotests/081 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/qemu-iotests/081 b/tests/qemu-iotests/081 index d89fabcdbd2..0a809f34995 100755 --- a/tests/qemu-iotests/081 +++ b/tests/qemu-iotests/081 @@ -119,7 +119,7 @@ run_qemu < Date: Wed, 21 Sep 2016 14:56:04 +0200 Subject: [PATCH 282/723] qemu-iotests/087: Avoid blockdev-add with id We want to remove the 'id' option for blockdev-add. This removes one user of the option and makes it use only node names. The test cases that test conflicts between the 'id' option to blockdev-add and existing block devices or the 'node-name' of the same command can be removed because it won't be possible to specify this at the end of the series. Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake --- tests/qemu-iotests/087 | 62 +++----------------------------------- tests/qemu-iotests/087.out | 6 +--- 2 files changed, 6 insertions(+), 62 deletions(-) diff --git a/tests/qemu-iotests/087 b/tests/qemu-iotests/087 index e7bca37efc1..5c04577b366 100755 --- a/tests/qemu-iotests/087 +++ b/tests/qemu-iotests/087 @@ -77,50 +77,12 @@ echo echo === Duplicate ID === echo -run_qemu < Date: Wed, 21 Sep 2016 14:56:05 +0200 Subject: [PATCH 283/723] qemu-iotests/117: Avoid blockdev-add with id We want to remove the 'id' option for blockdev-add. This removes one user of the option and makes it use only node names. Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake --- tests/qemu-iotests/117 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/qemu-iotests/117 b/tests/qemu-iotests/117 index 9385b3f8da4..5b28039e17d 100755 --- a/tests/qemu-iotests/117 +++ b/tests/qemu-iotests/117 @@ -52,14 +52,14 @@ _send_qemu_cmd $QEMU_HANDLE \ _send_qemu_cmd $QEMU_HANDLE \ "{ 'execute': 'blockdev-add', - 'arguments': { 'options': { 'id': 'protocol', + 'arguments': { 'options': { 'node-name': 'protocol', 'driver': 'file', 'filename': '$TEST_IMG' } } }" \ 'return' _send_qemu_cmd $QEMU_HANDLE \ "{ 'execute': 'blockdev-add', - 'arguments': { 'options': { 'id': 'format', + 'arguments': { 'options': { 'node-name': 'format', 'driver': '$IMGFMT', 'file': 'protocol' } } }" \ 'return' From e4fd2e9dfca0b592e329eec9ba753914e7941104 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Wed, 21 Sep 2016 14:56:06 +0200 Subject: [PATCH 284/723] qemu-iotests/118: Avoid blockdev-add with id We want to remove the 'id' option for blockdev-add. This removes one user of the option and makes it use only node names. Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake --- tests/qemu-iotests/118 | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/qemu-iotests/118 b/tests/qemu-iotests/118 index 0380069ef68..e63a40fa946 100755 --- a/tests/qemu-iotests/118 +++ b/tests/qemu-iotests/118 @@ -648,13 +648,9 @@ class TestBlockJobsAfterCycle(ChangeBaseClass): qemu_img('create', '-f', iotests.imgfmt, old_img, '1M') self.vm = iotests.VM() + self.vm.add_drive_raw("id=drive0,driver=null-co,if=none") self.vm.launch() - result = self.vm.qmp('blockdev-add', - options={'id': 'drive0', - 'driver': 'null-co'}) - self.assert_qmp(result, 'return', {}) - result = self.vm.qmp('query-block') self.assert_qmp(result, 'return[0]/inserted/image/format', 'null-co') From eed875838e8d667e1fad5f6f5872c3d60ee266dd Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Wed, 21 Sep 2016 14:56:07 +0200 Subject: [PATCH 285/723] qemu-iotests/124: Avoid blockdev-add with id We want to remove the 'id' option for blockdev-add. This removes one user of the option and makes it use only node names. Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake --- tests/qemu-iotests/124 | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/tests/qemu-iotests/124 b/tests/qemu-iotests/124 index de7cdbe00eb..2f0bc24cd02 100644 --- a/tests/qemu-iotests/124 +++ b/tests/qemu-iotests/124 @@ -49,8 +49,8 @@ def transaction_bitmap_clear(node, name, **kwargs): def transaction_drive_backup(device, target, **kwargs): - return transaction_action('drive-backup', device=device, target=target, - **kwargs) + return transaction_action('drive-backup', job_id=device, device=device, + target=target, **kwargs) class Bitmap: @@ -177,7 +177,8 @@ class TestIncrementalBackupBase(iotests.QMPTestCase): def create_anchor_backup(self, drive=None): if drive is None: drive = self.drives[-1] - res = self.do_qmp_backup(device=drive['id'], sync='full', + res = self.do_qmp_backup(job_id=drive['id'], + device=drive['id'], sync='full', format=drive['fmt'], target=drive['backup']) self.assertTrue(res) self.files.append(drive['backup']) @@ -188,7 +189,8 @@ class TestIncrementalBackupBase(iotests.QMPTestCase): if bitmap is None: bitmap = self.bitmaps[-1] _, reference = bitmap.last_target() - res = self.do_qmp_backup(device=bitmap.drive['id'], sync='full', + res = self.do_qmp_backup(job_id=bitmap.drive['id'], + device=bitmap.drive['id'], sync='full', format=bitmap.drive['fmt'], target=reference) self.assertTrue(res) @@ -221,7 +223,8 @@ class TestIncrementalBackupBase(iotests.QMPTestCase): parent, _ = bitmap.last_target() target = self.prepare_backup(bitmap, parent) - res = self.do_qmp_backup(device=bitmap.drive['id'], + res = self.do_qmp_backup(job_id=bitmap.drive['id'], + device=bitmap.drive['id'], sync='incremental', bitmap=bitmap.name, format=bitmap.drive['fmt'], target=target, mode='existing') @@ -414,7 +417,7 @@ class TestIncrementalBackup(TestIncrementalBackupBase): # Create a blkdebug interface to this img as 'drive1' result = self.vm.qmp('blockdev-add', options={ - 'id': drive1['id'], + 'node-name': drive1['id'], 'driver': drive1['fmt'], 'file': { 'driver': 'blkdebug', @@ -558,7 +561,7 @@ class TestIncrementalBackupBlkdebug(TestIncrementalBackupBase): drive0 = self.drives[0] result = self.vm.qmp('blockdev-add', options={ - 'id': drive0['id'], + 'node-name': drive0['id'], 'driver': drive0['fmt'], 'file': { 'driver': 'blkdebug', From 62acae8a9d20c872212aec59d4a0a634a97e87f0 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Wed, 21 Sep 2016 14:56:08 +0200 Subject: [PATCH 286/723] qemu-iotests/139: Avoid blockdev-add with id We want to remove the 'id' option for blockdev-add. This removes one user of the option and makes it use only node names. Some test cases that used to work with an unattached BlockBackend are removed, either because they don't make sense with an attached device or because the equivalent test case with an attached device already exists. Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake --- tests/qemu-iotests/139 | 178 ++++++++++++------------------------- tests/qemu-iotests/139.out | 4 +- 2 files changed, 59 insertions(+), 123 deletions(-) diff --git a/tests/qemu-iotests/139 b/tests/qemu-iotests/139 index a4b969499c3..47a4c26e29d 100644 --- a/tests/qemu-iotests/139 +++ b/tests/qemu-iotests/139 @@ -31,6 +31,7 @@ class TestBlockdevDel(iotests.QMPTestCase): def setUp(self): iotests.qemu_img('create', '-f', iotests.imgfmt, base_img, '1M') self.vm = iotests.VM() + self.vm.add_device("virtio-scsi-pci,id=virtio-scsi") self.vm.launch() def tearDown(self): @@ -39,18 +40,6 @@ class TestBlockdevDel(iotests.QMPTestCase): if os.path.isfile(new_img): os.remove(new_img) - # Check whether a BlockBackend exists - def checkBlockBackend(self, backend, node, must_exist = True): - result = self.vm.qmp('query-block') - backends = filter(lambda x: x['device'] == backend, result['return']) - self.assertLessEqual(len(backends), 1) - self.assertEqual(must_exist, len(backends) == 1) - if must_exist: - if node: - self.assertEqual(backends[0]['inserted']['node-name'], node) - else: - self.assertFalse(backends[0].has_key('inserted')) - # Check whether a BlockDriverState exists def checkBlockDriverState(self, node, must_exist = True): result = self.vm.qmp('query-named-block-nodes') @@ -58,24 +47,6 @@ class TestBlockdevDel(iotests.QMPTestCase): self.assertLessEqual(len(nodes), 1) self.assertEqual(must_exist, len(nodes) == 1) - # Add a new BlockBackend (with its attached BlockDriverState) - def addBlockBackend(self, backend, node): - file_node = '%s_file' % node - self.checkBlockBackend(backend, node, False) - self.checkBlockDriverState(node, False) - self.checkBlockDriverState(file_node, False) - opts = {'driver': iotests.imgfmt, - 'id': backend, - 'node-name': node, - 'file': {'driver': 'file', - 'node-name': file_node, - 'filename': base_img}} - result = self.vm.qmp('blockdev-add', conv_keys = False, options = opts) - self.assert_qmp(result, 'return', {}) - self.checkBlockBackend(backend, node) - self.checkBlockDriverState(node) - self.checkBlockDriverState(file_node) - # Add a BlockDriverState without a BlockBackend def addBlockDriverState(self, node): file_node = '%s_file' % node @@ -105,23 +76,6 @@ class TestBlockdevDel(iotests.QMPTestCase): self.assert_qmp(result, 'return', {}) self.checkBlockDriverState(node) - # Delete a BlockBackend - def delBlockBackend(self, backend, node, expect_error = False, - destroys_media = True): - self.checkBlockBackend(backend, node) - if node: - self.checkBlockDriverState(node) - result = self.vm.qmp('x-blockdev-del', id = backend) - if expect_error: - self.assert_qmp(result, 'error/class', 'GenericError') - if node: - self.checkBlockDriverState(node) - else: - self.assert_qmp(result, 'return', {}) - if node: - self.checkBlockDriverState(node, not destroys_media) - self.checkBlockBackend(backend, node, must_exist = expect_error) - # Delete a BlockDriverState def delBlockDriverState(self, node, expect_error = False): self.checkBlockDriverState(node) @@ -133,51 +87,47 @@ class TestBlockdevDel(iotests.QMPTestCase): self.checkBlockDriverState(node, expect_error) # Add a device model - def addDeviceModel(self, device, backend): + def addDeviceModel(self, device, backend, driver = 'virtio-blk-pci'): result = self.vm.qmp('device_add', id = device, - driver = 'virtio-blk-pci', drive = backend) + driver = driver, drive = backend) self.assert_qmp(result, 'return', {}) # Delete a device model - def delDeviceModel(self, device): + def delDeviceModel(self, device, is_virtio_blk = True): result = self.vm.qmp('device_del', id = device) self.assert_qmp(result, 'return', {}) result = self.vm.qmp('system_reset') self.assert_qmp(result, 'return', {}) - device_path = '/machine/peripheral/%s/virtio-backend' % device - event = self.vm.event_wait(name="DEVICE_DELETED", - match={'data': {'path': device_path}}) - self.assertNotEqual(event, None) + if is_virtio_blk: + device_path = '/machine/peripheral/%s/virtio-backend' % device + event = self.vm.event_wait(name="DEVICE_DELETED", + match={'data': {'path': device_path}}) + self.assertNotEqual(event, None) event = self.vm.event_wait(name="DEVICE_DELETED", match={'data': {'device': device}}) self.assertNotEqual(event, None) # Remove a BlockDriverState - def ejectDrive(self, backend, node, expect_error = False, + def ejectDrive(self, device, node, expect_error = False, destroys_media = True): - self.checkBlockBackend(backend, node) self.checkBlockDriverState(node) - result = self.vm.qmp('eject', device = backend) + result = self.vm.qmp('eject', id = device) if expect_error: self.assert_qmp(result, 'error/class', 'GenericError') self.checkBlockDriverState(node) - self.checkBlockBackend(backend, node) else: self.assert_qmp(result, 'return', {}) self.checkBlockDriverState(node, not destroys_media) - self.checkBlockBackend(backend, None) # Insert a BlockDriverState - def insertDrive(self, backend, node): - self.checkBlockBackend(backend, None) + def insertDrive(self, device, node): self.checkBlockDriverState(node) result = self.vm.qmp('x-blockdev-insert-medium', - device = backend, node_name = node) + id = device, node_name = node) self.assert_qmp(result, 'return', {}) - self.checkBlockBackend(backend, node) self.checkBlockDriverState(node) # Create a snapshot using 'blockdev-snapshot-sync' @@ -204,26 +154,23 @@ class TestBlockdevDel(iotests.QMPTestCase): self.checkBlockDriverState(overlay) # Create a mirror - def createMirror(self, backend, node, new_node): - self.checkBlockBackend(backend, node) + def createMirror(self, node, new_node): self.checkBlockDriverState(new_node, False) - opts = {'device': backend, + opts = {'device': node, + 'job-id': node, 'target': new_img, 'node-name': new_node, 'sync': 'top', 'format': iotests.imgfmt} result = self.vm.qmp('drive-mirror', conv_keys=False, **opts) self.assert_qmp(result, 'return', {}) - self.checkBlockBackend(backend, node) self.checkBlockDriverState(new_node) # Complete an existing block job - def completeBlockJob(self, backend, node_before, node_after): - self.checkBlockBackend(backend, node_before) - result = self.vm.qmp('block-job-complete', device=backend) + def completeBlockJob(self, id, node_before, node_after): + result = self.vm.qmp('block-job-complete', device=id) self.assert_qmp(result, 'return', {}) - self.wait_until_completed(backend) - self.checkBlockBackend(backend, node_after) + self.wait_until_completed(id) # Add a BlkDebug node # Note that the purpose of this is to test the x-blockdev-del @@ -297,89 +244,78 @@ class TestBlockdevDel(iotests.QMPTestCase): # The tests start here # ######################## - def testWrongParameters(self): - self.addBlockBackend('drive0', 'node0') - result = self.vm.qmp('x-blockdev-del') - self.assert_qmp(result, 'error/class', 'GenericError') - result = self.vm.qmp('x-blockdev-del', id='drive0', node_name='node0') - self.assert_qmp(result, 'error/class', 'GenericError') - self.delBlockBackend('drive0', 'node0') - - def testBlockBackend(self): - self.addBlockBackend('drive0', 'node0') - # You cannot delete a BDS that is attached to a backend - self.delBlockDriverState('node0', expect_error = True) - self.delBlockBackend('drive0', 'node0') - def testBlockDriverState(self): self.addBlockDriverState('node0') # You cannot delete a file BDS directly self.delBlockDriverState('node0_file', expect_error = True) self.delBlockDriverState('node0') - def testEject(self): - self.addBlockBackend('drive0', 'node0') - self.ejectDrive('drive0', 'node0') - self.delBlockBackend('drive0', None) - def testDeviceModel(self): - self.addBlockBackend('drive0', 'node0') - self.addDeviceModel('device0', 'drive0') - self.ejectDrive('drive0', 'node0', expect_error = True) - self.delBlockBackend('drive0', 'node0', expect_error = True) + self.addBlockDriverState('node0') + self.addDeviceModel('device0', 'node0') + self.ejectDrive('device0', 'node0', expect_error = True) + self.delBlockDriverState('node0', expect_error = True) self.delDeviceModel('device0') - self.delBlockBackend('drive0', 'node0') + self.delBlockDriverState('node0') def testAttachMedia(self): # This creates a BlockBackend and removes its media - self.addBlockBackend('drive0', 'node0') - self.ejectDrive('drive0', 'node0') - # This creates a new BlockDriverState and inserts it into the backend + self.addBlockDriverState('node0') + self.addDeviceModel('device0', 'node0', 'scsi-cd') + self.ejectDrive('device0', 'node0', destroys_media = False) + self.delBlockDriverState('node0') + + # This creates a new BlockDriverState and inserts it into the device self.addBlockDriverState('node1') - self.insertDrive('drive0', 'node1') - # The backend can't be removed: the new BDS has an extra reference - self.delBlockBackend('drive0', 'node1', expect_error = True) + self.insertDrive('device0', 'node1') + # The node can't be removed: the new device has an extra reference self.delBlockDriverState('node1', expect_error = True) # The BDS still exists after being ejected, but now it can be removed - self.ejectDrive('drive0', 'node1', destroys_media = False) + self.ejectDrive('device0', 'node1', destroys_media = False) self.delBlockDriverState('node1') - self.delBlockBackend('drive0', None) + self.delDeviceModel('device0', False) def testSnapshotSync(self): - self.addBlockBackend('drive0', 'node0') + self.addBlockDriverState('node0') + self.addDeviceModel('device0', 'node0') self.createSnapshotSync('node0', 'overlay0') # This fails because node0 is now being used as a backing image self.delBlockDriverState('node0', expect_error = True) - # This succeeds because overlay0 only has the backend reference - self.delBlockBackend('drive0', 'overlay0') - self.checkBlockDriverState('node0', False) + self.delBlockDriverState('overlay0', expect_error = True) + # This succeeds because device0 only has the backend reference + self.delDeviceModel('device0') + # FIXME Would still be there if blockdev-snapshot-sync took a ref + self.checkBlockDriverState('overlay0', False) + self.delBlockDriverState('node0') def testSnapshot(self): - self.addBlockBackend('drive0', 'node0') + self.addBlockDriverState('node0') + self.addDeviceModel('device0', 'node0', 'scsi-cd') self.addBlockDriverStateOverlay('overlay0') self.createSnapshot('node0', 'overlay0') - self.delBlockBackend('drive0', 'overlay0', expect_error = True) self.delBlockDriverState('node0', expect_error = True) self.delBlockDriverState('overlay0', expect_error = True) - self.ejectDrive('drive0', 'overlay0', destroys_media = False) - self.delBlockBackend('drive0', None) + self.ejectDrive('device0', 'overlay0', destroys_media = False) self.delBlockDriverState('node0', expect_error = True) self.delBlockDriverState('overlay0') - self.checkBlockDriverState('node0', False) + self.delBlockDriverState('node0') def testMirror(self): - self.addBlockBackend('drive0', 'node0') - self.createMirror('drive0', 'node0', 'mirror0') + self.addBlockDriverState('node0') + self.addDeviceModel('device0', 'node0', 'scsi-cd') + self.createMirror('node0', 'mirror0') # The block job prevents removing the device - self.delBlockBackend('drive0', 'node0', expect_error = True) self.delBlockDriverState('node0', expect_error = True) self.delBlockDriverState('mirror0', expect_error = True) - self.wait_ready('drive0') - self.completeBlockJob('drive0', 'node0', 'mirror0') + self.wait_ready('node0') + self.completeBlockJob('node0', 'node0', 'mirror0') self.assert_no_active_block_jobs() - self.checkBlockDriverState('node0', False) - # This succeeds because the backend now points to mirror0 - self.delBlockBackend('drive0', 'mirror0') + # This succeeds because the device now points to mirror0 + self.delBlockDriverState('node0') + self.delBlockDriverState('mirror0', expect_error = True) + self.delDeviceModel('device0', False) + # FIXME mirror0 disappears, drive-mirror doesn't take a reference + #self.delBlockDriverState('mirror0') def testBlkDebug(self): self.addBlkDebug('debug0', 'node0') diff --git a/tests/qemu-iotests/139.out b/tests/qemu-iotests/139.out index 281b69efeac..dae404e2786 100644 --- a/tests/qemu-iotests/139.out +++ b/tests/qemu-iotests/139.out @@ -1,5 +1,5 @@ -............ +......... ---------------------------------------------------------------------- -Ran 12 tests +Ran 9 tests OK From e467da7b92ca207f02d29f52583a1097440a83cc Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Wed, 21 Sep 2016 14:56:09 +0200 Subject: [PATCH 287/723] block: Avoid printing NULL string in error messages Even for nodes that have a BlockBackend attached, bdrv_get_parent_name() can return NULL if the BB is anonymous (e.g. it belongs to a block job or a device that was created with a drive= option). Remove the information from the error message. The user probably knows already why the node is still in use. Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake --- blockdev.c | 9 +++------ tests/qemu-iotests/085.out | 6 +++--- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/blockdev.c b/blockdev.c index 405145ae95f..17c2671c5e2 100644 --- a/blockdev.c +++ b/blockdev.c @@ -1803,8 +1803,7 @@ static void external_snapshot_prepare(BlkActionState *common, } if (bdrv_has_blk(state->new_bs)) { - error_setg(errp, "The snapshot is already in use by %s", - bdrv_get_parent_name(state->new_bs)); + error_setg(errp, "The snapshot is already in use"); return; } @@ -2532,8 +2531,7 @@ void qmp_x_blockdev_insert_medium(bool has_device, const char *device, } if (bdrv_has_blk(bs)) { - error_setg(errp, "Node '%s' is already in use by '%s'", node_name, - bdrv_get_parent_name(bs)); + error_setg(errp, "Node '%s' is already in use", node_name); return; } @@ -3941,8 +3939,7 @@ void qmp_x_blockdev_del(bool has_id, const char *id, return; } if (bdrv_has_blk(bs)) { - error_setg(errp, "Node %s is in use by %s", - node_name, bdrv_get_parent_name(bs)); + error_setg(errp, "Node %s is in use", node_name); return; } aio_context = bdrv_get_aio_context(bs); diff --git a/tests/qemu-iotests/085.out b/tests/qemu-iotests/085.out index 01c78d68946..08e4bb72187 100644 --- a/tests/qemu-iotests/085.out +++ b/tests/qemu-iotests/085.out @@ -68,9 +68,9 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/ === Invalid command - snapshot node used as active layer === -{"error": {"class": "GenericError", "desc": "The snapshot is already in use by virtio0"}} -{"error": {"class": "GenericError", "desc": "The snapshot is already in use by virtio0"}} -{"error": {"class": "GenericError", "desc": "The snapshot is already in use by virtio1"}} +{"error": {"class": "GenericError", "desc": "The snapshot is already in use"}} +{"error": {"class": "GenericError", "desc": "The snapshot is already in use"}} +{"error": {"class": "GenericError", "desc": "The snapshot is already in use"}} === Invalid command - snapshot node used as backing hd === From 78645881508ebcfced97dc608b90179b264914e9 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Wed, 21 Sep 2016 14:56:10 +0200 Subject: [PATCH 288/723] qemu-iotests/141: Avoid blockdev-add with id We want to remove the 'id' option for blockdev-add. This removes one user of the option and makes it use only node names. Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake --- tests/qemu-iotests/141 | 24 ++++++++++++++---------- tests/qemu-iotests/141.out | 24 ++++++++++++------------ 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/tests/qemu-iotests/141 b/tests/qemu-iotests/141 index b2617e5e2b9..c092d872dce 100755 --- a/tests/qemu-iotests/141 +++ b/tests/qemu-iotests/141 @@ -51,7 +51,7 @@ test_blockjob() "{'execute': 'blockdev-add', 'arguments': { 'options': { - 'id': 'drv0', + 'node-name': 'drv0', 'driver': '$IMGFMT', 'file': { 'driver': 'file', @@ -66,18 +66,18 @@ test_blockjob() # We want this to return an error because the block job is still running _send_qemu_cmd $QEMU_HANDLE \ - "{'execute': 'x-blockdev-remove-medium', - 'arguments': {'device': 'drv0'}}" \ + "{'execute': 'x-blockdev-del', + 'arguments': {'node-name': 'drv0'}}" \ 'error' _send_qemu_cmd $QEMU_HANDLE \ "{'execute': 'block-job-cancel', - 'arguments': {'device': 'drv0'}}" \ + 'arguments': {'device': 'job0'}}" \ "$3" _send_qemu_cmd $QEMU_HANDLE \ "{'execute': 'x-blockdev-del', - 'arguments': {'id': 'drv0'}}" \ + 'arguments': {'node-name': 'drv0'}}" \ 'return' } @@ -101,7 +101,8 @@ echo test_blockjob \ "{'execute': 'drive-backup', - 'arguments': {'device': 'drv0', + 'arguments': {'job-id': 'job0', + 'device': 'drv0', 'target': '$TEST_DIR/o.$IMGFMT', 'format': '$IMGFMT', 'sync': 'none'}}" \ @@ -117,7 +118,8 @@ echo test_blockjob \ "{'execute': 'drive-mirror', - 'arguments': {'device': 'drv0', + 'arguments': {'job-id': 'job0', + 'device': 'drv0', 'target': '$TEST_DIR/o.$IMGFMT', 'format': '$IMGFMT', 'sync': 'none'}}" \ @@ -134,7 +136,7 @@ echo test_blockjob \ "{'execute': 'block-commit', - 'arguments': {'device': 'drv0'}}" \ + 'arguments': {'job-id': 'job0', 'device': 'drv0'}}" \ 'BLOCK_JOB_READY' \ 'BLOCK_JOB_COMPLETED' @@ -150,7 +152,8 @@ $QEMU_IO -c 'write 0 1M' "$TEST_DIR/m.$IMGFMT" | _filter_qemu_io test_blockjob \ "{'execute': 'block-commit', - 'arguments': {'device': 'drv0', + 'arguments': {'job-id': 'job0', + 'device': 'drv0', 'top': '$TEST_DIR/m.$IMGFMT', 'speed': 1}}" \ 'return' \ @@ -172,7 +175,8 @@ $QEMU_IO -c 'write 0 1M' "$TEST_DIR/b.$IMGFMT" | _filter_qemu_io test_blockjob \ "{'execute': 'block-stream', - 'arguments': {'device': 'drv0', + 'arguments': {'job-id': 'job0', + 'device': 'drv0', 'speed': 1}}" \ 'return' \ 'BLOCK_JOB_CANCELLED' diff --git a/tests/qemu-iotests/141.out b/tests/qemu-iotests/141.out index eaf1e603ed7..195ca1a6049 100644 --- a/tests/qemu-iotests/141.out +++ b/tests/qemu-iotests/141.out @@ -9,30 +9,30 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/m. {"return": {}} Formatting 'TEST_DIR/o.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT backing_fmt=IMGFMT {"return": {}} -{"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: block device is in use by block job: backup"}} +{"error": {"class": "GenericError", "desc": "Node drv0 is in use"}} {"return": {}} -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "drv0", "len": 1048576, "offset": 0, "speed": 0, "type": "backup"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "job0", "len": 1048576, "offset": 0, "speed": 0, "type": "backup"}} {"return": {}} === Testing drive-mirror === {"return": {}} Formatting 'TEST_DIR/o.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT backing_fmt=IMGFMT -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "drv0", "len": 0, "offset": 0, "speed": 0, "type": "mirror"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "mirror"}} {"return": {}} -{"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: block device is in use by block job: mirror"}} +{"error": {"class": "GenericError", "desc": "Node drv0 is in use"}} {"return": {}} -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "drv0", "len": 0, "offset": 0, "speed": 0, "type": "mirror"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "mirror"}} {"return": {}} === Testing active block-commit === {"return": {}} -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "drv0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}} {"return": {}} -{"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: block device is in use by block job: commit"}} +{"error": {"class": "GenericError", "desc": "Node drv0 is in use"}} {"return": {}} -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "drv0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}} {"return": {}} === Testing non-active block-commit === @@ -41,9 +41,9 @@ wrote 1048576/1048576 bytes at offset 0 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) {"return": {}} {"return": {}} -{"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: block device is in use by block job: commit"}} +{"error": {"class": "GenericError", "desc": "Node drv0 is in use"}} {"return": {}} -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "drv0", "len": 1048576, "offset": 524288, "speed": 1, "type": "commit"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "job0", "len": 1048576, "offset": 524288, "speed": 1, "type": "commit"}} {"return": {}} === Testing block-stream === @@ -52,8 +52,8 @@ wrote 1048576/1048576 bytes at offset 0 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) {"return": {}} {"return": {}} -{"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: block device is in use by block job: stream"}} +{"error": {"class": "GenericError", "desc": "Node drv0 is in use"}} {"return": {}} -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "drv0", "len": 1048576, "offset": 524288, "speed": 1, "type": "stream"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "job0", "len": 1048576, "offset": 524288, "speed": 1, "type": "stream"}} {"return": {}} *** done From 9ec8873e684c2dae6fadb3a801057c613ccd2a6b Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Wed, 21 Sep 2016 14:56:11 +0200 Subject: [PATCH 289/723] block: Remove BB interface from blockdev-add/del With this patch, blockdev-add always works on a node level, i.e. it creates a BDS, but no BB. Consequently, x-blockdev-del doesn't need the 'device' option any more, but 'node-name' becomes mandatory. Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake --- blockdev.c | 124 ++++++++++--------------------------- docs/qmp-commands.txt | 24 +++---- qapi/block-core.json | 30 ++------- tests/qemu-iotests/087.out | 2 +- 4 files changed, 48 insertions(+), 132 deletions(-) diff --git a/blockdev.c b/blockdev.c index 17c2671c5e2..29c6561fd89 100644 --- a/blockdev.c +++ b/blockdev.c @@ -2844,7 +2844,7 @@ void hmp_drive_del(Monitor *mon, const QDict *qdict) bs = bdrv_find_node(id); if (bs) { - qmp_x_blockdev_del(false, NULL, true, id, &local_err); + qmp_x_blockdev_del(id, &local_err); if (local_err) { error_report_err(local_err); } @@ -3827,7 +3827,6 @@ void hmp_drive_add_node(Monitor *mon, const char *optstr) void qmp_blockdev_add(BlockdevOptions *options, Error **errp) { BlockDriverState *bs; - BlockBackend *blk = NULL; QObject *obj; Visitor *v = qmp_output_visitor_new(&obj); QDict *qdict; @@ -3859,37 +3858,21 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp) qdict_flatten(qdict); - if (options->has_id) { - blk = blockdev_init(NULL, qdict, &local_err); - if (local_err) { - error_propagate(errp, local_err); - goto fail; - } - - bs = blk_bs(blk); - } else { - if (!qdict_get_try_str(qdict, "node-name")) { - error_setg(errp, "'id' and/or 'node-name' need to be specified for " - "the root node"); - goto fail; - } - - bs = bds_tree_init(qdict, errp); - if (!bs) { - goto fail; - } + if (!qdict_get_try_str(qdict, "node-name")) { + error_setg(errp, "'node-name' must be specified for the root node"); + goto fail; + } - QTAILQ_INSERT_TAIL(&monitor_bdrv_states, bs, monitor_list); + bs = bds_tree_init(qdict, errp); + if (!bs) { + goto fail; } + QTAILQ_INSERT_TAIL(&monitor_bdrv_states, bs, monitor_list); + if (bs && bdrv_key_required(bs)) { - if (blk) { - monitor_remove_blk(blk); - blk_unref(blk); - } else { - QTAILQ_REMOVE(&monitor_bdrv_states, bs, monitor_list); - bdrv_unref(bs); - } + QTAILQ_REMOVE(&monitor_bdrv_states, bs, monitor_list); + bdrv_unref(bs); error_setg(errp, "blockdev-add doesn't support encrypted devices"); goto fail; } @@ -3898,81 +3881,42 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp) visit_free(v); } -void qmp_x_blockdev_del(bool has_id, const char *id, - bool has_node_name, const char *node_name, Error **errp) +void qmp_x_blockdev_del(const char *node_name, Error **errp) { AioContext *aio_context; - BlockBackend *blk; BlockDriverState *bs; - if (has_id && has_node_name) { - error_setg(errp, "Only one of id and node-name must be specified"); - return; - } else if (!has_id && !has_node_name) { - error_setg(errp, "No block device specified"); + bs = bdrv_find_node(node_name); + if (!bs) { + error_setg(errp, "Cannot find node %s", node_name); return; } - - if (has_id) { - /* blk_by_name() never returns a BB that is not owned by the monitor */ - blk = blk_by_name(id); - if (!blk) { - error_setg(errp, "Cannot find block backend %s", id); - return; - } - if (blk_legacy_dinfo(blk)) { - error_setg(errp, "Deleting block backend added with drive-add" - " is not supported"); - return; - } - if (blk_get_refcnt(blk) > 1) { - error_setg(errp, "Block backend %s is in use", id); - return; - } - bs = blk_bs(blk); - aio_context = blk_get_aio_context(blk); - } else { - blk = NULL; - bs = bdrv_find_node(node_name); - if (!bs) { - error_setg(errp, "Cannot find node %s", node_name); - return; - } - if (bdrv_has_blk(bs)) { - error_setg(errp, "Node %s is in use", node_name); - return; - } - aio_context = bdrv_get_aio_context(bs); + if (bdrv_has_blk(bs)) { + error_setg(errp, "Node %s is in use", node_name); + return; } - + aio_context = bdrv_get_aio_context(bs); aio_context_acquire(aio_context); - if (bs) { - if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_DRIVE_DEL, errp)) { - goto out; - } - - if (!blk && !QTAILQ_IN_USE(bs, monitor_list)) { - error_setg(errp, "Node %s is not owned by the monitor", - bs->node_name); - goto out; - } + if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_DRIVE_DEL, errp)) { + goto out; + } - if (bs->refcnt > 1) { - error_setg(errp, "Block device %s is in use", - bdrv_get_device_or_node_name(bs)); - goto out; - } + if (!bs->monitor_list.tqe_prev) { + error_setg(errp, "Node %s is not owned by the monitor", + bs->node_name); + goto out; } - if (blk) { - monitor_remove_blk(blk); - blk_unref(blk); - } else { - QTAILQ_REMOVE(&monitor_bdrv_states, bs, monitor_list); - bdrv_unref(bs); + if (bs->refcnt > 1) { + error_setg(errp, "Block device %s is in use", + bdrv_get_device_or_node_name(bs)); + goto out; } + QTAILQ_REMOVE(&monitor_bdrv_states, bs, monitor_list); + bdrv_unref(bs); + out: aio_context_release(aio_context); } diff --git a/docs/qmp-commands.txt b/docs/qmp-commands.txt index 41f56981af9..e0adcebc67c 100644 --- a/docs/qmp-commands.txt +++ b/docs/qmp-commands.txt @@ -3141,7 +3141,7 @@ Example (2): "arguments": { "options": { "driver": "qcow2", - "id": "my_disk", + "node-name": "my_disk", "discard": "unmap", "cache": { "direct": true, @@ -3168,18 +3168,9 @@ x-blockdev-del ------------ Since 2.5 -Deletes a block device thas has been added using blockdev-add. -The selected device can be either a block backend or a graph node. - -In the former case the backend will be destroyed, along with its -inserted medium if there's any. The command will fail if the backend -or its medium are in use. - -In the latter case the node will be destroyed. The command will fail -if the node is attached to a block backend or is otherwise being -used. - -One of "id" or "node-name" must be specified, but not both. +Deletes a block device that has been added using blockdev-add. +The command will fail if the node is attached to a device or is +otherwise being used. This command is still a work in progress and is considered experimental. Stay away from it unless you want to help with its @@ -3187,8 +3178,7 @@ development. Arguments: -- "id": Name of the block backend device to delete (json-string, optional) -- "node-name": Name of the graph node to delete (json-string, optional) +- "node-name": Name of the graph node to delete (json-string) Example: @@ -3196,7 +3186,7 @@ Example: "arguments": { "options": { "driver": "qcow2", - "id": "drive0", + "node-name": "node0", "file": { "driver": "file", "filename": "test.qcow2" @@ -3208,7 +3198,7 @@ Example: <- { "return": {} } -> { "execute": "x-blockdev-del", - "arguments": { "id": "drive0" } + "arguments": { "node-name": "node0" } } <- { "return": {} } diff --git a/qapi/block-core.json b/qapi/block-core.json index 5f04dab0275..92193ab0a1d 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -2217,13 +2217,8 @@ # block devices, independent of the block driver: # # @driver: block driver name -# @id: #optional id by which the new block device can be referred to. -# This option is only allowed on the top level of blockdev-add. -# A BlockBackend will be created by blockdev-add if and only if -# this option is given. -# @node-name: #optional the name of a block driver state node (Since 2.0). -# This option is required on the top level of blockdev-add if -# the @id option is not given there. +# @node-name: #optional the node name of the new node (Since 2.0). +# This option is required on the top level of blockdev-add. # @discard: #optional discard-related options (default: ignore) # @cache: #optional cache-related options # @aio: #optional AIO backend (default: threads) @@ -2238,8 +2233,6 @@ ## { 'union': 'BlockdevOptions', 'base': { 'driver': 'BlockdevDriver', -# TODO 'id' is a BB-level option, remove it - '*id': 'str', '*node-name': 'str', '*discard': 'BlockdevDiscardOptions', '*cache': 'BlockdevCacheOptions', @@ -2323,29 +2316,18 @@ # @x-blockdev-del: # # Deletes a block device that has been added using blockdev-add. -# The selected device can be either a block backend or a graph node. -# -# In the former case the backend will be destroyed, along with its -# inserted medium if there's any. The command will fail if the backend -# or its medium are in use. -# -# In the latter case the node will be destroyed. The command will fail -# if the node is attached to a block backend or is otherwise being -# used. -# -# One of @id or @node-name must be specified, but not both. +# The command will fail if the node is attached to a device or is +# otherwise being used. # # This command is still a work in progress and is considered # experimental. Stay away from it unless you want to help with its # development. # -# @id: #optional Name of the block backend device to delete. -# -# @node-name: #optional Name of the graph node to delete. +# @node-name: Name of the graph node to delete. # # Since: 2.5 ## -{ 'command': 'x-blockdev-del', 'data': { '*id': 'str', '*node-name': 'str' } } +{ 'command': 'x-blockdev-del', 'data': { 'node-name': 'str' } } ## # @blockdev-open-tray: diff --git a/tests/qemu-iotests/087.out b/tests/qemu-iotests/087.out index f2d6f968050..bef68626c8d 100644 --- a/tests/qemu-iotests/087.out +++ b/tests/qemu-iotests/087.out @@ -6,7 +6,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 Testing: QMP_VERSION {"return": {}} -{"error": {"class": "GenericError", "desc": "'id' and/or 'node-name' need to be specified for the root node"}} +{"error": {"class": "GenericError", "desc": "'node-name' must be specified for the root node"}} {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"} From 5d443f5adad6ddd8238602990b7e86404a288d48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Fri, 9 Sep 2016 15:34:43 +0400 Subject: [PATCH 290/723] tests: add /vhost-user/connect-fail test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check early connection failure and resume. Signed-off-by: Marc-André Lureau Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/vhost-user-test.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c index b89a5511266..ab91e1684f2 100644 --- a/tests/vhost-user-test.c +++ b/tests/vhost-user-test.c @@ -135,6 +135,7 @@ typedef struct TestServer { CompatGCond data_cond; int log_fd; uint64_t rings; + bool test_fail; } TestServer; static const char *tmpfs; @@ -249,6 +250,12 @@ static void chr_read(void *opaque, const uint8_t *buf, int size) uint8_t *p = (uint8_t *) &msg; int fd; + if (s->test_fail) { + qemu_chr_disconnect(chr); + /* now switch to non-failure */ + s->test_fail = false; + } + if (size != VHOST_USER_HDR_SIZE) { g_test_message("Wrong message size received %d\n", size); return; @@ -715,6 +722,35 @@ static void test_reconnect(void) g_test_trap_assert_passed(); g_free(path); } + +static void test_connect_fail_subprocess(void) +{ + TestServer *s = test_server_new("connect-fail"); + char *cmd; + + s->test_fail = true; + g_thread_new("connect", connect_thread, s); + cmd = GET_QEMU_CMDE(s, 2, ",server", ""); + qtest_start(cmd); + g_free(cmd); + + init_virtio_dev(s); + wait_for_fds(s); + wait_for_rings_started(s, 2); + + qtest_end(); + test_server_free(s); +} + +static void test_connect_fail(void) +{ + gchar *path = g_strdup_printf("/%s/vhost-user/connect-fail/subprocess", + qtest_get_arch()); + g_test_trap_subprocess(path, 0, 0); + g_test_trap_assert_passed(); + g_free(path); +} + #endif int main(int argc, char **argv) @@ -766,6 +802,9 @@ int main(int argc, char **argv) qtest_add_func("/vhost-user/reconnect/subprocess", test_reconnect_subprocess); qtest_add_func("/vhost-user/reconnect", test_reconnect); + qtest_add_func("/vhost-user/connect-fail/subprocess", + test_connect_fail_subprocess); + qtest_add_func("/vhost-user/connect-fail", test_connect_fail); #endif ret = g_test_run(); From ed0a8d92527195bd6009096533e7d0cd8be6fca1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Fri, 9 Sep 2016 15:34:44 +0400 Subject: [PATCH 291/723] tests: add a simple /vhost-user/multiqueue test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This test just checks that 2 virtio-net queues can be setup over vhost-user and waits for them to be started. Signed-off-by: Marc-André Lureau Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/Makefile.include | 2 +- tests/vhost-user-test.c | 109 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 107 insertions(+), 4 deletions(-) diff --git a/tests/Makefile.include b/tests/Makefile.include index d8101b35437..2aa78c18201 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -656,7 +656,7 @@ tests/usb-hcd-ehci-test$(EXESUF): tests/usb-hcd-ehci-test.o $(libqos-usb-obj-y) tests/usb-hcd-xhci-test$(EXESUF): tests/usb-hcd-xhci-test.o $(libqos-usb-obj-y) tests/pc-cpu-test$(EXESUF): tests/pc-cpu-test.o tests/postcopy-test$(EXESUF): tests/postcopy-test.o -tests/vhost-user-test$(EXESUF): tests/vhost-user-test.o qemu-char.o qemu-timer.o $(qtest-obj-y) $(test-io-obj-y) $(libqos-virtio-obj-y) +tests/vhost-user-test$(EXESUF): tests/vhost-user-test.o qemu-char.o qemu-timer.o $(qtest-obj-y) $(test-io-obj-y) $(libqos-virtio-obj-y) $(libqos-pc-obj-y) tests/qemu-iotests/socket_scm_helper$(EXESUF): tests/qemu-iotests/socket_scm_helper.o tests/test-qemu-opts$(EXESUF): tests/test-qemu-opts.o $(test-util-obj-y) tests/test-write-threshold$(EXESUF): tests/test-write-threshold.o $(test-block-obj-y) diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c index ab91e1684f2..ffdd398f86d 100644 --- a/tests/vhost-user-test.c +++ b/tests/vhost-user-test.c @@ -20,6 +20,11 @@ #include "libqos/pci-pc.h" #include "libqos/virtio-pci.h" +#include "libqos/pci-pc.h" +#include "libqos/virtio-pci.h" +#include "libqos/malloc-pc.h" +#include "hw/virtio/virtio-net.h" + #include #include #include @@ -50,6 +55,7 @@ #define VHOST_MEMORY_MAX_NREGIONS 8 #define VHOST_USER_F_PROTOCOL_FEATURES 30 +#define VHOST_USER_PROTOCOL_F_MQ 0 #define VHOST_USER_PROTOCOL_F_LOG_SHMFD 1 #define VHOST_LOG_PAGE 0x1000 @@ -72,6 +78,7 @@ typedef enum VhostUserRequest { VHOST_USER_SET_VRING_ERR = 14, VHOST_USER_GET_PROTOCOL_FEATURES = 15, VHOST_USER_SET_PROTOCOL_FEATURES = 16, + VHOST_USER_GET_QUEUE_NUM = 17, VHOST_USER_SET_VRING_ENABLE = 18, VHOST_USER_MAX } VhostUserRequest; @@ -136,6 +143,7 @@ typedef struct TestServer { int log_fd; uint64_t rings; bool test_fail; + int queues; } TestServer; static const char *tmpfs; @@ -281,6 +289,9 @@ static void chr_read(void *opaque, const uint8_t *buf, int size) msg.size = sizeof(m.payload.u64); msg.payload.u64 = 0x1ULL << VHOST_F_LOG_ALL | 0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES; + if (s->queues > 1) { + msg.payload.u64 |= 0x1ULL << VIRTIO_NET_F_MQ; + } p = (uint8_t *) &msg; qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size); break; @@ -295,6 +306,9 @@ static void chr_read(void *opaque, const uint8_t *buf, int size) msg.flags |= VHOST_USER_REPLY_MASK; msg.size = sizeof(m.payload.u64); msg.payload.u64 = 1 << VHOST_USER_PROTOCOL_F_LOG_SHMFD; + if (s->queues > 1) { + msg.payload.u64 |= 1 << VHOST_USER_PROTOCOL_F_MQ; + } p = (uint8_t *) &msg; qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size); break; @@ -307,7 +321,7 @@ static void chr_read(void *opaque, const uint8_t *buf, int size) p = (uint8_t *) &msg; qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size); - assert(msg.payload.state.index < 2); + assert(msg.payload.state.index < s->queues * 2); s->rings &= ~(0x1ULL << msg.payload.state.index); break; @@ -347,10 +361,18 @@ static void chr_read(void *opaque, const uint8_t *buf, int size) break; case VHOST_USER_SET_VRING_BASE: - assert(msg.payload.state.index < 2); + assert(msg.payload.state.index < s->queues * 2); s->rings |= 0x1ULL << msg.payload.state.index; break; + case VHOST_USER_GET_QUEUE_NUM: + msg.flags |= VHOST_USER_REPLY_MASK; + msg.size = sizeof(m.payload.u64); + msg.payload.u64 = s->queues; + p = (uint8_t *) &msg; + qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size); + break; + default: break; } @@ -397,6 +419,7 @@ static TestServer *test_server_new(const gchar *name) g_cond_init(&server->data_cond); server->log_fd = -1; + server->queues = 1; return server; } @@ -648,7 +671,6 @@ static void test_migrate(void) global_qtest = global; } -#ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS static void wait_for_rings_started(TestServer *s, size_t count) { gint64 end_time; @@ -666,6 +688,7 @@ static void wait_for_rings_started(TestServer *s, size_t count) g_mutex_unlock(&s->data_mutex); } +#ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS static gboolean reconnect_cb(gpointer user_data) { @@ -753,6 +776,85 @@ static void test_connect_fail(void) #endif +static QVirtioPCIDevice *virtio_net_pci_init(QPCIBus *bus, int slot) +{ + QVirtioPCIDevice *dev; + + dev = qvirtio_pci_device_find(bus, VIRTIO_ID_NET); + g_assert(dev != NULL); + g_assert_cmphex(dev->vdev.device_type, ==, VIRTIO_ID_NET); + + qvirtio_pci_device_enable(dev); + qvirtio_reset(&qvirtio_pci, &dev->vdev); + qvirtio_set_acknowledge(&qvirtio_pci, &dev->vdev); + qvirtio_set_driver(&qvirtio_pci, &dev->vdev); + + return dev; +} + +static void driver_init(const QVirtioBus *bus, QVirtioDevice *dev) +{ + uint32_t features; + + features = qvirtio_get_features(bus, dev); + features = features & ~(QVIRTIO_F_BAD_FEATURE | + (1u << VIRTIO_RING_F_INDIRECT_DESC) | + (1u << VIRTIO_RING_F_EVENT_IDX)); + qvirtio_set_features(bus, dev, features); + + qvirtio_set_driver_ok(bus, dev); +} + +#define PCI_SLOT 0x04 + +static void test_multiqueue(void) +{ + const int queues = 2; + TestServer *s = test_server_new("mq"); + QVirtioPCIDevice *dev; + QPCIBus *bus; + QVirtQueuePCI *vq[queues * 2]; + QGuestAllocator *alloc; + char *cmd; + int i; + + s->queues = queues; + test_server_listen(s); + + cmd = g_strdup_printf(QEMU_CMD_MEM QEMU_CMD_CHR QEMU_CMD_NETDEV ",queues=%d " + "-device virtio-net-pci,netdev=net0,mq=on,vectors=%d", + 512, 512, root, s->chr_name, + s->socket_path, "", s->chr_name, + queues, queues * 2 + 2); + qtest_start(cmd); + g_free(cmd); + + bus = qpci_init_pc(); + dev = virtio_net_pci_init(bus, PCI_SLOT); + + alloc = pc_alloc_init(); + for (i = 0; i < queues * 2; i++) { + vq[i] = (QVirtQueuePCI *)qvirtqueue_setup(&qvirtio_pci, &dev->vdev, + alloc, i); + } + + driver_init(&qvirtio_pci, &dev->vdev); + wait_for_rings_started(s, queues * 2); + + /* End test */ + for (i = 0; i < queues * 2; i++) { + qvirtqueue_cleanup(&qvirtio_pci, &vq[i]->vq, alloc); + } + pc_alloc_uninit(alloc); + qvirtio_pci_device_disable(dev); + g_free(dev->pdev); + g_free(dev); + qpci_free_pc(bus); + qtest_end(); + + test_server_free(s); +} + int main(int argc, char **argv) { QTestState *s = NULL; @@ -798,6 +900,7 @@ int main(int argc, char **argv) qtest_add_data_func("/vhost-user/read-guest-mem", server, read_guest_mem); qtest_add_func("/vhost-user/migrate", test_migrate); + qtest_add_func("/vhost-user/multiqueue", test_multiqueue); #ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS qtest_add_func("/vhost-user/reconnect/subprocess", test_reconnect_subprocess); From 9294d76c15e5d0cabc626bc4d95f95f896abc8d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Fri, 9 Sep 2016 15:34:45 +0400 Subject: [PATCH 292/723] tests: add /vhost-user/flags-mismatch test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check that qemu disconnects the backend that doesn't have the previously acked features. Signed-off-by: Marc-André Lureau Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/vhost-user-test.c | 60 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c index ffdd398f86d..a39846e6fd8 100644 --- a/tests/vhost-user-test.c +++ b/tests/vhost-user-test.c @@ -130,6 +130,13 @@ static VhostUserMsg m __attribute__ ((unused)); #define VHOST_USER_VERSION (0x1) /*****************************************************************************/ +enum { + TEST_FLAGS_OK, + TEST_FLAGS_DISCONNECT, + TEST_FLAGS_BAD, + TEST_FLAGS_END, +}; + typedef struct TestServer { gchar *socket_path; gchar *mig_path; @@ -143,6 +150,7 @@ typedef struct TestServer { int log_fd; uint64_t rings; bool test_fail; + int test_flags; int queues; } TestServer; @@ -292,6 +300,10 @@ static void chr_read(void *opaque, const uint8_t *buf, int size) if (s->queues > 1) { msg.payload.u64 |= 0x1ULL << VIRTIO_NET_F_MQ; } + if (s->test_flags >= TEST_FLAGS_BAD) { + msg.payload.u64 = 0; + s->test_flags = TEST_FLAGS_END; + } p = (uint8_t *) &msg; qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size); break; @@ -299,6 +311,10 @@ static void chr_read(void *opaque, const uint8_t *buf, int size) case VHOST_USER_SET_FEATURES: g_assert_cmpint(msg.payload.u64 & (0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES), !=, 0ULL); + if (s->test_flags == TEST_FLAGS_DISCONNECT) { + qemu_chr_disconnect(chr); + s->test_flags = TEST_FLAGS_BAD; + } break; case VHOST_USER_GET_PROTOCOL_FEATURES: @@ -424,6 +440,16 @@ static TestServer *test_server_new(const gchar *name) return server; } +static void chr_event(void *opaque, int event) +{ + TestServer *s = opaque; + + if (s->test_flags == TEST_FLAGS_END && + event == CHR_EVENT_CLOSED) { + s->test_flags = TEST_FLAGS_OK; + } +} + static void test_server_create_chr(TestServer *server, const gchar *opt) { gchar *chr_path; @@ -432,7 +458,8 @@ static void test_server_create_chr(TestServer *server, const gchar *opt) server->chr = qemu_chr_new(server->chr_name, chr_path, NULL); g_free(chr_path); - qemu_chr_add_handlers(server->chr, chr_can_read, chr_read, NULL, server); + qemu_chr_add_handlers(server->chr, chr_can_read, chr_read, + chr_event, server); } static void test_server_listen(TestServer *server) @@ -774,6 +801,34 @@ static void test_connect_fail(void) g_free(path); } +static void test_flags_mismatch_subprocess(void) +{ + TestServer *s = test_server_new("flags-mismatch"); + char *cmd; + + s->test_flags = TEST_FLAGS_DISCONNECT; + g_thread_new("connect", connect_thread, s); + cmd = GET_QEMU_CMDE(s, 2, ",server", ""); + qtest_start(cmd); + g_free(cmd); + + init_virtio_dev(s); + wait_for_fds(s); + wait_for_rings_started(s, 2); + + qtest_end(); + test_server_free(s); +} + +static void test_flags_mismatch(void) +{ + gchar *path = g_strdup_printf("/%s/vhost-user/flags-mismatch/subprocess", + qtest_get_arch()); + g_test_trap_subprocess(path, 0, 0); + g_test_trap_assert_passed(); + g_free(path); +} + #endif static QVirtioPCIDevice *virtio_net_pci_init(QPCIBus *bus, int slot) @@ -908,6 +963,9 @@ int main(int argc, char **argv) qtest_add_func("/vhost-user/connect-fail/subprocess", test_connect_fail_subprocess); qtest_add_func("/vhost-user/connect-fail", test_connect_fail); + qtest_add_func("/vhost-user/flags-mismatch/subprocess", + test_flags_mismatch_subprocess); + qtest_add_func("/vhost-user/flags-mismatch", test_flags_mismatch); #endif ret = g_test_run(); From 973e7170dddefb491a48df5cba33b2ae151013a0 Mon Sep 17 00:00:00 2001 From: Prasad J Pandit Date: Mon, 19 Sep 2016 23:55:45 +0530 Subject: [PATCH 293/723] virtio: add check for descriptor's mapped address virtio back end uses set of buffers to facilitate I/O operations. If its size is too large, 'cpu_physical_memory_map' could return a null address. This would result in a null dereference while un-mapping descriptors. Add check to avoid it. Reported-by: Qinghao Tang Signed-off-by: Prasad J Pandit Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Laszlo Ersek --- hw/virtio/virtio.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index fcf3358d6c0..bb656b1ccff 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -495,6 +495,11 @@ static void virtqueue_map_desc(unsigned int *p_num_sg, hwaddr *addr, struct iove } iov[num_sg].iov_base = cpu_physical_memory_map(pa, &len, is_write); + if (!iov[num_sg].iov_base) { + error_report("virtio: bogus descriptor or out of resources"); + exit(1); + } + iov[num_sg].iov_len = len; addr[num_sg] = pa; From 2e0910329bb602559d91e0db5c3f65486f14d955 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Mon, 19 Sep 2016 10:32:33 +0200 Subject: [PATCH 294/723] pc: clean up COMPAT macro chaining Since commit bacc344c ("machine: add properties to compat_props incrementaly") there is no need to chain per machine type compat macro. Clean up places where it was done anyway so it will be consistent and won't confuse contributors during addtion of new machine types. Signed-off-by: Igor Mammedov Reviewed-by: Eduardo Habkost --- include/hw/i386/pc.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index ab8e3195052..b0a61f356b1 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -375,7 +375,6 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *); #define PC_COMPAT_2_7 \ - PC_COMPAT_2_8 \ HW_COMPAT_2_7 #define PC_COMPAT_2_6 \ @@ -405,7 +404,6 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *); }, #define PC_COMPAT_2_5 \ - PC_COMPAT_2_6 \ HW_COMPAT_2_5 /* Helper for setting model-id for CPU models that changed model-id From 152fcbecad3775ba8950060616b59f6c23bc97e8 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Mon, 19 Sep 2016 10:32:34 +0200 Subject: [PATCH 295/723] target-i386: turn off CPU.l3-cache only for 2.7 and older machine types commit (14c985cff target-i386: present virtual L3 cache info for vcpus) misplaced compat property putting it in new 2.8 machine type which would effectively to disable feature until 2.9 is released. Intent of commit probably should be to disable feature for 2.7 and older while allowing not yet released 2.8 to have feature enabled by default. Cc: qemu-stable@nongnu.org Signed-off-by: Igor Mammedov Reviewed-by: Marcel Apfelbaum Reviewed-by: Eduardo Habkost --- include/hw/i386/pc.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index b0a61f356b1..29a6c9b60b6 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -367,16 +367,15 @@ int e820_get_num_entries(void); bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *); #define PC_COMPAT_2_8 \ + +#define PC_COMPAT_2_7 \ + HW_COMPAT_2_7 \ {\ .driver = TYPE_X86_CPU,\ .property = "l3-cache",\ .value = "off",\ }, - -#define PC_COMPAT_2_7 \ - HW_COMPAT_2_7 - #define PC_COMPAT_2_6 \ HW_COMPAT_2_6 \ {\ From 8275e2f6be8b10c2b3da0fe6927d0ce7ad438c80 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 21 Sep 2016 16:52:18 +0100 Subject: [PATCH 296/723] virtio: fix stray tab character Fix a single occurrence of a tab character in a file that otherwise uses spaces for indentation. Signed-off-by: Stefan Hajnoczi Reviewed-by: Fam Zheng Acked-by: Cornelia Huck Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Acked-by: Cornelia Huck --- hw/virtio/virtio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index bb656b1ccff..1199149a18b 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -1613,7 +1613,7 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id) "inconsistent with Host index 0x%x", i, vdev->vq[i].last_avail_idx); return -1; - } + } if (k->load_queue) { ret = k->load_queue(qbus->parent, i, f); if (ret) From f5ed36635d8fa73feb66fe12b3b9c2ed90a1adbe Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 21 Sep 2016 16:52:19 +0100 Subject: [PATCH 297/723] virtio: stop virtqueue processing if device is broken QEMU prints an error message and exits when the device enters an invalid state. Terminating the process is heavy-handed. The guest may still be able to function even if there is a bug in a virtio guest driver. Moreover, exiting is a bug in nested virtualization where a nested guest could DoS other nested guests by killing a pass-through virtio device. I don't think this configuration is possible today but it is likely in the future. If the broken flag is set, do not process virtqueues or write back used descriptors. The broken flag can be cleared again by resetting the device. Signed-off-by: Stefan Hajnoczi Reviewed-by: Cornelia Huck Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Cornelia Huck --- hw/virtio/virtio.c | 39 ++++++++++++++++++++++++++++++++++++++ include/hw/virtio/virtio.h | 3 +++ 2 files changed, 42 insertions(+) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 1199149a18b..1671ea8451a 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -303,6 +303,10 @@ void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem, virtqueue_unmap_sg(vq, elem, len); + if (unlikely(vq->vdev->broken)) { + return; + } + idx = (idx + vq->used_idx) % vq->vring.num; uelem.id = elem->index; @@ -313,6 +317,12 @@ void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem, void virtqueue_flush(VirtQueue *vq, unsigned int count) { uint16_t old, new; + + if (unlikely(vq->vdev->broken)) { + vq->inuse -= count; + return; + } + /* Make sure buffer is written before we update index. */ smp_wmb(); trace_virtqueue_flush(vq, count); @@ -583,6 +593,9 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz) struct iovec iov[VIRTQUEUE_MAX_SIZE]; VRingDesc desc; + if (unlikely(vdev->broken)) { + return NULL; + } if (virtio_queue_empty(vq)) { return NULL; } @@ -747,6 +760,10 @@ static void virtio_notify_vector(VirtIODevice *vdev, uint16_t vector) BusState *qbus = qdev_get_parent_bus(DEVICE(vdev)); VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); + if (unlikely(vdev->broken)) { + return; + } + if (k->notify) { k->notify(qbus->parent, vector); } @@ -830,6 +847,7 @@ void virtio_reset(void *opaque) k->reset(vdev); } + vdev->broken = false; vdev->guest_features = 0; vdev->queue_sel = 0; vdev->status = 0; @@ -1137,6 +1155,10 @@ static void virtio_queue_notify_vq(VirtQueue *vq) if (vq->vring.desc && vq->handle_output) { VirtIODevice *vdev = vq->vdev; + if (unlikely(vdev->broken)) { + return; + } + trace_virtio_queue_notify(vdev, vq - vdev->vq, vq); vq->handle_output(vdev, vq); } @@ -1758,6 +1780,7 @@ void virtio_init(VirtIODevice *vdev, const char *name, vdev->config_vector = VIRTIO_NO_VECTOR; vdev->vq = g_malloc0(sizeof(VirtQueue) * VIRTIO_QUEUE_MAX); vdev->vm_running = runstate_is_running(); + vdev->broken = false; for (i = 0; i < VIRTIO_QUEUE_MAX; i++) { vdev->vq[i].vector = VIRTIO_NO_VECTOR; vdev->vq[i].vdev = vdev; @@ -1944,6 +1967,22 @@ void virtio_device_set_child_bus_name(VirtIODevice *vdev, char *bus_name) vdev->bus_name = g_strdup(bus_name); } +void GCC_FMT_ATTR(2, 3) virtio_error(VirtIODevice *vdev, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + error_vreport(fmt, ap); + va_end(ap); + + vdev->broken = true; + + if (virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) { + virtio_set_status(vdev, vdev->status | VIRTIO_CONFIG_S_NEEDS_RESET); + virtio_notify_config(vdev); + } +} + static void virtio_device_realize(DeviceState *dev, Error **errp) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index f05559d569a..888c8debe6a 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -87,6 +87,7 @@ struct VirtIODevice VirtQueue *vq; uint16_t device_id; bool vm_running; + bool broken; /* device in invalid state, needs reset */ VMChangeStateEntry *vmstate; char *bus_name; uint8_t device_endian; @@ -135,6 +136,8 @@ void virtio_init(VirtIODevice *vdev, const char *name, uint16_t device_id, size_t config_size); void virtio_cleanup(VirtIODevice *vdev); +void virtio_error(VirtIODevice *vdev, const char *fmt, ...) GCC_FMT_ATTR(2, 3); + /* Set the child bus name. */ void virtio_device_set_child_bus_name(VirtIODevice *vdev, char *bus_name); From 791b1daf724ea835a32e90b2b15df1e20dae6f57 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 21 Sep 2016 16:52:20 +0100 Subject: [PATCH 298/723] virtio: migrate vdev->broken flag Send a subsection if the vdev->broken flag is set. This allows live migration of broken virtio devices. The subsection is only sent if vdev->broken has been set. In most cases the flag will be clear and no subsection will be sent. Signed-off-by: Stefan Hajnoczi Reviewed-by: Cornelia Huck Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Cornelia Huck --- hw/virtio/virtio.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 1671ea8451a..bac6b51f7cb 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -1343,6 +1343,13 @@ static bool virtio_extra_state_needed(void *opaque) k->has_extra_state(qbus->parent); } +static bool virtio_broken_needed(void *opaque) +{ + VirtIODevice *vdev = opaque; + + return vdev->broken; +} + static const VMStateDescription vmstate_virtqueue = { .name = "virtqueue_state", .version_id = 1, @@ -1457,6 +1464,17 @@ static const VMStateDescription vmstate_virtio_64bit_features = { } }; +static const VMStateDescription vmstate_virtio_broken = { + .name = "virtio/broken", + .version_id = 1, + .minimum_version_id = 1, + .needed = &virtio_broken_needed, + .fields = (VMStateField[]) { + VMSTATE_BOOL(broken, VirtIODevice), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_virtio = { .name = "virtio", .version_id = 1, @@ -1470,6 +1488,7 @@ static const VMStateDescription vmstate_virtio = { &vmstate_virtio_64bit_features, &vmstate_virtio_virtqueues, &vmstate_virtio_ringsize, + &vmstate_virtio_broken, &vmstate_virtio_extra_state, NULL } From ec55da192403e4a1e05f767c8762273d43ea7da4 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 21 Sep 2016 16:52:21 +0100 Subject: [PATCH 299/723] virtio: handle virtqueue_map_desc() errors Errors can occur during virtqueue_pop(), especially in virtqueue_map_desc(). In order to handle this we must unmap iov[] before returning NULL. The caller will consider the virtqueue empty and the virtio_error() call will have marked the device broken. Signed-off-by: Stefan Hajnoczi Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio.c | 74 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 55 insertions(+), 19 deletions(-) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index bac6b51f7cb..f2d6c3c43aa 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -484,30 +484,33 @@ int virtqueue_avail_bytes(VirtQueue *vq, unsigned int in_bytes, return in_bytes <= in_total && out_bytes <= out_total; } -static void virtqueue_map_desc(unsigned int *p_num_sg, hwaddr *addr, struct iovec *iov, +static bool virtqueue_map_desc(VirtIODevice *vdev, unsigned int *p_num_sg, + hwaddr *addr, struct iovec *iov, unsigned int max_num_sg, bool is_write, hwaddr pa, size_t sz) { + bool ok = false; unsigned num_sg = *p_num_sg; assert(num_sg <= max_num_sg); if (!sz) { - error_report("virtio: zero sized buffers are not allowed"); - exit(1); + virtio_error(vdev, "virtio: zero sized buffers are not allowed"); + goto out; } while (sz) { hwaddr len = sz; if (num_sg == max_num_sg) { - error_report("virtio: too many write descriptors in indirect table"); - exit(1); + virtio_error(vdev, "virtio: too many write descriptors in " + "indirect table"); + goto out; } iov[num_sg].iov_base = cpu_physical_memory_map(pa, &len, is_write); if (!iov[num_sg].iov_base) { - error_report("virtio: bogus descriptor or out of resources"); - exit(1); + virtio_error(vdev, "virtio: bogus descriptor or out of resources"); + goto out; } iov[num_sg].iov_len = len; @@ -517,7 +520,28 @@ static void virtqueue_map_desc(unsigned int *p_num_sg, hwaddr *addr, struct iove pa += len; num_sg++; } + ok = true; + +out: *p_num_sg = num_sg; + return ok; +} + +/* Only used by error code paths before we have a VirtQueueElement (therefore + * virtqueue_unmap_sg() can't be used). Assumes buffers weren't written to + * yet. + */ +static void virtqueue_undo_map_desc(unsigned int out_num, unsigned int in_num, + struct iovec *iov) +{ + unsigned int i; + + for (i = 0; i < out_num + in_num; i++) { + int is_write = i >= out_num; + + cpu_physical_memory_unmap(iov->iov_base, iov->iov_len, is_write, 0); + iov++; + } } static void virtqueue_map_iovec(struct iovec *sg, hwaddr *addr, @@ -609,8 +633,8 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz) max = vq->vring.num; if (vq->inuse >= vq->vring.num) { - error_report("Virtqueue size exceeded"); - exit(1); + virtio_error(vdev, "Virtqueue size exceeded"); + return NULL; } i = head = virtqueue_get_head(vq, vq->last_avail_idx++); @@ -621,8 +645,8 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz) vring_desc_read(vdev, &desc, desc_pa, i); if (desc.flags & VRING_DESC_F_INDIRECT) { if (desc.len % sizeof(VRingDesc)) { - error_report("Invalid size for indirect buffer table"); - exit(1); + virtio_error(vdev, "Invalid size for indirect buffer table"); + return NULL; } /* loop over the indirect descriptor table */ @@ -634,22 +658,30 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz) /* Collect all the descriptors */ do { + bool map_ok; + if (desc.flags & VRING_DESC_F_WRITE) { - virtqueue_map_desc(&in_num, addr + out_num, iov + out_num, - VIRTQUEUE_MAX_SIZE - out_num, true, desc.addr, desc.len); + map_ok = virtqueue_map_desc(vdev, &in_num, addr + out_num, + iov + out_num, + VIRTQUEUE_MAX_SIZE - out_num, true, + desc.addr, desc.len); } else { if (in_num) { - error_report("Incorrect order for descriptors"); - exit(1); + virtio_error(vdev, "Incorrect order for descriptors"); + goto err_undo_map; } - virtqueue_map_desc(&out_num, addr, iov, - VIRTQUEUE_MAX_SIZE, false, desc.addr, desc.len); + map_ok = virtqueue_map_desc(vdev, &out_num, addr, iov, + VIRTQUEUE_MAX_SIZE, false, + desc.addr, desc.len); + } + if (!map_ok) { + goto err_undo_map; } /* If we've got too many, that implies a descriptor loop. */ if ((in_num + out_num) > max) { - error_report("Looped descriptor"); - exit(1); + virtio_error(vdev, "Looped descriptor"); + goto err_undo_map; } } while ((i = virtqueue_read_next_desc(vdev, &desc, desc_pa, max)) != max); @@ -669,6 +701,10 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz) trace_virtqueue_pop(vq, elem, elem->in_num, elem->out_num); return elem; + +err_undo_map: + virtqueue_undo_map_desc(out_num, in_num, iov); + return NULL; } /* Reading and writing a structure directly to QEMUFile is *awful*, but From d65abf85e7e5fce31905eaea322ef2ea26e5f2db Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 21 Sep 2016 16:52:22 +0100 Subject: [PATCH 300/723] virtio: handle virtqueue_get_avail_bytes() errors If the vring is invalid, tell the caller no bytes are available and mark the device broken. Signed-off-by: Stefan Hajnoczi Reviewed-by: Cornelia Huck Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Cornelia Huck --- hw/virtio/virtio.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index f2d6c3c43aa..10c2f3d7a4a 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -426,14 +426,14 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, if (desc.flags & VRING_DESC_F_INDIRECT) { if (desc.len % sizeof(VRingDesc)) { - error_report("Invalid size for indirect buffer table"); - exit(1); + virtio_error(vdev, "Invalid size for indirect buffer table"); + goto err; } /* If we've got too many, that implies a descriptor loop. */ if (num_bufs >= max) { - error_report("Looped descriptor"); - exit(1); + virtio_error(vdev, "Looped descriptor"); + goto err; } /* loop over the indirect descriptor table */ @@ -447,8 +447,8 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, do { /* If we've got too many, that implies a descriptor loop. */ if (++num_bufs > max) { - error_report("Looped descriptor"); - exit(1); + virtio_error(vdev, "Looped descriptor"); + goto err; } if (desc.flags & VRING_DESC_F_WRITE) { @@ -473,6 +473,11 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, if (out_bytes) { *out_bytes = out_total; } + return; + +err: + in_total = out_total = 0; + goto done; } int virtqueue_avail_bytes(VirtQueue *vq, unsigned int in_bytes, From b1c7c07f2db2096451791882e9d1cdc301b66cdb Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 21 Sep 2016 16:52:23 +0100 Subject: [PATCH 301/723] virtio: use unsigned int for virtqueue_get_avail_bytes() index The virtio code uses int, unsigned int, and uint16_t for virtqueue indices. The uint16_t is used for the low-level descriptor layout in virtio_ring.h while code that isn't concerned with descriptor layout can use unsigned int. Use of int is problematic because it can result in signed/unsigned comparison and incompatible int*/unsigned int* pointer types. Make the virtqueue_get_avail_bytes() 'i' variable unsigned int. This eliminates the need to introduce casts and modify code further in the patches that follow. Signed-off-by: Stefan Hajnoczi Reviewed-by: Cornelia Huck Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Cornelia Huck --- hw/virtio/virtio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 10c2f3d7a4a..973d0c22280 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -416,7 +416,7 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, unsigned int max, num_bufs, indirect = 0; VRingDesc desc; hwaddr desc_pa; - int i; + unsigned int i; max = vq->vring.num; num_bufs = total_bufs; From 412e0e81b17488e228b4f8451df6a4af26064bb4 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 21 Sep 2016 16:52:24 +0100 Subject: [PATCH 302/723] virtio: handle virtqueue_read_next_desc() errors Stop processing the vring if an avail ring index is invalid. Signed-off-by: Stefan Hajnoczi Reviewed-by: Cornelia Huck Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Cornelia Huck --- hw/virtio/virtio.c | 45 ++++++++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 973d0c22280..82142c67031 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -377,28 +377,33 @@ static unsigned int virtqueue_get_head(VirtQueue *vq, unsigned int idx) return head; } -static unsigned virtqueue_read_next_desc(VirtIODevice *vdev, VRingDesc *desc, - hwaddr desc_pa, unsigned int max) -{ - unsigned int next; +enum { + VIRTQUEUE_READ_DESC_ERROR = -1, + VIRTQUEUE_READ_DESC_DONE = 0, /* end of chain */ + VIRTQUEUE_READ_DESC_MORE = 1, /* more buffers in chain */ +}; +static int virtqueue_read_next_desc(VirtIODevice *vdev, VRingDesc *desc, + hwaddr desc_pa, unsigned int max, + unsigned int *next) +{ /* If this descriptor says it doesn't chain, we're done. */ if (!(desc->flags & VRING_DESC_F_NEXT)) { - return max; + return VIRTQUEUE_READ_DESC_DONE; } /* Check they're not leading us off end of descriptors. */ - next = desc->next; + *next = desc->next; /* Make sure compiler knows to grab that: we don't want it changing! */ smp_wmb(); - if (next >= max) { - error_report("Desc next is %u", next); - exit(1); + if (*next >= max) { + virtio_error(vdev, "Desc next is %u", *next); + return VIRTQUEUE_READ_DESC_ERROR; } - vring_desc_read(vdev, desc, desc_pa, next); - return next; + vring_desc_read(vdev, desc, desc_pa, *next); + return VIRTQUEUE_READ_DESC_MORE; } void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, @@ -407,6 +412,7 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, { unsigned int idx; unsigned int total_bufs, in_total, out_total; + int rc; idx = vq->last_avail_idx; @@ -459,7 +465,13 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, if (in_total >= max_in_bytes && out_total >= max_out_bytes) { goto done; } - } while ((i = virtqueue_read_next_desc(vdev, &desc, desc_pa, max)) != max); + + rc = virtqueue_read_next_desc(vdev, &desc, desc_pa, max, &i); + } while (rc == VIRTQUEUE_READ_DESC_MORE); + + if (rc == VIRTQUEUE_READ_DESC_ERROR) { + goto err; + } if (!indirect) total_bufs = num_bufs; @@ -621,6 +633,7 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz) hwaddr addr[VIRTQUEUE_MAX_SIZE]; struct iovec iov[VIRTQUEUE_MAX_SIZE]; VRingDesc desc; + int rc; if (unlikely(vdev->broken)) { return NULL; @@ -688,7 +701,13 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz) virtio_error(vdev, "Looped descriptor"); goto err_undo_map; } - } while ((i = virtqueue_read_next_desc(vdev, &desc, desc_pa, max)) != max); + + rc = virtqueue_read_next_desc(vdev, &desc, desc_pa, max, &i); + } while (rc == VIRTQUEUE_READ_DESC_MORE); + + if (rc == VIRTQUEUE_READ_DESC_ERROR) { + goto err_undo_map; + } /* Now copy what we have collected and mapped */ elem = virtqueue_alloc_element(sz, out_num, in_num); From 4355c1abcaedd64a18d627284a3b7e54acb00714 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 21 Sep 2016 16:52:25 +0100 Subject: [PATCH 303/723] virtio: handle virtqueue_num_heads() errors If the avail ring index is bogus virtqueue_num_heads() must return -EINVAL. The only caller is virtqueue_get_avail_bytes(). Return saying no bytes are available when virtqueue_num_heads() fails. Signed-off-by: Stefan Hajnoczi Reviewed-by: Cornelia Huck Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Cornelia Huck --- hw/virtio/virtio.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 82142c67031..b7ac356629a 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -347,9 +347,9 @@ static int virtqueue_num_heads(VirtQueue *vq, unsigned int idx) /* Check it isn't doing very strange things with descriptor numbers. */ if (num_heads > vq->vring.num) { - error_report("Guest moved used index from %u to %u", + virtio_error(vq->vdev, "Guest moved used index from %u to %u", idx, vq->shadow_avail_idx); - exit(1); + return -EINVAL; } /* On success, callers read a descriptor at vq->last_avail_idx. * Make sure descriptor read does not bypass avail index read. */ @@ -417,7 +417,7 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, idx = vq->last_avail_idx; total_bufs = in_total = out_total = 0; - while (virtqueue_num_heads(vq, idx)) { + while ((rc = virtqueue_num_heads(vq, idx)) > 0) { VirtIODevice *vdev = vq->vdev; unsigned int max, num_bufs, indirect = 0; VRingDesc desc; @@ -478,6 +478,11 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, else total_bufs++; } + + if (rc < 0) { + goto err; + } + done: if (in_bytes) { *in_bytes = in_total; From fb1131b674e492a5f91abd77b9fcc9a9e2b88eb7 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 21 Sep 2016 16:52:26 +0100 Subject: [PATCH 304/723] virtio: handle virtqueue_get_head() errors Stop processing the vring if virtqueue_get_head() fetches an out-of-bounds head index. Signed-off-by: Stefan Hajnoczi Reviewed-by: Cornelia Huck Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Cornelia Huck --- hw/virtio/virtio.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index b7ac356629a..18ce3334572 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -360,21 +360,20 @@ static int virtqueue_num_heads(VirtQueue *vq, unsigned int idx) return num_heads; } -static unsigned int virtqueue_get_head(VirtQueue *vq, unsigned int idx) +static bool virtqueue_get_head(VirtQueue *vq, unsigned int idx, + unsigned int *head) { - unsigned int head; - /* Grab the next descriptor number they're advertising, and increment * the index we've seen. */ - head = vring_avail_ring(vq, idx % vq->vring.num); + *head = vring_avail_ring(vq, idx % vq->vring.num); /* If their number is silly, that's a fatal mistake. */ - if (head >= vq->vring.num) { - error_report("Guest says index %u is available", head); - exit(1); + if (*head >= vq->vring.num) { + virtio_error(vq->vdev, "Guest says index %u is available", *head); + return false; } - return head; + return true; } enum { @@ -426,7 +425,11 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, max = vq->vring.num; num_bufs = total_bufs; - i = virtqueue_get_head(vq, idx++); + + if (!virtqueue_get_head(vq, idx++, &i)) { + goto err; + } + desc_pa = vq->vring.desc; vring_desc_read(vdev, &desc, desc_pa, i); @@ -660,11 +663,15 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz) return NULL; } - i = head = virtqueue_get_head(vq, vq->last_avail_idx++); + if (!virtqueue_get_head(vq, vq->last_avail_idx++, &head)) { + return NULL; + } + if (virtio_vdev_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) { vring_set_avail_event(vq, vq->last_avail_idx); } + i = head; vring_desc_read(vdev, &desc, desc_pa, i); if (desc.flags & VRING_DESC_F_INDIRECT) { if (desc.len % sizeof(VRingDesc)) { From ab71cc0d589b054dccac2756c78042608b8e5b6e Mon Sep 17 00:00:00 2001 From: David Kiarie Date: Tue, 20 Sep 2016 18:42:31 +0300 Subject: [PATCH 305/723] hw/pci: Prepare for AMD IOMMU Introduce PCI macros from for use by AMD IOMMU Signed-off-by: David Kiarie Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- include/hw/pci/pci.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index e8b83bbb1e6..772692f1b27 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -13,9 +13,12 @@ /* PCI bus */ #define PCI_DEVFN(slot, func) ((((slot) & 0x1f) << 3) | ((func) & 0x07)) +#define PCI_BUS_NUM(x) (((x) >> 8) & 0xff) #define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f) #define PCI_FUNC(devfn) ((devfn) & 0x07) #define PCI_BUILD_BDF(bus, devfn) ((bus << 8) | (devfn)) +#define PCI_BUS_MAX 256 +#define PCI_DEVFN_MAX 256 #define PCI_SLOT_MAX 32 #define PCI_FUNC_MAX 8 From d61e45ecc78caf0141dd309c104c5e1fd2716a57 Mon Sep 17 00:00:00 2001 From: David Kiarie Date: Tue, 20 Sep 2016 18:42:32 +0300 Subject: [PATCH 306/723] hw/i386/trace-events: Add AMD IOMMU trace events Signed-off-by: David Kiarie Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/trace-events | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/hw/i386/trace-events b/hw/i386/trace-events index 5b99eba7b97..1938b988d99 100644 --- a/hw/i386/trace-events +++ b/hw/i386/trace-events @@ -13,3 +13,32 @@ mhp_pc_dimm_assigned_address(uint64_t addr) "0x%"PRIx64 # hw/i386/x86-iommu.c x86_iommu_iec_notify(bool global, uint32_t index, uint32_t mask) "Notify IEC invalidation: global=%d index=%" PRIu32 " mask=%" PRIu32 + +# hw/i386/amd_iommu.c +amdvi_evntlog_fail(uint64_t addr, uint32_t head) "error: fail to write at addr 0x%"PRIx64" + offset 0x%"PRIx32 +amdvi_cache_update(uint16_t domid, uint8_t bus, uint8_t slot, uint8_t func, uint64_t gpa, uint64_t txaddr) " update iotlb domid 0x%"PRIx16" devid: %02x:%02x.%x gpa 0x%"PRIx64" hpa 0x%"PRIx64 +amdvi_completion_wait_fail(uint64_t addr) "error: fail to write at address 0x%"PRIx64 +amdvi_mmio_write(const char *reg, uint64_t addr, unsigned size, uint64_t val, uint64_t offset) "%s write addr 0x%"PRIx64", size %u, val 0x%"PRIx64", offset 0x%"PRIx64 +amdvi_mmio_read(const char *reg, uint64_t addr, unsigned size, uint64_t offset) "%s read addr 0x%"PRIx64", size %u offset 0x%"PRIx64 +amdvi_command_error(uint64_t status) "error: Executing commands with command buffer disabled 0x%"PRIx64 +amdvi_command_read_fail(uint64_t addr, uint32_t head) "error: fail to access memory at 0x%"PRIx64" + 0x%"PRIx32 +amdvi_command_exec(uint32_t head, uint32_t tail, uint64_t buf) "command buffer head at 0x%"PRIx32" command buffer tail at 0x%"PRIx32" command buffer base at 0x%"PRIx64 +amdvi_unhandled_command(uint8_t type) "unhandled command 0x%"PRIx8 +amdvi_intr_inval(void) "Interrupt table invalidated" +amdvi_iotlb_inval(void) "IOTLB pages invalidated" +amdvi_prefetch_pages(void) "Pre-fetch of AMD-Vi pages requested" +amdvi_pages_inval(uint16_t domid) "AMD-Vi pages for domain 0x%"PRIx16 " invalidated" +amdvi_all_inval(void) "Invalidation of all AMD-Vi cache requested " +amdvi_ppr_exec(void) "Execution of PPR queue requested " +amdvi_devtab_inval(uint8_t bus, uint8_t slot, uint8_t func) "device table entry for devid: %02x:%02x.%x invalidated" +amdvi_completion_wait(uint64_t addr, uint64_t data) "completion wait requested with store address 0x%"PRIx64" and store data 0x%"PRIx64 +amdvi_control_status(uint64_t val) "MMIO_STATUS state 0x%"PRIx64 +amdvi_iotlb_reset(void) "IOTLB exceed size limit - reset " +amdvi_completion_wait_exec(uint64_t addr, uint64_t data) "completion wait requested with store address 0x%"PRIx64" and store data 0x%"PRIx64 +amdvi_dte_get_fail(uint64_t addr, uint32_t offset) "error: failed to access Device Entry devtab 0x%"PRIx64" offset 0x%"PRIx32 +amdvi_invalid_dte(uint64_t addr) "PTE entry at 0x%"PRIx64" is invalid " +amdvi_get_pte_hwerror(uint64_t addr) "hardware error eccessing PTE at addr 0x%"PRIx64 +amdvi_mode_invalid(uint8_t level, uint64_t addr)"error: translation level 0x%"PRIx8" translating addr 0x%"PRIx64 +amdvi_page_fault(uint64_t addr) "error: page fault accessing guest physical address 0x%"PRIx64 +amdvi_iotlb_hit(uint8_t bus, uint8_t slot, uint8_t func, uint64_t addr, uint64_t txaddr) "hit iotlb devid %02x:%02x.%x gpa 0x%"PRIx64" hpa 0x%"PRIx64 +amdvi_translation_result(uint8_t bus, uint8_t slot, uint8_t func, uint64_t addr, uint64_t txaddr) "devid: %02x:%02x.%x gpa 0x%"PRIx64" hpa 0x%"PRIx64 From d29a09ca68428b5708024ea2e9143de0a031081d Mon Sep 17 00:00:00 2001 From: David Kiarie Date: Tue, 20 Sep 2016 18:42:33 +0300 Subject: [PATCH 307/723] hw/i386: Introduce AMD IOMMU Add AMD IOMMU emulaton to Qemu in addition to Intel IOMMU. The IOMMU does basic translation, error checking and has a minimal IOTLB implementation. This IOMMU bypassed the need for target aborts by responding with IOMMU_NONE access rights and exempts the region 0xfee00000-0xfeefffff from translation as it is the q35 interrupt region. We advertise features that are not yet implemented to please the Linux IOMMU driver. IOTLB aims at implementing commands on real IOMMUs which is essential for debugging and may not offer any performance benefits Signed-off-by: David Kiarie Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/Makefile.objs | 1 + hw/i386/amd_iommu.c | 1200 +++++++++++++++++++++++++++++++++++++++++ hw/i386/amd_iommu.h | 289 ++++++++++ 3 files changed, 1490 insertions(+) create mode 100644 hw/i386/amd_iommu.c create mode 100644 hw/i386/amd_iommu.h diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index 90e94ffefda..909ead6a77e 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -3,6 +3,7 @@ obj-y += multiboot.o obj-y += pc.o pc_piix.o pc_q35.o obj-y += pc_sysfw.o obj-y += x86-iommu.o intel_iommu.o +obj-y += amd_iommu.o obj-$(CONFIG_XEN) += ../xenpv/ xen/ obj-y += kvmvapic.o diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c new file mode 100644 index 00000000000..4eec9b80eda --- /dev/null +++ b/hw/i386/amd_iommu.c @@ -0,0 +1,1200 @@ +/* + * QEMU emulation of AMD IOMMU (AMD-Vi) + * + * Copyright (C) 2011 Eduard - Gabriel Munteanu + * Copyright (C) 2015 David Kiarie, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + * + * Cache implementation inspired by hw/i386/intel_iommu.c + */ +#include "qemu/osdep.h" +#include "hw/i386/amd_iommu.h" +#include "trace.h" + +/* used AMD-Vi MMIO registers */ +const char *amdvi_mmio_low[] = { + "AMDVI_MMIO_DEVTAB_BASE", + "AMDVI_MMIO_CMDBUF_BASE", + "AMDVI_MMIO_EVTLOG_BASE", + "AMDVI_MMIO_CONTROL", + "AMDVI_MMIO_EXCL_BASE", + "AMDVI_MMIO_EXCL_LIMIT", + "AMDVI_MMIO_EXT_FEATURES", + "AMDVI_MMIO_PPR_BASE", + "UNHANDLED" +}; +const char *amdvi_mmio_high[] = { + "AMDVI_MMIO_COMMAND_HEAD", + "AMDVI_MMIO_COMMAND_TAIL", + "AMDVI_MMIO_EVTLOG_HEAD", + "AMDVI_MMIO_EVTLOG_TAIL", + "AMDVI_MMIO_STATUS", + "AMDVI_MMIO_PPR_HEAD", + "AMDVI_MMIO_PPR_TAIL", + "UNHANDLED" +}; + +struct AMDVIAddressSpace { + uint8_t bus_num; /* bus number */ + uint8_t devfn; /* device function */ + AMDVIState *iommu_state; /* AMDVI - one per machine */ + MemoryRegion iommu; /* Device's address translation region */ + MemoryRegion iommu_ir; /* Device's interrupt remapping region */ + AddressSpace as; /* device's corresponding address space */ +}; + +/* AMDVI cache entry */ +typedef struct AMDVIIOTLBEntry { + uint16_t domid; /* assigned domain id */ + uint16_t devid; /* device owning entry */ + uint64_t perms; /* access permissions */ + uint64_t translated_addr; /* translated address */ + uint64_t page_mask; /* physical page size */ +} AMDVIIOTLBEntry; + +/* configure MMIO registers at startup/reset */ +static void amdvi_set_quad(AMDVIState *s, hwaddr addr, uint64_t val, + uint64_t romask, uint64_t w1cmask) +{ + stq_le_p(&s->mmior[addr], val); + stq_le_p(&s->romask[addr], romask); + stq_le_p(&s->w1cmask[addr], w1cmask); +} + +static uint16_t amdvi_readw(AMDVIState *s, hwaddr addr) +{ + return lduw_le_p(&s->mmior[addr]); +} + +static uint32_t amdvi_readl(AMDVIState *s, hwaddr addr) +{ + return ldl_le_p(&s->mmior[addr]); +} + +static uint64_t amdvi_readq(AMDVIState *s, hwaddr addr) +{ + return ldq_le_p(&s->mmior[addr]); +} + +/* internal write */ +static void amdvi_writeq_raw(AMDVIState *s, uint64_t val, hwaddr addr) +{ + stq_le_p(&s->mmior[addr], val); +} + +/* external write */ +static void amdvi_writew(AMDVIState *s, hwaddr addr, uint16_t val) +{ + uint16_t romask = lduw_le_p(&s->romask[addr]); + uint16_t w1cmask = lduw_le_p(&s->w1cmask[addr]); + uint16_t oldval = lduw_le_p(&s->mmior[addr]); + stw_le_p(&s->mmior[addr], + ((oldval & romask) | (val & ~romask)) & ~(val & w1cmask)); +} + +static void amdvi_writel(AMDVIState *s, hwaddr addr, uint32_t val) +{ + uint32_t romask = ldl_le_p(&s->romask[addr]); + uint32_t w1cmask = ldl_le_p(&s->w1cmask[addr]); + uint32_t oldval = ldl_le_p(&s->mmior[addr]); + stl_le_p(&s->mmior[addr], + ((oldval & romask) | (val & ~romask)) & ~(val & w1cmask)); +} + +static void amdvi_writeq(AMDVIState *s, hwaddr addr, uint64_t val) +{ + uint64_t romask = ldq_le_p(&s->romask[addr]); + uint64_t w1cmask = ldq_le_p(&s->w1cmask[addr]); + uint32_t oldval = ldq_le_p(&s->mmior[addr]); + stq_le_p(&s->mmior[addr], + ((oldval & romask) | (val & ~romask)) & ~(val & w1cmask)); +} + +/* OR a 64-bit register with a 64-bit value */ +static bool amdvi_test_mask(AMDVIState *s, hwaddr addr, uint64_t val) +{ + return amdvi_readq(s, addr) | val; +} + +/* OR a 64-bit register with a 64-bit value storing result in the register */ +static void amdvi_assign_orq(AMDVIState *s, hwaddr addr, uint64_t val) +{ + amdvi_writeq_raw(s, addr, amdvi_readq(s, addr) | val); +} + +/* AND a 64-bit register with a 64-bit value storing result in the register */ +static void amdvi_assign_andq(AMDVIState *s, hwaddr addr, uint64_t val) +{ + amdvi_writeq_raw(s, addr, amdvi_readq(s, addr) & val); +} + +static void amdvi_generate_msi_interrupt(AMDVIState *s) +{ + MSIMessage msg; + MemTxAttrs attrs; + + attrs.requester_id = pci_requester_id(&s->pci.dev); + + if (msi_enabled(&s->pci.dev)) { + msg = msi_get_message(&s->pci.dev, 0); + address_space_stl_le(&address_space_memory, msg.address, msg.data, + attrs, NULL); + } +} + +static void amdvi_log_event(AMDVIState *s, uint64_t *evt) +{ + /* event logging not enabled */ + if (!s->evtlog_enabled || amdvi_test_mask(s, AMDVI_MMIO_STATUS, + AMDVI_MMIO_STATUS_EVT_OVF)) { + return; + } + + /* event log buffer full */ + if (s->evtlog_tail >= s->evtlog_len) { + amdvi_assign_orq(s, AMDVI_MMIO_STATUS, AMDVI_MMIO_STATUS_EVT_OVF); + /* generate interrupt */ + amdvi_generate_msi_interrupt(s); + return; + } + + if (dma_memory_write(&address_space_memory, s->evtlog + s->evtlog_tail, + &evt, AMDVI_EVENT_LEN)) { + trace_amdvi_evntlog_fail(s->evtlog, s->evtlog_tail); + } + + s->evtlog_tail += AMDVI_EVENT_LEN; + amdvi_assign_orq(s, AMDVI_MMIO_STATUS, AMDVI_MMIO_STATUS_COMP_INT); + amdvi_generate_msi_interrupt(s); +} + +static void amdvi_setevent_bits(uint64_t *buffer, uint64_t value, int start, + int length) +{ + int index = start / 64, bitpos = start % 64; + uint64_t mask = ((1 << length) - 1) << bitpos; + buffer[index] &= ~mask; + buffer[index] |= (value << bitpos) & mask; +} +/* + * AMDVi event structure + * 0:15 -> DeviceID + * 55:63 -> event type + miscellaneous info + * 63:127 -> related address + */ +static void amdvi_encode_event(uint64_t *evt, uint16_t devid, uint64_t addr, + uint16_t info) +{ + amdvi_setevent_bits(evt, devid, 0, 16); + amdvi_setevent_bits(evt, info, 55, 8); + amdvi_setevent_bits(evt, addr, 63, 64); +} +/* log an error encountered during a page walk + * + * @addr: virtual address in translation request + */ +static void amdvi_page_fault(AMDVIState *s, uint16_t devid, + hwaddr addr, uint16_t info) +{ + uint64_t evt[4]; + + info |= AMDVI_EVENT_IOPF_I | AMDVI_EVENT_IOPF; + amdvi_encode_event(evt, devid, addr, info); + amdvi_log_event(s, evt); + pci_word_test_and_set_mask(s->pci.dev.config + PCI_STATUS, + PCI_STATUS_SIG_TARGET_ABORT); +} +/* + * log a master abort accessing device table + * @devtab : address of device table entry + * @info : error flags + */ +static void amdvi_log_devtab_error(AMDVIState *s, uint16_t devid, + hwaddr devtab, uint16_t info) +{ + uint64_t evt[4]; + + info |= AMDVI_EVENT_DEV_TAB_HW_ERROR; + + amdvi_encode_event(evt, devid, devtab, info); + amdvi_log_event(s, evt); + pci_word_test_and_set_mask(s->pci.dev.config + PCI_STATUS, + PCI_STATUS_SIG_TARGET_ABORT); +} +/* log an event trying to access command buffer + * @addr : address that couldn't be accessed + */ +static void amdvi_log_command_error(AMDVIState *s, hwaddr addr) +{ + uint64_t evt[4], info = AMDVI_EVENT_COMMAND_HW_ERROR; + + amdvi_encode_event(evt, 0, addr, info); + amdvi_log_event(s, evt); + pci_word_test_and_set_mask(s->pci.dev.config + PCI_STATUS, + PCI_STATUS_SIG_TARGET_ABORT); +} +/* log an illegal comand event + * @addr : address of illegal command + */ +static void amdvi_log_illegalcom_error(AMDVIState *s, uint16_t info, + hwaddr addr) +{ + uint64_t evt[4]; + + info |= AMDVI_EVENT_ILLEGAL_COMMAND_ERROR; + amdvi_encode_event(evt, 0, addr, info); + amdvi_log_event(s, evt); +} +/* log an error accessing device table + * + * @devid : device owning the table entry + * @devtab : address of device table entry + * @info : error flags + */ +static void amdvi_log_illegaldevtab_error(AMDVIState *s, uint16_t devid, + hwaddr addr, uint16_t info) +{ + uint64_t evt[4]; + + info |= AMDVI_EVENT_ILLEGAL_DEVTAB_ENTRY; + amdvi_encode_event(evt, devid, addr, info); + amdvi_log_event(s, evt); +} +/* log an error accessing a PTE entry + * @addr : address that couldn't be accessed + */ +static void amdvi_log_pagetab_error(AMDVIState *s, uint16_t devid, + hwaddr addr, uint16_t info) +{ + uint64_t evt[4]; + + info |= AMDVI_EVENT_PAGE_TAB_HW_ERROR; + amdvi_encode_event(evt, devid, addr, info); + amdvi_log_event(s, evt); + pci_word_test_and_set_mask(s->pci.dev.config + PCI_STATUS, + PCI_STATUS_SIG_TARGET_ABORT); +} + +static gboolean amdvi_uint64_equal(gconstpointer v1, gconstpointer v2) +{ + return *((const uint64_t *)v1) == *((const uint64_t *)v2); +} + +static guint amdvi_uint64_hash(gconstpointer v) +{ + return (guint)*(const uint64_t *)v; +} + +static AMDVIIOTLBEntry *amdvi_iotlb_lookup(AMDVIState *s, hwaddr addr, + uint64_t devid) +{ + uint64_t key = (addr >> AMDVI_PAGE_SHIFT_4K) | + ((uint64_t)(devid) << AMDVI_DEVID_SHIFT); + return g_hash_table_lookup(s->iotlb, &key); +} + +static void amdvi_iotlb_reset(AMDVIState *s) +{ + assert(s->iotlb); + trace_amdvi_iotlb_reset(); + g_hash_table_remove_all(s->iotlb); +} + +static gboolean amdvi_iotlb_remove_by_devid(gpointer key, gpointer value, + gpointer user_data) +{ + AMDVIIOTLBEntry *entry = (AMDVIIOTLBEntry *)value; + uint16_t devid = *(uint16_t *)user_data; + return entry->devid == devid; +} + +static void amdvi_iotlb_remove_page(AMDVIState *s, hwaddr addr, + uint64_t devid) +{ + uint64_t key = (addr >> AMDVI_PAGE_SHIFT_4K) | + ((uint64_t)(devid) << AMDVI_DEVID_SHIFT); + g_hash_table_remove(s->iotlb, &key); +} + +static void amdvi_update_iotlb(AMDVIState *s, uint16_t devid, + uint64_t gpa, IOMMUTLBEntry to_cache, + uint16_t domid) +{ + AMDVIIOTLBEntry *entry = g_malloc(sizeof(*entry)); + uint64_t *key = g_malloc(sizeof(key)); + uint64_t gfn = gpa >> AMDVI_PAGE_SHIFT_4K; + + /* don't cache erroneous translations */ + if (to_cache.perm != IOMMU_NONE) { + trace_amdvi_cache_update(domid, PCI_BUS_NUM(devid), PCI_SLOT(devid), + PCI_FUNC(devid), gpa, to_cache.translated_addr); + + if (g_hash_table_size(s->iotlb) >= AMDVI_IOTLB_MAX_SIZE) { + amdvi_iotlb_reset(s); + } + + entry->domid = domid; + entry->perms = to_cache.perm; + entry->translated_addr = to_cache.translated_addr; + entry->page_mask = to_cache.addr_mask; + *key = gfn | ((uint64_t)(devid) << AMDVI_DEVID_SHIFT); + g_hash_table_replace(s->iotlb, key, entry); + } +} + +static void amdvi_completion_wait(AMDVIState *s, uint64_t *cmd) +{ + /* pad the last 3 bits */ + hwaddr addr = cpu_to_le64(extract64(cmd[0], 3, 49)) << 3; + uint64_t data = cpu_to_le64(cmd[1]); + + if (extract64(cmd[0], 51, 8)) { + amdvi_log_illegalcom_error(s, extract64(cmd[0], 60, 4), + s->cmdbuf + s->cmdbuf_head); + } + if (extract64(cmd[0], 0, 1)) { + if (dma_memory_write(&address_space_memory, addr, &data, + AMDVI_COMPLETION_DATA_SIZE)) { + trace_amdvi_completion_wait_fail(addr); + } + } + /* set completion interrupt */ + if (extract64(cmd[0], 1, 1)) { + amdvi_test_mask(s, AMDVI_MMIO_STATUS, AMDVI_MMIO_STATUS_COMP_INT); + /* generate interrupt */ + amdvi_generate_msi_interrupt(s); + } + trace_amdvi_completion_wait(addr, data); +} + +/* log error without aborting since linux seems to be using reserved bits */ +static void amdvi_inval_devtab_entry(AMDVIState *s, uint64_t *cmd) +{ + uint16_t devid = cpu_to_le16((uint16_t)extract64(cmd[0], 0, 16)); + + /* This command should invalidate internal caches of which there isn't */ + if (extract64(cmd[0], 15, 16) || cmd[1]) { + amdvi_log_illegalcom_error(s, extract64(cmd[0], 60, 4), + s->cmdbuf + s->cmdbuf_head); + } + trace_amdvi_devtab_inval(PCI_BUS_NUM(devid), PCI_SLOT(devid), + PCI_FUNC(devid)); +} + +static void amdvi_complete_ppr(AMDVIState *s, uint64_t *cmd) +{ + if (extract64(cmd[0], 15, 16) || extract64(cmd[0], 19, 8) || + extract64(cmd[1], 0, 2) || extract64(cmd[1], 3, 29) + || extract64(cmd[1], 47, 16)) { + amdvi_log_illegalcom_error(s, extract64(cmd[0], 60, 4), + s->cmdbuf + s->cmdbuf_head); + } + trace_amdvi_ppr_exec(); +} + +static void amdvi_inval_all(AMDVIState *s, uint64_t *cmd) +{ + if (extract64(cmd[0], 0, 60) || cmd[1]) { + amdvi_log_illegalcom_error(s, extract64(cmd[0], 60, 4), + s->cmdbuf + s->cmdbuf_head); + } + + amdvi_iotlb_reset(s); + trace_amdvi_all_inval(); +} + +static gboolean amdvi_iotlb_remove_by_domid(gpointer key, gpointer value, + gpointer user_data) +{ + AMDVIIOTLBEntry *entry = (AMDVIIOTLBEntry *)value; + uint16_t domid = *(uint16_t *)user_data; + return entry->domid == domid; +} + +/* we don't have devid - we can't remove pages by address */ +static void amdvi_inval_pages(AMDVIState *s, uint64_t *cmd) +{ + uint16_t domid = cpu_to_le16((uint16_t)extract64(cmd[0], 32, 16)); + + if (extract64(cmd[0], 20, 12) || extract64(cmd[0], 16, 12) || + extract64(cmd[0], 3, 10)) { + amdvi_log_illegalcom_error(s, extract64(cmd[0], 60, 4), + s->cmdbuf + s->cmdbuf_head); + } + + g_hash_table_foreach_remove(s->iotlb, amdvi_iotlb_remove_by_domid, + &domid); + trace_amdvi_pages_inval(domid); +} + +static void amdvi_prefetch_pages(AMDVIState *s, uint64_t *cmd) +{ + if (extract64(cmd[0], 16, 8) || extract64(cmd[0], 20, 8) || + extract64(cmd[1], 1, 1) || extract64(cmd[1], 3, 1) || + extract64(cmd[1], 5, 7)) { + amdvi_log_illegalcom_error(s, extract64(cmd[0], 60, 4), + s->cmdbuf + s->cmdbuf_head); + } + + trace_amdvi_prefetch_pages(); +} + +static void amdvi_inval_inttable(AMDVIState *s, uint64_t *cmd) +{ + if (extract64(cmd[0], 16, 16) || cmd[1]) { + amdvi_log_illegalcom_error(s, extract64(cmd[0], 60, 4), + s->cmdbuf + s->cmdbuf_head); + return; + } + + trace_amdvi_intr_inval(); +} + +/* FIXME: Try to work with the specified size instead of all the pages + * when the S bit is on + */ +static void iommu_inval_iotlb(AMDVIState *s, uint64_t *cmd) +{ + + uint16_t devid = extract64(cmd[0], 0, 16); + if (extract64(cmd[1], 1, 1) || extract64(cmd[1], 3, 9)) { + amdvi_log_illegalcom_error(s, extract64(cmd[0], 60, 4), + s->cmdbuf + s->cmdbuf_head); + return; + } + + if (extract64(cmd[1], 0, 1)) { + g_hash_table_foreach_remove(s->iotlb, amdvi_iotlb_remove_by_devid, + &devid); + } else { + amdvi_iotlb_remove_page(s, cpu_to_le64(extract64(cmd[1], 12, 52)) << 12, + cpu_to_le16(extract64(cmd[1], 0, 16))); + } + trace_amdvi_iotlb_inval(); +} + +/* not honouring reserved bits is regarded as an illegal command */ +static void amdvi_cmdbuf_exec(AMDVIState *s) +{ + uint64_t cmd[2]; + + if (dma_memory_read(&address_space_memory, s->cmdbuf + s->cmdbuf_head, + cmd, AMDVI_COMMAND_SIZE)) { + trace_amdvi_command_read_fail(s->cmdbuf, s->cmdbuf_head); + amdvi_log_command_error(s, s->cmdbuf + s->cmdbuf_head); + return; + } + + switch (extract64(cmd[0], 60, 4)) { + case AMDVI_CMD_COMPLETION_WAIT: + amdvi_completion_wait(s, cmd); + break; + case AMDVI_CMD_INVAL_DEVTAB_ENTRY: + amdvi_inval_devtab_entry(s, cmd); + break; + case AMDVI_CMD_INVAL_AMDVI_PAGES: + amdvi_inval_pages(s, cmd); + break; + case AMDVI_CMD_INVAL_IOTLB_PAGES: + iommu_inval_iotlb(s, cmd); + break; + case AMDVI_CMD_INVAL_INTR_TABLE: + amdvi_inval_inttable(s, cmd); + break; + case AMDVI_CMD_PREFETCH_AMDVI_PAGES: + amdvi_prefetch_pages(s, cmd); + break; + case AMDVI_CMD_COMPLETE_PPR_REQUEST: + amdvi_complete_ppr(s, cmd); + break; + case AMDVI_CMD_INVAL_AMDVI_ALL: + amdvi_inval_all(s, cmd); + break; + default: + trace_amdvi_unhandled_command(extract64(cmd[1], 60, 4)); + /* log illegal command */ + amdvi_log_illegalcom_error(s, extract64(cmd[1], 60, 4), + s->cmdbuf + s->cmdbuf_head); + } +} + +static void amdvi_cmdbuf_run(AMDVIState *s) +{ + if (!s->cmdbuf_enabled) { + trace_amdvi_command_error(amdvi_readq(s, AMDVI_MMIO_CONTROL)); + return; + } + + /* check if there is work to do. */ + while (s->cmdbuf_head != s->cmdbuf_tail) { + trace_amdvi_command_exec(s->cmdbuf_head, s->cmdbuf_tail, s->cmdbuf); + amdvi_cmdbuf_exec(s); + s->cmdbuf_head += AMDVI_COMMAND_SIZE; + amdvi_writeq_raw(s, s->cmdbuf_head, AMDVI_MMIO_COMMAND_HEAD); + + /* wrap head pointer */ + if (s->cmdbuf_head >= s->cmdbuf_len * AMDVI_COMMAND_SIZE) { + s->cmdbuf_head = 0; + } + } +} + +static void amdvi_mmio_trace(hwaddr addr, unsigned size) +{ + uint8_t index = (addr & ~0x2000) / 8; + + if ((addr & 0x2000)) { + /* high table */ + index = index >= AMDVI_MMIO_REGS_HIGH ? AMDVI_MMIO_REGS_HIGH : index; + trace_amdvi_mmio_read(amdvi_mmio_high[index], addr, size, addr & ~0x07); + } else { + index = index >= AMDVI_MMIO_REGS_LOW ? AMDVI_MMIO_REGS_LOW : index; + trace_amdvi_mmio_read(amdvi_mmio_high[index], addr, size, addr & ~0x07); + } +} + +static uint64_t amdvi_mmio_read(void *opaque, hwaddr addr, unsigned size) +{ + AMDVIState *s = opaque; + + uint64_t val = -1; + if (addr + size > AMDVI_MMIO_SIZE) { + trace_amdvi_mmio_read("error: addr outside region: max ", + (uint64_t)AMDVI_MMIO_SIZE, addr, size); + return (uint64_t)-1; + } + + if (size == 2) { + val = amdvi_readw(s, addr); + } else if (size == 4) { + val = amdvi_readl(s, addr); + } else if (size == 8) { + val = amdvi_readq(s, addr); + } + amdvi_mmio_trace(addr, size); + + return val; +} + +static void amdvi_handle_control_write(AMDVIState *s) +{ + unsigned long control = amdvi_readq(s, AMDVI_MMIO_CONTROL); + s->enabled = !!(control & AMDVI_MMIO_CONTROL_AMDVIEN); + + s->ats_enabled = !!(control & AMDVI_MMIO_CONTROL_HTTUNEN); + s->evtlog_enabled = s->enabled && !!(control & + AMDVI_MMIO_CONTROL_EVENTLOGEN); + + s->evtlog_intr = !!(control & AMDVI_MMIO_CONTROL_EVENTINTEN); + s->completion_wait_intr = !!(control & AMDVI_MMIO_CONTROL_COMWAITINTEN); + s->cmdbuf_enabled = s->enabled && !!(control & + AMDVI_MMIO_CONTROL_CMDBUFLEN); + + /* update the flags depending on the control register */ + if (s->cmdbuf_enabled) { + amdvi_assign_orq(s, AMDVI_MMIO_STATUS, AMDVI_MMIO_STATUS_CMDBUF_RUN); + } else { + amdvi_assign_andq(s, AMDVI_MMIO_STATUS, ~AMDVI_MMIO_STATUS_CMDBUF_RUN); + } + if (s->evtlog_enabled) { + amdvi_assign_orq(s, AMDVI_MMIO_STATUS, AMDVI_MMIO_STATUS_EVT_RUN); + } else { + amdvi_assign_andq(s, AMDVI_MMIO_STATUS, ~AMDVI_MMIO_STATUS_EVT_RUN); + } + + trace_amdvi_control_status(control); + amdvi_cmdbuf_run(s); +} + +static inline void amdvi_handle_devtab_write(AMDVIState *s) + +{ + uint64_t val = amdvi_readq(s, AMDVI_MMIO_DEVICE_TABLE); + s->devtab = (val & AMDVI_MMIO_DEVTAB_BASE_MASK); + + /* set device table length */ + s->devtab_len = ((val & AMDVI_MMIO_DEVTAB_SIZE_MASK) + 1 * + (AMDVI_MMIO_DEVTAB_SIZE_UNIT / + AMDVI_MMIO_DEVTAB_ENTRY_SIZE)); +} + +static inline void amdvi_handle_cmdhead_write(AMDVIState *s) +{ + s->cmdbuf_head = amdvi_readq(s, AMDVI_MMIO_COMMAND_HEAD) + & AMDVI_MMIO_CMDBUF_HEAD_MASK; + amdvi_cmdbuf_run(s); +} + +static inline void amdvi_handle_cmdbase_write(AMDVIState *s) +{ + s->cmdbuf = amdvi_readq(s, AMDVI_MMIO_COMMAND_BASE) + & AMDVI_MMIO_CMDBUF_BASE_MASK; + s->cmdbuf_len = 1UL << (amdvi_readq(s, AMDVI_MMIO_CMDBUF_SIZE_BYTE) + & AMDVI_MMIO_CMDBUF_SIZE_MASK); + s->cmdbuf_head = s->cmdbuf_tail = 0; +} + +static inline void amdvi_handle_cmdtail_write(AMDVIState *s) +{ + s->cmdbuf_tail = amdvi_readq(s, AMDVI_MMIO_COMMAND_TAIL) + & AMDVI_MMIO_CMDBUF_TAIL_MASK; + amdvi_cmdbuf_run(s); +} + +static inline void amdvi_handle_excllim_write(AMDVIState *s) +{ + uint64_t val = amdvi_readq(s, AMDVI_MMIO_EXCL_LIMIT); + s->excl_limit = (val & AMDVI_MMIO_EXCL_LIMIT_MASK) | + AMDVI_MMIO_EXCL_LIMIT_LOW; +} + +static inline void amdvi_handle_evtbase_write(AMDVIState *s) +{ + uint64_t val = amdvi_readq(s, AMDVI_MMIO_EVENT_BASE); + s->evtlog = val & AMDVI_MMIO_EVTLOG_BASE_MASK; + s->evtlog_len = 1UL << (amdvi_readq(s, AMDVI_MMIO_EVTLOG_SIZE_BYTE) + & AMDVI_MMIO_EVTLOG_SIZE_MASK); +} + +static inline void amdvi_handle_evttail_write(AMDVIState *s) +{ + uint64_t val = amdvi_readq(s, AMDVI_MMIO_EVENT_TAIL); + s->evtlog_tail = val & AMDVI_MMIO_EVTLOG_TAIL_MASK; +} + +static inline void amdvi_handle_evthead_write(AMDVIState *s) +{ + uint64_t val = amdvi_readq(s, AMDVI_MMIO_EVENT_HEAD); + s->evtlog_head = val & AMDVI_MMIO_EVTLOG_HEAD_MASK; +} + +static inline void amdvi_handle_pprbase_write(AMDVIState *s) +{ + uint64_t val = amdvi_readq(s, AMDVI_MMIO_PPR_BASE); + s->ppr_log = val & AMDVI_MMIO_PPRLOG_BASE_MASK; + s->pprlog_len = 1UL << (amdvi_readq(s, AMDVI_MMIO_PPRLOG_SIZE_BYTE) + & AMDVI_MMIO_PPRLOG_SIZE_MASK); +} + +static inline void amdvi_handle_pprhead_write(AMDVIState *s) +{ + uint64_t val = amdvi_readq(s, AMDVI_MMIO_PPR_HEAD); + s->pprlog_head = val & AMDVI_MMIO_PPRLOG_HEAD_MASK; +} + +static inline void amdvi_handle_pprtail_write(AMDVIState *s) +{ + uint64_t val = amdvi_readq(s, AMDVI_MMIO_PPR_TAIL); + s->pprlog_tail = val & AMDVI_MMIO_PPRLOG_TAIL_MASK; +} + +/* FIXME: something might go wrong if System Software writes in chunks + * of one byte but linux writes in chunks of 4 bytes so currently it + * works correctly with linux but will definitely be busted if software + * reads/writes 8 bytes + */ +static void amdvi_mmio_reg_write(AMDVIState *s, unsigned size, uint64_t val, + hwaddr addr) +{ + if (size == 2) { + amdvi_writew(s, addr, val); + } else if (size == 4) { + amdvi_writel(s, addr, val); + } else if (size == 8) { + amdvi_writeq(s, addr, val); + } +} + +static void amdvi_mmio_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ + AMDVIState *s = opaque; + unsigned long offset = addr & 0x07; + + if (addr + size > AMDVI_MMIO_SIZE) { + trace_amdvi_mmio_write("error: addr outside region: max ", + (uint64_t)AMDVI_MMIO_SIZE, size, val, offset); + return; + } + + amdvi_mmio_trace(addr, size); + switch (addr & ~0x07) { + case AMDVI_MMIO_CONTROL: + amdvi_mmio_reg_write(s, size, val, addr); + amdvi_handle_control_write(s); + break; + case AMDVI_MMIO_DEVICE_TABLE: + amdvi_mmio_reg_write(s, size, val, addr); + /* set device table address + * This also suffers from inability to tell whether software + * is done writing + */ + if (offset || (size == 8)) { + amdvi_handle_devtab_write(s); + } + break; + case AMDVI_MMIO_COMMAND_HEAD: + amdvi_mmio_reg_write(s, size, val, addr); + amdvi_handle_cmdhead_write(s); + break; + case AMDVI_MMIO_COMMAND_BASE: + amdvi_mmio_reg_write(s, size, val, addr); + /* FIXME - make sure System Software has finished writing incase + * it writes in chucks less than 8 bytes in a robust way.As for + * now, this hacks works for the linux driver + */ + if (offset || (size == 8)) { + amdvi_handle_cmdbase_write(s); + } + break; + case AMDVI_MMIO_COMMAND_TAIL: + amdvi_mmio_reg_write(s, size, val, addr); + amdvi_handle_cmdtail_write(s); + break; + case AMDVI_MMIO_EVENT_BASE: + amdvi_mmio_reg_write(s, size, val, addr); + amdvi_handle_evtbase_write(s); + break; + case AMDVI_MMIO_EVENT_HEAD: + amdvi_mmio_reg_write(s, size, val, addr); + amdvi_handle_evthead_write(s); + break; + case AMDVI_MMIO_EVENT_TAIL: + amdvi_mmio_reg_write(s, size, val, addr); + amdvi_handle_evttail_write(s); + break; + case AMDVI_MMIO_EXCL_LIMIT: + amdvi_mmio_reg_write(s, size, val, addr); + amdvi_handle_excllim_write(s); + break; + /* PPR log base - unused for now */ + case AMDVI_MMIO_PPR_BASE: + amdvi_mmio_reg_write(s, size, val, addr); + amdvi_handle_pprbase_write(s); + break; + /* PPR log head - also unused for now */ + case AMDVI_MMIO_PPR_HEAD: + amdvi_mmio_reg_write(s, size, val, addr); + amdvi_handle_pprhead_write(s); + break; + /* PPR log tail - unused for now */ + case AMDVI_MMIO_PPR_TAIL: + amdvi_mmio_reg_write(s, size, val, addr); + amdvi_handle_pprtail_write(s); + break; + } +} + +static inline uint64_t amdvi_get_perms(uint64_t entry) +{ + return (entry & (AMDVI_DEV_PERM_READ | AMDVI_DEV_PERM_WRITE)) >> + AMDVI_DEV_PERM_SHIFT; +} + +/* a valid entry should have V = 1 and reserved bits honoured */ +static bool amdvi_validate_dte(AMDVIState *s, uint16_t devid, + uint64_t *dte) +{ + if ((dte[0] & AMDVI_DTE_LOWER_QUAD_RESERVED) + || (dte[1] & AMDVI_DTE_MIDDLE_QUAD_RESERVED) + || (dte[2] & AMDVI_DTE_UPPER_QUAD_RESERVED) || dte[3]) { + amdvi_log_illegaldevtab_error(s, devid, + s->devtab + + devid * AMDVI_DEVTAB_ENTRY_SIZE, 0); + return false; + } + + return dte[0] & AMDVI_DEV_VALID; +} + +/* get a device table entry given the devid */ +static bool amdvi_get_dte(AMDVIState *s, int devid, uint64_t *entry) +{ + uint32_t offset = devid * AMDVI_DEVTAB_ENTRY_SIZE; + + if (dma_memory_read(&address_space_memory, s->devtab + offset, entry, + AMDVI_DEVTAB_ENTRY_SIZE)) { + trace_amdvi_dte_get_fail(s->devtab, offset); + /* log error accessing dte */ + amdvi_log_devtab_error(s, devid, s->devtab + offset, 0); + return false; + } + + *entry = le64_to_cpu(*entry); + if (!amdvi_validate_dte(s, devid, entry)) { + trace_amdvi_invalid_dte(entry[0]); + return false; + } + + return true; +} + +/* get pte translation mode */ +static inline uint8_t get_pte_translation_mode(uint64_t pte) +{ + return (pte >> AMDVI_DEV_MODE_RSHIFT) & AMDVI_DEV_MODE_MASK; +} + +static inline uint64_t pte_override_page_mask(uint64_t pte) +{ + uint8_t page_mask = 12; + uint64_t addr = (pte & AMDVI_DEV_PT_ROOT_MASK) ^ AMDVI_DEV_PT_ROOT_MASK; + /* find the first zero bit */ + while (addr & 1) { + page_mask++; + addr = addr >> 1; + } + + return ~((1ULL << page_mask) - 1); +} + +static inline uint64_t pte_get_page_mask(uint64_t oldlevel) +{ + return ~((1UL << ((oldlevel * 9) + 3)) - 1); +} + +static inline uint64_t amdvi_get_pte_entry(AMDVIState *s, uint64_t pte_addr, + uint16_t devid) +{ + uint64_t pte; + + if (dma_memory_read(&address_space_memory, pte_addr, &pte, sizeof(pte))) { + trace_amdvi_get_pte_hwerror(pte_addr); + amdvi_log_pagetab_error(s, devid, pte_addr, 0); + pte = 0; + return pte; + } + + pte = le64_to_cpu(pte); + return pte; +} + +static void amdvi_page_walk(AMDVIAddressSpace *as, uint64_t *dte, + IOMMUTLBEntry *ret, unsigned perms, + hwaddr addr) +{ + unsigned level, present, pte_perms, oldlevel; + uint64_t pte = dte[0], pte_addr, page_mask; + + /* make sure the DTE has TV = 1 */ + if (pte & AMDVI_DEV_TRANSLATION_VALID) { + level = get_pte_translation_mode(pte); + if (level >= 7) { + trace_amdvi_mode_invalid(level, addr); + return; + } + if (level == 0) { + goto no_remap; + } + + /* we are at the leaf page table or page table encodes a huge page */ + while (level > 0) { + pte_perms = amdvi_get_perms(pte); + present = pte & 1; + if (!present || perms != (perms & pte_perms)) { + amdvi_page_fault(as->iommu_state, as->devfn, addr, perms); + trace_amdvi_page_fault(addr); + return; + } + + /* go to the next lower level */ + pte_addr = pte & AMDVI_DEV_PT_ROOT_MASK; + /* add offset and load pte */ + pte_addr += ((addr >> (3 + 9 * level)) & 0x1FF) << 3; + pte = amdvi_get_pte_entry(as->iommu_state, pte_addr, as->devfn); + if (!pte) { + return; + } + oldlevel = level; + level = get_pte_translation_mode(pte); + if (level == 0x7) { + break; + } + } + + if (level == 0x7) { + page_mask = pte_override_page_mask(pte); + } else { + page_mask = pte_get_page_mask(oldlevel); + } + + /* get access permissions from pte */ + ret->iova = addr & page_mask; + ret->translated_addr = (pte & AMDVI_DEV_PT_ROOT_MASK) & page_mask; + ret->addr_mask = ~page_mask; + ret->perm = amdvi_get_perms(pte); + return; + } +no_remap: + ret->iova = addr & AMDVI_PAGE_MASK_4K; + ret->translated_addr = addr & AMDVI_PAGE_MASK_4K; + ret->addr_mask = ~AMDVI_PAGE_MASK_4K; + ret->perm = amdvi_get_perms(pte); +} + +static void amdvi_do_translate(AMDVIAddressSpace *as, hwaddr addr, + bool is_write, IOMMUTLBEntry *ret) +{ + AMDVIState *s = as->iommu_state; + uint16_t devid = PCI_BUILD_BDF(as->bus_num, as->devfn); + AMDVIIOTLBEntry *iotlb_entry = amdvi_iotlb_lookup(s, addr, devid); + uint64_t entry[4]; + + if (iotlb_entry) { + trace_amdvi_iotlb_hit(PCI_BUS_NUM(devid), PCI_SLOT(devid), + PCI_FUNC(devid), addr, iotlb_entry->translated_addr); + ret->iova = addr & ~iotlb_entry->page_mask; + ret->translated_addr = iotlb_entry->translated_addr; + ret->addr_mask = iotlb_entry->page_mask; + ret->perm = iotlb_entry->perms; + return; + } + + /* devices with V = 0 are not translated */ + if (!amdvi_get_dte(s, devid, entry)) { + goto out; + } + + amdvi_page_walk(as, entry, ret, + is_write ? AMDVI_PERM_WRITE : AMDVI_PERM_READ, addr); + + amdvi_update_iotlb(s, devid, addr, *ret, + entry[1] & AMDVI_DEV_DOMID_ID_MASK); + return; + +out: + ret->iova = addr & AMDVI_PAGE_MASK_4K; + ret->translated_addr = addr & AMDVI_PAGE_MASK_4K; + ret->addr_mask = ~AMDVI_PAGE_MASK_4K; + ret->perm = IOMMU_RW; +} + +static inline bool amdvi_is_interrupt_addr(hwaddr addr) +{ + return addr >= AMDVI_INT_ADDR_FIRST && addr <= AMDVI_INT_ADDR_LAST; +} + +static IOMMUTLBEntry amdvi_translate(MemoryRegion *iommu, hwaddr addr, + bool is_write) +{ + AMDVIAddressSpace *as = container_of(iommu, AMDVIAddressSpace, iommu); + AMDVIState *s = as->iommu_state; + IOMMUTLBEntry ret = { + .target_as = &address_space_memory, + .iova = addr, + .translated_addr = 0, + .addr_mask = ~(hwaddr)0, + .perm = IOMMU_NONE + }; + + if (!s->enabled) { + /* AMDVI disabled - corresponds to iommu=off not + * failure to provide any parameter + */ + ret.iova = addr & AMDVI_PAGE_MASK_4K; + ret.translated_addr = addr & AMDVI_PAGE_MASK_4K; + ret.addr_mask = ~AMDVI_PAGE_MASK_4K; + ret.perm = IOMMU_RW; + return ret; + } else if (amdvi_is_interrupt_addr(addr)) { + ret.iova = addr & AMDVI_PAGE_MASK_4K; + ret.translated_addr = addr & AMDVI_PAGE_MASK_4K; + ret.addr_mask = ~AMDVI_PAGE_MASK_4K; + ret.perm = IOMMU_WO; + return ret; + } + + amdvi_do_translate(as, addr, is_write, &ret); + trace_amdvi_translation_result(as->bus_num, PCI_SLOT(as->devfn), + PCI_FUNC(as->devfn), addr, ret.translated_addr); + return ret; +} + +static AddressSpace *amdvi_host_dma_iommu(PCIBus *bus, void *opaque, int devfn) +{ + AMDVIState *s = opaque; + AMDVIAddressSpace **iommu_as; + int bus_num = pci_bus_num(bus); + + iommu_as = s->address_spaces[bus_num]; + + /* allocate memory during the first run */ + if (!iommu_as) { + iommu_as = g_malloc0(sizeof(AMDVIAddressSpace *) * PCI_DEVFN_MAX); + s->address_spaces[bus_num] = iommu_as; + } + + /* set up AMD-Vi region */ + if (!iommu_as[devfn]) { + iommu_as[devfn] = g_malloc0(sizeof(AMDVIAddressSpace)); + iommu_as[devfn]->bus_num = (uint8_t)bus_num; + iommu_as[devfn]->devfn = (uint8_t)devfn; + iommu_as[devfn]->iommu_state = s; + + memory_region_init_iommu(&iommu_as[devfn]->iommu, OBJECT(s), + &s->iommu_ops, "amd-iommu", UINT64_MAX); + address_space_init(&iommu_as[devfn]->as, &iommu_as[devfn]->iommu, + "amd-iommu"); + } + return &iommu_as[devfn]->as; +} + +static const MemoryRegionOps mmio_mem_ops = { + .read = amdvi_mmio_read, + .write = amdvi_mmio_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .impl = { + .min_access_size = 1, + .max_access_size = 8, + .unaligned = false, + }, + .valid = { + .min_access_size = 1, + .max_access_size = 8, + } +}; + +static void amdvi_iommu_notify_started(MemoryRegion *iommu) +{ + AMDVIAddressSpace *as = container_of(iommu, AMDVIAddressSpace, iommu); + + hw_error("device %02x.%02x.%x requires iommu notifier which is not " + "currently supported", as->bus_num, PCI_SLOT(as->devfn), + PCI_FUNC(as->devfn)); +} + +static void amdvi_init(AMDVIState *s) +{ + amdvi_iotlb_reset(s); + + s->iommu_ops.translate = amdvi_translate; + s->iommu_ops.notify_started = amdvi_iommu_notify_started; + s->devtab_len = 0; + s->cmdbuf_len = 0; + s->cmdbuf_head = 0; + s->cmdbuf_tail = 0; + s->evtlog_head = 0; + s->evtlog_tail = 0; + s->excl_enabled = false; + s->excl_allow = false; + s->mmio_enabled = false; + s->enabled = false; + s->ats_enabled = false; + s->cmdbuf_enabled = false; + + /* reset MMIO */ + memset(s->mmior, 0, AMDVI_MMIO_SIZE); + amdvi_set_quad(s, AMDVI_MMIO_EXT_FEATURES, AMDVI_EXT_FEATURES, + 0xffffffffffffffef, 0); + amdvi_set_quad(s, AMDVI_MMIO_STATUS, 0, 0x98, 0x67); + + /* reset device ident */ + pci_config_set_vendor_id(s->pci.dev.config, PCI_VENDOR_ID_AMD); + pci_config_set_prog_interface(s->pci.dev.config, 00); + pci_config_set_device_id(s->pci.dev.config, s->devid); + pci_config_set_class(s->pci.dev.config, 0x0806); + + /* reset AMDVI specific capabilities, all r/o */ + pci_set_long(s->pci.dev.config + s->capab_offset, AMDVI_CAPAB_FEATURES); + pci_set_long(s->pci.dev.config + s->capab_offset + AMDVI_CAPAB_BAR_LOW, + s->mmio.addr & ~(0xffff0000)); + pci_set_long(s->pci.dev.config + s->capab_offset + AMDVI_CAPAB_BAR_HIGH, + (s->mmio.addr & ~(0xffff)) >> 16); + pci_set_long(s->pci.dev.config + s->capab_offset + AMDVI_CAPAB_RANGE, + 0xff000000); + pci_set_long(s->pci.dev.config + s->capab_offset + AMDVI_CAPAB_MISC, 0); + pci_set_long(s->pci.dev.config + s->capab_offset + AMDVI_CAPAB_MISC, + AMDVI_MAX_PH_ADDR | AMDVI_MAX_GVA_ADDR | AMDVI_MAX_VA_ADDR); +} + +static void amdvi_reset(DeviceState *dev) +{ + AMDVIState *s = AMD_IOMMU_DEVICE(dev); + + msi_reset(&s->pci.dev); + amdvi_init(s); +} + +static void amdvi_realize(DeviceState *dev, Error **err) +{ + AMDVIState *s = AMD_IOMMU_DEVICE(dev); + PCIBus *bus = PC_MACHINE(qdev_get_machine())->bus; + s->iotlb = g_hash_table_new_full(amdvi_uint64_hash, + amdvi_uint64_equal, g_free, g_free); + + /* This device should take care of IOMMU PCI properties */ + qdev_set_parent_bus(DEVICE(&s->pci), &bus->qbus); + object_property_set_bool(OBJECT(&s->pci), true, "realized", err); + s->capab_offset = pci_add_capability(&s->pci.dev, AMDVI_CAPAB_ID_SEC, 0, + AMDVI_CAPAB_SIZE); + pci_add_capability(&s->pci.dev, PCI_CAP_ID_MSI, 0, AMDVI_CAPAB_REG_SIZE); + pci_add_capability(&s->pci.dev, PCI_CAP_ID_HT, 0, AMDVI_CAPAB_REG_SIZE); + + /* set up MMIO */ + memory_region_init_io(&s->mmio, OBJECT(s), &mmio_mem_ops, s, "amdvi-mmio", + AMDVI_MMIO_SIZE); + + sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->mmio); + sysbus_mmio_map(SYS_BUS_DEVICE(s), 0, AMDVI_BASE_ADDR); + pci_setup_iommu(bus, amdvi_host_dma_iommu, s); + s->devid = object_property_get_int(OBJECT(&s->pci), "addr", err); + msi_init(&s->pci.dev, 0, 1, true, false, err); + amdvi_init(s); +} + +static const VMStateDescription vmstate_amdvi = { + .name = "amd-iommu", + .unmigratable = 1 +}; + +static void amdvi_instance_init(Object *klass) +{ + AMDVIState *s = AMD_IOMMU_DEVICE(klass); + + object_initialize(&s->pci, sizeof(s->pci), TYPE_AMD_IOMMU_PCI); +} + +static void amdvi_class_init(ObjectClass *klass, void* data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + X86IOMMUClass *dc_class = X86_IOMMU_CLASS(klass); + + dc->reset = amdvi_reset; + dc->vmsd = &vmstate_amdvi; + dc->hotpluggable = false; + dc_class->realize = amdvi_realize; +} + +static const TypeInfo amdvi = { + .name = TYPE_AMD_IOMMU_DEVICE, + .parent = TYPE_X86_IOMMU_DEVICE, + .instance_size = sizeof(AMDVIState), + .instance_init = amdvi_instance_init, + .class_init = amdvi_class_init +}; + +static const TypeInfo amdviPCI = { + .name = "AMDVI-PCI", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(AMDVIPCIState), +}; + +static void amdviPCI_register_types(void) +{ + type_register_static(&amdviPCI); + type_register_static(&amdvi); +} + +type_init(amdviPCI_register_types); diff --git a/hw/i386/amd_iommu.h b/hw/i386/amd_iommu.h new file mode 100644 index 00000000000..884926e9e7a --- /dev/null +++ b/hw/i386/amd_iommu.h @@ -0,0 +1,289 @@ +/* + * QEMU emulation of an AMD IOMMU (AMD-Vi) + * + * Copyright (C) 2011 Eduard - Gabriel Munteanu + * Copyright (C) 2015 David Kiarie, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#ifndef AMD_IOMMU_H_ +#define AMD_IOMMU_H_ + +#include "hw/hw.h" +#include "hw/pci/pci.h" +#include "hw/pci/msi.h" +#include "hw/sysbus.h" +#include "sysemu/dma.h" +#include "hw/i386/pc.h" +#include "hw/pci/pci_bus.h" +#include "hw/i386/x86-iommu.h" + +/* Capability registers */ +#define AMDVI_CAPAB_BAR_LOW 0x04 +#define AMDVI_CAPAB_BAR_HIGH 0x08 +#define AMDVI_CAPAB_RANGE 0x0C +#define AMDVI_CAPAB_MISC 0x10 + +#define AMDVI_CAPAB_SIZE 0x18 +#define AMDVI_CAPAB_REG_SIZE 0x04 + +/* Capability header data */ +#define AMDVI_CAPAB_ID_SEC 0xf +#define AMDVI_CAPAB_FLAT_EXT (1 << 28) +#define AMDVI_CAPAB_EFR_SUP (1 << 27) +#define AMDVI_CAPAB_FLAG_NPCACHE (1 << 26) +#define AMDVI_CAPAB_FLAG_HTTUNNEL (1 << 25) +#define AMDVI_CAPAB_FLAG_IOTLBSUP (1 << 24) +#define AMDVI_CAPAB_INIT_TYPE (3 << 16) + +/* No. of used MMIO registers */ +#define AMDVI_MMIO_REGS_HIGH 8 +#define AMDVI_MMIO_REGS_LOW 7 + +/* MMIO registers */ +#define AMDVI_MMIO_DEVICE_TABLE 0x0000 +#define AMDVI_MMIO_COMMAND_BASE 0x0008 +#define AMDVI_MMIO_EVENT_BASE 0x0010 +#define AMDVI_MMIO_CONTROL 0x0018 +#define AMDVI_MMIO_EXCL_BASE 0x0020 +#define AMDVI_MMIO_EXCL_LIMIT 0x0028 +#define AMDVI_MMIO_EXT_FEATURES 0x0030 +#define AMDVI_MMIO_COMMAND_HEAD 0x2000 +#define AMDVI_MMIO_COMMAND_TAIL 0x2008 +#define AMDVI_MMIO_EVENT_HEAD 0x2010 +#define AMDVI_MMIO_EVENT_TAIL 0x2018 +#define AMDVI_MMIO_STATUS 0x2020 +#define AMDVI_MMIO_PPR_BASE 0x0038 +#define AMDVI_MMIO_PPR_HEAD 0x2030 +#define AMDVI_MMIO_PPR_TAIL 0x2038 + +#define AMDVI_MMIO_SIZE 0x4000 + +#define AMDVI_MMIO_DEVTAB_SIZE_MASK ((1ULL << 12) - 1) +#define AMDVI_MMIO_DEVTAB_BASE_MASK (((1ULL << 52) - 1) & ~ \ + AMDVI_MMIO_DEVTAB_SIZE_MASK) +#define AMDVI_MMIO_DEVTAB_ENTRY_SIZE 32 +#define AMDVI_MMIO_DEVTAB_SIZE_UNIT 4096 + +/* some of this are similar but just for readability */ +#define AMDVI_MMIO_CMDBUF_SIZE_BYTE (AMDVI_MMIO_COMMAND_BASE + 7) +#define AMDVI_MMIO_CMDBUF_SIZE_MASK 0x0f +#define AMDVI_MMIO_CMDBUF_BASE_MASK AMDVI_MMIO_DEVTAB_BASE_MASK +#define AMDVI_MMIO_CMDBUF_HEAD_MASK (((1ULL << 19) - 1) & ~0x0f) +#define AMDVI_MMIO_CMDBUF_TAIL_MASK AMDVI_MMIO_EVTLOG_HEAD_MASK + +#define AMDVI_MMIO_EVTLOG_SIZE_BYTE (AMDVI_MMIO_EVENT_BASE + 7) +#define AMDVI_MMIO_EVTLOG_SIZE_MASK AMDVI_MMIO_CMDBUF_SIZE_MASK +#define AMDVI_MMIO_EVTLOG_BASE_MASK AMDVI_MMIO_CMDBUF_BASE_MASK +#define AMDVI_MMIO_EVTLOG_HEAD_MASK (((1ULL << 19) - 1) & ~0x0f) +#define AMDVI_MMIO_EVTLOG_TAIL_MASK AMDVI_MMIO_EVTLOG_HEAD_MASK + +#define AMDVI_MMIO_PPRLOG_SIZE_BYTE (AMDVI_MMIO_EVENT_BASE + 7) +#define AMDVI_MMIO_PPRLOG_HEAD_MASK AMDVI_MMIO_EVTLOG_HEAD_MASK +#define AMDVI_MMIO_PPRLOG_TAIL_MASK AMDVI_MMIO_EVTLOG_HEAD_MASK +#define AMDVI_MMIO_PPRLOG_BASE_MASK AMDVI_MMIO_EVTLOG_BASE_MASK +#define AMDVI_MMIO_PPRLOG_SIZE_MASK AMDVI_MMIO_EVTLOG_SIZE_MASK + +#define AMDVI_MMIO_EXCL_ENABLED_MASK (1ULL << 0) +#define AMDVI_MMIO_EXCL_ALLOW_MASK (1ULL << 1) +#define AMDVI_MMIO_EXCL_LIMIT_MASK AMDVI_MMIO_DEVTAB_BASE_MASK +#define AMDVI_MMIO_EXCL_LIMIT_LOW 0xfff + +/* mmio control register flags */ +#define AMDVI_MMIO_CONTROL_AMDVIEN (1ULL << 0) +#define AMDVI_MMIO_CONTROL_HTTUNEN (1ULL << 1) +#define AMDVI_MMIO_CONTROL_EVENTLOGEN (1ULL << 2) +#define AMDVI_MMIO_CONTROL_EVENTINTEN (1ULL << 3) +#define AMDVI_MMIO_CONTROL_COMWAITINTEN (1ULL << 4) +#define AMDVI_MMIO_CONTROL_CMDBUFLEN (1ULL << 12) + +/* MMIO status register bits */ +#define AMDVI_MMIO_STATUS_CMDBUF_RUN (1 << 4) +#define AMDVI_MMIO_STATUS_EVT_RUN (1 << 3) +#define AMDVI_MMIO_STATUS_COMP_INT (1 << 2) +#define AMDVI_MMIO_STATUS_EVT_OVF (1 << 0) + +#define AMDVI_CMDBUF_ID_BYTE 0x07 +#define AMDVI_CMDBUF_ID_RSHIFT 4 + +#define AMDVI_CMD_COMPLETION_WAIT 0x01 +#define AMDVI_CMD_INVAL_DEVTAB_ENTRY 0x02 +#define AMDVI_CMD_INVAL_AMDVI_PAGES 0x03 +#define AMDVI_CMD_INVAL_IOTLB_PAGES 0x04 +#define AMDVI_CMD_INVAL_INTR_TABLE 0x05 +#define AMDVI_CMD_PREFETCH_AMDVI_PAGES 0x06 +#define AMDVI_CMD_COMPLETE_PPR_REQUEST 0x07 +#define AMDVI_CMD_INVAL_AMDVI_ALL 0x08 + +#define AMDVI_DEVTAB_ENTRY_SIZE 32 + +/* Device table entry bits 0:63 */ +#define AMDVI_DEV_VALID (1ULL << 0) +#define AMDVI_DEV_TRANSLATION_VALID (1ULL << 1) +#define AMDVI_DEV_MODE_MASK 0x7 +#define AMDVI_DEV_MODE_RSHIFT 9 +#define AMDVI_DEV_PT_ROOT_MASK 0xffffffffff000 +#define AMDVI_DEV_PT_ROOT_RSHIFT 12 +#define AMDVI_DEV_PERM_SHIFT 61 +#define AMDVI_DEV_PERM_READ (1ULL << 61) +#define AMDVI_DEV_PERM_WRITE (1ULL << 62) + +/* Device table entry bits 64:127 */ +#define AMDVI_DEV_DOMID_ID_MASK ((1ULL << 16) - 1) + +/* Event codes and flags, as stored in the info field */ +#define AMDVI_EVENT_ILLEGAL_DEVTAB_ENTRY (0x1U << 12) +#define AMDVI_EVENT_IOPF (0x2U << 12) +#define AMDVI_EVENT_IOPF_I (1U << 3) +#define AMDVI_EVENT_DEV_TAB_HW_ERROR (0x3U << 12) +#define AMDVI_EVENT_PAGE_TAB_HW_ERROR (0x4U << 12) +#define AMDVI_EVENT_ILLEGAL_COMMAND_ERROR (0x5U << 12) +#define AMDVI_EVENT_COMMAND_HW_ERROR (0x6U << 12) + +#define AMDVI_EVENT_LEN 16 +#define AMDVI_PERM_READ (1 << 0) +#define AMDVI_PERM_WRITE (1 << 1) + +#define AMDVI_FEATURE_PREFETCH (1ULL << 0) /* page prefetch */ +#define AMDVI_FEATURE_PPR (1ULL << 1) /* PPR Support */ +#define AMDVI_FEATURE_GT (1ULL << 4) /* Guest Translation */ +#define AMDVI_FEATURE_IA (1ULL << 6) /* inval all support */ +#define AMDVI_FEATURE_GA (1ULL << 7) /* guest VAPIC support */ +#define AMDVI_FEATURE_HE (1ULL << 8) /* hardware error regs */ +#define AMDVI_FEATURE_PC (1ULL << 9) /* Perf counters */ + +/* reserved DTE bits */ +#define AMDVI_DTE_LOWER_QUAD_RESERVED 0x80300000000000fc +#define AMDVI_DTE_MIDDLE_QUAD_RESERVED 0x0000000000000100 +#define AMDVI_DTE_UPPER_QUAD_RESERVED 0x08f0000000000000 + +/* AMDVI paging mode */ +#define AMDVI_GATS_MODE (6ULL << 12) +#define AMDVI_HATS_MODE (6ULL << 10) + +/* IOTLB */ +#define AMDVI_IOTLB_MAX_SIZE 1024 +#define AMDVI_DEVID_SHIFT 36 + +/* extended feature support */ +#define AMDVI_EXT_FEATURES (AMDVI_FEATURE_PREFETCH | AMDVI_FEATURE_PPR | \ + AMDVI_FEATURE_IA | AMDVI_FEATURE_GT | AMDVI_FEATURE_HE | \ + AMDVI_GATS_MODE | AMDVI_HATS_MODE) + +/* capabilities header */ +#define AMDVI_CAPAB_FEATURES (AMDVI_CAPAB_FLAT_EXT | \ + AMDVI_CAPAB_FLAG_NPCACHE | AMDVI_CAPAB_FLAG_IOTLBSUP \ + | AMDVI_CAPAB_ID_SEC | AMDVI_CAPAB_INIT_TYPE | \ + AMDVI_CAPAB_FLAG_HTTUNNEL | AMDVI_CAPAB_EFR_SUP) + +/* AMDVI default address */ +#define AMDVI_BASE_ADDR 0xfed80000 + +/* page management constants */ +#define AMDVI_PAGE_SHIFT 12 +#define AMDVI_PAGE_SIZE (1ULL << AMDVI_PAGE_SHIFT) + +#define AMDVI_PAGE_SHIFT_4K 12 +#define AMDVI_PAGE_MASK_4K (~((1ULL << AMDVI_PAGE_SHIFT_4K) - 1)) + +#define AMDVI_MAX_VA_ADDR (48UL << 5) +#define AMDVI_MAX_PH_ADDR (40UL << 8) +#define AMDVI_MAX_GVA_ADDR (48UL << 15) + +/* Completion Wait data size */ +#define AMDVI_COMPLETION_DATA_SIZE 8 + +#define AMDVI_COMMAND_SIZE 16 +/* Completion Wait data size */ +#define AMDVI_COMPLETION_DATA_SIZE 8 + +#define AMDVI_COMMAND_SIZE 16 + +#define AMDVI_INT_ADDR_FIRST 0xfee00000 +#define AMDVI_INT_ADDR_LAST 0xfeefffff + +#define TYPE_AMD_IOMMU_DEVICE "amd-iommu" +#define AMD_IOMMU_DEVICE(obj)\ + OBJECT_CHECK(AMDVIState, (obj), TYPE_AMD_IOMMU_DEVICE) + +#define TYPE_AMD_IOMMU_PCI "AMDVI-PCI" + +typedef struct AMDVIAddressSpace AMDVIAddressSpace; + +/* functions to steal PCI config space */ +typedef struct AMDVIPCIState { + PCIDevice dev; /* The PCI device itself */ +} AMDVIPCIState; + +typedef struct AMDVIState { + X86IOMMUState iommu; /* IOMMU bus device */ + AMDVIPCIState pci; /* IOMMU PCI device */ + + uint32_t version; + uint32_t capab_offset; /* capability offset pointer */ + + uint64_t mmio_addr; + + uint32_t devid; /* auto-assigned devid */ + + bool enabled; /* IOMMU enabled */ + bool ats_enabled; /* address translation enabled */ + bool cmdbuf_enabled; /* command buffer enabled */ + bool evtlog_enabled; /* event log enabled */ + bool excl_enabled; + + hwaddr devtab; /* base address device table */ + size_t devtab_len; /* device table length */ + + hwaddr cmdbuf; /* command buffer base address */ + uint64_t cmdbuf_len; /* command buffer length */ + uint32_t cmdbuf_head; /* current IOMMU read position */ + uint32_t cmdbuf_tail; /* next Software write position */ + bool completion_wait_intr; + + hwaddr evtlog; /* base address event log */ + bool evtlog_intr; + uint32_t evtlog_len; /* event log length */ + uint32_t evtlog_head; /* current IOMMU write position */ + uint32_t evtlog_tail; /* current Software read position */ + + /* unused for now */ + hwaddr excl_base; /* base DVA - IOMMU exclusion range */ + hwaddr excl_limit; /* limit of IOMMU exclusion range */ + bool excl_allow; /* translate accesses to the exclusion range */ + bool excl_enable; /* exclusion range enabled */ + + hwaddr ppr_log; /* base address ppr log */ + uint32_t pprlog_len; /* ppr log len */ + uint32_t pprlog_head; /* ppr log head */ + uint32_t pprlog_tail; /* ppr log tail */ + + MemoryRegion mmio; /* MMIO region */ + uint8_t mmior[AMDVI_MMIO_SIZE]; /* read/write MMIO */ + uint8_t w1cmask[AMDVI_MMIO_SIZE]; /* read/write 1 clear mask */ + uint8_t romask[AMDVI_MMIO_SIZE]; /* MMIO read/only mask */ + bool mmio_enabled; + + /* IOMMU function */ + MemoryRegionIOMMUOps iommu_ops; + + /* for each served device */ + AMDVIAddressSpace **address_spaces[PCI_BUS_MAX]; + + /* IOTLB */ + GHashTable *iotlb; +} AMDVIState; + +#endif From fb9f592623b0f9bb82a88d68d7921fb581918ef5 Mon Sep 17 00:00:00 2001 From: David Kiarie Date: Tue, 20 Sep 2016 18:42:34 +0300 Subject: [PATCH 308/723] hw/i386: AMD IOMMU IVRS table Add IVRS table for AMD IOMMU. Generate IVRS or DMAR depending on emulated IOMMU. Signed-off-by: David Kiarie Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/aml-build.c | 2 +- hw/i386/acpi-build.c | 76 ++++++++++++++++++++++++++++++++----- hw/i386/amd_iommu.c | 2 + hw/i386/intel_iommu.c | 1 + hw/i386/x86-iommu.c | 6 +++ include/hw/acpi/aml-build.h | 1 + include/hw/i386/x86-iommu.h | 12 ++++++ 7 files changed, 90 insertions(+), 10 deletions(-) diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c index db3e914fb44..b2a1e4033b3 100644 --- a/hw/acpi/aml-build.c +++ b/hw/acpi/aml-build.c @@ -226,7 +226,7 @@ static void build_extop_package(GArray *package, uint8_t op) build_prepend_byte(package, 0x5B); /* ExtOpPrefix */ } -static void build_append_int_noprefix(GArray *table, uint64_t value, int size) +void build_append_int_noprefix(GArray *table, uint64_t value, int size) { int i; diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 433febafdd9..c20bc71a676 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -59,7 +59,8 @@ #include "qapi/qmp/qint.h" #include "qom/qom-qobject.h" -#include "hw/i386/x86-iommu.h" +#include "hw/i386/amd_iommu.h" +#include "hw/i386/intel_iommu.h" #include "hw/acpi/ipmi.h" @@ -2562,6 +2563,62 @@ build_dmar_q35(GArray *table_data, BIOSLinker *linker) build_header(linker, table_data, (void *)(table_data->data + dmar_start), "DMAR", table_data->len - dmar_start, 1, NULL, NULL); } +/* + * IVRS table as specified in AMD IOMMU Specification v2.62, Section 5.2 + * accessible here http://support.amd.com/TechDocs/48882_IOMMU.pdf + */ +static void +build_amd_iommu(GArray *table_data, BIOSLinker *linker) +{ + int iommu_start = table_data->len; + AMDVIState *s = AMD_IOMMU_DEVICE(x86_iommu_get_default()); + + /* IVRS header */ + acpi_data_push(table_data, sizeof(AcpiTableHeader)); + /* IVinfo - IO virtualization information common to all + * IOMMU units in a system + */ + build_append_int_noprefix(table_data, 40UL << 8/* PASize */, 4); + /* reserved */ + build_append_int_noprefix(table_data, 0, 8); + + /* IVHD definition - type 10h */ + build_append_int_noprefix(table_data, 0x10, 1); + /* virtualization flags */ + build_append_int_noprefix(table_data, + (1UL << 0) | /* HtTunEn */ + (1UL << 4) | /* iotblSup */ + (1UL << 6) | /* PrefSup */ + (1UL << 7), /* PPRSup */ + 1); + /* IVHD length */ + build_append_int_noprefix(table_data, 0x24, 2); + /* DeviceID */ + build_append_int_noprefix(table_data, s->devid, 2); + /* Capability offset */ + build_append_int_noprefix(table_data, s->capab_offset, 2); + /* IOMMU base address */ + build_append_int_noprefix(table_data, s->mmio.addr, 8); + /* PCI Segment Group */ + build_append_int_noprefix(table_data, 0, 2); + /* IOMMU info */ + build_append_int_noprefix(table_data, 0, 2); + /* IOMMU Feature Reporting */ + build_append_int_noprefix(table_data, + (48UL << 30) | /* HATS */ + (48UL << 28) | /* GATS */ + (1UL << 2), /* GTSup */ + 4); + /* + * Type 1 device entry reporting all devices + * These are 4-byte device entries currently reporting the range of + * Refer to Spec - Table 95:IVHD Device Entry Type Codes(4-byte) + */ + build_append_int_noprefix(table_data, 0x0000001, 4); + + build_header(linker, table_data, (void *)(table_data->data + iommu_start), + "IVRS", table_data->len - iommu_start, 1, NULL, NULL); +} static GArray * build_rsdp(GArray *rsdp_table, BIOSLinker *linker, unsigned rsdt_tbl_offset) @@ -2622,11 +2679,6 @@ static bool acpi_get_mcfg(AcpiMcfgInfo *mcfg) return true; } -static bool acpi_has_iommu(void) -{ - return !!x86_iommu_get_default(); -} - static void acpi_build(AcpiBuildTables *tables, MachineState *machine) { @@ -2706,9 +2758,15 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine) acpi_add_table(table_offsets, tables_blob); build_mcfg_q35(tables_blob, tables->linker, &mcfg); } - if (acpi_has_iommu()) { - acpi_add_table(table_offsets, tables_blob); - build_dmar_q35(tables_blob, tables->linker); + if (x86_iommu_get_default()) { + IommuType IOMMUType = x86_iommu_get_type(); + if (IOMMUType == TYPE_AMD) { + acpi_add_table(table_offsets, tables_blob); + build_amd_iommu(tables_blob, tables->linker); + } else if (IOMMUType == TYPE_INTEL) { + acpi_add_table(table_offsets, tables_blob); + build_dmar_q35(tables_blob, tables->linker); + } } if (pcms->acpi_nvdimm_state.is_enabled) { nvdimm_build_acpi(table_offsets, tables_blob, tables->linker, diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index 4eec9b80eda..a91a1798cb0 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -1130,11 +1130,13 @@ static void amdvi_reset(DeviceState *dev) static void amdvi_realize(DeviceState *dev, Error **err) { AMDVIState *s = AMD_IOMMU_DEVICE(dev); + X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(dev); PCIBus *bus = PC_MACHINE(qdev_get_machine())->bus; s->iotlb = g_hash_table_new_full(amdvi_uint64_hash, amdvi_uint64_equal, g_free, g_free); /* This device should take care of IOMMU PCI properties */ + x86_iommu->type = TYPE_AMD; qdev_set_parent_bus(DEVICE(&s->pci), &bus->qbus); object_property_set_bool(OBJECT(&s->pci), true, "realized", err); s->capab_offset = pci_add_capability(&s->pci.dev, AMDVI_CAPAB_ID_SEC, 0, diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 28c31a2cdfa..d6e02c821a8 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -2453,6 +2453,7 @@ static void vtd_realize(DeviceState *dev, Error **errp) X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(dev); VTD_DPRINTF(GENERAL, ""); + x86_iommu->type = TYPE_INTEL; memset(s->vtd_as_by_bus_num, 0, sizeof(s->vtd_as_by_bus_num)); memory_region_init_io(&s->csrmem, OBJECT(s), &vtd_mem_ops, s, "intel_iommu", DMAR_REG_SIZE); diff --git a/hw/i386/x86-iommu.c b/hw/i386/x86-iommu.c index ce26b2a71d9..2278af7c32c 100644 --- a/hw/i386/x86-iommu.c +++ b/hw/i386/x86-iommu.c @@ -71,6 +71,11 @@ X86IOMMUState *x86_iommu_get_default(void) return x86_iommu_default; } +IommuType x86_iommu_get_type(void) +{ + return x86_iommu_default->type; +} + static void x86_iommu_realize(DeviceState *dev, Error **errp) { X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(dev); @@ -79,6 +84,7 @@ static void x86_iommu_realize(DeviceState *dev, Error **errp) if (x86_class->realize) { x86_class->realize(dev, errp); } + x86_iommu_set_default(X86_IOMMU_DEVICE(dev)); } diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h index e5f087803f5..559326cbd50 100644 --- a/include/hw/acpi/aml-build.h +++ b/include/hw/acpi/aml-build.h @@ -367,6 +367,7 @@ Aml *aml_sizeof(Aml *arg); Aml *aml_concatenate(Aml *source1, Aml *source2, Aml *target); Aml *aml_object_type(Aml *object); +void build_append_int_noprefix(GArray *table, uint64_t value, int size); void build_header(BIOSLinker *linker, GArray *table_data, AcpiTableHeader *h, const char *sig, int len, uint8_t rev, diff --git a/include/hw/i386/x86-iommu.h b/include/hw/i386/x86-iommu.h index c48e8dd5976..0c89d9835b6 100644 --- a/include/hw/i386/x86-iommu.h +++ b/include/hw/i386/x86-iommu.h @@ -37,6 +37,12 @@ typedef struct X86IOMMUState X86IOMMUState; typedef struct X86IOMMUClass X86IOMMUClass; +typedef enum IommuType { + TYPE_INTEL, + TYPE_AMD, + TYPE_NONE +} IommuType; + struct X86IOMMUClass { SysBusDeviceClass parent; /* Intel/AMD specific realize() hook */ @@ -67,6 +73,7 @@ typedef struct IEC_Notifier IEC_Notifier; struct X86IOMMUState { SysBusDevice busdev; bool intr_supported; /* Whether vIOMMU supports IR */ + IommuType type; /* IOMMU type - AMD/Intel */ QLIST_HEAD(, IEC_Notifier) iec_notifiers; /* IEC notify list */ }; @@ -76,6 +83,11 @@ struct X86IOMMUState { */ X86IOMMUState *x86_iommu_get_default(void); +/* + * x86_iommu_get_type - get IOMMU type + */ +IommuType x86_iommu_get_type(void); + /** * x86_iommu_iec_register_notifier - register IEC (Interrupt Entry * Cache) notifiers From cdb3081269347fd9271fd1b7a9df312e2953bdd9 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Fri, 23 Sep 2016 13:02:26 +0800 Subject: [PATCH 309/723] memory: introduce IOMMUNotifier and its caps IOMMU Notifier list is used for notifying IO address mapping changes. Currently VFIO is the only user. However it is possible that future consumer like vhost would like to only listen to part of its notifications (e.g., cache invalidations). This patch introduced IOMMUNotifier and IOMMUNotfierFlag bits for a finer grained control of it. IOMMUNotifier contains a bitfield for the notify consumer describing what kind of notification it is interested in. Currently two kinds of notifications are defined: - IOMMU_NOTIFIER_MAP: for newly mapped entries (additions) - IOMMU_NOTIFIER_UNMAP: for entries to be removed (cache invalidates) When registering the IOMMU notifier, we need to specify one or multiple types of messages to listen to. When notifications are triggered, its type will be checked against the notifier's type bits, and only notifiers with registered bits will be notified. (For any IOMMU implementation, an in-place mapping change should be notified with an UNMAP followed by a MAP.) Signed-off-by: Peter Xu Message-Id: <1474606948-14391-2-git-send-email-peterx@redhat.com> Signed-off-by: Paolo Bonzini --- hw/vfio/common.c | 4 +-- include/exec/memory.h | 47 +++++++++++++++++++++++++++++------ include/hw/vfio/vfio-common.h | 2 +- memory.c | 37 ++++++++++++++++++++------- 4 files changed, 71 insertions(+), 19 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index b313e7c2c66..29188a12fca 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -293,11 +293,10 @@ static bool vfio_listener_skipped_section(MemoryRegionSection *section) section->offset_within_address_space & (1ULL << 63); } -static void vfio_iommu_map_notify(Notifier *n, void *data) +static void vfio_iommu_map_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb) { VFIOGuestIOMMU *giommu = container_of(n, VFIOGuestIOMMU, n); VFIOContainer *container = giommu->container; - IOMMUTLBEntry *iotlb = data; hwaddr iova = iotlb->iova + giommu->iommu_offset; MemoryRegion *mr; hwaddr xlat; @@ -454,6 +453,7 @@ static void vfio_listener_region_add(MemoryListener *listener, section->offset_within_region; giommu->container = container; giommu->n.notify = vfio_iommu_map_notify; + giommu->n.notifier_flags = IOMMU_NOTIFIER_ALL; QLIST_INSERT_HEAD(&container->giommu_list, giommu, giommu_next); memory_region_register_iommu_notifier(giommu->iommu, &giommu->n); diff --git a/include/exec/memory.h b/include/exec/memory.h index 3e4d4164cd4..14cda673f9f 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -67,6 +67,27 @@ struct IOMMUTLBEntry { IOMMUAccessFlags perm; }; +/* + * Bitmap for different IOMMUNotifier capabilities. Each notifier can + * register with one or multiple IOMMU Notifier capability bit(s). + */ +typedef enum { + IOMMU_NOTIFIER_NONE = 0, + /* Notify cache invalidations */ + IOMMU_NOTIFIER_UNMAP = 0x1, + /* Notify entry changes (newly created entries) */ + IOMMU_NOTIFIER_MAP = 0x2, +} IOMMUNotifierFlag; + +#define IOMMU_NOTIFIER_ALL (IOMMU_NOTIFIER_MAP | IOMMU_NOTIFIER_UNMAP) + +struct IOMMUNotifier { + void (*notify)(struct IOMMUNotifier *notifier, IOMMUTLBEntry *data); + IOMMUNotifierFlag notifier_flags; + QLIST_ENTRY(IOMMUNotifier) node; +}; +typedef struct IOMMUNotifier IOMMUNotifier; + /* New-style MMIO accessors can indicate that the transaction failed. * A zero (MEMTX_OK) response means success; anything else is a failure * of some kind. The memory subsystem will bitwise-OR together results @@ -201,7 +222,7 @@ struct MemoryRegion { const char *name; unsigned ioeventfd_nb; MemoryRegionIoeventfd *ioeventfds; - NotifierList iommu_notify; + QLIST_HEAD(, IOMMUNotifier) iommu_notify; }; /** @@ -607,6 +628,15 @@ uint64_t memory_region_iommu_get_min_page_size(MemoryRegion *mr); /** * memory_region_notify_iommu: notify a change in an IOMMU translation entry. * + * The notification type will be decided by entry.perm bits: + * + * - For UNMAP (cache invalidation) notifies: set entry.perm to IOMMU_NONE. + * - For MAP (newly added entry) notifies: set entry.perm to the + * permission of the page (which is definitely !IOMMU_NONE). + * + * Note: for any IOMMU implementation, an in-place mapping change + * should be notified with an UNMAP followed by a MAP. + * * @mr: the memory region that was changed * @entry: the new entry in the IOMMU translation table. The entry * replaces all old entries for the same virtual I/O address range. @@ -620,11 +650,12 @@ void memory_region_notify_iommu(MemoryRegion *mr, * IOMMU translation entries. * * @mr: the memory region to observe - * @n: the notifier to be added; the notifier receives a pointer to an - * #IOMMUTLBEntry as the opaque value; the pointer ceases to be - * valid on exit from the notifier. + * @n: the IOMMUNotifier to be added; the notify callback receives a + * pointer to an #IOMMUTLBEntry as the opaque value; the pointer + * ceases to be valid on exit from the notifier. */ -void memory_region_register_iommu_notifier(MemoryRegion *mr, Notifier *n); +void memory_region_register_iommu_notifier(MemoryRegion *mr, + IOMMUNotifier *n); /** * memory_region_iommu_replay: replay existing IOMMU translations to @@ -636,7 +667,8 @@ void memory_region_register_iommu_notifier(MemoryRegion *mr, Notifier *n); * @is_write: Whether to treat the replay as a translate "write" * through the iommu */ -void memory_region_iommu_replay(MemoryRegion *mr, Notifier *n, bool is_write); +void memory_region_iommu_replay(MemoryRegion *mr, IOMMUNotifier *n, + bool is_write); /** * memory_region_unregister_iommu_notifier: unregister a notifier for @@ -646,7 +678,8 @@ void memory_region_iommu_replay(MemoryRegion *mr, Notifier *n, bool is_write); * needs to be called * @n: the notifier to be removed. */ -void memory_region_unregister_iommu_notifier(MemoryRegion *mr, Notifier *n); +void memory_region_unregister_iommu_notifier(MemoryRegion *mr, + IOMMUNotifier *n); /** * memory_region_name: get a memory region's name diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index 94dfae387a4..c17602e5337 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -93,7 +93,7 @@ typedef struct VFIOGuestIOMMU { VFIOContainer *container; MemoryRegion *iommu; hwaddr iommu_offset; - Notifier n; + IOMMUNotifier n; QLIST_ENTRY(VFIOGuestIOMMU) giommu_next; } VFIOGuestIOMMU; diff --git a/memory.c b/memory.c index 1a1baf574cb..69d9d9ab7fc 100644 --- a/memory.c +++ b/memory.c @@ -1413,7 +1413,7 @@ void memory_region_init_iommu(MemoryRegion *mr, memory_region_init(mr, owner, name, size); mr->iommu_ops = ops, mr->terminates = true; /* then re-forwards */ - notifier_list_init(&mr->iommu_notify); + QLIST_INIT(&mr->iommu_notify); } static void memory_region_finalize(Object *obj) @@ -1508,13 +1508,16 @@ bool memory_region_is_logging(MemoryRegion *mr, uint8_t client) return memory_region_get_dirty_log_mask(mr) & (1 << client); } -void memory_region_register_iommu_notifier(MemoryRegion *mr, Notifier *n) +void memory_region_register_iommu_notifier(MemoryRegion *mr, + IOMMUNotifier *n) { + /* We need to register for at least one bitfield */ + assert(n->notifier_flags != IOMMU_NOTIFIER_NONE); if (mr->iommu_ops->notify_started && - QLIST_EMPTY(&mr->iommu_notify.notifiers)) { + QLIST_EMPTY(&mr->iommu_notify)) { mr->iommu_ops->notify_started(mr); } - notifier_list_add(&mr->iommu_notify, n); + QLIST_INSERT_HEAD(&mr->iommu_notify, n, node); } uint64_t memory_region_iommu_get_min_page_size(MemoryRegion *mr) @@ -1526,7 +1529,8 @@ uint64_t memory_region_iommu_get_min_page_size(MemoryRegion *mr) return TARGET_PAGE_SIZE; } -void memory_region_iommu_replay(MemoryRegion *mr, Notifier *n, bool is_write) +void memory_region_iommu_replay(MemoryRegion *mr, IOMMUNotifier *n, + bool is_write) { hwaddr addr, granularity; IOMMUTLBEntry iotlb; @@ -1547,11 +1551,12 @@ void memory_region_iommu_replay(MemoryRegion *mr, Notifier *n, bool is_write) } } -void memory_region_unregister_iommu_notifier(MemoryRegion *mr, Notifier *n) +void memory_region_unregister_iommu_notifier(MemoryRegion *mr, + IOMMUNotifier *n) { - notifier_remove(n); + QLIST_REMOVE(n, node); if (mr->iommu_ops->notify_stopped && - QLIST_EMPTY(&mr->iommu_notify.notifiers)) { + QLIST_EMPTY(&mr->iommu_notify)) { mr->iommu_ops->notify_stopped(mr); } } @@ -1559,8 +1564,22 @@ void memory_region_unregister_iommu_notifier(MemoryRegion *mr, Notifier *n) void memory_region_notify_iommu(MemoryRegion *mr, IOMMUTLBEntry entry) { + IOMMUNotifier *iommu_notifier; + IOMMUNotifierFlag request_flags; + assert(memory_region_is_iommu(mr)); - notifier_list_notify(&mr->iommu_notify, &entry); + + if (entry.perm & IOMMU_RW) { + request_flags = IOMMU_NOTIFIER_MAP; + } else { + request_flags = IOMMU_NOTIFIER_UNMAP; + } + + QLIST_FOREACH(iommu_notifier, &mr->iommu_notify, node) { + if (iommu_notifier->notifier_flags & request_flags) { + iommu_notifier->notify(iommu_notifier, &entry); + } + } } void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client) From 5bf3d319030b1e95116ba49b31339f2bdd1d3b2a Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Fri, 23 Sep 2016 13:02:27 +0800 Subject: [PATCH 310/723] memory: introduce IOMMUOps.notify_flag_changed The new interface can be used to replace the old notify_started() and notify_stopped(). Meanwhile it provides explicit flags so that IOMMUs can know what kind of notifications it is requested for. Acked-by: David Gibson Signed-off-by: Peter Xu Message-Id: <1474606948-14391-3-git-send-email-peterx@redhat.com> Signed-off-by: Paolo Bonzini --- hw/i386/amd_iommu.c | 6 ++++-- hw/i386/intel_iommu.c | 6 ++++-- hw/ppc/spapr_iommu.c | 18 ++++++++++-------- include/exec/memory.h | 9 +++++---- memory.c | 29 +++++++++++++++++++++-------- 5 files changed, 44 insertions(+), 24 deletions(-) diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index a91a1798cb0..a868539fb01 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -1066,7 +1066,9 @@ static const MemoryRegionOps mmio_mem_ops = { } }; -static void amdvi_iommu_notify_started(MemoryRegion *iommu) +static void amdvi_iommu_notify_flag_changed(MemoryRegion *iommu, + IOMMUNotifierFlag old, + IOMMUNotifierFlag new) { AMDVIAddressSpace *as = container_of(iommu, AMDVIAddressSpace, iommu); @@ -1080,7 +1082,7 @@ static void amdvi_init(AMDVIState *s) amdvi_iotlb_reset(s); s->iommu_ops.translate = amdvi_translate; - s->iommu_ops.notify_started = amdvi_iommu_notify_started; + s->iommu_ops.notify_flag_changed = amdvi_iommu_notify_flag_changed; s->devtab_len = 0; s->cmdbuf_len = 0; s->cmdbuf_head = 0; diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index d6e02c821a8..b6cc38c73d6 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -1974,7 +1974,9 @@ static IOMMUTLBEntry vtd_iommu_translate(MemoryRegion *iommu, hwaddr addr, return ret; } -static void vtd_iommu_notify_started(MemoryRegion *iommu) +static void vtd_iommu_notify_flag_changed(MemoryRegion *iommu, + IOMMUNotifierFlag old, + IOMMUNotifierFlag new) { VTDAddressSpace *vtd_as = container_of(iommu, VTDAddressSpace, iommu); @@ -2348,7 +2350,7 @@ static void vtd_init(IntelIOMMUState *s) memset(s->womask, 0, DMAR_REG_SIZE); s->iommu_ops.translate = vtd_iommu_translate; - s->iommu_ops.notify_started = vtd_iommu_notify_started; + s->iommu_ops.notify_flag_changed = vtd_iommu_notify_flag_changed; s->root = 0; s->root_extended = false; s->dmar_enabled = false; diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c index f20b0b884fb..ae30bbe30f3 100644 --- a/hw/ppc/spapr_iommu.c +++ b/hw/ppc/spapr_iommu.c @@ -156,14 +156,17 @@ static uint64_t spapr_tce_get_min_page_size(MemoryRegion *iommu) return 1ULL << tcet->page_shift; } -static void spapr_tce_notify_started(MemoryRegion *iommu) +static void spapr_tce_notify_flag_changed(MemoryRegion *iommu, + IOMMUNotifierFlag old, + IOMMUNotifierFlag new) { - spapr_tce_set_need_vfio(container_of(iommu, sPAPRTCETable, iommu), true); -} + struct sPAPRTCETable *tbl = container_of(iommu, sPAPRTCETable, iommu); -static void spapr_tce_notify_stopped(MemoryRegion *iommu) -{ - spapr_tce_set_need_vfio(container_of(iommu, sPAPRTCETable, iommu), false); + if (old == IOMMU_NOTIFIER_NONE && new != IOMMU_NOTIFIER_NONE) { + spapr_tce_set_need_vfio(tbl, true); + } else if (old != IOMMU_NOTIFIER_NONE && new == IOMMU_NOTIFIER_NONE) { + spapr_tce_set_need_vfio(tbl, false); + } } static int spapr_tce_table_post_load(void *opaque, int version_id) @@ -246,8 +249,7 @@ static const VMStateDescription vmstate_spapr_tce_table = { static MemoryRegionIOMMUOps spapr_iommu_ops = { .translate = spapr_tce_translate_iommu, .get_min_page_size = spapr_tce_get_min_page_size, - .notify_started = spapr_tce_notify_started, - .notify_stopped = spapr_tce_notify_stopped, + .notify_flag_changed = spapr_tce_notify_flag_changed, }; static int spapr_tce_table_realize(DeviceState *dev) diff --git a/include/exec/memory.h b/include/exec/memory.h index 14cda673f9f..a3f988b6408 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -174,10 +174,10 @@ struct MemoryRegionIOMMUOps { IOMMUTLBEntry (*translate)(MemoryRegion *iommu, hwaddr addr, bool is_write); /* Returns minimum supported page size */ uint64_t (*get_min_page_size)(MemoryRegion *iommu); - /* Called when the first notifier is set */ - void (*notify_started)(MemoryRegion *iommu); - /* Called when the last notifier is removed */ - void (*notify_stopped)(MemoryRegion *iommu); + /* Called when IOMMU Notifier flag changed */ + void (*notify_flag_changed)(MemoryRegion *iommu, + IOMMUNotifierFlag old_flags, + IOMMUNotifierFlag new_flags); }; typedef struct CoalescedMemoryRange CoalescedMemoryRange; @@ -223,6 +223,7 @@ struct MemoryRegion { unsigned ioeventfd_nb; MemoryRegionIoeventfd *ioeventfds; QLIST_HEAD(, IOMMUNotifier) iommu_notify; + IOMMUNotifierFlag iommu_notify_flags; }; /** diff --git a/memory.c b/memory.c index 69d9d9ab7fc..27a3f2fca28 100644 --- a/memory.c +++ b/memory.c @@ -1414,6 +1414,7 @@ void memory_region_init_iommu(MemoryRegion *mr, mr->iommu_ops = ops, mr->terminates = true; /* then re-forwards */ QLIST_INIT(&mr->iommu_notify); + mr->iommu_notify_flags = IOMMU_NOTIFIER_NONE; } static void memory_region_finalize(Object *obj) @@ -1508,16 +1509,31 @@ bool memory_region_is_logging(MemoryRegion *mr, uint8_t client) return memory_region_get_dirty_log_mask(mr) & (1 << client); } +static void memory_region_update_iommu_notify_flags(MemoryRegion *mr) +{ + IOMMUNotifierFlag flags = IOMMU_NOTIFIER_NONE; + IOMMUNotifier *iommu_notifier; + + QLIST_FOREACH(iommu_notifier, &mr->iommu_notify, node) { + flags |= iommu_notifier->notifier_flags; + } + + if (flags != mr->iommu_notify_flags && + mr->iommu_ops->notify_flag_changed) { + mr->iommu_ops->notify_flag_changed(mr, mr->iommu_notify_flags, + flags); + } + + mr->iommu_notify_flags = flags; +} + void memory_region_register_iommu_notifier(MemoryRegion *mr, IOMMUNotifier *n) { /* We need to register for at least one bitfield */ assert(n->notifier_flags != IOMMU_NOTIFIER_NONE); - if (mr->iommu_ops->notify_started && - QLIST_EMPTY(&mr->iommu_notify)) { - mr->iommu_ops->notify_started(mr); - } QLIST_INSERT_HEAD(&mr->iommu_notify, n, node); + memory_region_update_iommu_notify_flags(mr); } uint64_t memory_region_iommu_get_min_page_size(MemoryRegion *mr) @@ -1555,10 +1571,7 @@ void memory_region_unregister_iommu_notifier(MemoryRegion *mr, IOMMUNotifier *n) { QLIST_REMOVE(n, node); - if (mr->iommu_ops->notify_stopped && - QLIST_EMPTY(&mr->iommu_notify)) { - mr->iommu_ops->notify_stopped(mr); - } + memory_region_update_iommu_notify_flags(mr); } void memory_region_notify_iommu(MemoryRegion *mr, From 1c0fbfa3dedf49115e194e533a7b6a640a28447c Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Wed, 10 Aug 2016 17:47:16 +0300 Subject: [PATCH 311/723] virtio-net: allow increasing rx queue size This allows increasing the rx queue size up to 1024: unlike with tx, guests don't put in huge S/G lists into RX so the risk of running into the max 1024 limitation due to some off-by-one seems small. It's helpful for users like OVS-DPDK which don't do any buffering on the host - 1K roughly matches 500 entries in tun + 256 in the current rx queue, which seems to work reasonably well. We could probably make do with ~750 entries but virtio spec limits us to powers of two. It might be a good idea to specify an s/g size limit in a future version. It also might be possible to make the queue size smaller down the road, 64 seems like the minimal value which will still work (as guests seem to assume a queue full of 1.5K buffers is enough to process the largest incoming packet, which is ~64K). No one actually asked for this, and with virtio 1 guests can reduce ring size without need for host configuration, so don't bother with this for now. Cc: Cornelia Huck Cc: Jason Wang Suggested-by: Patrik Hermansson Signed-off-by: Michael S. Tsirkin Reviewed-by: Cornelia Huck Signed-off-by: Jason Wang --- hw/net/virtio-net.c | 26 +++++++++++++++++++++++++- include/hw/virtio/virtio-net.h | 1 + 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 01f1351554a..6b8ae2c1faf 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -31,6 +31,11 @@ #define MAC_TABLE_ENTRIES 64 #define MAX_VLAN (1 << 12) /* Per 802.1Q definition */ +/* previously fixed value */ +#define VIRTIO_NET_RX_QUEUE_DEFAULT_SIZE 256 +/* for now, only allow larger queues; with virtio-1, guest can downsize */ +#define VIRTIO_NET_RX_QUEUE_MIN_SIZE VIRTIO_NET_RX_QUEUE_DEFAULT_SIZE + /* * Calculate the number of bytes up to and including the given 'field' of * 'container'. @@ -1412,7 +1417,8 @@ static void virtio_net_add_queue(VirtIONet *n, int index) { VirtIODevice *vdev = VIRTIO_DEVICE(n); - n->vqs[index].rx_vq = virtio_add_queue(vdev, 256, virtio_net_handle_rx); + n->vqs[index].rx_vq = virtio_add_queue(vdev, n->net_conf.rx_queue_size, + virtio_net_handle_rx); if (n->net_conf.tx && !strcmp(n->net_conf.tx, "timer")) { n->vqs[index].tx_vq = virtio_add_queue(vdev, 256, virtio_net_handle_tx_timer); @@ -1720,6 +1726,22 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp) virtio_net_set_config_size(n, n->host_features); virtio_init(vdev, "virtio-net", VIRTIO_ID_NET, n->config_size); + /* + * We set a lower limit on RX queue size to what it always was. + * Guests that want a smaller ring can always resize it without + * help from us (using virtio 1 and up). + */ + if (n->net_conf.rx_queue_size < VIRTIO_NET_RX_QUEUE_MIN_SIZE || + n->net_conf.rx_queue_size > VIRTQUEUE_MAX_SIZE || + (n->net_conf.rx_queue_size & (n->net_conf.rx_queue_size - 1))) { + error_setg(errp, "Invalid rx_queue_size (= %" PRIu16 "), " + "must be a power of 2 between %d and %d.", + n->net_conf.rx_queue_size, VIRTIO_NET_RX_QUEUE_MIN_SIZE, + VIRTQUEUE_MAX_SIZE); + virtio_cleanup(vdev); + return; + } + n->max_queues = MAX(n->nic_conf.peers.queues, 1); if (n->max_queues * 2 + 1 > VIRTIO_QUEUE_MAX) { error_setg(errp, "Invalid number of queues (= %" PRIu32 "), " @@ -1880,6 +1902,8 @@ static Property virtio_net_properties[] = { TX_TIMER_INTERVAL), DEFINE_PROP_INT32("x-txburst", VirtIONet, net_conf.txburst, TX_BURST), DEFINE_PROP_STRING("tx", VirtIONet, net_conf.tx), + DEFINE_PROP_UINT16("rx_queue_size", VirtIONet, net_conf.rx_queue_size, + VIRTIO_NET_RX_QUEUE_DEFAULT_SIZE), DEFINE_PROP_END_OF_LIST(), }; diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h index 91ed97cfcde..0ced975c57a 100644 --- a/include/hw/virtio/virtio-net.h +++ b/include/hw/virtio/virtio-net.h @@ -35,6 +35,7 @@ typedef struct virtio_net_conf uint32_t txtimer; int32_t txburst; char *tx; + uint16_t rx_queue_size; } virtio_net_conf; /* Maximum packet size we can receive from tap device: header + 64k */ From a4543b1b37dc05be84c7a95751af9d473f5fb41a Mon Sep 17 00:00:00 2001 From: Shmulik Ladkani Date: Mon, 5 Sep 2016 12:11:02 +0300 Subject: [PATCH 312/723] net: hmp_host_net_remove: Del the -net option of the removed host_net Upon hmp_host_net_remove(), the appropriate -net client is deleted (according to the given vlan_id and device id), as well as the corresponsing hub port. However, the relevant '-net' option that was added by former hmp_host_net_add() call is still present in "net" options group. This makes the following legit HMP sequence erroneous: (qemu) host_net_add tap id=n1,ifname=tap1,script=no,downscript=no,vlan=1 (qemu) host_net_remove 1 n1 (qemu) host_net_add tap id=n1,ifname=tap1,script=no,downscript=no,vlan=1 Duplicate ID 'n1' for net Fix, by deleting the stored '-net' option associated with the given device id. Signed-off-by: Shmulik Ladkani Signed-off-by: Jason Wang --- net/net.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/net.c b/net/net.c index d51cb298827..0bec096d75b 100644 --- a/net/net.c +++ b/net/net.c @@ -1179,6 +1179,7 @@ void hmp_host_net_remove(Monitor *mon, const QDict *qdict) qemu_del_net_client(nc->peer); qemu_del_net_client(nc); + qemu_opts_del(qemu_opts_find(qemu_find_opts("net"), device)); } void netdev_add(QemuOpts *opts, Error **errp) From e92aa36ac89fad49dc18d88e1d40f0d0fccdfa83 Mon Sep 17 00:00:00 2001 From: Zhang Chen Date: Tue, 27 Sep 2016 10:22:25 +0800 Subject: [PATCH 313/723] qemu-char: Add qemu_chr_add_handlers_full() for GMaincontext Add qemu_chr_add_handlers_full() API, we can use this API pass in a GMainContext,make handler run in the context rather than main_loop. This comments from Daniel P . Berrange. Signed-off-by: Zhang Chen Signed-off-by: Li Zhijian Signed-off-by: Wen Congyang Reviewed-by: Daniel P. Berrange Signed-off-by: Jason Wang --- include/sysemu/char.h | 11 ++++++- qemu-char.c | 77 +++++++++++++++++++++++++++++-------------- 2 files changed, 63 insertions(+), 25 deletions(-) diff --git a/include/sysemu/char.h b/include/sysemu/char.h index ee7e55468f8..0d0465ae0e0 100644 --- a/include/sysemu/char.h +++ b/include/sysemu/char.h @@ -65,7 +65,8 @@ struct CharDriverState { int (*chr_sync_read)(struct CharDriverState *s, const uint8_t *buf, int len); GSource *(*chr_add_watch)(struct CharDriverState *s, GIOCondition cond); - void (*chr_update_read_handler)(struct CharDriverState *s); + void (*chr_update_read_handler)(struct CharDriverState *s, + GMainContext *context); int (*chr_ioctl)(struct CharDriverState *s, int cmd, void *arg); int (*get_msgfds)(struct CharDriverState *s, int* fds, int num); int (*set_msgfds)(struct CharDriverState *s, int *fds, int num); @@ -422,6 +423,14 @@ void qemu_chr_add_handlers(CharDriverState *s, IOEventHandler *fd_event, void *opaque); +/* This API can make handler run in the context what you pass to. */ +void qemu_chr_add_handlers_full(CharDriverState *s, + IOCanReadHandler *fd_can_read, + IOReadHandler *fd_read, + IOEventHandler *fd_event, + void *opaque, + GMainContext *context); + void qemu_chr_be_generic_open(CharDriverState *s); void qemu_chr_accept_input(CharDriverState *s); int qemu_chr_add_client(CharDriverState *s, int fd); diff --git a/qemu-char.c b/qemu-char.c index 8826419d7d5..fb456cec345 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -449,11 +449,12 @@ void qemu_chr_fe_printf(CharDriverState *s, const char *fmt, ...) static void remove_fd_in_watch(CharDriverState *chr); -void qemu_chr_add_handlers(CharDriverState *s, - IOCanReadHandler *fd_can_read, - IOReadHandler *fd_read, - IOEventHandler *fd_event, - void *opaque) +void qemu_chr_add_handlers_full(CharDriverState *s, + IOCanReadHandler *fd_can_read, + IOReadHandler *fd_read, + IOEventHandler *fd_event, + void *opaque, + GMainContext *context) { int fe_open; @@ -467,8 +468,9 @@ void qemu_chr_add_handlers(CharDriverState *s, s->chr_read = fd_read; s->chr_event = fd_event; s->handler_opaque = opaque; - if (fe_open && s->chr_update_read_handler) - s->chr_update_read_handler(s); + if (fe_open && s->chr_update_read_handler) { + s->chr_update_read_handler(s, context); + } if (!s->explicit_fe_open) { qemu_chr_fe_set_open(s, fe_open); @@ -481,6 +483,16 @@ void qemu_chr_add_handlers(CharDriverState *s, } } +void qemu_chr_add_handlers(CharDriverState *s, + IOCanReadHandler *fd_can_read, + IOReadHandler *fd_read, + IOEventHandler *fd_event, + void *opaque) +{ + qemu_chr_add_handlers_full(s, fd_can_read, fd_read, + fd_event, opaque, NULL); +} + static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len) { return len; @@ -722,7 +734,8 @@ static void mux_chr_event(void *opaque, int event) mux_chr_send_event(d, i, event); } -static void mux_chr_update_read_handler(CharDriverState *chr) +static void mux_chr_update_read_handler(CharDriverState *chr, + GMainContext *context) { MuxDriver *d = chr->opaque; @@ -736,8 +749,10 @@ static void mux_chr_update_read_handler(CharDriverState *chr) d->chr_event[d->mux_cnt] = chr->chr_event; /* Fix up the real driver with mux routines */ if (d->mux_cnt == 0) { - qemu_chr_add_handlers(d->drv, mux_chr_can_read, mux_chr_read, - mux_chr_event, chr); + qemu_chr_add_handlers_full(d->drv, mux_chr_can_read, + mux_chr_read, + mux_chr_event, + chr, context); } if (d->focus != -1) { mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_OUT); @@ -853,6 +868,7 @@ typedef struct IOWatchPoll IOCanReadHandler *fd_can_read; GSourceFunc fd_read; void *opaque; + GMainContext *context; } IOWatchPoll; static IOWatchPoll *io_watch_poll_from_source(GSource *source) @@ -860,7 +876,8 @@ static IOWatchPoll *io_watch_poll_from_source(GSource *source) return container_of(source, IOWatchPoll, parent); } -static gboolean io_watch_poll_prepare(GSource *source, gint *timeout_) +static gboolean io_watch_poll_prepare(GSource *source, + gint *timeout_) { IOWatchPoll *iwp = io_watch_poll_from_source(source); bool now_active = iwp->fd_can_read(iwp->opaque) > 0; @@ -873,7 +890,7 @@ static gboolean io_watch_poll_prepare(GSource *source, gint *timeout_) iwp->src = qio_channel_create_watch( iwp->ioc, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL); g_source_set_callback(iwp->src, iwp->fd_read, iwp->opaque, NULL); - g_source_attach(iwp->src, NULL); + g_source_attach(iwp->src, iwp->context); } else { g_source_destroy(iwp->src); g_source_unref(iwp->src); @@ -920,19 +937,22 @@ static GSourceFuncs io_watch_poll_funcs = { static guint io_add_watch_poll(QIOChannel *ioc, IOCanReadHandler *fd_can_read, QIOChannelFunc fd_read, - gpointer user_data) + gpointer user_data, + GMainContext *context) { IOWatchPoll *iwp; int tag; - iwp = (IOWatchPoll *) g_source_new(&io_watch_poll_funcs, sizeof(IOWatchPoll)); + iwp = (IOWatchPoll *) g_source_new(&io_watch_poll_funcs, + sizeof(IOWatchPoll)); iwp->fd_can_read = fd_can_read; iwp->opaque = user_data; iwp->ioc = ioc; iwp->fd_read = (GSourceFunc) fd_read; iwp->src = NULL; + iwp->context = context; - tag = g_source_attach(&iwp->parent, NULL); + tag = g_source_attach(&iwp->parent, context); g_source_unref(&iwp->parent); return tag; } @@ -1064,7 +1084,8 @@ static GSource *fd_chr_add_watch(CharDriverState *chr, GIOCondition cond) return qio_channel_create_watch(s->ioc_out, cond); } -static void fd_chr_update_read_handler(CharDriverState *chr) +static void fd_chr_update_read_handler(CharDriverState *chr, + GMainContext *context) { FDCharDriver *s = chr->opaque; @@ -1072,7 +1093,8 @@ static void fd_chr_update_read_handler(CharDriverState *chr) if (s->ioc_in) { chr->fd_in_tag = io_add_watch_poll(s->ioc_in, fd_chr_read_poll, - fd_chr_read, chr); + fd_chr_read, chr, + context); } } @@ -1319,7 +1341,8 @@ static void pty_chr_update_read_handler_locked(CharDriverState *chr) } } -static void pty_chr_update_read_handler(CharDriverState *chr) +static void pty_chr_update_read_handler(CharDriverState *chr, + GMainContext *context) { qemu_mutex_lock(&chr->chr_write_lock); pty_chr_update_read_handler_locked(chr); @@ -1423,7 +1446,8 @@ static void pty_chr_state(CharDriverState *chr, int connected) if (!chr->fd_in_tag) { chr->fd_in_tag = io_add_watch_poll(s->ioc, pty_chr_read_poll, - pty_chr_read, chr); + pty_chr_read, + chr, NULL); } } } @@ -2565,7 +2589,8 @@ static gboolean udp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque) return TRUE; } -static void udp_chr_update_read_handler(CharDriverState *chr) +static void udp_chr_update_read_handler(CharDriverState *chr, + GMainContext *context) { NetCharDriver *s = chr->opaque; @@ -2573,7 +2598,8 @@ static void udp_chr_update_read_handler(CharDriverState *chr) if (s->ioc) { chr->fd_in_tag = io_add_watch_poll(s->ioc, udp_chr_read_poll, - udp_chr_read, chr); + udp_chr_read, chr, + context); } } @@ -2976,12 +3002,14 @@ static void tcp_chr_connect(void *opaque) if (s->ioc) { chr->fd_in_tag = io_add_watch_poll(s->ioc, tcp_chr_read_poll, - tcp_chr_read, chr); + tcp_chr_read, + chr, NULL); } qemu_chr_be_generic_open(chr); } -static void tcp_chr_update_read_handler(CharDriverState *chr) +static void tcp_chr_update_read_handler(CharDriverState *chr, + GMainContext *context) { TCPCharDriver *s = chr->opaque; @@ -2993,7 +3021,8 @@ static void tcp_chr_update_read_handler(CharDriverState *chr) if (s->ioc) { chr->fd_in_tag = io_add_watch_poll(s->ioc, tcp_chr_read_poll, - tcp_chr_read, chr); + tcp_chr_read, chr, + context); } } From 7dce4e6fd2baa4935074fa03736588017c1a8b84 Mon Sep 17 00:00:00 2001 From: Zhang Chen Date: Tue, 27 Sep 2016 10:22:26 +0800 Subject: [PATCH 314/723] colo-compare: introduce colo compare initialization This a COLO net ascii figure: Primary qemu Secondary qemu +--------------------------------------------------------------+ +----------------------------------------------------------------+ | +----------------------------------------------------------+ | | +-----------------------------------------------------------+ | | | | | | | | | | | guest | | | | guest | | | | | | | | | | | +-------^--------------------------+-----------------------+ | | +---------------------+--------+----------------------------+ | | | | | | ^ | | | | | | | | | | | | +------------------------------------------------------+ | | | | |netfilter| | | | | | netfilter | | | | +----------+ +----------------------------+ | | | +-----------------------------------------------------------+ | | | | | | | out | | | | | | filter excute order | | | | | | +-----------------------------+ | | | | | | +-------------------> | | | | | | | | | | | | | | | | TCP | | | | +-----+--+-+ +-----v----+ +-----v----+ |pri +----+----+sec| | | | +------------+ +---+----+---v+rewriter++ +------------+ | | | | | | | | | | |in | |in | | | | | | | | | | | | | | | | filter | | filter | | filter +------> colo <------+ +--------> filter +--> adjust | adjust +--> filter | | | | | | mirror | |redirector| |redirector| | | compare | | | | | | redirector | | ack | seq | | redirector | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +----^-----+ +----+-----+ +----------+ | +---------+ | | | | +------------+ +--------+--------------+ +---+--------+ | | | | | tx | rx rx | | | | | tx all | rx | | | | | | | | | | +-----------------------------------------------------------+ | | | | +--------------+ | | | | | | | | | filter excute order | | | | | | | | | | +----------------> | | | +--------------------------------------------------------+ | | +-----------------------------------------+ | | | | | | | | | +--------------------------------------------------------------+ +----------------------------------------------------------------+ |guest receive | guest send | | +--------+----------------------------v------------------------+ | | NOTE: filter direction is rx/tx/all | tap | rx:receive packets sent to the netdev | | tx:receive packets sent by the netdev +--------------------------------------------------------------+ In COLO-compare, we do packet comparing job. Packets coming from the primary char indev will be sent to outdev. Packets coming from the secondary char dev will be dropped after comparing. colo-comapre need two input chardev and one output chardev: primary_in=chardev1-id (source: primary send packet) secondary_in=chardev2-id (source: secondary send packet) outdev=chardev3-id usage: primary: -netdev tap,id=hn0,vhost=off,script=/etc/qemu-ifup,downscript=/etc/qemu-ifdown -device e1000,id=e0,netdev=hn0,mac=52:a4:00:12:78:66 -chardev socket,id=mirror0,host=3.3.3.3,port=9003,server,nowait -chardev socket,id=compare1,host=3.3.3.3,port=9004,server,nowait -chardev socket,id=compare0,host=3.3.3.3,port=9001,server,nowait -chardev socket,id=compare0-0,host=3.3.3.3,port=9001 -chardev socket,id=compare_out,host=3.3.3.3,port=9005,server,nowait -chardev socket,id=compare_out0,host=3.3.3.3,port=9005 -object filter-mirror,id=m0,netdev=hn0,queue=tx,outdev=mirror0 -object filter-redirector,netdev=hn0,id=redire0,queue=rx,indev=compare_out -object filter-redirector,netdev=hn0,id=redire1,queue=rx,outdev=compare0 -object colo-compare,id=comp0,primary_in=compare0-0,secondary_in=compare1,outdev=compare_out0 secondary: -netdev tap,id=hn0,vhost=off,script=/etc/qemu-ifup,down script=/etc/qemu-ifdown -device e1000,netdev=hn0,mac=52:a4:00:12:78:66 -chardev socket,id=red0,host=3.3.3.3,port=9003 -chardev socket,id=red1,host=3.3.3.3,port=9004 -object filter-redirector,id=f1,netdev=hn0,queue=tx,indev=red0 -object filter-redirector,id=f2,netdev=hn0,queue=rx,outdev=red1 Signed-off-by: Zhang Chen Signed-off-by: Li Zhijian Signed-off-by: Wen Congyang Signed-off-by: Jason Wang --- net/Makefile.objs | 1 + net/colo-compare.c | 270 +++++++++++++++++++++++++++++++++++++++++++++ qemu-options.hx | 39 +++++++ vl.c | 3 +- 4 files changed, 312 insertions(+), 1 deletion(-) create mode 100644 net/colo-compare.c diff --git a/net/Makefile.objs b/net/Makefile.objs index b7c22fddbf2..ba92f73a51c 100644 --- a/net/Makefile.objs +++ b/net/Makefile.objs @@ -16,3 +16,4 @@ common-obj-$(CONFIG_NETMAP) += netmap.o common-obj-y += filter.o common-obj-y += filter-buffer.o common-obj-y += filter-mirror.o +common-obj-y += colo-compare.o diff --git a/net/colo-compare.c b/net/colo-compare.c new file mode 100644 index 00000000000..dc5f70ca503 --- /dev/null +++ b/net/colo-compare.c @@ -0,0 +1,270 @@ +/* + * COarse-grain LOck-stepping Virtual Machines for Non-stop Service (COLO) + * (a.k.a. Fault Tolerance or Continuous Replication) + * + * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD. + * Copyright (c) 2016 FUJITSU LIMITED + * Copyright (c) 2016 Intel Corporation + * + * Author: Zhang Chen + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * later. See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu/error-report.h" +#include "qemu-common.h" +#include "qapi/qmp/qerror.h" +#include "qapi/error.h" +#include "net/net.h" +#include "qom/object_interfaces.h" +#include "qemu/iov.h" +#include "qom/object.h" +#include "qemu/typedefs.h" +#include "net/queue.h" +#include "sysemu/char.h" +#include "qemu/sockets.h" +#include "qapi-visit.h" + +#define TYPE_COLO_COMPARE "colo-compare" +#define COLO_COMPARE(obj) \ + OBJECT_CHECK(CompareState, (obj), TYPE_COLO_COMPARE) + +#define COMPARE_READ_LEN_MAX NET_BUFSIZE + +typedef struct CompareState { + Object parent; + + char *pri_indev; + char *sec_indev; + char *outdev; + CharDriverState *chr_pri_in; + CharDriverState *chr_sec_in; + CharDriverState *chr_out; + SocketReadState pri_rs; + SocketReadState sec_rs; +} CompareState; + +typedef struct CompareClass { + ObjectClass parent_class; +} CompareClass; + +typedef struct CompareChardevProps { + bool is_socket; +} CompareChardevProps; + +static char *compare_get_pri_indev(Object *obj, Error **errp) +{ + CompareState *s = COLO_COMPARE(obj); + + return g_strdup(s->pri_indev); +} + +static void compare_set_pri_indev(Object *obj, const char *value, Error **errp) +{ + CompareState *s = COLO_COMPARE(obj); + + g_free(s->pri_indev); + s->pri_indev = g_strdup(value); +} + +static char *compare_get_sec_indev(Object *obj, Error **errp) +{ + CompareState *s = COLO_COMPARE(obj); + + return g_strdup(s->sec_indev); +} + +static void compare_set_sec_indev(Object *obj, const char *value, Error **errp) +{ + CompareState *s = COLO_COMPARE(obj); + + g_free(s->sec_indev); + s->sec_indev = g_strdup(value); +} + +static char *compare_get_outdev(Object *obj, Error **errp) +{ + CompareState *s = COLO_COMPARE(obj); + + return g_strdup(s->outdev); +} + +static void compare_set_outdev(Object *obj, const char *value, Error **errp) +{ + CompareState *s = COLO_COMPARE(obj); + + g_free(s->outdev); + s->outdev = g_strdup(value); +} + +static void compare_pri_rs_finalize(SocketReadState *pri_rs) +{ + /* if packet_enqueue pri pkt failed we will send unsupported packet */ +} + +static void compare_sec_rs_finalize(SocketReadState *sec_rs) +{ + /* if packet_enqueue sec pkt failed we will notify trace */ +} + +static int compare_chardev_opts(void *opaque, + const char *name, const char *value, + Error **errp) +{ + CompareChardevProps *props = opaque; + + if (strcmp(name, "backend") == 0 && + strcmp(value, "socket") == 0) { + props->is_socket = true; + return 0; + } else if (strcmp(name, "host") == 0 || + (strcmp(name, "port") == 0) || + (strcmp(name, "server") == 0) || + (strcmp(name, "wait") == 0) || + (strcmp(name, "path") == 0)) { + return 0; + } else { + error_setg(errp, + "COLO-compare does not support a chardev with option %s=%s", + name, value); + return -1; + } +} + +/* + * Return 0 is success. + * Return 1 is failed. + */ +static int find_and_check_chardev(CharDriverState **chr, + char *chr_name, + Error **errp) +{ + CompareChardevProps props; + + *chr = qemu_chr_find(chr_name); + if (*chr == NULL) { + error_setg(errp, "Device '%s' not found", + chr_name); + return 1; + } + + memset(&props, 0, sizeof(props)); + if (qemu_opt_foreach((*chr)->opts, compare_chardev_opts, &props, errp)) { + return 1; + } + + if (!props.is_socket) { + error_setg(errp, "chardev \"%s\" is not a tcp socket", + chr_name); + return 1; + } + return 0; +} + +/* + * Called from the main thread on the primary + * to setup colo-compare. + */ +static void colo_compare_complete(UserCreatable *uc, Error **errp) +{ + CompareState *s = COLO_COMPARE(uc); + + if (!s->pri_indev || !s->sec_indev || !s->outdev) { + error_setg(errp, "colo compare needs 'primary_in' ," + "'secondary_in','outdev' property set"); + return; + } else if (!strcmp(s->pri_indev, s->outdev) || + !strcmp(s->sec_indev, s->outdev) || + !strcmp(s->pri_indev, s->sec_indev)) { + error_setg(errp, "'indev' and 'outdev' could not be same " + "for compare module"); + return; + } + + if (find_and_check_chardev(&s->chr_pri_in, s->pri_indev, errp)) { + return; + } + + if (find_and_check_chardev(&s->chr_sec_in, s->sec_indev, errp)) { + return; + } + + if (find_and_check_chardev(&s->chr_out, s->outdev, errp)) { + return; + } + + qemu_chr_fe_claim_no_fail(s->chr_pri_in); + + qemu_chr_fe_claim_no_fail(s->chr_sec_in); + + qemu_chr_fe_claim_no_fail(s->chr_out); + + net_socket_rs_init(&s->pri_rs, compare_pri_rs_finalize); + net_socket_rs_init(&s->sec_rs, compare_sec_rs_finalize); + + return; +} + +static void colo_compare_class_init(ObjectClass *oc, void *data) +{ + UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); + + ucc->complete = colo_compare_complete; +} + +static void colo_compare_init(Object *obj) +{ + object_property_add_str(obj, "primary_in", + compare_get_pri_indev, compare_set_pri_indev, + NULL); + object_property_add_str(obj, "secondary_in", + compare_get_sec_indev, compare_set_sec_indev, + NULL); + object_property_add_str(obj, "outdev", + compare_get_outdev, compare_set_outdev, + NULL); +} + +static void colo_compare_finalize(Object *obj) +{ + CompareState *s = COLO_COMPARE(obj); + + if (s->chr_pri_in) { + qemu_chr_add_handlers(s->chr_pri_in, NULL, NULL, NULL, NULL); + qemu_chr_fe_release(s->chr_pri_in); + } + if (s->chr_sec_in) { + qemu_chr_add_handlers(s->chr_sec_in, NULL, NULL, NULL, NULL); + qemu_chr_fe_release(s->chr_sec_in); + } + if (s->chr_out) { + qemu_chr_fe_release(s->chr_out); + } + + g_free(s->pri_indev); + g_free(s->sec_indev); + g_free(s->outdev); +} + +static const TypeInfo colo_compare_info = { + .name = TYPE_COLO_COMPARE, + .parent = TYPE_OBJECT, + .instance_size = sizeof(CompareState), + .instance_init = colo_compare_init, + .instance_finalize = colo_compare_finalize, + .class_size = sizeof(CompareClass), + .class_init = colo_compare_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_USER_CREATABLE }, + { } + } +}; + +static void register_types(void) +{ + type_register_static(&colo_compare_info); +} + +type_init(register_types); diff --git a/qemu-options.hx b/qemu-options.hx index 0b621bb99e8..d0ed69aa106 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -3894,6 +3894,45 @@ Dump the network traffic on netdev @var{dev} to the file specified by The file format is libpcap, so it can be analyzed with tools such as tcpdump or Wireshark. +@item -object colo-compare,id=@var{id},primary_in=@var{chardevid},secondary_in=@var{chardevid}, +outdev=@var{chardevid} + +Colo-compare gets packet from primary_in@var{chardevid} and secondary_in@var{chardevid}, than compare primary packet with +secondary packet. If the packets are same, we will output primary +packet to outdev@var{chardevid}, else we will notify colo-frame +do checkpoint and send primary packet to outdev@var{chardevid}. + +we must use it with the help of filter-mirror and filter-redirector. + +@example + +primary: +-netdev tap,id=hn0,vhost=off,script=/etc/qemu-ifup,downscript=/etc/qemu-ifdown +-device e1000,id=e0,netdev=hn0,mac=52:a4:00:12:78:66 +-chardev socket,id=mirror0,host=3.3.3.3,port=9003,server,nowait +-chardev socket,id=compare1,host=3.3.3.3,port=9004,server,nowait +-chardev socket,id=compare0,host=3.3.3.3,port=9001,server,nowait +-chardev socket,id=compare0-0,host=3.3.3.3,port=9001 +-chardev socket,id=compare_out,host=3.3.3.3,port=9005,server,nowait +-chardev socket,id=compare_out0,host=3.3.3.3,port=9005 +-object filter-mirror,id=m0,netdev=hn0,queue=tx,outdev=mirror0 +-object filter-redirector,netdev=hn0,id=redire0,queue=rx,indev=compare_out +-object filter-redirector,netdev=hn0,id=redire1,queue=rx,outdev=compare0 +-object colo-compare,id=comp0,primary_in=compare0-0,secondary_in=compare1,outdev=compare_out0 + +secondary: +-netdev tap,id=hn0,vhost=off,script=/etc/qemu-ifup,down script=/etc/qemu-ifdown +-device e1000,netdev=hn0,mac=52:a4:00:12:78:66 +-chardev socket,id=red0,host=3.3.3.3,port=9003 +-chardev socket,id=red1,host=3.3.3.3,port=9004 +-object filter-redirector,id=f1,netdev=hn0,queue=tx,indev=red0 +-object filter-redirector,id=f2,netdev=hn0,queue=rx,outdev=red1 + +@end example + +If you want to know the detail of above command line, you can read +the colo-compare git log. + @item -object secret,id=@var{id},data=@var{string},format=@var{raw|base64}[,keyid=@var{secretid},iv=@var{string}] @item -object secret,id=@var{id},file=@var{filename},format=@var{raw|base64}[,keyid=@var{secretid},iv=@var{string}] diff --git a/vl.c b/vl.c index 215a6f9c7a0..7dadb9e1a4d 100644 --- a/vl.c +++ b/vl.c @@ -2845,7 +2845,8 @@ static bool object_create_initial(const char *type) if (g_str_equal(type, "filter-buffer") || g_str_equal(type, "filter-dump") || g_str_equal(type, "filter-mirror") || - g_str_equal(type, "filter-redirector")) { + g_str_equal(type, "filter-redirector") || + g_str_equal(type, "colo-compare")) { return false; } From 59509ec16b7ee92b3f8261c554023aa1d3169317 Mon Sep 17 00:00:00 2001 From: Zhang Chen Date: Tue, 27 Sep 2016 10:22:27 +0800 Subject: [PATCH 315/723] net/colo.c: add colo.c to define and handle packet The net/colo.c is used by colo-compare and filter-rewriter. this can share common data structure like net packet, and other functions. Signed-off-by: Zhang Chen Signed-off-by: Li Zhijian Signed-off-by: Wen Congyang Signed-off-by: Jason Wang --- net/Makefile.objs | 1 + net/colo-compare.c | 114 +++++++++++++++++++++++++++++++++++++++++++-- net/colo.c | 86 ++++++++++++++++++++++++++++++++++ net/colo.h | 37 +++++++++++++++ trace-events | 6 +++ 5 files changed, 240 insertions(+), 4 deletions(-) create mode 100644 net/colo.c create mode 100644 net/colo.h diff --git a/net/Makefile.objs b/net/Makefile.objs index ba92f73a51c..beb504bbff1 100644 --- a/net/Makefile.objs +++ b/net/Makefile.objs @@ -17,3 +17,4 @@ common-obj-y += filter.o common-obj-y += filter-buffer.o common-obj-y += filter-mirror.o common-obj-y += colo-compare.o +common-obj-y += colo.o diff --git a/net/colo-compare.c b/net/colo-compare.c index dc5f70ca503..cea9b27dd46 100644 --- a/net/colo-compare.c +++ b/net/colo-compare.c @@ -14,6 +14,7 @@ #include "qemu/osdep.h" #include "qemu/error-report.h" +#include "trace.h" #include "qemu-common.h" #include "qapi/qmp/qerror.h" #include "qapi/error.h" @@ -26,13 +27,34 @@ #include "sysemu/char.h" #include "qemu/sockets.h" #include "qapi-visit.h" +#include "net/colo.h" #define TYPE_COLO_COMPARE "colo-compare" #define COLO_COMPARE(obj) \ OBJECT_CHECK(CompareState, (obj), TYPE_COLO_COMPARE) -#define COMPARE_READ_LEN_MAX NET_BUFSIZE - +/* + + CompareState ++ + | | + +---------------+ +---------------+ +---------------+ + |conn list +--->conn +--------->conn | + +---------------+ +---------------+ +---------------+ + | | | | | | + +---------------+ +---v----+ +---v----+ +---v----+ +---v----+ + |primary | |secondary |primary | |secondary + |packet | |packet + |packet | |packet + + +--------+ +--------+ +--------+ +--------+ + | | | | + +---v----+ +---v----+ +---v----+ +---v----+ + |primary | |secondary |primary | |secondary + |packet | |packet + |packet | |packet + + +--------+ +--------+ +--------+ +--------+ + | | | | + +---v----+ +---v----+ +---v----+ +---v----+ + |primary | |secondary |primary | |secondary + |packet | |packet + |packet | |packet + + +--------+ +--------+ +--------+ +--------+ +*/ typedef struct CompareState { Object parent; @@ -44,6 +66,9 @@ typedef struct CompareState { CharDriverState *chr_out; SocketReadState pri_rs; SocketReadState sec_rs; + + /* hashtable to save connection */ + GHashTable *connection_track_table; } CompareState; typedef struct CompareClass { @@ -54,6 +79,76 @@ typedef struct CompareChardevProps { bool is_socket; } CompareChardevProps; +enum { + PRIMARY_IN = 0, + SECONDARY_IN, +}; + +static int compare_chr_send(CharDriverState *out, + const uint8_t *buf, + uint32_t size); + +/* + * Return 0 on success, if return -1 means the pkt + * is unsupported(arp and ipv6) and will be sent later + */ +static int packet_enqueue(CompareState *s, int mode) +{ + Packet *pkt = NULL; + + if (mode == PRIMARY_IN) { + pkt = packet_new(s->pri_rs.buf, s->pri_rs.packet_len); + } else { + pkt = packet_new(s->sec_rs.buf, s->sec_rs.packet_len); + } + + if (parse_packet_early(pkt)) { + packet_destroy(pkt, NULL); + pkt = NULL; + return -1; + } + /* TODO: get connection key from pkt */ + + /* + * TODO: use connection key get conn from + * connection_track_table + */ + + /* + * TODO: insert pkt to it's conn->primary_list + * or conn->secondary_list + */ + + return 0; +} + +static int compare_chr_send(CharDriverState *out, + const uint8_t *buf, + uint32_t size) +{ + int ret = 0; + uint32_t len = htonl(size); + + if (!size) { + return 0; + } + + ret = qemu_chr_fe_write_all(out, (uint8_t *)&len, sizeof(len)); + if (ret != sizeof(len)) { + goto err; + } + + ret = qemu_chr_fe_write_all(out, (uint8_t *)buf, size); + if (ret != size) { + goto err; + } + + return 0; + +err: + return ret < 0 ? ret : -EIO; +} + static char *compare_get_pri_indev(Object *obj, Error **errp) { CompareState *s = COLO_COMPARE(obj); @@ -101,12 +196,21 @@ static void compare_set_outdev(Object *obj, const char *value, Error **errp) static void compare_pri_rs_finalize(SocketReadState *pri_rs) { - /* if packet_enqueue pri pkt failed we will send unsupported packet */ + CompareState *s = container_of(pri_rs, CompareState, pri_rs); + + if (packet_enqueue(s, PRIMARY_IN)) { + trace_colo_compare_main("primary: unsupported packet in"); + compare_chr_send(s->chr_out, pri_rs->buf, pri_rs->packet_len); + } } static void compare_sec_rs_finalize(SocketReadState *sec_rs) { - /* if packet_enqueue sec pkt failed we will notify trace */ + CompareState *s = container_of(sec_rs, CompareState, sec_rs); + + if (packet_enqueue(s, SECONDARY_IN)) { + trace_colo_compare_main("secondary: unsupported packet in"); + } } static int compare_chardev_opts(void *opaque, @@ -204,6 +308,8 @@ static void colo_compare_complete(UserCreatable *uc, Error **errp) net_socket_rs_init(&s->pri_rs, compare_pri_rs_finalize); net_socket_rs_init(&s->sec_rs, compare_sec_rs_finalize); + /* use g_hash_table_new_full() to new a hashtable */ + return; } diff --git a/net/colo.c b/net/colo.c new file mode 100644 index 00000000000..8582175b420 --- /dev/null +++ b/net/colo.c @@ -0,0 +1,86 @@ +/* + * COarse-grain LOck-stepping Virtual Machines for Non-stop Service (COLO) + * (a.k.a. Fault Tolerance or Continuous Replication) + * + * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD. + * Copyright (c) 2016 FUJITSU LIMITED + * Copyright (c) 2016 Intel Corporation + * + * Author: Zhang Chen + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * later. See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "trace.h" +#include "net/colo.h" + +int parse_packet_early(Packet *pkt) +{ + int network_length; + static const uint8_t vlan[] = {0x81, 0x00}; + uint8_t *data = pkt->data; + uint16_t l3_proto; + ssize_t l2hdr_len = eth_get_l2_hdr_length(data); + + if (pkt->size < ETH_HLEN) { + trace_colo_proxy_main("pkt->size < ETH_HLEN"); + return 1; + } + + /* + * TODO: support vlan. + */ + if (!memcmp(&data[12], vlan, sizeof(vlan))) { + trace_colo_proxy_main("COLO-proxy don't support vlan"); + return 1; + } + + pkt->network_header = data + l2hdr_len; + + const struct iovec l2vec = { + .iov_base = (void *) data, + .iov_len = l2hdr_len + }; + l3_proto = eth_get_l3_proto(&l2vec, 1, l2hdr_len); + + if (l3_proto != ETH_P_IP) { + return 1; + } + + network_length = pkt->ip->ip_hl * 4; + if (pkt->size < l2hdr_len + network_length) { + trace_colo_proxy_main("pkt->size < network_header + network_length"); + return 1; + } + pkt->transport_header = pkt->network_header + network_length; + + return 0; +} + +Packet *packet_new(const void *data, int size) +{ + Packet *pkt = g_slice_new(Packet); + + pkt->data = g_memdup(data, size); + pkt->size = size; + + return pkt; +} + +void packet_destroy(void *opaque, void *user_data) +{ + Packet *pkt = opaque; + + g_free(pkt->data); + g_slice_free(Packet, pkt); +} + +/* + * Clear hashtable, stop this hash growing really huge + */ +void connection_hashtable_reset(GHashTable *connection_track_table) +{ + g_hash_table_remove_all(connection_track_table); +} diff --git a/net/colo.h b/net/colo.h new file mode 100644 index 00000000000..e211eda4c69 --- /dev/null +++ b/net/colo.h @@ -0,0 +1,37 @@ +/* + * COarse-grain LOck-stepping Virtual Machines for Non-stop Service (COLO) + * (a.k.a. Fault Tolerance or Continuous Replication) + * + * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD. + * Copyright (c) 2016 FUJITSU LIMITED + * Copyright (c) 2016 Intel Corporation + * + * Author: Zhang Chen + * + * 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 QEMU_COLO_PROXY_H +#define QEMU_COLO_PROXY_H + +#include "slirp/slirp.h" + +#define HASHTABLE_MAX_SIZE 16384 + +typedef struct Packet { + void *data; + union { + uint8_t *network_header; + struct ip *ip; + }; + uint8_t *transport_header; + int size; +} Packet; + +int parse_packet_early(Packet *pkt); +void connection_hashtable_reset(GHashTable *connection_track_table); +Packet *packet_new(const void *data, int size); +void packet_destroy(void *opaque, void *user_data); + +#endif /* QEMU_COLO_PROXY_H */ diff --git a/trace-events b/trace-events index 8d59631ae83..9b4186f9b64 100644 --- a/trace-events +++ b/trace-events @@ -139,6 +139,12 @@ memory_region_subpage_write(int cpu_index, void *mr, uint64_t offset, uint64_t v memory_region_tb_read(int cpu_index, uint64_t addr, uint64_t value, unsigned size) "cpu %d addr %#"PRIx64" value %#"PRIx64" size %u" memory_region_tb_write(int cpu_index, uint64_t addr, uint64_t value, unsigned size) "cpu %d addr %#"PRIx64" value %#"PRIx64" size %u" +# net/colo.c +colo_proxy_main(const char *chr) ": %s" + +# net/colo-compare.c +colo_compare_main(const char *chr) ": %s" + ### Guest events, keep at bottom # @vaddr: Access' virtual address. From ccf0426c09f0989d9874f7c63aff58376e1d972a Mon Sep 17 00:00:00 2001 From: Zhang Chen Date: Tue, 27 Sep 2016 10:22:28 +0800 Subject: [PATCH 316/723] Jhash: add linux kernel jhashtable in qemu Jhash will be used by colo-compare and filter-rewriter to save and lookup net connection info Signed-off-by: Zhang Chen Signed-off-by: Li Zhijian Signed-off-by: Wen Congyang Signed-off-by: Jason Wang --- include/qemu/jhash.h | 59 ++++++++++++++++++++++++++++++++++++++++++++ net/colo.h | 1 + 2 files changed, 60 insertions(+) create mode 100644 include/qemu/jhash.h diff --git a/include/qemu/jhash.h b/include/qemu/jhash.h new file mode 100644 index 00000000000..72222426151 --- /dev/null +++ b/include/qemu/jhash.h @@ -0,0 +1,59 @@ +/* jhash.h: Jenkins hash support. + * + * Copyright (C) 2006. Bob Jenkins (bob_jenkins@burtleburtle.net) + * + * http://burtleburtle.net/bob/hash/ + * + * These are the credits from Bob's sources: + * + * lookup3.c, by Bob Jenkins, May 2006, Public Domain. + * + * These are functions for producing 32-bit hashes for hash table lookup. + * hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() + * are externally useful functions. Routines to test the hash are included + * if SELF_TEST is defined. You can use this free for any purpose. It's in + * the public domain. It has no warranty. + * + * Copyright (C) 2009-2010 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu) + * + * I've modified Bob's hash to be useful in the Linux kernel, and + * any bugs present are my fault. + * Jozsef + */ + +#ifndef QEMU_JHASH_H__ +#define QEMU_JHASH_H__ + +#include "qemu/bitops.h" + +/* + * hashtable relation copy from linux kernel jhash + */ + +/* __jhash_mix -- mix 3 32-bit values reversibly. */ +#define __jhash_mix(a, b, c) \ +{ \ + a -= c; a ^= rol32(c, 4); c += b; \ + b -= a; b ^= rol32(a, 6); a += c; \ + c -= b; c ^= rol32(b, 8); b += a; \ + a -= c; a ^= rol32(c, 16); c += b; \ + b -= a; b ^= rol32(a, 19); a += c; \ + c -= b; c ^= rol32(b, 4); b += a; \ +} + +/* __jhash_final - final mixing of 3 32-bit values (a,b,c) into c */ +#define __jhash_final(a, b, c) \ +{ \ + c ^= b; c -= rol32(b, 14); \ + a ^= c; a -= rol32(c, 11); \ + b ^= a; b -= rol32(a, 25); \ + c ^= b; c -= rol32(b, 16); \ + a ^= c; a -= rol32(c, 4); \ + b ^= a; b -= rol32(a, 14); \ + c ^= b; c -= rol32(b, 24); \ +} + +/* An arbitrary initial parameter */ +#define JHASH_INITVAL 0xdeadbeef + +#endif /* QEMU_JHASH_H__ */ diff --git a/net/colo.h b/net/colo.h index e211eda4c69..05dc0b63cb6 100644 --- a/net/colo.h +++ b/net/colo.h @@ -16,6 +16,7 @@ #define QEMU_COLO_PROXY_H #include "slirp/slirp.h" +#include "qemu/jhash.h" #define HASHTABLE_MAX_SIZE 16384 From b6540d403d28d9ecbbf0ab76b82fb0fa92dc75ce Mon Sep 17 00:00:00 2001 From: Zhang Chen Date: Tue, 27 Sep 2016 10:22:29 +0800 Subject: [PATCH 317/723] colo-compare: track connection and enqueue packet In this patch we use kernel jhash table to track connection, and then enqueue net packet like this: + CompareState ++ | | +---------------+ +---------------+ +---------------+ |conn list +--->conn +--------->conn | +---------------+ +---------------+ +---------------+ | | | | | | +---------------+ +---v----+ +---v----+ +---v----+ +---v----+ |primary | |secondary |primary | |secondary |packet | |packet + |packet | |packet + +--------+ +--------+ +--------+ +--------+ | | | | +---v----+ +---v----+ +---v----+ +---v----+ |primary | |secondary |primary | |secondary |packet | |packet + |packet | |packet + +--------+ +--------+ +--------+ +--------+ | | | | +---v----+ +---v----+ +---v----+ +---v----+ |primary | |secondary |primary | |secondary |packet | |packet + |packet | |packet + +--------+ +--------+ +--------+ +--------+ We use conn_list to record connection info. When we want to enqueue a packet, firstly get the connection from connection_track_table. then push the packet to g_queue(pri/sec) in it's own conn. Signed-off-by: Zhang Chen Signed-off-by: Li Zhijian Signed-off-by: Wen Congyang Signed-off-by: Jason Wang --- net/colo-compare.c | 53 +++++++++++++++++----- net/colo.c | 108 +++++++++++++++++++++++++++++++++++++++++++++ net/colo.h | 39 ++++++++++++++++ 3 files changed, 190 insertions(+), 10 deletions(-) diff --git a/net/colo-compare.c b/net/colo-compare.c index cea9b27dd46..bcc1beb610c 100644 --- a/net/colo-compare.c +++ b/net/colo-compare.c @@ -33,6 +33,8 @@ #define COLO_COMPARE(obj) \ OBJECT_CHECK(CompareState, (obj), TYPE_COLO_COMPARE) +#define MAX_QUEUE_SIZE 1024 + /* + CompareState ++ | | @@ -67,6 +69,11 @@ typedef struct CompareState { SocketReadState pri_rs; SocketReadState sec_rs; + /* connection list: the connections belonged to this NIC could be found + * in this list. + * element type: Connection + */ + GQueue conn_list; /* hashtable to save connection */ GHashTable *connection_track_table; } CompareState; @@ -94,7 +101,9 @@ static int compare_chr_send(CharDriverState *out, */ static int packet_enqueue(CompareState *s, int mode) { + ConnectionKey key; Packet *pkt = NULL; + Connection *conn; if (mode == PRIMARY_IN) { pkt = packet_new(s->pri_rs.buf, s->pri_rs.packet_len); @@ -107,17 +116,34 @@ static int packet_enqueue(CompareState *s, int mode) pkt = NULL; return -1; } - /* TODO: get connection key from pkt */ + fill_connection_key(pkt, &key); - /* - * TODO: use connection key get conn from - * connection_track_table - */ + conn = connection_get(s->connection_track_table, + &key, + &s->conn_list); - /* - * TODO: insert pkt to it's conn->primary_list - * or conn->secondary_list - */ + if (!conn->processing) { + g_queue_push_tail(&s->conn_list, conn); + conn->processing = true; + } + + if (mode == PRIMARY_IN) { + if (g_queue_get_length(&conn->primary_list) <= + MAX_QUEUE_SIZE) { + g_queue_push_tail(&conn->primary_list, pkt); + } else { + error_report("colo compare primary queue size too big," + "drop packet"); + } + } else { + if (g_queue_get_length(&conn->secondary_list) <= + MAX_QUEUE_SIZE) { + g_queue_push_tail(&conn->secondary_list, pkt); + } else { + error_report("colo compare secondary queue size too big," + "drop packet"); + } + } return 0; } @@ -308,7 +334,12 @@ static void colo_compare_complete(UserCreatable *uc, Error **errp) net_socket_rs_init(&s->pri_rs, compare_pri_rs_finalize); net_socket_rs_init(&s->sec_rs, compare_sec_rs_finalize); - /* use g_hash_table_new_full() to new a hashtable */ + g_queue_init(&s->conn_list); + + s->connection_track_table = g_hash_table_new_full(connection_key_hash, + connection_key_equal, + g_free, + connection_destroy); return; } @@ -349,6 +380,8 @@ static void colo_compare_finalize(Object *obj) qemu_chr_fe_release(s->chr_out); } + g_queue_free(&s->conn_list); + g_free(s->pri_indev); g_free(s->sec_indev); g_free(s->outdev); diff --git a/net/colo.c b/net/colo.c index 8582175b420..40b3b5e56c3 100644 --- a/net/colo.c +++ b/net/colo.c @@ -16,6 +16,29 @@ #include "trace.h" #include "net/colo.h" +uint32_t connection_key_hash(const void *opaque) +{ + const ConnectionKey *key = opaque; + uint32_t a, b, c; + + /* Jenkins hash */ + a = b = c = JHASH_INITVAL + sizeof(*key); + a += key->src.s_addr; + b += key->dst.s_addr; + c += (key->src_port | key->dst_port << 16); + __jhash_mix(a, b, c); + + a += key->ip_proto; + __jhash_final(a, b, c); + + return c; +} + +int connection_key_equal(const void *key1, const void *key2) +{ + return memcmp(key1, key2, sizeof(ConnectionKey)) == 0; +} + int parse_packet_early(Packet *pkt) { int network_length; @@ -59,6 +82,61 @@ int parse_packet_early(Packet *pkt) return 0; } +void fill_connection_key(Packet *pkt, ConnectionKey *key) +{ + uint32_t tmp_ports; + + memset(key, 0, sizeof(*key)); + key->ip_proto = pkt->ip->ip_p; + + switch (key->ip_proto) { + case IPPROTO_TCP: + case IPPROTO_UDP: + case IPPROTO_DCCP: + case IPPROTO_ESP: + case IPPROTO_SCTP: + case IPPROTO_UDPLITE: + tmp_ports = *(uint32_t *)(pkt->transport_header); + key->src = pkt->ip->ip_src; + key->dst = pkt->ip->ip_dst; + key->src_port = ntohs(tmp_ports & 0xffff); + key->dst_port = ntohs(tmp_ports >> 16); + break; + case IPPROTO_AH: + tmp_ports = *(uint32_t *)(pkt->transport_header + 4); + key->src = pkt->ip->ip_src; + key->dst = pkt->ip->ip_dst; + key->src_port = ntohs(tmp_ports & 0xffff); + key->dst_port = ntohs(tmp_ports >> 16); + break; + default: + break; + } +} + +Connection *connection_new(ConnectionKey *key) +{ + Connection *conn = g_slice_new(Connection); + + conn->ip_proto = key->ip_proto; + conn->processing = false; + g_queue_init(&conn->primary_list); + g_queue_init(&conn->secondary_list); + + return conn; +} + +void connection_destroy(void *opaque) +{ + Connection *conn = opaque; + + g_queue_foreach(&conn->primary_list, packet_destroy, NULL); + g_queue_free(&conn->primary_list); + g_queue_foreach(&conn->secondary_list, packet_destroy, NULL); + g_queue_free(&conn->secondary_list); + g_slice_free(Connection, conn); +} + Packet *packet_new(const void *data, int size) { Packet *pkt = g_slice_new(Packet); @@ -84,3 +162,33 @@ void connection_hashtable_reset(GHashTable *connection_track_table) { g_hash_table_remove_all(connection_track_table); } + +/* if not found, create a new connection and add to hash table */ +Connection *connection_get(GHashTable *connection_track_table, + ConnectionKey *key, + GQueue *conn_list) +{ + Connection *conn = g_hash_table_lookup(connection_track_table, key); + + if (conn == NULL) { + ConnectionKey *new_key = g_memdup(key, sizeof(*key)); + + conn = connection_new(key); + + if (g_hash_table_size(connection_track_table) > HASHTABLE_MAX_SIZE) { + trace_colo_proxy_main("colo proxy connection hashtable full," + " clear it"); + connection_hashtable_reset(connection_track_table); + /* + * clear the conn_list + */ + while (!g_queue_is_empty(conn_list)) { + connection_destroy(g_queue_pop_head(conn_list)); + } + } + + g_hash_table_insert(connection_track_table, new_key, conn); + } + + return conn; +} diff --git a/net/colo.h b/net/colo.h index 05dc0b63cb6..c511bcdeb9f 100644 --- a/net/colo.h +++ b/net/colo.h @@ -20,6 +20,18 @@ #define HASHTABLE_MAX_SIZE 16384 +#ifndef IPPROTO_DCCP +#define IPPROTO_DCCP 33 +#endif + +#ifndef IPPROTO_SCTP +#define IPPROTO_SCTP 132 +#endif + +#ifndef IPPROTO_UDPLITE +#define IPPROTO_UDPLITE 136 +#endif + typedef struct Packet { void *data; union { @@ -30,7 +42,34 @@ typedef struct Packet { int size; } Packet; +typedef struct ConnectionKey { + /* (src, dst) must be grouped, in the same way than in IP header */ + struct in_addr src; + struct in_addr dst; + uint16_t src_port; + uint16_t dst_port; + uint8_t ip_proto; +} QEMU_PACKED ConnectionKey; + +typedef struct Connection { + /* connection primary send queue: element type: Packet */ + GQueue primary_list; + /* connection secondary send queue: element type: Packet */ + GQueue secondary_list; + /* flag to enqueue unprocessed_connections */ + bool processing; + uint8_t ip_proto; +} Connection; + +uint32_t connection_key_hash(const void *opaque); +int connection_key_equal(const void *opaque1, const void *opaque2); int parse_packet_early(Packet *pkt); +void fill_connection_key(Packet *pkt, ConnectionKey *key); +Connection *connection_new(ConnectionKey *key); +void connection_destroy(void *opaque); +Connection *connection_get(GHashTable *connection_track_table, + ConnectionKey *key, + GQueue *conn_list); void connection_hashtable_reset(GHashTable *connection_track_table); Packet *packet_new(const void *data, int size); void packet_destroy(void *opaque, void *user_data); From 0682e15b19b2f41c0568142b42518b9471168597 Mon Sep 17 00:00:00 2001 From: Zhang Chen Date: Tue, 27 Sep 2016 10:22:30 +0800 Subject: [PATCH 318/723] colo-compare: introduce packet comparison thread If primary packet is same with secondary packet, we will send primary packet and drop secondary packet, otherwise notify COLO frame to do checkpoint. If primary packet comes but secondary packet does not, after REGULAR_PACKET_CHECK_MS milliseconds we set the primary packet as old_packet,then do a checkpoint. Signed-off-by: Zhang Chen Signed-off-by: Li Zhijian Signed-off-by: Wen Congyang Signed-off-by: Jason Wang --- net/colo-compare.c | 233 +++++++++++++++++++++++++++++++++++++++++++++ net/colo.c | 1 + net/colo.h | 3 + trace-events | 2 + 4 files changed, 239 insertions(+) diff --git a/net/colo-compare.c b/net/colo-compare.c index bcc1beb610c..9596c8b3086 100644 --- a/net/colo-compare.c +++ b/net/colo-compare.c @@ -33,8 +33,12 @@ #define COLO_COMPARE(obj) \ OBJECT_CHECK(CompareState, (obj), TYPE_COLO_COMPARE) +#define COMPARE_READ_LEN_MAX NET_BUFSIZE #define MAX_QUEUE_SIZE 1024 +/* TODO: Should be configurable */ +#define REGULAR_PACKET_CHECK_MS 3000 + /* + CompareState ++ | | @@ -76,6 +80,11 @@ typedef struct CompareState { GQueue conn_list; /* hashtable to save connection */ GHashTable *connection_track_table; + /* compare thread, a thread for each NIC */ + QemuThread thread; + /* Timer used on the primary to find packets that are never matched */ + QEMUTimer *timer; + QemuMutex timer_check_lock; } CompareState; typedef struct CompareClass { @@ -148,6 +157,118 @@ static int packet_enqueue(CompareState *s, int mode) return 0; } +/* + * The IP packets sent by primary and secondary + * will be compared in here + * TODO support ip fragment, Out-Of-Order + * return: 0 means packet same + * > 0 || < 0 means packet different + */ +static int colo_packet_compare(Packet *ppkt, Packet *spkt) +{ + trace_colo_compare_ip_info(ppkt->size, inet_ntoa(ppkt->ip->ip_src), + inet_ntoa(ppkt->ip->ip_dst), spkt->size, + inet_ntoa(spkt->ip->ip_src), + inet_ntoa(spkt->ip->ip_dst)); + + if (ppkt->size == spkt->size) { + return memcmp(ppkt->data, spkt->data, spkt->size); + } else { + return -1; + } +} + +static int colo_packet_compare_all(Packet *spkt, Packet *ppkt) +{ + trace_colo_compare_main("compare all"); + return colo_packet_compare(ppkt, spkt); +} + +static int colo_old_packet_check_one(Packet *pkt, int64_t *check_time) +{ + int64_t now = qemu_clock_get_ms(QEMU_CLOCK_HOST); + + if ((now - pkt->creation_ms) > (*check_time)) { + trace_colo_old_packet_check_found(pkt->creation_ms); + return 0; + } else { + return 1; + } +} + +static void colo_old_packet_check_one_conn(void *opaque, + void *user_data) +{ + Connection *conn = opaque; + GList *result = NULL; + int64_t check_time = REGULAR_PACKET_CHECK_MS; + + result = g_queue_find_custom(&conn->primary_list, + &check_time, + (GCompareFunc)colo_old_packet_check_one); + + if (result) { + /* do checkpoint will flush old packet */ + /* TODO: colo_notify_checkpoint();*/ + } +} + +/* + * Look for old packets that the secondary hasn't matched, + * if we have some then we have to checkpoint to wake + * the secondary up. + */ +static void colo_old_packet_check(void *opaque) +{ + CompareState *s = opaque; + + g_queue_foreach(&s->conn_list, colo_old_packet_check_one_conn, NULL); +} + +/* + * Called from the compare thread on the primary + * for compare connection + */ +static void colo_compare_connection(void *opaque, void *user_data) +{ + CompareState *s = user_data; + Connection *conn = opaque; + Packet *pkt = NULL; + GList *result = NULL; + int ret; + + while (!g_queue_is_empty(&conn->primary_list) && + !g_queue_is_empty(&conn->secondary_list)) { + qemu_mutex_lock(&s->timer_check_lock); + pkt = g_queue_pop_tail(&conn->primary_list); + qemu_mutex_unlock(&s->timer_check_lock); + result = g_queue_find_custom(&conn->secondary_list, + pkt, (GCompareFunc)colo_packet_compare_all); + + if (result) { + ret = compare_chr_send(s->chr_out, pkt->data, pkt->size); + if (ret < 0) { + error_report("colo_send_primary_packet failed"); + } + trace_colo_compare_main("packet same and release packet"); + g_queue_remove(&conn->secondary_list, result->data); + packet_destroy(pkt, NULL); + } else { + /* + * If one packet arrive late, the secondary_list or + * primary_list will be empty, so we can't compare it + * until next comparison. + */ + trace_colo_compare_main("packet different"); + qemu_mutex_lock(&s->timer_check_lock); + g_queue_push_tail(&conn->primary_list, pkt); + qemu_mutex_unlock(&s->timer_check_lock); + /* TODO: colo_notify_checkpoint();*/ + break; + } + } +} + static int compare_chr_send(CharDriverState *out, const uint8_t *buf, uint32_t size) @@ -175,6 +296,65 @@ static int compare_chr_send(CharDriverState *out, return ret < 0 ? ret : -EIO; } +static int compare_chr_can_read(void *opaque) +{ + return COMPARE_READ_LEN_MAX; +} + +/* + * Called from the main thread on the primary for packets + * arriving over the socket from the primary. + */ +static void compare_pri_chr_in(void *opaque, const uint8_t *buf, int size) +{ + CompareState *s = COLO_COMPARE(opaque); + int ret; + + ret = net_fill_rstate(&s->pri_rs, buf, size); + if (ret == -1) { + qemu_chr_add_handlers(s->chr_pri_in, NULL, NULL, NULL, NULL); + error_report("colo-compare primary_in error"); + } +} + +/* + * Called from the main thread on the primary for packets + * arriving over the socket from the secondary. + */ +static void compare_sec_chr_in(void *opaque, const uint8_t *buf, int size) +{ + CompareState *s = COLO_COMPARE(opaque); + int ret; + + ret = net_fill_rstate(&s->sec_rs, buf, size); + if (ret == -1) { + qemu_chr_add_handlers(s->chr_sec_in, NULL, NULL, NULL, NULL); + error_report("colo-compare secondary_in error"); + } +} + +static void *colo_compare_thread(void *opaque) +{ + GMainContext *worker_context; + GMainLoop *compare_loop; + CompareState *s = opaque; + + worker_context = g_main_context_new(); + + qemu_chr_add_handlers_full(s->chr_pri_in, compare_chr_can_read, + compare_pri_chr_in, NULL, s, worker_context); + qemu_chr_add_handlers_full(s->chr_sec_in, compare_chr_can_read, + compare_sec_chr_in, NULL, s, worker_context); + + compare_loop = g_main_loop_new(worker_context, FALSE); + + g_main_loop_run(compare_loop); + + g_main_loop_unref(compare_loop); + g_main_context_unref(worker_context); + return NULL; +} + static char *compare_get_pri_indev(Object *obj, Error **errp) { CompareState *s = COLO_COMPARE(obj); @@ -227,6 +407,9 @@ static void compare_pri_rs_finalize(SocketReadState *pri_rs) if (packet_enqueue(s, PRIMARY_IN)) { trace_colo_compare_main("primary: unsupported packet in"); compare_chr_send(s->chr_out, pri_rs->buf, pri_rs->packet_len); + } else { + /* compare connection */ + g_queue_foreach(&s->conn_list, colo_compare_connection, s); } } @@ -236,6 +419,9 @@ static void compare_sec_rs_finalize(SocketReadState *sec_rs) if (packet_enqueue(s, SECONDARY_IN)) { trace_colo_compare_main("secondary: unsupported packet in"); + } else { + /* compare connection */ + g_queue_foreach(&s->conn_list, colo_compare_connection, s); } } @@ -293,6 +479,26 @@ static int find_and_check_chardev(CharDriverState **chr, return 0; } +/* + * Check old packet regularly so it can watch for any packets + * that the secondary hasn't produced equivalents of. + */ +static void check_old_packet_regular(void *opaque) +{ + CompareState *s = opaque; + + timer_mod(s->timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + + REGULAR_PACKET_CHECK_MS); + /* if have old packet we will notify checkpoint */ + /* + * TODO: Make timer handler run in compare thread + * like qemu_chr_add_handlers_full. + */ + qemu_mutex_lock(&s->timer_check_lock); + colo_old_packet_check(s); + qemu_mutex_unlock(&s->timer_check_lock); +} + /* * Called from the main thread on the primary * to setup colo-compare. @@ -300,6 +506,8 @@ static int find_and_check_chardev(CharDriverState **chr, static void colo_compare_complete(UserCreatable *uc, Error **errp) { CompareState *s = COLO_COMPARE(uc); + char thread_name[64]; + static int compare_id; if (!s->pri_indev || !s->sec_indev || !s->outdev) { error_setg(errp, "colo compare needs 'primary_in' ," @@ -335,12 +543,25 @@ static void colo_compare_complete(UserCreatable *uc, Error **errp) net_socket_rs_init(&s->sec_rs, compare_sec_rs_finalize); g_queue_init(&s->conn_list); + qemu_mutex_init(&s->timer_check_lock); s->connection_track_table = g_hash_table_new_full(connection_key_hash, connection_key_equal, g_free, connection_destroy); + sprintf(thread_name, "colo-compare %d", compare_id); + qemu_thread_create(&s->thread, thread_name, + colo_compare_thread, s, + QEMU_THREAD_JOINABLE); + compare_id++; + + /* A regular timer to kick any packets that the secondary doesn't match */ + s->timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, /* Only when guest runs */ + check_old_packet_regular, s); + timer_mod(s->timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + + REGULAR_PACKET_CHECK_MS); + return; } @@ -382,6 +603,18 @@ static void colo_compare_finalize(Object *obj) g_queue_free(&s->conn_list); + if (qemu_thread_is_self(&s->thread)) { + /* compare connection */ + g_queue_foreach(&s->conn_list, colo_compare_connection, s); + qemu_thread_join(&s->thread); + } + + if (s->timer) { + timer_del(s->timer); + } + + qemu_mutex_destroy(&s->timer_check_lock); + g_free(s->pri_indev); g_free(s->sec_indev); g_free(s->outdev); diff --git a/net/colo.c b/net/colo.c index 40b3b5e56c3..94f59925450 100644 --- a/net/colo.c +++ b/net/colo.c @@ -143,6 +143,7 @@ Packet *packet_new(const void *data, int size) pkt->data = g_memdup(data, size); pkt->size = size; + pkt->creation_ms = qemu_clock_get_ms(QEMU_CLOCK_HOST); return pkt; } diff --git a/net/colo.h b/net/colo.h index c511bcdeb9f..9a7d5e027a0 100644 --- a/net/colo.h +++ b/net/colo.h @@ -17,6 +17,7 @@ #include "slirp/slirp.h" #include "qemu/jhash.h" +#include "qemu/timer.h" #define HASHTABLE_MAX_SIZE 16384 @@ -40,6 +41,8 @@ typedef struct Packet { }; uint8_t *transport_header; int size; + /* Time of packet creation, in wall clock ms */ + int64_t creation_ms; } Packet; typedef struct ConnectionKey { diff --git a/trace-events b/trace-events index 9b4186f9b64..81de82c797c 100644 --- a/trace-events +++ b/trace-events @@ -144,6 +144,8 @@ colo_proxy_main(const char *chr) ": %s" # net/colo-compare.c colo_compare_main(const char *chr) ": %s" +colo_compare_ip_info(int psize, const char *sta, const char *stb, int ssize, const char *stc, const char *std) "ppkt size = %d, ip_src = %s, ip_dst = %s, spkt size = %d, ip_src = %s, ip_dst = %s" +colo_old_packet_check_found(int64_t old_time) "%" PRId64 ### Guest events, keep at bottom From f4b618360e5a81b097e2e35d52011bec3c63af68 Mon Sep 17 00:00:00 2001 From: Zhang Chen Date: Tue, 27 Sep 2016 10:22:31 +0800 Subject: [PATCH 319/723] colo-compare: add TCP, UDP, ICMP packet comparison We add TCP,UDP,ICMP packet comparison to replace IP packet comparison. This can increase the accuracy of the package comparison. Less checkpoint more efficiency. Signed-off-by: Zhang Chen Signed-off-by: Li Zhijian Signed-off-by: Wen Congyang Signed-off-by: Jason Wang --- net/colo-compare.c | 147 +++++++++++++++++++++++++++++++++++++++++++-- trace-events | 3 + 2 files changed, 146 insertions(+), 4 deletions(-) diff --git a/net/colo-compare.c b/net/colo-compare.c index 9596c8b3086..22b1da19f5b 100644 --- a/net/colo-compare.c +++ b/net/colo-compare.c @@ -19,6 +19,7 @@ #include "qapi/qmp/qerror.h" #include "qapi/error.h" #include "net/net.h" +#include "net/eth.h" #include "qom/object_interfaces.h" #include "qemu/iov.h" #include "qom/object.h" @@ -178,9 +179,131 @@ static int colo_packet_compare(Packet *ppkt, Packet *spkt) } } -static int colo_packet_compare_all(Packet *spkt, Packet *ppkt) +/* + * Called from the compare thread on the primary + * for compare tcp packet + * compare_tcp copied from Dr. David Alan Gilbert's branch + */ +static int colo_packet_compare_tcp(Packet *spkt, Packet *ppkt) +{ + struct tcphdr *ptcp, *stcp; + int res; + char *sdebug, *ddebug; + + trace_colo_compare_main("compare tcp"); + if (ppkt->size != spkt->size) { + if (trace_event_get_state(TRACE_COLO_COMPARE_MISCOMPARE)) { + trace_colo_compare_main("pkt size not same"); + } + return -1; + } + + ptcp = (struct tcphdr *)ppkt->transport_header; + stcp = (struct tcphdr *)spkt->transport_header; + + /* + * The 'identification' field in the IP header is *very* random + * it almost never matches. Fudge this by ignoring differences in + * unfragmented packets; they'll normally sort themselves out if different + * anyway, and it should recover at the TCP level. + * An alternative would be to get both the primary and secondary to rewrite + * somehow; but that would need some sync traffic to sync the state + */ + if (ntohs(ppkt->ip->ip_off) & IP_DF) { + spkt->ip->ip_id = ppkt->ip->ip_id; + /* and the sum will be different if the IDs were different */ + spkt->ip->ip_sum = ppkt->ip->ip_sum; + } + + res = memcmp(ppkt->data + ETH_HLEN, spkt->data + ETH_HLEN, + (spkt->size - ETH_HLEN)); + + if (res != 0 && trace_event_get_state(TRACE_COLO_COMPARE_MISCOMPARE)) { + sdebug = strdup(inet_ntoa(ppkt->ip->ip_src)); + ddebug = strdup(inet_ntoa(ppkt->ip->ip_dst)); + fprintf(stderr, "%s: src/dst: %s/%s p: seq/ack=%u/%u" + " s: seq/ack=%u/%u res=%d flags=%x/%x\n", + __func__, sdebug, ddebug, + (unsigned int)ntohl(ptcp->th_seq), + (unsigned int)ntohl(ptcp->th_ack), + (unsigned int)ntohl(stcp->th_seq), + (unsigned int)ntohl(stcp->th_ack), + res, ptcp->th_flags, stcp->th_flags); + + fprintf(stderr, "Primary len = %d\n", ppkt->size); + qemu_hexdump((char *)ppkt->data, stderr, "colo-compare", ppkt->size); + fprintf(stderr, "Secondary len = %d\n", spkt->size); + qemu_hexdump((char *)spkt->data, stderr, "colo-compare", spkt->size); + + g_free(sdebug); + g_free(ddebug); + } + + return res; +} + +/* + * Called from the compare thread on the primary + * for compare udp packet + */ +static int colo_packet_compare_udp(Packet *spkt, Packet *ppkt) +{ + int ret; + + trace_colo_compare_main("compare udp"); + ret = colo_packet_compare(ppkt, spkt); + + if (ret) { + trace_colo_compare_udp_miscompare("primary pkt size", ppkt->size); + qemu_hexdump((char *)ppkt->data, stderr, "colo-compare", ppkt->size); + trace_colo_compare_udp_miscompare("Secondary pkt size", spkt->size); + qemu_hexdump((char *)spkt->data, stderr, "colo-compare", spkt->size); + } + + return ret; +} + +/* + * Called from the compare thread on the primary + * for compare icmp packet + */ +static int colo_packet_compare_icmp(Packet *spkt, Packet *ppkt) { - trace_colo_compare_main("compare all"); + int network_length; + + trace_colo_compare_main("compare icmp"); + network_length = ppkt->ip->ip_hl * 4; + if (ppkt->size != spkt->size || + ppkt->size < network_length + ETH_HLEN) { + return -1; + } + + if (colo_packet_compare(ppkt, spkt)) { + trace_colo_compare_icmp_miscompare("primary pkt size", + ppkt->size); + qemu_hexdump((char *)ppkt->data, stderr, "colo-compare", + ppkt->size); + trace_colo_compare_icmp_miscompare("Secondary pkt size", + spkt->size); + qemu_hexdump((char *)spkt->data, stderr, "colo-compare", + spkt->size); + return -1; + } else { + return 0; + } +} + +/* + * Called from the compare thread on the primary + * for compare other packet + */ +static int colo_packet_compare_other(Packet *spkt, Packet *ppkt) +{ + trace_colo_compare_main("compare other"); + trace_colo_compare_ip_info(ppkt->size, inet_ntoa(ppkt->ip->ip_src), + inet_ntoa(ppkt->ip->ip_dst), spkt->size, + inet_ntoa(spkt->ip->ip_src), + inet_ntoa(spkt->ip->ip_dst)); return colo_packet_compare(ppkt, spkt); } @@ -242,8 +365,24 @@ static void colo_compare_connection(void *opaque, void *user_data) qemu_mutex_lock(&s->timer_check_lock); pkt = g_queue_pop_tail(&conn->primary_list); qemu_mutex_unlock(&s->timer_check_lock); - result = g_queue_find_custom(&conn->secondary_list, - pkt, (GCompareFunc)colo_packet_compare_all); + switch (conn->ip_proto) { + case IPPROTO_TCP: + result = g_queue_find_custom(&conn->secondary_list, + pkt, (GCompareFunc)colo_packet_compare_tcp); + break; + case IPPROTO_UDP: + result = g_queue_find_custom(&conn->secondary_list, + pkt, (GCompareFunc)colo_packet_compare_udp); + break; + case IPPROTO_ICMP: + result = g_queue_find_custom(&conn->secondary_list, + pkt, (GCompareFunc)colo_packet_compare_icmp); + break; + default: + result = g_queue_find_custom(&conn->secondary_list, + pkt, (GCompareFunc)colo_packet_compare_other); + break; + } if (result) { ret = compare_chr_send(s->chr_out, pkt->data, pkt->size); diff --git a/trace-events b/trace-events index 81de82c797c..b39536852e5 100644 --- a/trace-events +++ b/trace-events @@ -144,8 +144,11 @@ colo_proxy_main(const char *chr) ": %s" # net/colo-compare.c colo_compare_main(const char *chr) ": %s" +colo_compare_udp_miscompare(const char *sta, int size) ": %s = %d" +colo_compare_icmp_miscompare(const char *sta, int size) ": %s = %d" colo_compare_ip_info(int psize, const char *sta, const char *stb, int ssize, const char *stc, const char *std) "ppkt size = %d, ip_src = %s, ip_dst = %s, spkt size = %d, ip_src = %s, ip_dst = %s" colo_old_packet_check_found(int64_t old_time) "%" PRId64 +colo_compare_miscompare(void) "" ### Guest events, keep at bottom From e6eee8ab5148aee369416e5126d6d149319579be Mon Sep 17 00:00:00 2001 From: Zhang Chen Date: Tue, 27 Sep 2016 10:22:32 +0800 Subject: [PATCH 320/723] filter-rewriter: introduce filter-rewriter initialization Filter-rewriter is a part of COLO project. It will rewrite some of secondary packet to make secondary guest's tcp connection established successfully. In this module we will rewrite tcp packet's ack to the secondary from primary,and rewrite tcp packet's seq to the primary from secondary. usage: colo secondary: -object filter-redirector,id=f1,netdev=hn0,queue=tx,indev=red0 -object filter-redirector,id=f2,netdev=hn0,queue=rx,outdev=red1 -object filter-rewriter,id=rew0,netdev=hn0,queue=all Signed-off-by: Zhang Chen Signed-off-by: Li Zhijian Signed-off-by: Wen Congyang Signed-off-by: Jason Wang --- net/Makefile.objs | 1 + net/filter-rewriter.c | 105 ++++++++++++++++++++++++++++++++++++++++++ qemu-options.hx | 13 ++++++ vl.c | 3 +- 4 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 net/filter-rewriter.c diff --git a/net/Makefile.objs b/net/Makefile.objs index beb504bbff1..2a80df5fa77 100644 --- a/net/Makefile.objs +++ b/net/Makefile.objs @@ -18,3 +18,4 @@ common-obj-y += filter-buffer.o common-obj-y += filter-mirror.o common-obj-y += colo-compare.o common-obj-y += colo.o +common-obj-y += filter-rewriter.o diff --git a/net/filter-rewriter.c b/net/filter-rewriter.c new file mode 100644 index 00000000000..de29f07cb60 --- /dev/null +++ b/net/filter-rewriter.c @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD. + * Copyright (c) 2016 FUJITSU LIMITED + * Copyright (c) 2016 Intel Corporation + * + * Author: Zhang Chen + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * later. See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "net/colo.h" +#include "net/filter.h" +#include "net/net.h" +#include "qemu-common.h" +#include "qapi/error.h" +#include "qapi/qmp/qerror.h" +#include "qapi-visit.h" +#include "qom/object.h" +#include "qemu/main-loop.h" +#include "qemu/iov.h" +#include "net/checksum.h" + +#define FILTER_COLO_REWRITER(obj) \ + OBJECT_CHECK(RewriterState, (obj), TYPE_FILTER_REWRITER) + +#define TYPE_FILTER_REWRITER "filter-rewriter" + +typedef struct RewriterState { + NetFilterState parent_obj; + NetQueue *incoming_queue; + /* hashtable to save connection */ + GHashTable *connection_track_table; +} RewriterState; + +static void filter_rewriter_flush(NetFilterState *nf) +{ + RewriterState *s = FILTER_COLO_REWRITER(nf); + + if (!qemu_net_queue_flush(s->incoming_queue)) { + /* Unable to empty the queue, purge remaining packets */ + qemu_net_queue_purge(s->incoming_queue, nf->netdev); + } +} + +static ssize_t colo_rewriter_receive_iov(NetFilterState *nf, + NetClientState *sender, + unsigned flags, + const struct iovec *iov, + int iovcnt, + NetPacketSent *sent_cb) +{ + /* + * if we get tcp packet + * we will rewrite it to make secondary guest's + * connection established successfully + */ + return 0; +} + +static void colo_rewriter_cleanup(NetFilterState *nf) +{ + RewriterState *s = FILTER_COLO_REWRITER(nf); + + /* flush packets */ + if (s->incoming_queue) { + filter_rewriter_flush(nf); + g_free(s->incoming_queue); + } +} + +static void colo_rewriter_setup(NetFilterState *nf, Error **errp) +{ + RewriterState *s = FILTER_COLO_REWRITER(nf); + + s->connection_track_table = g_hash_table_new_full(connection_key_hash, + connection_key_equal, + g_free, + connection_destroy); + s->incoming_queue = qemu_new_net_queue(qemu_netfilter_pass_to_next, nf); +} + +static void colo_rewriter_class_init(ObjectClass *oc, void *data) +{ + NetFilterClass *nfc = NETFILTER_CLASS(oc); + + nfc->setup = colo_rewriter_setup; + nfc->cleanup = colo_rewriter_cleanup; + nfc->receive_iov = colo_rewriter_receive_iov; +} + +static const TypeInfo colo_rewriter_info = { + .name = TYPE_FILTER_REWRITER, + .parent = TYPE_NETFILTER, + .class_init = colo_rewriter_class_init, + .instance_size = sizeof(RewriterState), +}; + +static void register_types(void) +{ + type_register_static(&colo_rewriter_info); +} + +type_init(register_types); diff --git a/qemu-options.hx b/qemu-options.hx index d0ed69aa106..987d055481c 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -3887,6 +3887,19 @@ Create a filter-redirector we need to differ outdev id from indev id, id can not be the same. we can just use indev or outdev, but at least one of indev or outdev need to be specified. +@item -object filter-rewriter,id=@var{id},netdev=@var{netdevid},rewriter-mode=@var{mode}[,queue=@var{all|rx|tx}] + +Filter-rewriter is a part of COLO project.It will rewrite tcp packet to +secondary from primary to keep secondary tcp connection,and rewrite +tcp packet to primary from secondary make tcp packet can be handled by +client. + +usage: +colo secondary: +-object filter-redirector,id=f1,netdev=hn0,queue=tx,indev=red0 +-object filter-redirector,id=f2,netdev=hn0,queue=rx,outdev=red1 +-object filter-rewriter,id=rew0,netdev=hn0,queue=all + @item -object filter-dump,id=@var{id},netdev=@var{dev},file=@var{filename}][,maxlen=@var{len}] Dump the network traffic on netdev @var{dev} to the file specified by diff --git a/vl.c b/vl.c index 7dadb9e1a4d..eafda8d7373 100644 --- a/vl.c +++ b/vl.c @@ -2846,7 +2846,8 @@ static bool object_create_initial(const char *type) g_str_equal(type, "filter-dump") || g_str_equal(type, "filter-mirror") || g_str_equal(type, "filter-redirector") || - g_str_equal(type, "colo-compare")) { + g_str_equal(type, "colo-compare") || + g_str_equal(type, "filter-rewriter")) { return false; } From afe461240940077e7ea8313e9c547a4898263cd2 Mon Sep 17 00:00:00 2001 From: Zhang Chen Date: Tue, 27 Sep 2016 10:22:33 +0800 Subject: [PATCH 321/723] filter-rewriter: track connection and parse packet We use net/colo.h to track connection and parse packet Signed-off-by: Zhang Chen Signed-off-by: Li Zhijian Signed-off-by: Wen Congyang Signed-off-by: Jason Wang --- net/colo.c | 14 ++++++++++++ net/colo.h | 1 + net/filter-rewriter.c | 50 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+) diff --git a/net/colo.c b/net/colo.c index 94f59925450..124994c99fb 100644 --- a/net/colo.c +++ b/net/colo.c @@ -114,6 +114,20 @@ void fill_connection_key(Packet *pkt, ConnectionKey *key) } } +void reverse_connection_key(ConnectionKey *key) +{ + struct in_addr tmp_ip; + uint16_t tmp_port; + + tmp_ip = key->src; + key->src = key->dst; + key->dst = tmp_ip; + + tmp_port = key->src_port; + key->src_port = key->dst_port; + key->dst_port = tmp_port; +} + Connection *connection_new(ConnectionKey *key) { Connection *conn = g_slice_new(Connection); diff --git a/net/colo.h b/net/colo.h index 9a7d5e027a0..6720a3a8b76 100644 --- a/net/colo.h +++ b/net/colo.h @@ -68,6 +68,7 @@ uint32_t connection_key_hash(const void *opaque); int connection_key_equal(const void *opaque1, const void *opaque2); int parse_packet_early(Packet *pkt); void fill_connection_key(Packet *pkt, ConnectionKey *key); +void reverse_connection_key(ConnectionKey *key); Connection *connection_new(ConnectionKey *key); void connection_destroy(void *opaque); Connection *connection_get(GHashTable *connection_track_table, diff --git a/net/filter-rewriter.c b/net/filter-rewriter.c index de29f07cb60..9bf80d39558 100644 --- a/net/filter-rewriter.c +++ b/net/filter-rewriter.c @@ -44,6 +44,20 @@ static void filter_rewriter_flush(NetFilterState *nf) } } +/* + * Return 1 on success, if return 0 means the pkt + * is not TCP packet + */ +static int is_tcp_packet(Packet *pkt) +{ + if (!parse_packet_early(pkt) && + pkt->ip->ip_p == IPPROTO_TCP) { + return 1; + } else { + return 0; + } +} + static ssize_t colo_rewriter_receive_iov(NetFilterState *nf, NetClientState *sender, unsigned flags, @@ -51,11 +65,47 @@ static ssize_t colo_rewriter_receive_iov(NetFilterState *nf, int iovcnt, NetPacketSent *sent_cb) { + RewriterState *s = FILTER_COLO_REWRITER(nf); + Connection *conn; + ConnectionKey key; + Packet *pkt; + ssize_t size = iov_size(iov, iovcnt); + char *buf = g_malloc0(size); + + iov_to_buf(iov, iovcnt, 0, buf, size); + pkt = packet_new(buf, size); + /* * if we get tcp packet * we will rewrite it to make secondary guest's * connection established successfully */ + if (pkt && is_tcp_packet(pkt)) { + + fill_connection_key(pkt, &key); + + if (sender == nf->netdev) { + /* + * We need make tcp TX and RX packet + * into one connection. + */ + reverse_connection_key(&key); + } + conn = connection_get(s->connection_track_table, + &key, + NULL); + + if (sender == nf->netdev) { + /* NET_FILTER_DIRECTION_TX */ + /* handle_primary_tcp_pkt */ + } else { + /* NET_FILTER_DIRECTION_RX */ + /* handle_secondary_tcp_pkt */ + } + } + + packet_destroy(pkt, NULL); + pkt = NULL; return 0; } From 30656b097e9dd7978d3fe9416cb9f5a421a9e63e Mon Sep 17 00:00:00 2001 From: Zhang Chen Date: Tue, 27 Sep 2016 10:22:34 +0800 Subject: [PATCH 322/723] filter-rewriter: rewrite tcp packet to keep secondary connection We will rewrite tcp packet secondary received and sent. When colo guest is a tcp server. Firstly, client start a tcp handshake. the packet's seq=client_seq, ack=0,flag=SYN. COLO primary guest get this pkt and mirror(filter-mirror) to secondary guest, secondary get it use filter-redirector. Then,primary guest response pkt (seq=primary_seq,ack=client_seq+1,flag=ACK|SYN). secondary guest response pkt (seq=secondary_seq,ack=client_seq+1,flag=ACK|SYN). In here,we use filter-rewriter save the secondary_seq to it's tcp connection. Finally handshake,client send pkt (seq=client_seq+1,ack=primary_seq+1,flag=ACK). Here,filter-rewriter can get primary_seq, and rewrite ack from primary_seq+1 to secondary_seq+1, recalculate checksum. So the secondary tcp connection kept good. When we send/recv packet. client send pkt(seq=client_seq+1+data_len,ack=primary_seq+1,flag=ACK|PSH). filter-rewriter rewrite ack and send to secondary guest. primary guest response pkt (seq=primary_seq+1,ack=client_seq+1+data_len,flag=ACK) secondary guest response pkt (seq=secondary_seq+1,ack=client_seq+1+data_len,flag=ACK) we rewrite secondary guest seq from secondary_seq+1 to primary_seq+1. So tcp connection kept good. In code We use offset( = secondary_seq - primary_seq ) to rewrite seq or ack. handle_primary_tcp_pkt: tcp_pkt->th_ack += offset; handle_secondary_tcp_pkt: tcp_pkt->th_seq -= offset; Signed-off-by: Zhang Chen Signed-off-by: Li Zhijian Signed-off-by: Wen Congyang Signed-off-by: Jason Wang --- net/colo.c | 2 + net/colo.h | 7 +++ net/filter-rewriter.c | 112 +++++++++++++++++++++++++++++++++++++++++- trace-events | 5 ++ 4 files changed, 124 insertions(+), 2 deletions(-) diff --git a/net/colo.c b/net/colo.c index 124994c99fb..6a6eacd2dc2 100644 --- a/net/colo.c +++ b/net/colo.c @@ -134,6 +134,8 @@ Connection *connection_new(ConnectionKey *key) conn->ip_proto = key->ip_proto; conn->processing = false; + conn->offset = 0; + conn->syn_flag = 0; g_queue_init(&conn->primary_list); g_queue_init(&conn->secondary_list); diff --git a/net/colo.h b/net/colo.h index 6720a3a8b76..7c524f3a1cd 100644 --- a/net/colo.h +++ b/net/colo.h @@ -62,6 +62,13 @@ typedef struct Connection { /* flag to enqueue unprocessed_connections */ bool processing; uint8_t ip_proto; + /* offset = secondary_seq - primary_seq */ + tcp_seq offset; + /* + * we use this flag update offset func + * run once in independent tcp connection + */ + int syn_flag; } Connection; uint32_t connection_key_hash(const void *opaque); diff --git a/net/filter-rewriter.c b/net/filter-rewriter.c index 9bf80d39558..89abe72d4e6 100644 --- a/net/filter-rewriter.c +++ b/net/filter-rewriter.c @@ -10,6 +10,7 @@ */ #include "qemu/osdep.h" +#include "trace.h" #include "net/colo.h" #include "net/filter.h" #include "net/net.h" @@ -58,6 +59,93 @@ static int is_tcp_packet(Packet *pkt) } } +/* handle tcp packet from primary guest */ +static int handle_primary_tcp_pkt(NetFilterState *nf, + Connection *conn, + Packet *pkt) +{ + struct tcphdr *tcp_pkt; + + tcp_pkt = (struct tcphdr *)pkt->transport_header; + if (trace_event_get_state(TRACE_COLO_FILTER_REWRITER_DEBUG)) { + char *sdebug, *ddebug; + sdebug = strdup(inet_ntoa(pkt->ip->ip_src)); + ddebug = strdup(inet_ntoa(pkt->ip->ip_dst)); + trace_colo_filter_rewriter_pkt_info(__func__, sdebug, ddebug, + ntohl(tcp_pkt->th_seq), ntohl(tcp_pkt->th_ack), + tcp_pkt->th_flags); + trace_colo_filter_rewriter_conn_offset(conn->offset); + g_free(sdebug); + g_free(ddebug); + } + + if (((tcp_pkt->th_flags & (TH_ACK | TH_SYN)) == TH_SYN)) { + /* + * we use this flag update offset func + * run once in independent tcp connection + */ + conn->syn_flag = 1; + } + + if (((tcp_pkt->th_flags & (TH_ACK | TH_SYN)) == TH_ACK)) { + if (conn->syn_flag) { + /* + * offset = secondary_seq - primary seq + * ack packet sent by guest from primary node, + * so we use th_ack - 1 get primary_seq + */ + conn->offset -= (ntohl(tcp_pkt->th_ack) - 1); + conn->syn_flag = 0; + } + /* handle packets to the secondary from the primary */ + tcp_pkt->th_ack = htonl(ntohl(tcp_pkt->th_ack) + conn->offset); + + net_checksum_calculate((uint8_t *)pkt->data, pkt->size); + } + + return 0; +} + +/* handle tcp packet from secondary guest */ +static int handle_secondary_tcp_pkt(NetFilterState *nf, + Connection *conn, + Packet *pkt) +{ + struct tcphdr *tcp_pkt; + + tcp_pkt = (struct tcphdr *)pkt->transport_header; + + if (trace_event_get_state(TRACE_COLO_FILTER_REWRITER_DEBUG)) { + char *sdebug, *ddebug; + sdebug = strdup(inet_ntoa(pkt->ip->ip_src)); + ddebug = strdup(inet_ntoa(pkt->ip->ip_dst)); + trace_colo_filter_rewriter_pkt_info(__func__, sdebug, ddebug, + ntohl(tcp_pkt->th_seq), ntohl(tcp_pkt->th_ack), + tcp_pkt->th_flags); + trace_colo_filter_rewriter_conn_offset(conn->offset); + g_free(sdebug); + g_free(ddebug); + } + + if (((tcp_pkt->th_flags & (TH_ACK | TH_SYN)) == (TH_ACK | TH_SYN))) { + /* + * save offset = secondary_seq and then + * in handle_primary_tcp_pkt make offset + * = secondary_seq - primary_seq + */ + conn->offset = ntohl(tcp_pkt->th_seq); + } + + if ((tcp_pkt->th_flags & (TH_ACK | TH_SYN)) == TH_ACK) { + /* handle packets to the primary from the secondary*/ + tcp_pkt->th_seq = htonl(ntohl(tcp_pkt->th_seq) - conn->offset); + + net_checksum_calculate((uint8_t *)pkt->data, pkt->size); + } + + return 0; +} + static ssize_t colo_rewriter_receive_iov(NetFilterState *nf, NetClientState *sender, unsigned flags, @@ -97,10 +185,30 @@ static ssize_t colo_rewriter_receive_iov(NetFilterState *nf, if (sender == nf->netdev) { /* NET_FILTER_DIRECTION_TX */ - /* handle_primary_tcp_pkt */ + if (!handle_primary_tcp_pkt(nf, conn, pkt)) { + qemu_net_queue_send(s->incoming_queue, sender, 0, + (const uint8_t *)pkt->data, pkt->size, NULL); + packet_destroy(pkt, NULL); + pkt = NULL; + /* + * We block the packet here,after rewrite pkt + * and will send it + */ + return 1; + } } else { /* NET_FILTER_DIRECTION_RX */ - /* handle_secondary_tcp_pkt */ + if (!handle_secondary_tcp_pkt(nf, conn, pkt)) { + qemu_net_queue_send(s->incoming_queue, sender, 0, + (const uint8_t *)pkt->data, pkt->size, NULL); + packet_destroy(pkt, NULL); + pkt = NULL; + /* + * We block the packet here,after rewrite pkt + * and will send it + */ + return 1; + } } } diff --git a/trace-events b/trace-events index b39536852e5..1cb9d37ce4b 100644 --- a/trace-events +++ b/trace-events @@ -150,6 +150,11 @@ colo_compare_ip_info(int psize, const char *sta, const char *stb, int ssize, con colo_old_packet_check_found(int64_t old_time) "%" PRId64 colo_compare_miscompare(void) "" +# net/filter-rewriter.c +colo_filter_rewriter_debug(void) "" +colo_filter_rewriter_pkt_info(const char *func, const char *src, const char *dst, uint32_t seq, uint32_t ack, uint32_t flag) "%s: src/dst: %s/%s p: seq/ack=%u/%u flags=%x\n" +colo_filter_rewriter_conn_offset(uint32_t offset) ": offset=%u\n" + ### Guest events, keep at bottom # @vaddr: Access' virtual address. From 88f82ed1a774742942fe852b9b57dcaa287a94fb Mon Sep 17 00:00:00 2001 From: Zhang Chen Date: Tue, 27 Sep 2016 10:22:35 +0800 Subject: [PATCH 323/723] MAINTAINERS: add maintainer for COLO-proxy add Zhang Chen and Li zhijian as co-maintainers of COLO-proxy. Signed-off-by: Zhang Chen Signed-off-by: Li Zhijian Signed-off-by: Wen Congyang Signed-off-by: Jason Wang --- MAINTAINERS | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index a3a2ad7d2fe..f3c1f7f307c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1364,6 +1364,15 @@ F: util/uuid.c F: include/qemu/uuid.h F: tests/test-uuid.c +COLO Proxy +M: Zhang Chen +M: Li Zhijian +S: Supported +F: docs/colo-proxy.txt +F: net/colo* +F: net/filter-rewriter.c +F: net/filter-mirror.c + Usermode Emulation ------------------ Overall From 46cca4ecb2842e93fff94b78161c03e9943860a8 Mon Sep 17 00:00:00 2001 From: Zhang Chen Date: Tue, 27 Sep 2016 10:22:36 +0800 Subject: [PATCH 324/723] docs: Add documentation for COLO-proxy Introduce the design of COLO-proxy, and how to use it. Signed-off-by: Zhang Chen Signed-off-by: Jason Wang --- docs/colo-proxy.txt | 188 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 docs/colo-proxy.txt diff --git a/docs/colo-proxy.txt b/docs/colo-proxy.txt new file mode 100644 index 00000000000..76767cb34f8 --- /dev/null +++ b/docs/colo-proxy.txt @@ -0,0 +1,188 @@ +COLO-proxy +---------- +Copyright (c) 2016 Intel Corporation +Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD. +Copyright (c) 2016 Fujitsu, Corp. + +This work is licensed under the terms of the GNU GPL, version 2 or later. +See the COPYING file in the top-level directory. + +This document gives an overview of COLO proxy's design. + +== Background == +COLO-proxy is a part of COLO project. It is used +to compare the network package to help COLO decide +whether to do checkpoint. With COLO-proxy's help, +COLO greatly improves the performance. + +The filter-redirector, filter-mirror, colo-compare +and filter-rewriter compose the COLO-proxy. + +== Architecture == + +COLO-Proxy is based on qemu netfilter and it's a plugin for qemu netfilter +(except colo-compare). It keep Secondary VM connect normally to +client and compare packets sent by PVM with sent by SVM. +If the packet difference, notify COLO-frame to do checkpoint and send +all primary packet has queued. Otherwise just send the queued primary +packet and drop the queued secondary packet. + +Below is a COLO proxy ascii figure: + + Primary qemu Secondary qemu ++--------------------------------------------------------------+ +----------------------------------------------------------------+ +| +----------------------------------------------------------+ | | +-----------------------------------------------------------+ | +| | | | | | | | +| | guest | | | | guest | | +| | | | | | | | +| +-------^--------------------------+-----------------------+ | | +---------------------+--------+----------------------------+ | +| | | | | ^ | | +| | | | | | | | +| | +------------------------------------------------------+ | | | | +|netfilter| | | | | | netfilter | | | +| +----------+ +----------------------------+ | | | +-----------------------------------------------------------+ | +| | | | | | out | | | | | | filter excute order | | +| | | | +-----------------------------+ | | | | | | +-------------------> | | +| | | | | | | | | | | | | | TCP | | +| | +-----+--+-+ +-----v----+ +-----v----+ |pri +----+----+sec| | | | +------------+ +---+----+---v+rewriter++ +------------+ | | +| | | | | | | | |in | |in | | | | | | | | | | | | | +| | | filter | | filter | | filter +------> colo <------+ +--------> filter +--> adjust | adjust +--> filter | | | +| | | mirror | |redirector| |redirector| | | compare | | | | | | redirector | | ack | seq | | redirector | | | +| | | | | | | | | | | | | | | | | | | | | | | | +| | +----^-----+ +----+-----+ +----------+ | +---------+ | | | | +------------+ +--------+--------------+ +---+--------+ | | +| | | tx | rx rx | | | | | tx all | rx | | +| | | | | | | | +-----------------------------------------------------------+ | +| | | +--------------+ | | | | | | +| | | filter excute order | | | | | | | +| | | +----------------> | | | +--------------------------------------------------------+ | +| +-----------------------------------------+ | | | +| | | | | | ++--------------------------------------------------------------+ +----------------------------------------------------------------+ + |guest receive | guest send + | | ++--------+----------------------------v------------------------+ +| | NOTE: filter direction is rx/tx/all +| tap | rx:receive packets sent to the netdev +| | tx:receive packets sent by the netdev ++--------------------------------------------------------------+ + +1.Guest receive packet route: + +Primary: + +Tap --> Mirror Client Filter +Mirror client will send packet to guest,at the +same time, copy and forward packet to secondary +mirror server. + +Secondary: + +Mirror Server Filter --> TCP Rewriter +If receive packet is TCP packet,we will adjust ack +and update TCP checksum, then send to secondary +guest. Otherwise directly send to guest. + +2.Guest send packet route: + +Primary: + +Guest --> Redirect Server Filter +Redirect server filter receive primary guest packet +but do nothing, just pass to next filter. + +Redirect Server Filter --> COLO-Compare +COLO-compare receive primary guest packet then +waiting scondary redirect packet to compare it. +If packet same,send queued primary packet and clear +queued secondary packet, Otherwise send primary packet +and do checkpoint. + +COLO-Compare --> Another Redirector Filter +The redirector get packet from colo-compare by use +chardev socket. + +Redirector Filter --> Tap +Send the packet. + +Secondary: + +Guest --> TCP Rewriter Filter +If the packet is TCP packet,we will adjust seq +and update TCP checksum. Then send it to +redirect client filter. Otherwise directly send to +redirect client filter. + +Redirect Client Filter --> Redirect Server Filter +Forward packet to primary. + +== Components introduction == + +Filter-mirror is a netfilter plugin. +It gives qemu the ability to mirror +packets to a chardev. + +Filter-redirector is a netfilter plugin. +It gives qemu the ability to redirect net packet. +Redirector can redirect filter's net packet to outdev, +and redirect indev's packet to filter. + + filter + + + redirector | + +--------------+ + | | | + | | | + | | | + indev +---------+ +----------> outdev + | | | + | | | + | | | + +--------------+ + | + v + filter + +COLO-compare, we do packet comparing job. +Packets coming from the primary char indev will be sent to outdev. +Packets coming from the secondary char dev will be dropped after comparing. +COLO-comapre need two input chardev and one output chardev: +primary_in=chardev1-id (source: primary send packet) +secondary_in=chardev2-id (source: secondary send packet) +outdev=chardev3-id + +Filter-rewriter will rewrite some of secondary packet to make +secondary guest's tcp connection established successfully. +In this module we will rewrite tcp packet's ack to the secondary +from primary,and rewrite tcp packet's seq to the primary from +secondary. + +== Usage == + +Here, we use demo ip and port discribe more clearly. +Primary(ip:3.3.3.3): +-netdev tap,id=hn0,vhost=off,script=/etc/qemu-ifup,downscript=/etc/qemu-ifdown +-device e1000,id=e0,netdev=hn0,mac=52:a4:00:12:78:66 +-chardev socket,id=mirror0,host=3.3.3.3,port=9003,server,nowait +-chardev socket,id=compare1,host=3.3.3.3,port=9004,server,nowait +-chardev socket,id=compare0,host=3.3.3.3,port=9001,server,nowait +-chardev socket,id=compare0-0,host=3.3.3.3,port=9001 +-chardev socket,id=compare_out,host=3.3.3.3,port=9005,server,nowait +-chardev socket,id=compare_out0,host=3.3.3.3,port=9005 +-object filter-mirror,id=m0,netdev=hn0,queue=tx,outdev=mirror0 +-object filter-redirector,netdev=hn0,id=redire0,queue=rx,indev=compare_out +-object filter-redirector,netdev=hn0,id=redire1,queue=rx,outdev=compare0 +-object colo-compare,id=comp0,primary_in=compare0-0,secondary_in=compare1,outdev=compare_out0 + +Secondary(ip:3.3.3.8): +-netdev tap,id=hn0,vhost=off,script=/etc/qemu-ifup,down script=/etc/qemu-ifdown +-device e1000,netdev=hn0,mac=52:a4:00:12:78:66 +-chardev socket,id=red0,host=3.3.3.3,port=9003 +-chardev socket,id=red1,host=3.3.3.3,port=9004 +-object filter-redirector,id=f1,netdev=hn0,queue=tx,indev=red0 +-object filter-redirector,id=f2,netdev=hn0,queue=rx,outdev=red1 + +Note: + a.COLO-proxy must work with COLO-frame and Block-replication. + b.Primary COLO must be started firstly, because COLO-proxy needs + chardev socket server running before secondary started. + c.Filter-rewriter only rewrite tcp packet. From fb56d323e2c9472ba4c25fc0f13f2aaddda62380 Mon Sep 17 00:00:00 2001 From: Gonglei Date: Tue, 30 Aug 2016 12:06:21 +0800 Subject: [PATCH 325/723] e1000: fix buliding complaint hw/net/e1000e_core.c:56: warning: e1000e_set_interrupt_cause declared inline after being called hw/net/e1000e_core.c:56: warning: previous declaration of e1000e_set_interrupt_cause was here Signed-off-by: Gonglei Reviewed-by: Dmitry Fleytman Signed-off-by: Jason Wang --- hw/net/e1000e_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c index e0bd31c577b..03e3c462f18 100644 --- a/hw/net/e1000e_core.c +++ b/hw/net/e1000e_core.c @@ -2168,7 +2168,7 @@ e1000e_update_interrupt_state(E1000ECore *core) } } -static inline void +static void e1000e_set_interrupt_cause(E1000ECore *core, uint32_t val) { trace_e1000e_irq_set_cause_entry(val, core->mac[ICR]); From 584613eacb3840c1803e665ed7edd4ac186deced Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Tue, 13 Sep 2016 17:11:54 +1000 Subject: [PATCH 326/723] tap: Allow specifying a bridge The tap backend is already using qemu-bridge-helper to attach tap interface to a bridge but (unlike the bridge backend) it always uses the default bridge name - br0. This adds a "br" property support to the tap backend. Signed-off-by: Alexey Kardashevskiy Reviewed-by: Greg Kurz Tested-by: Greg Kurz Signed-off-by: Jason Wang --- net/tap.c | 4 +++- qapi-schema.json | 3 +++ qemu-options.hx | 12 +++++++----- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/net/tap.c b/net/tap.c index 6abb962efd8..b6896a7b7ce 100644 --- a/net/tap.c +++ b/net/tap.c @@ -857,7 +857,9 @@ int net_init_tap(const Netdev *netdev, const char *name, return -1; } - fd = net_bridge_run_helper(tap->helper, DEFAULT_BRIDGE_INTERFACE, + fd = net_bridge_run_helper(tap->helper, + tap->has_br ? + tap->br : DEFAULT_BRIDGE_INTERFACE, errp); if (fd == -1) { return -1; diff --git a/qapi-schema.json b/qapi-schema.json index e50706111cf..c3dcf11a4ac 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -2636,6 +2636,8 @@ # # @downscript: #optional script to shut down the interface # +# @br: #optional bridge name (since 2.8) +# # @helper: #optional command to execute to configure bridge # # @sndbuf: #optional send buffer limit. Understands [TGMKkb] suffixes. @@ -2665,6 +2667,7 @@ '*fds': 'str', '*script': 'str', '*downscript': 'str', + '*br': 'str', '*helper': 'str', '*sndbuf': 'size', '*vnet_hdr': 'bool', diff --git a/qemu-options.hx b/qemu-options.hx index 987d055481c..01f01dfadcb 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1598,10 +1598,11 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev, " configure a host TAP network backend with ID 'str'\n" #else "-netdev tap,id=str[,fd=h][,fds=x:y:...:z][,ifname=name][,script=file][,downscript=dfile]\n" - " [,helper=helper][,sndbuf=nbytes][,vnet_hdr=on|off][,vhost=on|off]\n" + " [,br=bridge][,helper=helper][,sndbuf=nbytes][,vnet_hdr=on|off][,vhost=on|off]\n" " [,vhostfd=h][,vhostfds=x:y:...:z][,vhostforce=on|off][,queues=n]\n" " [,poll-us=n]\n" " configure a host TAP network backend with ID 'str'\n" + " connected to a bridge (default=" DEFAULT_BRIDGE_INTERFACE ")\n" " use network scripts 'file' (default=" DEFAULT_NETWORK_SCRIPT ")\n" " to configure it and 'dfile' (default=" DEFAULT_NETWORK_DOWN_SCRIPT ")\n" " to deconfigure it\n" @@ -1888,8 +1889,8 @@ processed and applied to -net user. Mixing them with the new configuration syntax gives undefined results. Their use for new applications is discouraged as they will be removed from future versions. -@item -netdev tap,id=@var{id}[,fd=@var{h}][,ifname=@var{name}][,script=@var{file}][,downscript=@var{dfile}][,helper=@var{helper}] -@itemx -net tap[,vlan=@var{n}][,name=@var{name}][,fd=@var{h}][,ifname=@var{name}][,script=@var{file}][,downscript=@var{dfile}][,helper=@var{helper}] +@item -netdev tap,id=@var{id}[,fd=@var{h}][,ifname=@var{name}][,script=@var{file}][,downscript=@var{dfile}][,br=@var{bridge}][,helper=@var{helper}] +@itemx -net tap[,vlan=@var{n}][,name=@var{name}][,fd=@var{h}][,ifname=@var{name}][,script=@var{file}][,downscript=@var{dfile}][,br=@var{bridge}][,helper=@var{helper}] Connect the host TAP network interface @var{name} to VLAN @var{n}. Use the network script @var{file} to configure it and the network script @@ -1900,8 +1901,9 @@ automatically provides one. The default network configure script is to disable script execution. If running QEMU as an unprivileged user, use the network helper -@var{helper} to configure the TAP interface. The default network -helper executable is @file{/path/to/qemu-bridge-helper}. +@var{helper} to configure the TAP interface and attach it to the bridge. +The default network helper executable is @file{/path/to/qemu-bridge-helper} +and the default bridge device is @file{br0}. @option{fd}=@var{h} can be used to specify the handle of an already opened host TAP interface. From 47f9f15831faa549504ab9b035aaea44a02e5f95 Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Thu, 30 Jun 2016 11:49:40 +0200 Subject: [PATCH 327/723] net: limit allocation in nc_sendv_compat we only need to allocate enough memory to hold the packet. This might be less than NET_BUFSIZE. Additionally fail early if the packet is larger than NET_BUFSIZE. Signed-off-by: Peter Lieven Reviewed-by: Stefan Hajnoczi Signed-off-by: Jason Wang --- net/net.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/net/net.c b/net/net.c index 0bec096d75b..ec984bf782a 100644 --- a/net/net.c +++ b/net/net.c @@ -690,9 +690,13 @@ static ssize_t nc_sendv_compat(NetClientState *nc, const struct iovec *iov, buffer = iov[0].iov_base; offset = iov[0].iov_len; } else { - buf = g_new(uint8_t, NET_BUFSIZE); + offset = iov_size(iov, iovcnt); + if (offset > NET_BUFSIZE) { + return -1; + } + buf = g_malloc(offset); buffer = buf; - offset = iov_to_buf(iov, iovcnt, 0, buf, NET_BUFSIZE); + offset = iov_to_buf(iov, iovcnt, 0, buf, offset); } if (flags & QEMU_NET_PACKET_FLAG_RAW && nc->info->receive_raw) { From 6ee0e20b653817aa0adac89e21704842608e1639 Mon Sep 17 00:00:00 2001 From: Dmitry Fleytman Date: Thu, 15 Sep 2016 09:14:24 +0300 Subject: [PATCH 328/723] e1000e: Flush all receive queues on receive enable Before this patch first netdev queue only was flushed. Signed-off-by: Dmitry Fleytman Signed-off-by: Jason Wang --- hw/net/e1000e.c | 2 +- hw/net/e1000e_core.c | 2 +- hw/net/e1000e_core.h | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/hw/net/e1000e.c b/hw/net/e1000e.c index bad43f474e0..4994e1ca006 100644 --- a/hw/net/e1000e.c +++ b/hw/net/e1000e.c @@ -400,7 +400,7 @@ static void e1000e_write_config(PCIDevice *pci_dev, uint32_t address, if (range_covers_byte(address, len, PCI_COMMAND) && (pci_dev->config[PCI_COMMAND] & PCI_COMMAND_MASTER)) { - qemu_flush_queued_packets(qemu_get_queue(s->nic)); + e1000e_start_recv(&s->core); } } diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c index 03e3c462f18..ea2a484e9ef 100644 --- a/hw/net/e1000e_core.c +++ b/hw/net/e1000e_core.c @@ -953,7 +953,7 @@ e1000e_has_rxbufs(E1000ECore *core, const E1000E_RingInfo *r, core->rx_desc_buf_size; } -static inline void +void e1000e_start_recv(E1000ECore *core) { int i; diff --git a/hw/net/e1000e_core.h b/hw/net/e1000e_core.h index 5f413a9e08b..1ff6978ca1f 100644 --- a/hw/net/e1000e_core.h +++ b/hw/net/e1000e_core.h @@ -144,3 +144,6 @@ e1000e_receive(E1000ECore *core, const uint8_t *buf, size_t size); ssize_t e1000e_receive_iov(E1000ECore *core, const struct iovec *iov, int iovcnt); + +void +e1000e_start_recv(E1000ECore *core); From 40364748ddca8a510de5f345b8f7c1c49d24cd26 Mon Sep 17 00:00:00 2001 From: Dmitry Fleytman Date: Thu, 15 Sep 2016 09:14:25 +0300 Subject: [PATCH 329/723] e1000e: Flush receive queues on link up Signed-off-by: Dmitry Fleytman Signed-off-by: Jason Wang --- hw/net/e1000e_core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c index ea2a484e9ef..e8d50f65f01 100644 --- a/hw/net/e1000e_core.c +++ b/hw/net/e1000e_core.c @@ -1807,6 +1807,7 @@ e1000e_core_set_link_status(E1000ECore *core) core->autoneg_timer); } else { e1000x_update_regs_on_link_up(core->mac, core->phy[0]); + e1000e_start_recv(core); } } @@ -2187,6 +2188,8 @@ e1000e_autoneg_timer(void *opaque) E1000ECore *core = opaque; if (!qemu_get_queue(core->owner_nic)->link_down) { e1000x_update_regs_on_autoneg_done(core->mac, core->phy[0]); + e1000e_start_recv(core); + e1000e_update_flowctl_status(core); /* signal link status change to the guest */ e1000e_set_interrupt_cause(core, E1000_ICR_LSC); From 2d803144a637130b1f167b309bc8ac7142f76b26 Mon Sep 17 00:00:00 2001 From: Dmitry Fleytman Date: Thu, 15 Sep 2016 09:14:26 +0300 Subject: [PATCH 330/723] e1000e: Fix CTRL_EXT.EIAME behavior CTRL_EXT.EIAME bit controls clearing of IAM bits, but current code clears IMS bits instead. See spec. 10.2.2.5 Extended Device Control Register. Signed-off-by: Dmitry Fleytman Signed-off-by: Jason Wang --- hw/net/e1000e_core.c | 4 ++-- hw/net/trace-events | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c index e8d50f65f01..a198a884ed9 100644 --- a/hw/net/e1000e_core.c +++ b/hw/net/e1000e_core.c @@ -2008,8 +2008,8 @@ e1000e_msix_notify_one(E1000ECore *core, uint32_t cause, uint32_t int_cfg) } if (core->mac[CTRL_EXT] & E1000_CTRL_EXT_EIAME) { - trace_e1000e_irq_ims_clear_eiame(core->mac[IAM], cause); - e1000e_clear_ims_bits(core, core->mac[IAM] & cause); + trace_e1000e_irq_iam_clear_eiame(core->mac[IAM], cause); + core->mac[IAM] &= ~cause; } trace_e1000e_irq_icr_clear_eiac(core->mac[ICR], core->mac[EIAC]); diff --git a/hw/net/trace-events b/hw/net/trace-events index 47ab14ac71f..1a5c909939e 100644 --- a/hw/net/trace-events +++ b/hw/net/trace-events @@ -223,7 +223,7 @@ e1000e_irq_icr_read_entry(uint32_t icr) "Starting ICR read. Current ICR: 0x%x" e1000e_irq_icr_read_exit(uint32_t icr) "Ending ICR read. Current ICR: 0x%x" e1000e_irq_icr_clear_zero_ims(void) "Clearing ICR on read due to zero IMS" e1000e_irq_icr_clear_iame(void) "Clearing ICR on read due to IAME" -e1000e_irq_ims_clear_eiame(uint32_t iam, uint32_t cause) "Clearing IMS due to EIAME, IAM: 0x%X, cause: 0x%X" +e1000e_irq_iam_clear_eiame(uint32_t iam, uint32_t cause) "Clearing IMS due to EIAME, IAM: 0x%X, cause: 0x%X" e1000e_irq_icr_clear_eiac(uint32_t icr, uint32_t eiac) "Clearing ICR bits due to EIAC, ICR: 0x%X, EIAC: 0x%X" e1000e_irq_ims_clear_set_imc(uint32_t val) "Clearing IMS bits due to IMC write 0x%x" e1000e_irq_fire_delayed_interrupts(void) "Firing delayed interrupts" From 680e60b6ba5a26332d684a60a6d9f39c0a999941 Mon Sep 17 00:00:00 2001 From: Dmitry Fleytman Date: Thu, 15 Sep 2016 09:14:27 +0300 Subject: [PATCH 331/723] e1000e: Fix PBACLR implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch fixes incorrect check for interrypt type being used. PBSCLR register is valid for MSI-X only. See spec. 10.2.3.13 MSI—X PBA Clear Signed-off-by: Dmitry Fleytman Signed-off-by: Jason Wang --- hw/net/e1000e_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c index a198a884ed9..a5751acd5cb 100644 --- a/hw/net/e1000e_core.c +++ b/hw/net/e1000e_core.c @@ -2347,7 +2347,7 @@ e1000e_set_pbaclr(E1000ECore *core, int index, uint32_t val) core->mac[PBACLR] = val & E1000_PBACLR_VALID_MASK; - if (msix_enabled(core->owner)) { + if (!msix_enabled(core->owner)) { return; } From 8b54c6e1872825c76200bfb419dadeb6a84b3845 Mon Sep 17 00:00:00 2001 From: Dmitry Fleytman Date: Thu, 15 Sep 2016 09:14:28 +0300 Subject: [PATCH 332/723] e1000e: Fix OTHER interrupts processing for MSI-X Interrupt mask for legacy OTHER causes should not apply to MSI-X OTHER cause. Signed-off-by: Dmitry Fleytman Signed-off-by: Jason Wang --- hw/net/e1000e_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c index a5751acd5cb..d26b611ab96 100644 --- a/hw/net/e1000e_core.c +++ b/hw/net/e1000e_core.c @@ -2131,7 +2131,7 @@ e1000e_update_interrupt_state(E1000ECore *core) /* Set ICR[OTHER] for MSI-X */ if (is_msix) { - if (core->mac[ICR] & core->mac[IMS] & E1000_ICR_OTHER_CAUSES) { + if (core->mac[ICR] & E1000_ICR_OTHER_CAUSES) { core->mac[ICR] |= E1000_ICR_OTHER; trace_e1000e_irq_add_msi_other(core->mac[ICR]); } From 4100c026b69001f774bfff30b5773a2418306f8c Mon Sep 17 00:00:00 2001 From: Dmitry Fleytman Date: Thu, 15 Sep 2016 09:14:29 +0300 Subject: [PATCH 333/723] e1000e: Fix spurious RX TCP ACK interrupts Do not raise ACK interrupts when RFCTL.ACKDIS bit is set (see spec. 10.2.5.16). Signed-off-by: Dmitry Fleytman Signed-off-by: Jason Wang --- hw/net/e1000e_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c index d26b611ab96..02981364a3b 100644 --- a/hw/net/e1000e_core.c +++ b/hw/net/e1000e_core.c @@ -1710,7 +1710,8 @@ e1000e_receive_iov(E1000ECore *core, const struct iovec *iov, int iovcnt) } /* Perform ACK receive detection */ - if (e1000e_is_tcp_ack(core, core->rx_pkt)) { + if (!(core->mac[RFCTL] & E1000_RFCTL_ACK_DIS) && + (e1000e_is_tcp_ack(core, core->rx_pkt))) { n |= E1000_ICS_ACK; } From b38636b83727d611a354217fa9d17de5872d7da4 Mon Sep 17 00:00:00 2001 From: Dmitry Fleytman Date: Thu, 15 Sep 2016 09:14:30 +0300 Subject: [PATCH 334/723] e1000e: Fix EIAC register implementation This patch fixes 2 issues: 1. Bits set in EIAC register should be cleared from IMS when EIAM is not used. 2. Only bit that corresonds to the interrupt being raised should be cleared. See spec. 10.2.4.7 Interrupt Auto Clear Signed-off-by: Dmitry Fleytman Signed-off-by: Jason Wang --- hw/net/e1000e_core.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c index 02981364a3b..6505983c12e 100644 --- a/hw/net/e1000e_core.c +++ b/hw/net/e1000e_core.c @@ -2015,13 +2015,17 @@ e1000e_msix_notify_one(E1000ECore *core, uint32_t cause, uint32_t int_cfg) trace_e1000e_irq_icr_clear_eiac(core->mac[ICR], core->mac[EIAC]); - if (core->mac[EIAC] & E1000_ICR_OTHER) { - effective_eiac = (core->mac[EIAC] & E1000_EIAC_MASK) | - E1000_ICR_OTHER_CAUSES; - } else { - effective_eiac = core->mac[EIAC] & E1000_EIAC_MASK; + effective_eiac = core->mac[EIAC] & cause; + + if (effective_eiac == E1000_ICR_OTHER) { + effective_eiac |= E1000_ICR_OTHER_CAUSES; } + core->mac[ICR] &= ~effective_eiac; + + if (!(core->mac[CTRL_EXT] & E1000_CTRL_EXT_IAME)) { + core->mac[IMS] &= ~effective_eiac; + } } static void From 070c4b92b8cd5390889716677a0b92444d6e087a Mon Sep 17 00:00:00 2001 From: Prasad J Pandit Date: Thu, 22 Sep 2016 16:02:37 +0530 Subject: [PATCH 335/723] net: mcf: limit buffer descriptor count ColdFire Fast Ethernet Controller uses buffer descriptors to manage data flow to/fro receive & transmit queues. While transmitting packets, it could continue to read buffer descriptors if a buffer descriptor has length of zero and has crafted values in bd.flags. Set upper limit to number of buffer descriptors. Reported-by: Li Qiang Signed-off-by: Prasad J Pandit Reviewed-by: Paolo Bonzini Signed-off-by: Jason Wang --- hw/net/mcf_fec.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/net/mcf_fec.c b/hw/net/mcf_fec.c index 0ee8ad9d668..d31fea1f187 100644 --- a/hw/net/mcf_fec.c +++ b/hw/net/mcf_fec.c @@ -23,6 +23,7 @@ do { printf("mcf_fec: " fmt , ## __VA_ARGS__); } while (0) #define DPRINTF(fmt, ...) do {} while(0) #endif +#define FEC_MAX_DESC 1024 #define FEC_MAX_FRAME_SIZE 2032 typedef struct { @@ -149,7 +150,7 @@ static void mcf_fec_do_tx(mcf_fec_state *s) uint32_t addr; mcf_fec_bd bd; int frame_size; - int len; + int len, descnt = 0; uint8_t frame[FEC_MAX_FRAME_SIZE]; uint8_t *ptr; @@ -157,7 +158,7 @@ static void mcf_fec_do_tx(mcf_fec_state *s) ptr = frame; frame_size = 0; addr = s->tx_descriptor; - while (1) { + while (descnt++ < FEC_MAX_DESC) { mcf_fec_read_bd(&bd, addr); DPRINTF("tx_bd %x flags %04x len %d data %08x\n", addr, bd.flags, bd.length, bd.data); From a16d8ef54b8274ce9e7d7d6377a5a11f3c74668b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 22 Sep 2016 16:28:29 +0200 Subject: [PATCH 336/723] mcf_fec: fix error in qemu_send_packet argument This uses the wrong frame size for packets composed of multiple descriptors. Signed-off-by: Paolo Bonzini Signed-off-by: Jason Wang --- hw/net/mcf_fec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/net/mcf_fec.c b/hw/net/mcf_fec.c index d31fea1f187..dc61bac2fce 100644 --- a/hw/net/mcf_fec.c +++ b/hw/net/mcf_fec.c @@ -177,7 +177,7 @@ static void mcf_fec_do_tx(mcf_fec_state *s) if (bd.flags & FEC_BD_L) { /* Last buffer in frame. */ DPRINTF("Sending packet\n"); - qemu_send_packet(qemu_get_queue(s->nic), frame, len); + qemu_send_packet(qemu_get_queue(s->nic), frame, frame_size); ptr = frame; frame_size = 0; s->eir |= FEC_INT_TXF; From fa26f018393f18f5e91334820546bef07b133b88 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 22 Sep 2016 16:28:30 +0200 Subject: [PATCH 337/723] imx_fec: fix error in qemu_send_packet argument This uses the wrong frame size for packets composed of multiple descriptors. Signed-off-by: Paolo Bonzini Signed-off-by: Jason Wang --- hw/net/imx_fec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 1c415ab3b15..50c75642c67 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -429,7 +429,7 @@ static void imx_fec_do_tx(IMXFECState *s) frame_size += len; if (bd.flags & ENET_BD_L) { /* Last buffer in frame. */ - qemu_send_packet(qemu_get_queue(s->nic), frame, len); + qemu_send_packet(qemu_get_queue(s->nic), frame, frame_size); ptr = frame; frame_size = 0; s->regs[ENET_EIR] |= ENET_INT_TXF; From a3276f786c84d3410be5bc3a4b3e5036745e5a90 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Fri, 23 Sep 2016 13:02:28 +0800 Subject: [PATCH 338/723] intel_iommu, amd_iommu: allow UNMAP notifiers x86 vIOMMUs still lack of a complete IOMMU notifier mechanism. Before that is achieved, let's open a door for vhost DMAR support, which only requires cache invalidations (UNMAP operations). Meanwhile, convert hw_error() to error_report() and exit(1), to make the error messages cleaner and obvious (no CPU registers will be dumped). Reviewed-by: David Gibson Signed-off-by: Peter Xu Message-Id: <1474606948-14391-4-git-send-email-peterx@redhat.com> Signed-off-by: Paolo Bonzini --- hw/i386/amd_iommu.c | 10 +++++++--- hw/i386/intel_iommu.c | 12 ++++++++---- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index a868539fb01..023de526f6e 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -21,6 +21,7 @@ */ #include "qemu/osdep.h" #include "hw/i386/amd_iommu.h" +#include "qemu/error-report.h" #include "trace.h" /* used AMD-Vi MMIO registers */ @@ -1072,9 +1073,12 @@ static void amdvi_iommu_notify_flag_changed(MemoryRegion *iommu, { AMDVIAddressSpace *as = container_of(iommu, AMDVIAddressSpace, iommu); - hw_error("device %02x.%02x.%x requires iommu notifier which is not " - "currently supported", as->bus_num, PCI_SLOT(as->devfn), - PCI_FUNC(as->devfn)); + if (new & IOMMU_NOTIFIER_MAP) { + error_report("device %02x.%02x.%x requires iommu notifier which is not " + "currently supported", as->bus_num, PCI_SLOT(as->devfn), + PCI_FUNC(as->devfn)); + exit(1); + } } static void amdvi_init(AMDVIState *s) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index b6cc38c73d6..9f4e64af1ad 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -1980,10 +1980,14 @@ static void vtd_iommu_notify_flag_changed(MemoryRegion *iommu, { VTDAddressSpace *vtd_as = container_of(iommu, VTDAddressSpace, iommu); - hw_error("Device at bus %s addr %02x.%d requires iommu notifier which " - "is currently not supported by intel-iommu emulation", - vtd_as->bus->qbus.name, PCI_SLOT(vtd_as->devfn), - PCI_FUNC(vtd_as->devfn)); + if (new & IOMMU_NOTIFIER_MAP) { + error_report("Device at bus %s addr %02x.%d requires iommu " + "notifier which is currently not supported by " + "intel-iommu emulation", + vtd_as->bus->qbus.name, PCI_SLOT(vtd_as->devfn), + PCI_FUNC(vtd_as->devfn)); + exit(1); + } } static const VMStateDescription vtd_vmstate = { From 048a2e8869cb7e26013e40d860c9ebdf8e28c2ac Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Fri, 23 Sep 2016 13:33:15 +0800 Subject: [PATCH 339/723] x86: ioapic: boost default version to 0x20 It's 2.8 now, and maybe it's time to switch IOAPIC default version to 0x20. Signed-off-by: Peter Xu Message-Id: <1474608795-23058-1-git-send-email-peterx@redhat.com> Signed-off-by: Paolo Bonzini --- hw/intc/ioapic.c | 2 +- include/hw/compat.h | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/hw/intc/ioapic.c b/hw/intc/ioapic.c index 31791b09860..fd9208fde08 100644 --- a/hw/intc/ioapic.c +++ b/hw/intc/ioapic.c @@ -416,7 +416,7 @@ static void ioapic_realize(DeviceState *dev, Error **errp) } static Property ioapic_properties[] = { - DEFINE_PROP_UINT8("version", IOAPICCommonState, version, 0x11), + DEFINE_PROP_UINT8("version", IOAPICCommonState, version, 0x20), DEFINE_PROP_END_OF_LIST(), }; diff --git a/include/hw/compat.h b/include/hw/compat.h index a1d66944924..46412b229a7 100644 --- a/include/hw/compat.h +++ b/include/hw/compat.h @@ -6,6 +6,10 @@ .driver = "virtio-pci",\ .property = "page-per-vq",\ .value = "on",\ + },{\ + .driver = "ioapic",\ + .property = "version",\ + .value = "0x11",\ }, #define HW_COMPAT_2_6 \ From 63ae8b942d8e4095179bbf1a8946348bc71b7973 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 21 Sep 2016 18:49:07 +0200 Subject: [PATCH 340/723] checkpatch: downgrade "architecture specific defines should be avoided" Signed-off-by: Paolo Bonzini --- scripts/checkpatch.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index dde3f5f9d98..3afa19a766c 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -2407,7 +2407,7 @@ sub process { # we have e.g. CONFIG_LINUX and CONFIG_WIN32 for common cases # where they might be necessary. if ($line =~ m@^.\s*\#\s*if.*\b__@) { - ERROR("architecture specific defines should be avoided\n" . $herecurr); + WARN("architecture specific defines should be avoided\n" . $herecurr); } # Check that the storage class is at the beginning of a declaration From cc9d8a3b2c41c22fb09f90f3085e6036c199c3ca Mon Sep 17 00:00:00 2001 From: Felipe Franciosi Date: Fri, 23 Sep 2016 16:02:51 +0100 Subject: [PATCH 341/723] compiler: Swap 'public domain' header for license As discussed on the list [1], having a comment stating that this file is "public domain" is arguably wrong and not legally binding. This patch replaces that comment with a clear GPLv2+ license as proposed in [2]. [1] http://lists.nongnu.org/archive/html/qemu-devel/2016-09/msg06151.html [2] http://lists.nongnu.org/archive/html/qemu-devel/2016-09/msg06217.html Worth noting, compiler.h was originally created on 5c026320 by splitting qemu-common.h. At the time, qemu-common.h was already GPLv2+. Signed-off-by: Felipe Franciosi Message-Id: <1474642971-11866-1-git-send-email-felipe@nutanix.com> Signed-off-by: Paolo Bonzini --- include/qemu/compiler.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/qemu/compiler.h b/include/qemu/compiler.h index 338d3a65b37..157698bfa95 100644 --- a/include/qemu/compiler.h +++ b/include/qemu/compiler.h @@ -1,4 +1,8 @@ -/* public domain */ +/* compiler.h: macros to abstract away compiler specifics + * + * 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 COMPILER_H #define COMPILER_H From 9c1f8f4493e8355d0e48f7d1eebdf86893ba082d Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 22 Sep 2016 16:08:31 +0200 Subject: [PATCH 342/723] migration: sync all address spaces Migrating a VM during reboot sometimes results in differences between the source and destination in the SMRAM area. This is because migration_bitmap_sync() only fetches from KVM the dirty log of address_space_memory. SMRAM memory slots are ignored and the modifications to SMRAM are not sent to the destination. Reported-by: He Rongguang Reviewed-by: He Rongguang Signed-off-by: Paolo Bonzini --- include/exec/memory.h | 7 +++---- memory.c | 46 +++++++++++++++++++++++++++++++------------ migration/ram.c | 2 +- 3 files changed, 37 insertions(+), 18 deletions(-) diff --git a/include/exec/memory.h b/include/exec/memory.h index a3f988b6408..10d7eacc40f 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -1188,12 +1188,11 @@ MemoryRegionSection memory_region_find(MemoryRegion *mr, hwaddr addr, uint64_t size); /** - * address_space_sync_dirty_bitmap: synchronize the dirty log for all memory + * memory_global_dirty_log_sync: synchronize the dirty log for all memory * - * Synchronizes the dirty page log for an entire address space. - * @as: the address space that contains the memory being synchronized + * Synchronizes the dirty page log for all address spaces. */ -void address_space_sync_dirty_bitmap(AddressSpace *as); +void memory_global_dirty_log_sync(void); /** * memory_region_transaction_begin: Start a transaction. diff --git a/memory.c b/memory.c index 27a3f2fca28..58f92693e29 100644 --- a/memory.c +++ b/memory.c @@ -158,14 +158,10 @@ static bool memory_listener_match(MemoryListener *listener, /* No need to ref/unref .mr, the FlatRange keeps it alive. */ #define MEMORY_LISTENER_UPDATE_REGION(fr, as, dir, callback, _args...) \ - MEMORY_LISTENER_CALL(callback, dir, (&(MemoryRegionSection) { \ - .mr = (fr)->mr, \ - .address_space = (as), \ - .offset_within_region = (fr)->offset_in_region, \ - .size = (fr)->addr.size, \ - .offset_within_address_space = int128_get64((fr)->addr.start), \ - .readonly = (fr)->readonly, \ - }), ##_args) + do { \ + MemoryRegionSection mrs = section_from_flat_range(fr, as); \ + MEMORY_LISTENER_CALL(callback, dir, &mrs, ##_args); \ + } while(0) struct CoalescedMemoryRange { AddrRange addr; @@ -245,6 +241,19 @@ typedef struct AddressSpaceOps AddressSpaceOps; #define FOR_EACH_FLAT_RANGE(var, view) \ for (var = (view)->ranges; var < (view)->ranges + (view)->nr; ++var) +static inline MemoryRegionSection +section_from_flat_range(FlatRange *fr, AddressSpace *as) +{ + return (MemoryRegionSection) { + .mr = fr->mr, + .address_space = as, + .offset_within_region = fr->offset_in_region, + .size = fr->addr.size, + .offset_within_address_space = int128_get64(fr->addr.start), + .readonly = fr->readonly, + }; +} + static bool flatrange_equal(FlatRange *a, FlatRange *b) { return a->mr == b->mr @@ -2156,16 +2165,27 @@ bool memory_region_present(MemoryRegion *container, hwaddr addr) return mr && mr != container; } -void address_space_sync_dirty_bitmap(AddressSpace *as) +void memory_global_dirty_log_sync(void) { + MemoryListener *listener; + AddressSpace *as; FlatView *view; FlatRange *fr; - view = address_space_get_flatview(as); - FOR_EACH_FLAT_RANGE(fr, view) { - MEMORY_LISTENER_UPDATE_REGION(fr, as, Forward, log_sync); + QTAILQ_FOREACH(listener, &memory_listeners, link) { + if (!listener->log_sync) { + continue; + } + /* Global listeners are being phased out. */ + assert(listener->address_space_filter); + as = listener->address_space_filter; + view = address_space_get_flatview(as); + FOR_EACH_FLAT_RANGE(fr, view) { + MemoryRegionSection mrs = section_from_flat_range(fr, as); + listener->log_sync(listener, &mrs); + } + flatview_unref(view); } - flatview_unref(view); } void memory_global_dirty_log_start(void) diff --git a/migration/ram.c b/migration/ram.c index a6e1c63a08d..c8ec9f268fd 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -626,7 +626,7 @@ static void migration_bitmap_sync(void) } trace_migration_bitmap_sync_start(); - address_space_sync_dirty_bitmap(&address_space_memory); + memory_global_dirty_log_sync(); qemu_mutex_lock(&migration_bitmap_mutex); rcu_read_lock(); From 1f04b992cf643cd9eb98394d1960b1a5bdfa4b42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 26 Sep 2016 00:57:47 +0400 Subject: [PATCH 343/723] build-sys: remove unused GLIB_CFLAGS Message-Id: <20160925205748.6280-1-marcandre.lureau@redhat.com> Signed-off-by: Paolo Bonzini --- configure | 1 - 1 file changed, 1 deletion(-) diff --git a/configure b/configure index 8fa62ade57b..c83160025e4 100755 --- a/configure +++ b/configure @@ -5140,7 +5140,6 @@ fi if test "$glib_subprocess" = "yes" ; then echo "CONFIG_HAS_GLIB_SUBPROCESS_TESTS=y" >> $config_host_mak fi -echo "GLIB_CFLAGS=$glib_cflags" >> $config_host_mak if test "$gtk" = "yes" ; then echo "CONFIG_GTK=y" >> $config_host_mak echo "CONFIG_GTKABI=$gtkabi" >> $config_host_mak From 4a0588996a5848ce9550188d0f60642636815059 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 26 Sep 2016 00:57:48 +0400 Subject: [PATCH 344/723] build-sys: put glib_cflags in QEMU_CFLAGS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This way, overriding CFLAGS on make command line keeps glib-cflags and doesn't break the build. Signed-off-by: Marc-André Lureau Message-Id: <20160925205748.6280-2-marcandre.lureau@redhat.com> Signed-off-by: Paolo Bonzini --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index c83160025e4..5412d4f0b7e 100755 --- a/configure +++ b/configure @@ -2933,7 +2933,7 @@ for i in $glib_modules; do if $pkg_config --atleast-version=$glib_req_ver $i; then glib_cflags=$($pkg_config --cflags $i) glib_libs=$($pkg_config --libs $i) - CFLAGS="$glib_cflags $CFLAGS" + QEMU_CFLAGS="$glib_cflags $QEMU_CFLAGS" LIBS="$glib_libs $LIBS" libs_qga="$glib_libs $libs_qga" else From e0eeb4a21a3ca4b296220ce4449d8acef9de9049 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 2 Aug 2016 18:27:33 +0100 Subject: [PATCH 345/723] cpus: pass CPUState to run_on_cpu helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CPUState is a fairly common pointer to pass to these helpers. This means if you need other arguments for the async_run_on_cpu case you end up having to do a g_malloc to stuff additional data into the routine. For the current users this isn't a massive deal but for MTTCG this gets cumbersome when the only other parameter is often an address. This adds the typedef run_on_cpu_func for helper functions which has an explicit CPUState * passed as the first parameter. All the users of run_on_cpu and async_run_on_cpu have had their helpers updated to use CPUState where available. Signed-off-by: Alex Bennée [Sergey Fedorov: - eliminate more CPUState in user data; - remove unnecessary user data passing; - fix target-s390x/kvm.c and target-s390x/misc_helper.c] Signed-off-by: Sergey Fedorov Acked-by: David Gibson (ppc parts) Reviewed-by: Christian Borntraeger (s390 parts) Signed-off-by: Alex Bennée Message-Id: <1470158864-17651-3-git-send-email-alex.bennee@linaro.org> Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- cpus.c | 15 +++--- hw/i386/kvm/apic.c | 5 +- hw/i386/kvmvapic.c | 6 +-- hw/ppc/ppce500_spin.c | 31 ++++-------- hw/ppc/spapr.c | 6 +-- hw/ppc/spapr_hcall.c | 17 +++---- include/qom/cpu.h | 8 ++-- kvm-all.c | 21 +++----- target-i386/helper.c | 19 ++++---- target-i386/kvm.c | 6 +-- target-s390x/cpu.c | 4 +- target-s390x/cpu.h | 7 +-- target-s390x/kvm.c | 98 +++++++++++++++++++------------------- target-s390x/misc_helper.c | 4 +- 14 files changed, 109 insertions(+), 138 deletions(-) diff --git a/cpus.c b/cpus.c index e39ccb7f306..1a2a9b03342 100644 --- a/cpus.c +++ b/cpus.c @@ -557,9 +557,8 @@ static const VMStateDescription vmstate_timers = { } }; -static void cpu_throttle_thread(void *opaque) +static void cpu_throttle_thread(CPUState *cpu, void *opaque) { - CPUState *cpu = opaque; double pct; double throttle_ratio; long sleeptime_ns; @@ -589,7 +588,7 @@ static void cpu_throttle_timer_tick(void *opaque) } CPU_FOREACH(cpu) { if (!atomic_xchg(&cpu->throttle_thread_scheduled, 1)) { - async_run_on_cpu(cpu, cpu_throttle_thread, cpu); + async_run_on_cpu(cpu, cpu_throttle_thread, NULL); } } @@ -917,12 +916,12 @@ void qemu_init_cpu_loop(void) qemu_thread_get_self(&io_thread); } -void run_on_cpu(CPUState *cpu, void (*func)(void *data), void *data) +void run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data) { struct qemu_work_item wi; if (qemu_cpu_is_self(cpu)) { - func(data); + func(cpu, data); return; } @@ -950,12 +949,12 @@ void run_on_cpu(CPUState *cpu, void (*func)(void *data), void *data) } } -void async_run_on_cpu(CPUState *cpu, void (*func)(void *data), void *data) +void async_run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data) { struct qemu_work_item *wi; if (qemu_cpu_is_self(cpu)) { - func(data); + func(cpu, data); return; } @@ -1006,7 +1005,7 @@ static void flush_queued_work(CPUState *cpu) cpu->queued_work_last = NULL; } qemu_mutex_unlock(&cpu->work_mutex); - wi->func(wi->data); + wi->func(cpu, wi->data); qemu_mutex_lock(&cpu->work_mutex); if (wi->free) { g_free(wi); diff --git a/hw/i386/kvm/apic.c b/hw/i386/kvm/apic.c index f57fed1cb00..c016e63fc2b 100644 --- a/hw/i386/kvm/apic.c +++ b/hw/i386/kvm/apic.c @@ -125,7 +125,7 @@ static void kvm_apic_vapic_base_update(APICCommonState *s) } } -static void kvm_apic_put(void *data) +static void kvm_apic_put(CPUState *cs, void *data) { APICCommonState *s = data; struct kvm_lapic_state kapic; @@ -146,10 +146,9 @@ static void kvm_apic_post_load(APICCommonState *s) run_on_cpu(CPU(s->cpu), kvm_apic_put, s); } -static void do_inject_external_nmi(void *data) +static void do_inject_external_nmi(CPUState *cpu, void *data) { APICCommonState *s = data; - CPUState *cpu = CPU(s->cpu); uint32_t lvt; int ret; diff --git a/hw/i386/kvmvapic.c b/hw/i386/kvmvapic.c index a1cd9b5a292..74a549becfe 100644 --- a/hw/i386/kvmvapic.c +++ b/hw/i386/kvmvapic.c @@ -483,7 +483,7 @@ typedef struct VAPICEnableTPRReporting { bool enable; } VAPICEnableTPRReporting; -static void vapic_do_enable_tpr_reporting(void *data) +static void vapic_do_enable_tpr_reporting(CPUState *cpu, void *data) { VAPICEnableTPRReporting *info = data; @@ -734,10 +734,10 @@ static void vapic_realize(DeviceState *dev, Error **errp) nb_option_roms++; } -static void do_vapic_enable(void *data) +static void do_vapic_enable(CPUState *cs, void *data) { VAPICROMState *s = data; - X86CPU *cpu = X86_CPU(first_cpu); + X86CPU *cpu = X86_CPU(cs); static const uint8_t enabled = 1; cpu_physical_memory_write(s->vapic_paddr + offsetof(VAPICState, enabled), diff --git a/hw/ppc/ppce500_spin.c b/hw/ppc/ppce500_spin.c index 22c584eb8dd..8e16f651ea9 100644 --- a/hw/ppc/ppce500_spin.c +++ b/hw/ppc/ppce500_spin.c @@ -54,11 +54,6 @@ typedef struct SpinState { SpinInfo spin[MAX_CPUS]; } SpinState; -typedef struct spin_kick { - PowerPCCPU *cpu; - SpinInfo *spin; -} SpinKick; - static void spin_reset(void *opaque) { SpinState *s = opaque; @@ -89,16 +84,15 @@ static void mmubooke_create_initial_mapping(CPUPPCState *env, env->tlb_dirty = true; } -static void spin_kick(void *data) +static void spin_kick(CPUState *cs, void *data) { - SpinKick *kick = data; - CPUState *cpu = CPU(kick->cpu); - CPUPPCState *env = &kick->cpu->env; - SpinInfo *curspin = kick->spin; + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; + SpinInfo *curspin = data; hwaddr map_size = 64 * 1024 * 1024; hwaddr map_start; - cpu_synchronize_state(cpu); + cpu_synchronize_state(cs); stl_p(&curspin->pir, env->spr[SPR_BOOKE_PIR]); env->nip = ldq_p(&curspin->addr) & (map_size - 1); env->gpr[3] = ldq_p(&curspin->r3); @@ -112,10 +106,10 @@ static void spin_kick(void *data) map_start = ldq_p(&curspin->addr) & ~(map_size - 1); mmubooke_create_initial_mapping(env, 0, map_start, map_size); - cpu->halted = 0; - cpu->exception_index = -1; - cpu->stopped = false; - qemu_cpu_kick(cpu); + cs->halted = 0; + cs->exception_index = -1; + cs->stopped = false; + qemu_cpu_kick(cs); } static void spin_write(void *opaque, hwaddr addr, uint64_t value, @@ -153,12 +147,7 @@ static void spin_write(void *opaque, hwaddr addr, uint64_t value, if (!(ldq_p(&curspin->addr) & 1)) { /* run CPU */ - SpinKick kick = { - .cpu = POWERPC_CPU(cpu), - .spin = curspin, - }; - - run_on_cpu(cpu, spin_kick, &kick); + run_on_cpu(cpu, spin_kick, curspin); } } diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 9b506d5d3af..aa067aefdb2 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -2134,10 +2134,8 @@ static void spapr_machine_finalizefn(Object *obj) g_free(spapr->kvm_type); } -static void ppc_cpu_do_nmi_on_cpu(void *arg) +static void ppc_cpu_do_nmi_on_cpu(CPUState *cs, void *arg) { - CPUState *cs = arg; - cpu_synchronize_state(cs); ppc_cpu_do_system_reset(cs); } @@ -2147,7 +2145,7 @@ static void spapr_nmi(NMIState *n, int cpu_index, Error **errp) CPUState *cs; CPU_FOREACH(cs) { - async_run_on_cpu(cs, ppc_cpu_do_nmi_on_cpu, cs); + async_run_on_cpu(cs, ppc_cpu_do_nmi_on_cpu, NULL); } } diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 290a7122d40..c5e7e8c9959 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -13,19 +13,18 @@ #include "kvm_ppc.h" struct SPRSyncState { - CPUState *cs; int spr; target_ulong value; target_ulong mask; }; -static void do_spr_sync(void *arg) +static void do_spr_sync(CPUState *cs, void *arg) { struct SPRSyncState *s = arg; - PowerPCCPU *cpu = POWERPC_CPU(s->cs); + PowerPCCPU *cpu = POWERPC_CPU(cs); CPUPPCState *env = &cpu->env; - cpu_synchronize_state(s->cs); + cpu_synchronize_state(cs); env->spr[s->spr] &= ~s->mask; env->spr[s->spr] |= s->value; } @@ -34,7 +33,6 @@ static void set_spr(CPUState *cs, int spr, target_ulong value, target_ulong mask) { struct SPRSyncState s = { - .cs = cs, .spr = spr, .value = value, .mask = mask @@ -909,17 +907,17 @@ static target_ulong cas_get_option_vector(int vector, target_ulong table) } typedef struct { - PowerPCCPU *cpu; uint32_t cpu_version; Error *err; } SetCompatState; -static void do_set_compat(void *arg) +static void do_set_compat(CPUState *cs, void *arg) { + PowerPCCPU *cpu = POWERPC_CPU(cs); SetCompatState *s = arg; - cpu_synchronize_state(CPU(s->cpu)); - ppc_set_compat(s->cpu, s->cpu_version, &s->err); + cpu_synchronize_state(cs); + ppc_set_compat(cpu, s->cpu_version, &s->err); } #define get_compat_level(cpuver) ( \ @@ -1015,7 +1013,6 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu_, if (old_cpu_version != cpu_version) { CPU_FOREACH(cs) { SetCompatState s = { - .cpu = POWERPC_CPU(cs), .cpu_version = cpu_version, .err = NULL, }; diff --git a/include/qom/cpu.h b/include/qom/cpu.h index ce0c406f272..4aa9e61c5d3 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -232,9 +232,11 @@ struct kvm_run; #define TB_JMP_CACHE_SIZE (1 << TB_JMP_CACHE_BITS) /* work queue */ +typedef void (*run_on_cpu_func)(CPUState *cpu, void *data); + struct qemu_work_item { struct qemu_work_item *next; - void (*func)(void *data); + run_on_cpu_func func; void *data; int done; bool free; @@ -623,7 +625,7 @@ bool cpu_is_stopped(CPUState *cpu); * * Schedules the function @func for execution on the vCPU @cpu. */ -void run_on_cpu(CPUState *cpu, void (*func)(void *data), void *data); +void run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data); /** * async_run_on_cpu: @@ -633,7 +635,7 @@ void run_on_cpu(CPUState *cpu, void (*func)(void *data), void *data); * * Schedules the function @func for execution on the vCPU @cpu asynchronously. */ -void async_run_on_cpu(CPUState *cpu, void (*func)(void *data), void *data); +void async_run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data); /** * qemu_get_cpu: diff --git a/kvm-all.c b/kvm-all.c index 8a4382eed88..fc2898a9517 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -1847,10 +1847,8 @@ void kvm_flush_coalesced_mmio_buffer(void) s->coalesced_flush_in_progress = false; } -static void do_kvm_cpu_synchronize_state(void *arg) +static void do_kvm_cpu_synchronize_state(CPUState *cpu, void *arg) { - CPUState *cpu = arg; - if (!cpu->kvm_vcpu_dirty) { kvm_arch_get_registers(cpu); cpu->kvm_vcpu_dirty = true; @@ -1860,34 +1858,30 @@ static void do_kvm_cpu_synchronize_state(void *arg) void kvm_cpu_synchronize_state(CPUState *cpu) { if (!cpu->kvm_vcpu_dirty) { - run_on_cpu(cpu, do_kvm_cpu_synchronize_state, cpu); + run_on_cpu(cpu, do_kvm_cpu_synchronize_state, NULL); } } -static void do_kvm_cpu_synchronize_post_reset(void *arg) +static void do_kvm_cpu_synchronize_post_reset(CPUState *cpu, void *arg) { - CPUState *cpu = arg; - kvm_arch_put_registers(cpu, KVM_PUT_RESET_STATE); cpu->kvm_vcpu_dirty = false; } void kvm_cpu_synchronize_post_reset(CPUState *cpu) { - run_on_cpu(cpu, do_kvm_cpu_synchronize_post_reset, cpu); + run_on_cpu(cpu, do_kvm_cpu_synchronize_post_reset, NULL); } -static void do_kvm_cpu_synchronize_post_init(void *arg) +static void do_kvm_cpu_synchronize_post_init(CPUState *cpu, void *arg) { - CPUState *cpu = arg; - kvm_arch_put_registers(cpu, KVM_PUT_FULL_STATE); cpu->kvm_vcpu_dirty = false; } void kvm_cpu_synchronize_post_init(CPUState *cpu) { - run_on_cpu(cpu, do_kvm_cpu_synchronize_post_init, cpu); + run_on_cpu(cpu, do_kvm_cpu_synchronize_post_init, NULL); } int kvm_cpu_exec(CPUState *cpu) @@ -2216,7 +2210,7 @@ struct kvm_set_guest_debug_data { int err; }; -static void kvm_invoke_set_guest_debug(void *data) +static void kvm_invoke_set_guest_debug(CPUState *unused_cpu, void *data) { struct kvm_set_guest_debug_data *dbg_data = data; @@ -2234,7 +2228,6 @@ int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap) data.dbg.control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP; } kvm_arch_update_guest_debug(cpu, &data.dbg); - data.cpu = cpu; run_on_cpu(cpu, kvm_invoke_set_guest_debug, &data); return data.err; diff --git a/target-i386/helper.c b/target-i386/helper.c index 1c250b82452..9bc961bff34 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1113,7 +1113,6 @@ hwaddr x86_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) typedef struct MCEInjectionParams { Monitor *mon; - X86CPU *cpu; int bank; uint64_t status; uint64_t mcg_status; @@ -1122,14 +1121,14 @@ typedef struct MCEInjectionParams { int flags; } MCEInjectionParams; -static void do_inject_x86_mce(void *data) +static void do_inject_x86_mce(CPUState *cs, void *data) { MCEInjectionParams *params = data; - CPUX86State *cenv = ¶ms->cpu->env; - CPUState *cpu = CPU(params->cpu); + X86CPU *cpu = X86_CPU(cs); + CPUX86State *cenv = &cpu->env; uint64_t *banks = cenv->mce_banks + 4 * params->bank; - cpu_synchronize_state(cpu); + cpu_synchronize_state(cs); /* * If there is an MCE exception being processed, ignore this SRAO MCE @@ -1149,7 +1148,7 @@ static void do_inject_x86_mce(void *data) if ((cenv->mcg_cap & MCG_CTL_P) && cenv->mcg_ctl != ~(uint64_t)0) { monitor_printf(params->mon, "CPU %d: Uncorrected error reporting disabled\n", - cpu->cpu_index); + cs->cpu_index); return; } @@ -1161,7 +1160,7 @@ static void do_inject_x86_mce(void *data) monitor_printf(params->mon, "CPU %d: Uncorrected error reporting disabled for" " bank %d\n", - cpu->cpu_index, params->bank); + cs->cpu_index, params->bank); return; } @@ -1170,7 +1169,7 @@ static void do_inject_x86_mce(void *data) monitor_printf(params->mon, "CPU %d: Previous MCE still in progress, raising" " triple fault\n", - cpu->cpu_index); + cs->cpu_index); qemu_log_mask(CPU_LOG_RESET, "Triple fault\n"); qemu_system_reset_request(); return; @@ -1182,7 +1181,7 @@ static void do_inject_x86_mce(void *data) banks[3] = params->misc; cenv->mcg_status = params->mcg_status; banks[1] = params->status; - cpu_interrupt(cpu, CPU_INTERRUPT_MCE); + cpu_interrupt(cs, CPU_INTERRUPT_MCE); } else if (!(banks[1] & MCI_STATUS_VAL) || !(banks[1] & MCI_STATUS_UC)) { if (banks[1] & MCI_STATUS_VAL) { @@ -1204,7 +1203,6 @@ void cpu_x86_inject_mce(Monitor *mon, X86CPU *cpu, int bank, CPUX86State *cenv = &cpu->env; MCEInjectionParams params = { .mon = mon, - .cpu = cpu, .bank = bank, .status = status, .mcg_status = mcg_status, @@ -1245,7 +1243,6 @@ void cpu_x86_inject_mce(Monitor *mon, X86CPU *cpu, int bank, if (other_cs == cs) { continue; } - params.cpu = X86_CPU(other_cs); run_on_cpu(other_cs, do_inject_x86_mce, ¶ms); } } diff --git a/target-i386/kvm.c b/target-i386/kvm.c index a0e42b2c4ed..1955a6b3a4c 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -156,10 +156,8 @@ static int kvm_get_tsc(CPUState *cs) return 0; } -static inline void do_kvm_synchronize_tsc(void *arg) +static inline void do_kvm_synchronize_tsc(CPUState *cpu, void *arg) { - CPUState *cpu = arg; - kvm_get_tsc(cpu); } @@ -169,7 +167,7 @@ void kvm_synchronize_all_tsc(void) if (kvm_enabled()) { CPU_FOREACH(cpu) { - run_on_cpu(cpu, do_kvm_synchronize_tsc, cpu); + run_on_cpu(cpu, do_kvm_synchronize_tsc, NULL); } } } diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c index 2f3c8e245d3..35ae2cec4b4 100644 --- a/target-s390x/cpu.c +++ b/target-s390x/cpu.c @@ -164,7 +164,7 @@ static void s390_cpu_machine_reset_cb(void *opaque) { S390CPU *cpu = opaque; - run_on_cpu(CPU(cpu), s390_do_cpu_full_reset, CPU(cpu)); + run_on_cpu(CPU(cpu), s390_do_cpu_full_reset, NULL); } #endif @@ -220,7 +220,7 @@ static void s390_cpu_realizefn(DeviceState *dev, Error **errp) s390_cpu_gdb_init(cs); qemu_init_vcpu(cs); #if !defined(CONFIG_USER_ONLY) - run_on_cpu(cs, s390_do_cpu_full_reset, cs); + run_on_cpu(cs, s390_do_cpu_full_reset, NULL); #else cpu_reset(cs); #endif diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 5645e063af3..4fb34b598d6 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -502,17 +502,14 @@ static inline hwaddr decode_basedisp_s(CPUS390XState *env, uint32_t ipb, #define decode_basedisp_rs decode_basedisp_s /* helper functions for run_on_cpu() */ -static inline void s390_do_cpu_reset(void *arg) +static inline void s390_do_cpu_reset(CPUState *cs, void *arg) { - CPUState *cs = arg; S390CPUClass *scc = S390_CPU_GET_CLASS(cs); scc->cpu_reset(cs); } -static inline void s390_do_cpu_full_reset(void *arg) +static inline void s390_do_cpu_full_reset(CPUState *cs, void *arg) { - CPUState *cs = arg; - cpu_reset(cs); } diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 4b847a3be48..fd929e8351d 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -1385,7 +1385,6 @@ static int handle_diag(S390CPU *cpu, struct kvm_run *run, uint32_t ipb) } typedef struct SigpInfo { - S390CPU *cpu; uint64_t param; int cc; uint64_t *status_reg; @@ -1398,38 +1397,40 @@ static void set_sigp_status(SigpInfo *si, uint64_t status) si->cc = SIGP_CC_STATUS_STORED; } -static void sigp_start(void *arg) +static void sigp_start(CPUState *cs, void *arg) { + S390CPU *cpu = S390_CPU(cs); SigpInfo *si = arg; - if (s390_cpu_get_state(si->cpu) != CPU_STATE_STOPPED) { + if (s390_cpu_get_state(cpu) != CPU_STATE_STOPPED) { si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; return; } - s390_cpu_set_state(CPU_STATE_OPERATING, si->cpu); + s390_cpu_set_state(CPU_STATE_OPERATING, cpu); si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; } -static void sigp_stop(void *arg) +static void sigp_stop(CPUState *cs, void *arg) { + S390CPU *cpu = S390_CPU(cs); SigpInfo *si = arg; struct kvm_s390_irq irq = { .type = KVM_S390_SIGP_STOP, }; - if (s390_cpu_get_state(si->cpu) != CPU_STATE_OPERATING) { + if (s390_cpu_get_state(cpu) != CPU_STATE_OPERATING) { si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; return; } /* disabled wait - sleeping in user space */ - if (CPU(si->cpu)->halted) { - s390_cpu_set_state(CPU_STATE_STOPPED, si->cpu); + if (cs->halted) { + s390_cpu_set_state(CPU_STATE_STOPPED, cpu); } else { /* execute the stop function */ - si->cpu->env.sigp_order = SIGP_STOP; - kvm_s390_vcpu_interrupt(si->cpu, &irq); + cpu->env.sigp_order = SIGP_STOP; + kvm_s390_vcpu_interrupt(cpu, &irq); } si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; } @@ -1496,56 +1497,58 @@ static int kvm_s390_store_status(S390CPU *cpu, hwaddr addr, bool store_arch) return 0; } -static void sigp_stop_and_store_status(void *arg) +static void sigp_stop_and_store_status(CPUState *cs, void *arg) { + S390CPU *cpu = S390_CPU(cs); SigpInfo *si = arg; struct kvm_s390_irq irq = { .type = KVM_S390_SIGP_STOP, }; /* disabled wait - sleeping in user space */ - if (s390_cpu_get_state(si->cpu) == CPU_STATE_OPERATING && - CPU(si->cpu)->halted) { - s390_cpu_set_state(CPU_STATE_STOPPED, si->cpu); + if (s390_cpu_get_state(cpu) == CPU_STATE_OPERATING && cs->halted) { + s390_cpu_set_state(CPU_STATE_STOPPED, cpu); } - switch (s390_cpu_get_state(si->cpu)) { + switch (s390_cpu_get_state(cpu)) { case CPU_STATE_OPERATING: - si->cpu->env.sigp_order = SIGP_STOP_STORE_STATUS; - kvm_s390_vcpu_interrupt(si->cpu, &irq); + cpu->env.sigp_order = SIGP_STOP_STORE_STATUS; + kvm_s390_vcpu_interrupt(cpu, &irq); /* store will be performed when handling the stop intercept */ break; case CPU_STATE_STOPPED: /* already stopped, just store the status */ - cpu_synchronize_state(CPU(si->cpu)); - kvm_s390_store_status(si->cpu, KVM_S390_STORE_STATUS_DEF_ADDR, true); + cpu_synchronize_state(cs); + kvm_s390_store_status(cpu, KVM_S390_STORE_STATUS_DEF_ADDR, true); break; } si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; } -static void sigp_store_status_at_address(void *arg) +static void sigp_store_status_at_address(CPUState *cs, void *arg) { + S390CPU *cpu = S390_CPU(cs); SigpInfo *si = arg; uint32_t address = si->param & 0x7ffffe00u; /* cpu has to be stopped */ - if (s390_cpu_get_state(si->cpu) != CPU_STATE_STOPPED) { + if (s390_cpu_get_state(cpu) != CPU_STATE_STOPPED) { set_sigp_status(si, SIGP_STAT_INCORRECT_STATE); return; } - cpu_synchronize_state(CPU(si->cpu)); + cpu_synchronize_state(cs); - if (kvm_s390_store_status(si->cpu, address, false)) { + if (kvm_s390_store_status(cpu, address, false)) { set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER); return; } si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; } -static void sigp_store_adtl_status(void *arg) +static void sigp_store_adtl_status(CPUState *cs, void *arg) { + S390CPU *cpu = S390_CPU(cs); SigpInfo *si = arg; if (!s390_has_feat(S390_FEAT_VECTOR)) { @@ -1554,7 +1557,7 @@ static void sigp_store_adtl_status(void *arg) } /* cpu has to be stopped */ - if (s390_cpu_get_state(si->cpu) != CPU_STATE_STOPPED) { + if (s390_cpu_get_state(cpu) != CPU_STATE_STOPPED) { set_sigp_status(si, SIGP_STAT_INCORRECT_STATE); return; } @@ -1565,31 +1568,32 @@ static void sigp_store_adtl_status(void *arg) return; } - cpu_synchronize_state(CPU(si->cpu)); + cpu_synchronize_state(cs); - if (kvm_s390_store_adtl_status(si->cpu, si->param)) { + if (kvm_s390_store_adtl_status(cpu, si->param)) { set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER); return; } si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; } -static void sigp_restart(void *arg) +static void sigp_restart(CPUState *cs, void *arg) { + S390CPU *cpu = S390_CPU(cs); SigpInfo *si = arg; struct kvm_s390_irq irq = { .type = KVM_S390_RESTART, }; - switch (s390_cpu_get_state(si->cpu)) { + switch (s390_cpu_get_state(cpu)) { case CPU_STATE_STOPPED: /* the restart irq has to be delivered prior to any other pending irq */ - cpu_synchronize_state(CPU(si->cpu)); - do_restart_interrupt(&si->cpu->env); - s390_cpu_set_state(CPU_STATE_OPERATING, si->cpu); + cpu_synchronize_state(cs); + do_restart_interrupt(&cpu->env); + s390_cpu_set_state(CPU_STATE_OPERATING, cpu); break; case CPU_STATE_OPERATING: - kvm_s390_vcpu_interrupt(si->cpu, &irq); + kvm_s390_vcpu_interrupt(cpu, &irq); break; } si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; @@ -1597,20 +1601,18 @@ static void sigp_restart(void *arg) int kvm_s390_cpu_restart(S390CPU *cpu) { - SigpInfo si = { - .cpu = cpu, - }; + SigpInfo si = {}; run_on_cpu(CPU(cpu), sigp_restart, &si); DPRINTF("DONE: KVM cpu restart: %p\n", &cpu->env); return 0; } -static void sigp_initial_cpu_reset(void *arg) +static void sigp_initial_cpu_reset(CPUState *cs, void *arg) { + S390CPU *cpu = S390_CPU(cs); + S390CPUClass *scc = S390_CPU_GET_CLASS(cpu); SigpInfo *si = arg; - CPUState *cs = CPU(si->cpu); - S390CPUClass *scc = S390_CPU_GET_CLASS(si->cpu); cpu_synchronize_state(cs); scc->initial_cpu_reset(cs); @@ -1618,11 +1620,11 @@ static void sigp_initial_cpu_reset(void *arg) si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; } -static void sigp_cpu_reset(void *arg) +static void sigp_cpu_reset(CPUState *cs, void *arg) { + S390CPU *cpu = S390_CPU(cs); + S390CPUClass *scc = S390_CPU_GET_CLASS(cpu); SigpInfo *si = arg; - CPUState *cs = CPU(si->cpu); - S390CPUClass *scc = S390_CPU_GET_CLASS(si->cpu); cpu_synchronize_state(cs); scc->cpu_reset(cs); @@ -1630,12 +1632,13 @@ static void sigp_cpu_reset(void *arg) si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; } -static void sigp_set_prefix(void *arg) +static void sigp_set_prefix(CPUState *cs, void *arg) { + S390CPU *cpu = S390_CPU(cs); SigpInfo *si = arg; uint32_t addr = si->param & 0x7fffe000u; - cpu_synchronize_state(CPU(si->cpu)); + cpu_synchronize_state(cs); if (!address_space_access_valid(&address_space_memory, addr, sizeof(struct LowCore), false)) { @@ -1644,13 +1647,13 @@ static void sigp_set_prefix(void *arg) } /* cpu has to be stopped */ - if (s390_cpu_get_state(si->cpu) != CPU_STATE_STOPPED) { + if (s390_cpu_get_state(cpu) != CPU_STATE_STOPPED) { set_sigp_status(si, SIGP_STAT_INCORRECT_STATE); return; } - si->cpu->env.psa = addr; - cpu_synchronize_post_init(CPU(si->cpu)); + cpu->env.psa = addr; + cpu_synchronize_post_init(cs); si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; } @@ -1658,7 +1661,6 @@ static int handle_sigp_single_dst(S390CPU *dst_cpu, uint8_t order, uint64_t param, uint64_t *status_reg) { SigpInfo si = { - .cpu = dst_cpu, .param = param, .status_reg = status_reg, }; diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index 86da1947b98..4df2ec6c7da 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -126,7 +126,7 @@ static int modified_clear_reset(S390CPU *cpu) pause_all_vcpus(); cpu_synchronize_all_states(); CPU_FOREACH(t) { - run_on_cpu(t, s390_do_cpu_full_reset, t); + run_on_cpu(t, s390_do_cpu_full_reset, NULL); } s390_cmma_reset(); subsystem_reset(); @@ -145,7 +145,7 @@ static int load_normal_reset(S390CPU *cpu) pause_all_vcpus(); cpu_synchronize_all_states(); CPU_FOREACH(t) { - run_on_cpu(t, s390_do_cpu_reset, t); + run_on_cpu(t, s390_do_cpu_reset, NULL); } s390_cmma_reset(); subsystem_reset(); From fd38b25103ad9e3b51862424074d4eef75975623 Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Tue, 2 Aug 2016 18:27:34 +0100 Subject: [PATCH 346/723] cpus: Move common code out of {async_, }run_on_cpu() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the code common between run_on_cpu() and async_run_on_cpu() into a new function queue_work_on_cpu(). Signed-off-by: Sergey Fedorov Signed-off-by: Sergey Fedorov Reviewed-by: Alex Bennée Signed-off-by: Alex Bennée Message-Id: <1470158864-17651-4-git-send-email-alex.bennee@linaro.org> Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- cpus.c | 42 ++++++++++++++++++------------------------ 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/cpus.c b/cpus.c index 1a2a9b03342..ed7d30a6c13 100644 --- a/cpus.c +++ b/cpus.c @@ -916,6 +916,22 @@ void qemu_init_cpu_loop(void) qemu_thread_get_self(&io_thread); } +static void queue_work_on_cpu(CPUState *cpu, struct qemu_work_item *wi) +{ + qemu_mutex_lock(&cpu->work_mutex); + if (cpu->queued_work_first == NULL) { + cpu->queued_work_first = wi; + } else { + cpu->queued_work_last->next = wi; + } + cpu->queued_work_last = wi; + wi->next = NULL; + wi->done = false; + qemu_mutex_unlock(&cpu->work_mutex); + + qemu_cpu_kick(cpu); +} + void run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data) { struct qemu_work_item wi; @@ -929,18 +945,7 @@ void run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data) wi.data = data; wi.free = false; - qemu_mutex_lock(&cpu->work_mutex); - if (cpu->queued_work_first == NULL) { - cpu->queued_work_first = &wi; - } else { - cpu->queued_work_last->next = &wi; - } - cpu->queued_work_last = &wi; - wi.next = NULL; - wi.done = false; - qemu_mutex_unlock(&cpu->work_mutex); - - qemu_cpu_kick(cpu); + queue_work_on_cpu(cpu, &wi); while (!atomic_mb_read(&wi.done)) { CPUState *self_cpu = current_cpu; @@ -963,18 +968,7 @@ void async_run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data) wi->data = data; wi->free = true; - qemu_mutex_lock(&cpu->work_mutex); - if (cpu->queued_work_first == NULL) { - cpu->queued_work_first = wi; - } else { - cpu->queued_work_last->next = wi; - } - cpu->queued_work_last = wi; - wi->next = NULL; - wi->done = false; - qemu_mutex_unlock(&cpu->work_mutex); - - qemu_cpu_kick(cpu); + queue_work_on_cpu(cpu, wi); } static void qemu_kvm_destroy_vcpu(CPUState *cpu) From a5403c69fcf2c946d166faa27e5db8436a00d183 Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Tue, 2 Aug 2016 18:27:36 +0100 Subject: [PATCH 347/723] cpus: Rename flush_queued_work() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To avoid possible confusion, rename flush_queued_work() to process_queued_cpu_work(). Signed-off-by: Sergey Fedorov Signed-off-by: Sergey Fedorov Reviewed-by: Alex Bennée Signed-off-by: Alex Bennée Message-Id: <1470158864-17651-6-git-send-email-alex.bennee@linaro.org> Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- cpus.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpus.c b/cpus.c index ed7d30a6c13..28d62062f3e 100644 --- a/cpus.c +++ b/cpus.c @@ -983,7 +983,7 @@ static void qemu_tcg_destroy_vcpu(CPUState *cpu) { } -static void flush_queued_work(CPUState *cpu) +static void process_queued_cpu_work(CPUState *cpu) { struct qemu_work_item *wi; @@ -1018,7 +1018,7 @@ static void qemu_wait_io_event_common(CPUState *cpu) cpu->stopped = true; qemu_cond_broadcast(&qemu_pause_cond); } - flush_queued_work(cpu); + process_queued_cpu_work(cpu); cpu->thread_kicked = false; } From 959f593c0e010cc0ee2e47e7f45e66c0695683b7 Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Tue, 2 Aug 2016 18:27:37 +0100 Subject: [PATCH 348/723] linux-user: Use QemuMutex and QemuCond MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert pthread_mutex_t and pthread_cond_t to QemuMutex and QemuCond. This will allow to make some locks and conditional variables common between user and system mode emulation. Signed-off-by: Sergey Fedorov Signed-off-by: Sergey Fedorov Reviewed-by: Alex Bennée Signed-off-by: Alex Bennée Message-Id: <1470158864-17651-7-git-send-email-alex.bennee@linaro.org> Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- linux-user/main.c | 55 +++++++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index 8daebe07670..7a056fcfd60 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -111,17 +111,25 @@ int cpu_get_pic_interrupt(CPUX86State *env) We don't require a full sync, only that no cpus are executing guest code. The alternative is to map target atomic ops onto host equivalents, which requires quite a lot of per host/target work. */ -static pthread_mutex_t cpu_list_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t exclusive_lock = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t exclusive_cond = PTHREAD_COND_INITIALIZER; -static pthread_cond_t exclusive_resume = PTHREAD_COND_INITIALIZER; +static QemuMutex cpu_list_lock; +static QemuMutex exclusive_lock; +static QemuCond exclusive_cond; +static QemuCond exclusive_resume; static int pending_cpus; +void qemu_init_cpu_loop(void) +{ + qemu_mutex_init(&cpu_list_lock); + qemu_mutex_init(&exclusive_lock); + qemu_cond_init(&exclusive_cond); + qemu_cond_init(&exclusive_resume); +} + /* Make sure everything is in a consistent state for calling fork(). */ void fork_start(void) { qemu_mutex_lock(&tcg_ctx.tb_ctx.tb_lock); - pthread_mutex_lock(&exclusive_lock); + qemu_mutex_lock(&exclusive_lock); mmap_fork_start(); } @@ -138,14 +146,14 @@ void fork_end(int child) } } pending_cpus = 0; - pthread_mutex_init(&exclusive_lock, NULL); - pthread_mutex_init(&cpu_list_mutex, NULL); - pthread_cond_init(&exclusive_cond, NULL); - pthread_cond_init(&exclusive_resume, NULL); + qemu_mutex_init(&exclusive_lock); + qemu_mutex_init(&cpu_list_lock); + qemu_cond_init(&exclusive_cond); + qemu_cond_init(&exclusive_resume); qemu_mutex_init(&tcg_ctx.tb_ctx.tb_lock); gdbserver_fork(thread_cpu); } else { - pthread_mutex_unlock(&exclusive_lock); + qemu_mutex_unlock(&exclusive_lock); qemu_mutex_unlock(&tcg_ctx.tb_ctx.tb_lock); } } @@ -155,7 +163,7 @@ void fork_end(int child) static inline void exclusive_idle(void) { while (pending_cpus) { - pthread_cond_wait(&exclusive_resume, &exclusive_lock); + qemu_cond_wait(&exclusive_resume, &exclusive_lock); } } @@ -165,7 +173,7 @@ static inline void start_exclusive(void) { CPUState *other_cpu; - pthread_mutex_lock(&exclusive_lock); + qemu_mutex_lock(&exclusive_lock); exclusive_idle(); pending_cpus = 1; @@ -176,8 +184,8 @@ static inline void start_exclusive(void) cpu_exit(other_cpu); } } - if (pending_cpus > 1) { - pthread_cond_wait(&exclusive_cond, &exclusive_lock); + while (pending_cpus > 1) { + qemu_cond_wait(&exclusive_cond, &exclusive_lock); } } @@ -185,42 +193,42 @@ static inline void start_exclusive(void) static inline void __attribute__((unused)) end_exclusive(void) { pending_cpus = 0; - pthread_cond_broadcast(&exclusive_resume); - pthread_mutex_unlock(&exclusive_lock); + qemu_cond_broadcast(&exclusive_resume); + qemu_mutex_unlock(&exclusive_lock); } /* Wait for exclusive ops to finish, and begin cpu execution. */ static inline void cpu_exec_start(CPUState *cpu) { - pthread_mutex_lock(&exclusive_lock); + qemu_mutex_lock(&exclusive_lock); exclusive_idle(); cpu->running = true; - pthread_mutex_unlock(&exclusive_lock); + qemu_mutex_unlock(&exclusive_lock); } /* Mark cpu as not executing, and release pending exclusive ops. */ static inline void cpu_exec_end(CPUState *cpu) { - pthread_mutex_lock(&exclusive_lock); + qemu_mutex_lock(&exclusive_lock); cpu->running = false; if (pending_cpus > 1) { pending_cpus--; if (pending_cpus == 1) { - pthread_cond_signal(&exclusive_cond); + qemu_cond_signal(&exclusive_cond); } } exclusive_idle(); - pthread_mutex_unlock(&exclusive_lock); + qemu_mutex_unlock(&exclusive_lock); } void cpu_list_lock(void) { - pthread_mutex_lock(&cpu_list_mutex); + qemu_mutex_lock(&cpu_list_lock); } void cpu_list_unlock(void) { - pthread_mutex_unlock(&cpu_list_mutex); + qemu_mutex_unlock(&cpu_list_lock); } @@ -4211,6 +4219,7 @@ int main(int argc, char **argv, char **envp) int ret; int execfd; + qemu_init_cpu_loop(); module_call_init(MODULE_INIT_QOM); if ((envlist = envlist_create()) == NULL) { From 178f94297a23e68183ce08bb841cf5d209208b03 Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Tue, 2 Aug 2016 18:27:39 +0100 Subject: [PATCH 349/723] linux-user: Add qemu_cpu_is_self() and qemu_cpu_kick() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sergey Fedorov Signed-off-by: Sergey Fedorov Reviewed-by: Alex Bennée Signed-off-by: Alex Bennée Message-Id: <1470158864-17651-9-git-send-email-alex.bennee@linaro.org> Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- linux-user/main.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/linux-user/main.c b/linux-user/main.c index 7a056fcfd60..6e140102297 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -3777,6 +3777,16 @@ void cpu_loop(CPUTLGState *env) THREAD CPUState *thread_cpu; +bool qemu_cpu_is_self(CPUState *cpu) +{ + return thread_cpu == cpu; +} + +void qemu_cpu_kick(CPUState *cpu) +{ + cpu_exit(cpu); +} + void task_settid(TaskState *ts) { if (ts->ts_tid == 0) { From 267f685b8b20784c97251618b515fcd17b42aad6 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sun, 28 Aug 2016 03:45:14 +0200 Subject: [PATCH 350/723] cpus-common: move CPU list management to common code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a mutex for the CPU list to system emulation, as it will be used to manage safe work. Abstract manipulation of the CPU list in new functions cpu_list_add and cpu_list_remove. Reviewed-by: Richard Henderson Reviewed-by: Alex Bennée Signed-off-by: Paolo Bonzini --- Makefile.objs | 2 +- bsd-user/main.c | 9 +---- cpus-common.c | 83 +++++++++++++++++++++++++++++++++++++++ exec.c | 37 +---------------- include/exec/cpu-common.h | 5 +++ include/exec/exec-all.h | 11 ------ include/qom/cpu.h | 12 ++++++ linux-user/main.c | 17 ++------ vl.c | 1 + 9 files changed, 109 insertions(+), 68 deletions(-) create mode 100644 cpus-common.c diff --git a/Makefile.objs b/Makefile.objs index 7301544cddd..a8e022452f8 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -89,7 +89,7 @@ endif ####################################################################### # Target-independent parts used in system and user emulation -common-obj-y += tcg-runtime.o +common-obj-y += tcg-runtime.o cpus-common.o common-obj-y += hw/ common-obj-y += qom/ common-obj-y += disas/ diff --git a/bsd-user/main.c b/bsd-user/main.c index 0fb08e405d5..591c424e6ee 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -95,14 +95,6 @@ void fork_end(int child) } } -void cpu_list_lock(void) -{ -} - -void cpu_list_unlock(void) -{ -} - #ifdef TARGET_I386 /***********************************************************/ /* CPUX86 core interface */ @@ -748,6 +740,7 @@ int main(int argc, char **argv) if (argc <= 1) usage(); + qemu_init_cpu_list(); module_call_init(MODULE_INIT_QOM); if ((envlist = envlist_create()) == NULL) { diff --git a/cpus-common.c b/cpus-common.c new file mode 100644 index 00000000000..fda3848b7df --- /dev/null +++ b/cpus-common.c @@ -0,0 +1,83 @@ +/* + * CPU thread main loop - common bits for user and system mode emulation + * + * Copyright (c) 2003-2005 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "qemu/osdep.h" +#include "exec/cpu-common.h" +#include "qom/cpu.h" +#include "sysemu/cpus.h" + +static QemuMutex qemu_cpu_list_lock; + +void qemu_init_cpu_list(void) +{ + qemu_mutex_init(&qemu_cpu_list_lock); +} + +void cpu_list_lock(void) +{ + qemu_mutex_lock(&qemu_cpu_list_lock); +} + +void cpu_list_unlock(void) +{ + qemu_mutex_unlock(&qemu_cpu_list_lock); +} + +static bool cpu_index_auto_assigned; + +static int cpu_get_free_index(void) +{ + CPUState *some_cpu; + int cpu_index = 0; + + cpu_index_auto_assigned = true; + CPU_FOREACH(some_cpu) { + cpu_index++; + } + return cpu_index; +} + +void cpu_list_add(CPUState *cpu) +{ + qemu_mutex_lock(&qemu_cpu_list_lock); + if (cpu->cpu_index == UNASSIGNED_CPU_INDEX) { + cpu->cpu_index = cpu_get_free_index(); + assert(cpu->cpu_index != UNASSIGNED_CPU_INDEX); + } else { + assert(!cpu_index_auto_assigned); + } + QTAILQ_INSERT_TAIL(&cpus, cpu, node); + qemu_mutex_unlock(&qemu_cpu_list_lock); +} + +void cpu_list_remove(CPUState *cpu) +{ + qemu_mutex_lock(&qemu_cpu_list_lock); + if (!QTAILQ_IN_USE(cpu, node)) { + /* there is nothing to undo since cpu_exec_init() hasn't been called */ + qemu_mutex_unlock(&qemu_cpu_list_lock); + return; + } + + assert(!(cpu_index_auto_assigned && cpu != QTAILQ_LAST(&cpus, CPUTailQ))); + + QTAILQ_REMOVE(&cpus, cpu, node); + cpu->cpu_index = UNASSIGNED_CPU_INDEX; + qemu_mutex_unlock(&qemu_cpu_list_lock); +} diff --git a/exec.c b/exec.c index c81d5ab981e..c8389f93c3a 100644 --- a/exec.c +++ b/exec.c @@ -598,36 +598,11 @@ AddressSpace *cpu_get_address_space(CPUState *cpu, int asidx) } #endif -static bool cpu_index_auto_assigned; - -static int cpu_get_free_index(void) -{ - CPUState *some_cpu; - int cpu_index = 0; - - cpu_index_auto_assigned = true; - CPU_FOREACH(some_cpu) { - cpu_index++; - } - return cpu_index; -} - void cpu_exec_exit(CPUState *cpu) { CPUClass *cc = CPU_GET_CLASS(cpu); - cpu_list_lock(); - if (!QTAILQ_IN_USE(cpu, node)) { - /* there is nothing to undo since cpu_exec_init() hasn't been called */ - cpu_list_unlock(); - return; - } - - assert(!(cpu_index_auto_assigned && cpu != QTAILQ_LAST(&cpus, CPUTailQ))); - - QTAILQ_REMOVE(&cpus, cpu, node); - cpu->cpu_index = UNASSIGNED_CPU_INDEX; - cpu_list_unlock(); + cpu_list_remove(cpu); if (cc->vmsd != NULL) { vmstate_unregister(NULL, cc->vmsd, cpu); @@ -663,15 +638,7 @@ void cpu_exec_init(CPUState *cpu, Error **errp) object_ref(OBJECT(cpu->memory)); #endif - cpu_list_lock(); - if (cpu->cpu_index == UNASSIGNED_CPU_INDEX) { - cpu->cpu_index = cpu_get_free_index(); - assert(cpu->cpu_index != UNASSIGNED_CPU_INDEX); - } else { - assert(!cpu_index_auto_assigned); - } - QTAILQ_INSERT_TAIL(&cpus, cpu, node); - cpu_list_unlock(); + cpu_list_add(cpu); #ifndef CONFIG_USER_ONLY if (qdev_get_vmsd(DEVICE(cpu)) == NULL) { diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h index 952bcfeb4cb..869ba41b0c8 100644 --- a/include/exec/cpu-common.h +++ b/include/exec/cpu-common.h @@ -23,6 +23,11 @@ typedef struct CPUListState { FILE *file; } CPUListState; +/* The CPU list lock nests outside tb_lock/tb_unlock. */ +void qemu_init_cpu_list(void); +void cpu_list_lock(void); +void cpu_list_unlock(void); + #if !defined(CONFIG_USER_ONLY) enum device_endian { diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 008e09a3c14..336a57cde6b 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -56,17 +56,6 @@ TranslationBlock *tb_gen_code(CPUState *cpu, target_ulong pc, target_ulong cs_base, uint32_t flags, int cflags); -#if defined(CONFIG_USER_ONLY) -void cpu_list_lock(void); -void cpu_list_unlock(void); -#else -static inline void cpu_list_unlock(void) -{ -} -static inline void cpu_list_lock(void) -{ -} -#endif void cpu_exec_init(CPUState *cpu, Error **errp); void QEMU_NORETURN cpu_loop_exit(CPUState *cpu); diff --git a/include/qom/cpu.h b/include/qom/cpu.h index 4aa9e61c5d3..ea3233ff5b0 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -544,6 +544,18 @@ static inline int cpu_asidx_from_attrs(CPUState *cpu, MemTxAttrs attrs) } #endif +/** + * cpu_list_add: + * @cpu: The CPU to be added to the list of CPUs. + */ +void cpu_list_add(CPUState *cpu); + +/** + * cpu_list_remove: + * @cpu: The CPU to be removed from the list of CPUs. + */ +void cpu_list_remove(CPUState *cpu); + /** * cpu_reset: * @cpu: The CPU whose state is to be reset. diff --git a/linux-user/main.c b/linux-user/main.c index 6e140102297..719f0462e43 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -111,7 +111,6 @@ int cpu_get_pic_interrupt(CPUX86State *env) We don't require a full sync, only that no cpus are executing guest code. The alternative is to map target atomic ops onto host equivalents, which requires quite a lot of per host/target work. */ -static QemuMutex cpu_list_lock; static QemuMutex exclusive_lock; static QemuCond exclusive_cond; static QemuCond exclusive_resume; @@ -119,7 +118,6 @@ static int pending_cpus; void qemu_init_cpu_loop(void) { - qemu_mutex_init(&cpu_list_lock); qemu_mutex_init(&exclusive_lock); qemu_cond_init(&exclusive_cond); qemu_cond_init(&exclusive_resume); @@ -128,6 +126,7 @@ void qemu_init_cpu_loop(void) /* Make sure everything is in a consistent state for calling fork(). */ void fork_start(void) { + cpu_list_lock(); qemu_mutex_lock(&tcg_ctx.tb_ctx.tb_lock); qemu_mutex_lock(&exclusive_lock); mmap_fork_start(); @@ -147,14 +146,15 @@ void fork_end(int child) } pending_cpus = 0; qemu_mutex_init(&exclusive_lock); - qemu_mutex_init(&cpu_list_lock); qemu_cond_init(&exclusive_cond); qemu_cond_init(&exclusive_resume); qemu_mutex_init(&tcg_ctx.tb_ctx.tb_lock); + qemu_init_cpu_list(); gdbserver_fork(thread_cpu); } else { qemu_mutex_unlock(&exclusive_lock); qemu_mutex_unlock(&tcg_ctx.tb_ctx.tb_lock); + cpu_list_unlock(); } } @@ -221,16 +221,6 @@ static inline void cpu_exec_end(CPUState *cpu) qemu_mutex_unlock(&exclusive_lock); } -void cpu_list_lock(void) -{ - qemu_mutex_lock(&cpu_list_lock); -} - -void cpu_list_unlock(void) -{ - qemu_mutex_unlock(&cpu_list_lock); -} - #ifdef TARGET_I386 /***********************************************************/ @@ -4229,6 +4219,7 @@ int main(int argc, char **argv, char **envp) int ret; int execfd; + qemu_init_cpu_list(); qemu_init_cpu_loop(); module_call_init(MODULE_INIT_QOM); diff --git a/vl.c b/vl.c index 215a6f9c7a0..eda83fa93d0 100644 --- a/vl.c +++ b/vl.c @@ -3017,6 +3017,7 @@ int main(int argc, char **argv, char **envp) Error *err = NULL; bool list_data_dirs = false; + qemu_init_cpu_list(); qemu_init_cpu_loop(); qemu_mutex_lock_iothread(); From d148d90ee83738d45a90dc0b2fb7b1712f164103 Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Mon, 29 Aug 2016 09:51:00 +0200 Subject: [PATCH 351/723] cpus-common: move CPU work item management to common code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make CPU work core functions common between system and user-mode emulation. User-mode does not use run_on_cpu, so do not implement it. Signed-off-by: Sergey Fedorov Signed-off-by: Sergey Fedorov Reviewed-by: Alex Bennée Signed-off-by: Alex Bennée Message-Id: <1470158864-17651-10-git-send-email-alex.bennee@linaro.org> Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- bsd-user/main.c | 11 +++++- cpus-common.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++ cpus.c | 82 +---------------------------------------- include/qom/cpu.h | 27 ++++++++++---- linux-user/main.c | 25 +++++++++++++ 5 files changed, 148 insertions(+), 91 deletions(-) diff --git a/bsd-user/main.c b/bsd-user/main.c index 591c424e6ee..6dfa91230fc 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -68,11 +68,11 @@ int cpu_get_pic_interrupt(CPUX86State *env) #endif /* These are no-ops because we are not threadsafe. */ -static inline void cpu_exec_start(CPUArchState *env) +static inline void cpu_exec_start(CPUState *cpu) { } -static inline void cpu_exec_end(CPUArchState *env) +static inline void cpu_exec_end(CPUState *cpu) { } @@ -164,7 +164,11 @@ void cpu_loop(CPUX86State *env) //target_siginfo_t info; for(;;) { + cpu_exec_start(cs); trapnr = cpu_exec(cs); + cpu_exec_end(cs); + process_queued_cpu_work(cs); + switch(trapnr) { case 0x80: /* syscall from int $0x80 */ @@ -505,7 +509,10 @@ void cpu_loop(CPUSPARCState *env) //target_siginfo_t info; while (1) { + cpu_exec_start(cs); trapnr = cpu_exec(cs); + cpu_exec_end(cs); + process_queued_cpu_work(cs); switch (trapnr) { #ifndef TARGET_SPARC64 diff --git a/cpus-common.c b/cpus-common.c index fda3848b7df..2005bfe41fa 100644 --- a/cpus-common.c +++ b/cpus-common.c @@ -23,10 +23,12 @@ #include "sysemu/cpus.h" static QemuMutex qemu_cpu_list_lock; +static QemuCond qemu_work_cond; void qemu_init_cpu_list(void) { qemu_mutex_init(&qemu_cpu_list_lock); + qemu_cond_init(&qemu_work_cond); } void cpu_list_lock(void) @@ -81,3 +83,95 @@ void cpu_list_remove(CPUState *cpu) cpu->cpu_index = UNASSIGNED_CPU_INDEX; qemu_mutex_unlock(&qemu_cpu_list_lock); } + +struct qemu_work_item { + struct qemu_work_item *next; + run_on_cpu_func func; + void *data; + int done; + bool free; +}; + +static void queue_work_on_cpu(CPUState *cpu, struct qemu_work_item *wi) +{ + qemu_mutex_lock(&cpu->work_mutex); + if (cpu->queued_work_first == NULL) { + cpu->queued_work_first = wi; + } else { + cpu->queued_work_last->next = wi; + } + cpu->queued_work_last = wi; + wi->next = NULL; + wi->done = false; + qemu_mutex_unlock(&cpu->work_mutex); + + qemu_cpu_kick(cpu); +} + +void do_run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data, + QemuMutex *mutex) +{ + struct qemu_work_item wi; + + if (qemu_cpu_is_self(cpu)) { + func(cpu, data); + return; + } + + wi.func = func; + wi.data = data; + wi.free = false; + + queue_work_on_cpu(cpu, &wi); + while (!atomic_mb_read(&wi.done)) { + CPUState *self_cpu = current_cpu; + + qemu_cond_wait(&qemu_work_cond, mutex); + current_cpu = self_cpu; + } +} + +void async_run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data) +{ + struct qemu_work_item *wi; + + if (qemu_cpu_is_self(cpu)) { + func(cpu, data); + return; + } + + wi = g_malloc0(sizeof(struct qemu_work_item)); + wi->func = func; + wi->data = data; + wi->free = true; + + queue_work_on_cpu(cpu, wi); +} + +void process_queued_cpu_work(CPUState *cpu) +{ + struct qemu_work_item *wi; + + if (cpu->queued_work_first == NULL) { + return; + } + + qemu_mutex_lock(&cpu->work_mutex); + while (cpu->queued_work_first != NULL) { + wi = cpu->queued_work_first; + cpu->queued_work_first = wi->next; + if (!cpu->queued_work_first) { + cpu->queued_work_last = NULL; + } + qemu_mutex_unlock(&cpu->work_mutex); + wi->func(cpu, wi->data); + qemu_mutex_lock(&cpu->work_mutex); + if (wi->free) { + g_free(wi); + } else { + atomic_mb_set(&wi->done, true); + } + } + qemu_mutex_unlock(&cpu->work_mutex); + qemu_cond_broadcast(&qemu_work_cond); +} diff --git a/cpus.c b/cpus.c index 28d62062f3e..c3afd18ffb6 100644 --- a/cpus.c +++ b/cpus.c @@ -902,73 +902,21 @@ static QemuThread io_thread; static QemuCond qemu_cpu_cond; /* system init */ static QemuCond qemu_pause_cond; -static QemuCond qemu_work_cond; void qemu_init_cpu_loop(void) { qemu_init_sigbus(); qemu_cond_init(&qemu_cpu_cond); qemu_cond_init(&qemu_pause_cond); - qemu_cond_init(&qemu_work_cond); qemu_cond_init(&qemu_io_proceeded_cond); qemu_mutex_init(&qemu_global_mutex); qemu_thread_get_self(&io_thread); } -static void queue_work_on_cpu(CPUState *cpu, struct qemu_work_item *wi) -{ - qemu_mutex_lock(&cpu->work_mutex); - if (cpu->queued_work_first == NULL) { - cpu->queued_work_first = wi; - } else { - cpu->queued_work_last->next = wi; - } - cpu->queued_work_last = wi; - wi->next = NULL; - wi->done = false; - qemu_mutex_unlock(&cpu->work_mutex); - - qemu_cpu_kick(cpu); -} - void run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data) { - struct qemu_work_item wi; - - if (qemu_cpu_is_self(cpu)) { - func(cpu, data); - return; - } - - wi.func = func; - wi.data = data; - wi.free = false; - - queue_work_on_cpu(cpu, &wi); - while (!atomic_mb_read(&wi.done)) { - CPUState *self_cpu = current_cpu; - - qemu_cond_wait(&qemu_work_cond, &qemu_global_mutex); - current_cpu = self_cpu; - } -} - -void async_run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data) -{ - struct qemu_work_item *wi; - - if (qemu_cpu_is_self(cpu)) { - func(cpu, data); - return; - } - - wi = g_malloc0(sizeof(struct qemu_work_item)); - wi->func = func; - wi->data = data; - wi->free = true; - - queue_work_on_cpu(cpu, wi); + do_run_on_cpu(cpu, func, data, &qemu_global_mutex); } static void qemu_kvm_destroy_vcpu(CPUState *cpu) @@ -983,34 +931,6 @@ static void qemu_tcg_destroy_vcpu(CPUState *cpu) { } -static void process_queued_cpu_work(CPUState *cpu) -{ - struct qemu_work_item *wi; - - if (cpu->queued_work_first == NULL) { - return; - } - - qemu_mutex_lock(&cpu->work_mutex); - while (cpu->queued_work_first != NULL) { - wi = cpu->queued_work_first; - cpu->queued_work_first = wi->next; - if (!cpu->queued_work_first) { - cpu->queued_work_last = NULL; - } - qemu_mutex_unlock(&cpu->work_mutex); - wi->func(cpu, wi->data); - qemu_mutex_lock(&cpu->work_mutex); - if (wi->free) { - g_free(wi); - } else { - atomic_mb_set(&wi->done, true); - } - } - qemu_mutex_unlock(&cpu->work_mutex); - qemu_cond_broadcast(&qemu_work_cond); -} - static void qemu_wait_io_event_common(CPUState *cpu) { if (cpu->stop) { diff --git a/include/qom/cpu.h b/include/qom/cpu.h index ea3233ff5b0..c04e510ef1d 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -233,14 +233,7 @@ struct kvm_run; /* work queue */ typedef void (*run_on_cpu_func)(CPUState *cpu, void *data); - -struct qemu_work_item { - struct qemu_work_item *next; - run_on_cpu_func func; - void *data; - int done; - bool free; -}; +struct qemu_work_item; /** * CPUState: @@ -629,6 +622,18 @@ void qemu_cpu_kick(CPUState *cpu); */ bool cpu_is_stopped(CPUState *cpu); +/** + * do_run_on_cpu: + * @cpu: The vCPU to run on. + * @func: The function to be executed. + * @data: Data to pass to the function. + * @mutex: Mutex to release while waiting for @func to run. + * + * Used internally in the implementation of run_on_cpu. + */ +void do_run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data, + QemuMutex *mutex); + /** * run_on_cpu: * @cpu: The vCPU to run on. @@ -807,6 +812,12 @@ void cpu_remove(CPUState *cpu); */ void cpu_remove_sync(CPUState *cpu); +/** + * process_queued_cpu_work() - process all items on CPU work queue + * @cpu: The CPU which work queue to process. + */ +void process_queued_cpu_work(CPUState *cpu); + /** * qemu_init_vcpu: * @cpu: The vCPU to initialize. diff --git a/linux-user/main.c b/linux-user/main.c index 719f0462e43..e3eca40a752 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -294,6 +294,8 @@ void cpu_loop(CPUX86State *env) cpu_exec_start(cs); trapnr = cpu_exec(cs); cpu_exec_end(cs); + process_queued_cpu_work(cs); + switch(trapnr) { case 0x80: /* linux syscall from int $0x80 */ @@ -735,6 +737,8 @@ void cpu_loop(CPUARMState *env) cpu_exec_start(cs); trapnr = cpu_exec(cs); cpu_exec_end(cs); + process_queued_cpu_work(cs); + switch(trapnr) { case EXCP_UDEF: { @@ -1071,6 +1075,7 @@ void cpu_loop(CPUARMState *env) cpu_exec_start(cs); trapnr = cpu_exec(cs); cpu_exec_end(cs); + process_queued_cpu_work(cs); switch (trapnr) { case EXCP_SWI: @@ -1159,6 +1164,8 @@ void cpu_loop(CPUUniCore32State *env) cpu_exec_start(cs); trapnr = cpu_exec(cs); cpu_exec_end(cs); + process_queued_cpu_work(cs); + switch (trapnr) { case UC32_EXCP_PRIV: { @@ -1364,6 +1371,7 @@ void cpu_loop (CPUSPARCState *env) cpu_exec_start(cs); trapnr = cpu_exec(cs); cpu_exec_end(cs); + process_queued_cpu_work(cs); /* Compute PSR before exposing state. */ if (env->cc_op != CC_OP_FLAGS) { @@ -1636,6 +1644,8 @@ void cpu_loop(CPUPPCState *env) cpu_exec_start(cs); trapnr = cpu_exec(cs); cpu_exec_end(cs); + process_queued_cpu_work(cs); + switch(trapnr) { case POWERPC_EXCP_NONE: /* Just go on */ @@ -2482,6 +2492,8 @@ void cpu_loop(CPUMIPSState *env) cpu_exec_start(cs); trapnr = cpu_exec(cs); cpu_exec_end(cs); + process_queued_cpu_work(cs); + switch(trapnr) { case EXCP_SYSCALL: env->active_tc.PC += 4; @@ -2722,6 +2734,7 @@ void cpu_loop(CPUOpenRISCState *env) cpu_exec_start(cs); trapnr = cpu_exec(cs); cpu_exec_end(cs); + process_queued_cpu_work(cs); gdbsig = 0; switch (trapnr) { @@ -2816,6 +2829,7 @@ void cpu_loop(CPUSH4State *env) cpu_exec_start(cs); trapnr = cpu_exec(cs); cpu_exec_end(cs); + process_queued_cpu_work(cs); switch (trapnr) { case 0x160: @@ -2882,6 +2896,8 @@ void cpu_loop(CPUCRISState *env) cpu_exec_start(cs); trapnr = cpu_exec(cs); cpu_exec_end(cs); + process_queued_cpu_work(cs); + switch (trapnr) { case 0xaa: { @@ -2947,6 +2963,8 @@ void cpu_loop(CPUMBState *env) cpu_exec_start(cs); trapnr = cpu_exec(cs); cpu_exec_end(cs); + process_queued_cpu_work(cs); + switch (trapnr) { case 0xaa: { @@ -3064,6 +3082,8 @@ void cpu_loop(CPUM68KState *env) cpu_exec_start(cs); trapnr = cpu_exec(cs); cpu_exec_end(cs); + process_queued_cpu_work(cs); + switch(trapnr) { case EXCP_ILLEGAL: { @@ -3207,6 +3227,7 @@ void cpu_loop(CPUAlphaState *env) cpu_exec_start(cs); trapnr = cpu_exec(cs); cpu_exec_end(cs); + process_queued_cpu_work(cs); /* All of the traps imply a transition through PALcode, which implies an REI instruction has been executed. Which means @@ -3399,6 +3420,8 @@ void cpu_loop(CPUS390XState *env) cpu_exec_start(cs); trapnr = cpu_exec(cs); cpu_exec_end(cs); + process_queued_cpu_work(cs); + switch (trapnr) { case EXCP_INTERRUPT: /* Just indicate that signals should be handled asap. */ @@ -3708,6 +3731,8 @@ void cpu_loop(CPUTLGState *env) cpu_exec_start(cs); trapnr = cpu_exec(cs); cpu_exec_end(cs); + process_queued_cpu_work(cs); + switch (trapnr) { case TILEGX_EXCP_SYSCALL: { From 0e55539c076a61b0b10a1aea1158fc20fb159d99 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 6 Sep 2016 17:28:03 +0200 Subject: [PATCH 352/723] cpus-common: fix uninitialized variable use in run_on_cpu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Alex Bennée Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- cpus-common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpus-common.c b/cpus-common.c index 2005bfe41fa..d6cd4262353 100644 --- a/cpus-common.c +++ b/cpus-common.c @@ -88,8 +88,7 @@ struct qemu_work_item { struct qemu_work_item *next; run_on_cpu_func func; void *data; - int done; - bool free; + bool free, done; }; static void queue_work_on_cpu(CPUState *cpu, struct qemu_work_item *wi) @@ -120,6 +119,7 @@ void do_run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data, wi.func = func; wi.data = data; + wi.done = false; wi.free = false; queue_work_on_cpu(cpu, &wi); From ab129972c8b41e15b0521895a46fd9c752b68a5e Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 31 Aug 2016 16:56:04 +0200 Subject: [PATCH 353/723] cpus-common: move exclusive work infrastructure from linux-user MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will serve as the base for async_safe_run_on_cpu. Because start_exclusive uses CPU_FOREACH, merge exclusive_lock with qemu_cpu_list_lock: together with a call to exclusive_idle (via cpu_exec_start/end) in cpu_list_add, this protects exclusive work against concurrent CPU addition and removal. Reviewed-by: Alex Bennée Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- bsd-user/main.c | 17 --------- cpus-common.c | 82 ++++++++++++++++++++++++++++++++++++++++++++ cpus.c | 2 ++ include/qom/cpu.h | 44 +++++++++++++++++++++++- linux-user/main.c | 87 ----------------------------------------------- 5 files changed, 127 insertions(+), 105 deletions(-) diff --git a/bsd-user/main.c b/bsd-user/main.c index 6dfa91230fc..35125b720ff 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -67,23 +67,6 @@ int cpu_get_pic_interrupt(CPUX86State *env) } #endif -/* These are no-ops because we are not threadsafe. */ -static inline void cpu_exec_start(CPUState *cpu) -{ -} - -static inline void cpu_exec_end(CPUState *cpu) -{ -} - -static inline void start_exclusive(void) -{ -} - -static inline void end_exclusive(void) -{ -} - void fork_start(void) { } diff --git a/cpus-common.c b/cpus-common.c index d6cd4262353..7d935fd3dd9 100644 --- a/cpus-common.c +++ b/cpus-common.c @@ -23,11 +23,21 @@ #include "sysemu/cpus.h" static QemuMutex qemu_cpu_list_lock; +static QemuCond exclusive_cond; +static QemuCond exclusive_resume; static QemuCond qemu_work_cond; +static int pending_cpus; + void qemu_init_cpu_list(void) { + /* This is needed because qemu_init_cpu_list is also called by the + * child process in a fork. */ + pending_cpus = 0; + qemu_mutex_init(&qemu_cpu_list_lock); + qemu_cond_init(&exclusive_cond); + qemu_cond_init(&exclusive_resume); qemu_cond_init(&qemu_work_cond); } @@ -55,6 +65,12 @@ static int cpu_get_free_index(void) return cpu_index; } +static void finish_safe_work(CPUState *cpu) +{ + cpu_exec_start(cpu); + cpu_exec_end(cpu); +} + void cpu_list_add(CPUState *cpu) { qemu_mutex_lock(&qemu_cpu_list_lock); @@ -66,6 +82,8 @@ void cpu_list_add(CPUState *cpu) } QTAILQ_INSERT_TAIL(&cpus, cpu, node); qemu_mutex_unlock(&qemu_cpu_list_lock); + + finish_safe_work(cpu); } void cpu_list_remove(CPUState *cpu) @@ -148,6 +166,70 @@ void async_run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data) queue_work_on_cpu(cpu, wi); } +/* Wait for pending exclusive operations to complete. The CPU list lock + must be held. */ +static inline void exclusive_idle(void) +{ + while (pending_cpus) { + qemu_cond_wait(&exclusive_resume, &qemu_cpu_list_lock); + } +} + +/* Start an exclusive operation. + Must only be called from outside cpu_exec, takes + qemu_cpu_list_lock. */ +void start_exclusive(void) +{ + CPUState *other_cpu; + + qemu_mutex_lock(&qemu_cpu_list_lock); + exclusive_idle(); + + /* Make all other cpus stop executing. */ + pending_cpus = 1; + CPU_FOREACH(other_cpu) { + if (other_cpu->running) { + pending_cpus++; + qemu_cpu_kick(other_cpu); + } + } + while (pending_cpus > 1) { + qemu_cond_wait(&exclusive_cond, &qemu_cpu_list_lock); + } +} + +/* Finish an exclusive operation. Releases qemu_cpu_list_lock. */ +void end_exclusive(void) +{ + pending_cpus = 0; + qemu_cond_broadcast(&exclusive_resume); + qemu_mutex_unlock(&qemu_cpu_list_lock); +} + +/* Wait for exclusive ops to finish, and begin cpu execution. */ +void cpu_exec_start(CPUState *cpu) +{ + qemu_mutex_lock(&qemu_cpu_list_lock); + exclusive_idle(); + cpu->running = true; + qemu_mutex_unlock(&qemu_cpu_list_lock); +} + +/* Mark cpu as not executing, and release pending exclusive ops. */ +void cpu_exec_end(CPUState *cpu) +{ + qemu_mutex_lock(&qemu_cpu_list_lock); + cpu->running = false; + if (pending_cpus > 1) { + pending_cpus--; + if (pending_cpus == 1) { + qemu_cond_signal(&exclusive_cond); + } + } + exclusive_idle(); + qemu_mutex_unlock(&qemu_cpu_list_lock); +} + void process_queued_cpu_work(CPUState *cpu) { struct qemu_work_item *wi; diff --git a/cpus.c b/cpus.c index c3afd18ffb6..fbd70f59f74 100644 --- a/cpus.c +++ b/cpus.c @@ -1457,7 +1457,9 @@ static int tcg_cpu_exec(CPUState *cpu) cpu->icount_decr.u16.low = decr; cpu->icount_extra = count; } + cpu_exec_start(cpu); ret = cpu_exec(cpu); + cpu_exec_end(cpu); #ifdef CONFIG_PROFILER tcg_time += profile_getclock() - ti; #endif diff --git a/include/qom/cpu.h b/include/qom/cpu.h index c04e510ef1d..f8726140f63 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -242,7 +242,8 @@ struct qemu_work_item; * @nr_threads: Number of threads within this CPU. * @numa_node: NUMA node this CPU is belonging to. * @host_tid: Host thread ID. - * @running: #true if CPU is currently running (usermode). + * @running: #true if CPU is currently running; + * valid under cpu_list_lock. * @created: Indicates whether the CPU thread has been successfully created. * @interrupt_request: Indicates a pending interrupt request. * @halted: Nonzero if the CPU is in suspended state. @@ -818,6 +819,47 @@ void cpu_remove_sync(CPUState *cpu); */ void process_queued_cpu_work(CPUState *cpu); +/** + * cpu_exec_start: + * @cpu: The CPU for the current thread. + * + * Record that a CPU has started execution and can be interrupted with + * cpu_exit. + */ +void cpu_exec_start(CPUState *cpu); + +/** + * cpu_exec_end: + * @cpu: The CPU for the current thread. + * + * Record that a CPU has stopped execution and exclusive sections + * can be executed without interrupting it. + */ +void cpu_exec_end(CPUState *cpu); + +/** + * start_exclusive: + * + * Wait for a concurrent exclusive section to end, and then start + * a section of work that is run while other CPUs are not running + * between cpu_exec_start and cpu_exec_end. CPUs that are running + * cpu_exec are exited immediately. CPUs that call cpu_exec_start + * during the exclusive section go to sleep until this CPU calls + * end_exclusive. + * + * Returns with the CPU list lock taken (which nests outside all + * other locks except the BQL). + */ +void start_exclusive(void); + +/** + * end_exclusive: + * + * Concludes an exclusive execution section started by start_exclusive. + * Releases the CPU list lock. + */ +void end_exclusive(void); + /** * qemu_init_vcpu: * @cpu: The vCPU to initialize. diff --git a/linux-user/main.c b/linux-user/main.c index e3eca40a752..c8f85736142 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -107,28 +107,11 @@ int cpu_get_pic_interrupt(CPUX86State *env) /***********************************************************/ /* Helper routines for implementing atomic operations. */ -/* To implement exclusive operations we force all cpus to syncronise. - We don't require a full sync, only that no cpus are executing guest code. - The alternative is to map target atomic ops onto host equivalents, - which requires quite a lot of per host/target work. */ -static QemuMutex exclusive_lock; -static QemuCond exclusive_cond; -static QemuCond exclusive_resume; -static int pending_cpus; - -void qemu_init_cpu_loop(void) -{ - qemu_mutex_init(&exclusive_lock); - qemu_cond_init(&exclusive_cond); - qemu_cond_init(&exclusive_resume); -} - /* Make sure everything is in a consistent state for calling fork(). */ void fork_start(void) { cpu_list_lock(); qemu_mutex_lock(&tcg_ctx.tb_ctx.tb_lock); - qemu_mutex_lock(&exclusive_lock); mmap_fork_start(); } @@ -144,84 +127,15 @@ void fork_end(int child) QTAILQ_REMOVE(&cpus, cpu, node); } } - pending_cpus = 0; - qemu_mutex_init(&exclusive_lock); - qemu_cond_init(&exclusive_cond); - qemu_cond_init(&exclusive_resume); qemu_mutex_init(&tcg_ctx.tb_ctx.tb_lock); qemu_init_cpu_list(); gdbserver_fork(thread_cpu); } else { - qemu_mutex_unlock(&exclusive_lock); qemu_mutex_unlock(&tcg_ctx.tb_ctx.tb_lock); cpu_list_unlock(); } } -/* Wait for pending exclusive operations to complete. The exclusive lock - must be held. */ -static inline void exclusive_idle(void) -{ - while (pending_cpus) { - qemu_cond_wait(&exclusive_resume, &exclusive_lock); - } -} - -/* Start an exclusive operation. - Must only be called from outside cpu_exec. */ -static inline void start_exclusive(void) -{ - CPUState *other_cpu; - - qemu_mutex_lock(&exclusive_lock); - exclusive_idle(); - - pending_cpus = 1; - /* Make all other cpus stop executing. */ - CPU_FOREACH(other_cpu) { - if (other_cpu->running) { - pending_cpus++; - cpu_exit(other_cpu); - } - } - while (pending_cpus > 1) { - qemu_cond_wait(&exclusive_cond, &exclusive_lock); - } -} - -/* Finish an exclusive operation. */ -static inline void __attribute__((unused)) end_exclusive(void) -{ - pending_cpus = 0; - qemu_cond_broadcast(&exclusive_resume); - qemu_mutex_unlock(&exclusive_lock); -} - -/* Wait for exclusive ops to finish, and begin cpu execution. */ -static inline void cpu_exec_start(CPUState *cpu) -{ - qemu_mutex_lock(&exclusive_lock); - exclusive_idle(); - cpu->running = true; - qemu_mutex_unlock(&exclusive_lock); -} - -/* Mark cpu as not executing, and release pending exclusive ops. */ -static inline void cpu_exec_end(CPUState *cpu) -{ - qemu_mutex_lock(&exclusive_lock); - cpu->running = false; - if (pending_cpus > 1) { - pending_cpus--; - if (pending_cpus == 1) { - qemu_cond_signal(&exclusive_cond); - } - } - exclusive_idle(); - qemu_mutex_unlock(&exclusive_lock); -} - - #ifdef TARGET_I386 /***********************************************************/ /* CPUX86 core interface */ @@ -4245,7 +4159,6 @@ int main(int argc, char **argv, char **envp) int execfd; qemu_init_cpu_list(); - qemu_init_cpu_loop(); module_call_init(MODULE_INIT_QOM); if ((envlist = envlist_create()) == NULL) { From a200f2fb571f337db37f865aec18f655fa3c872b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 2 Sep 2016 23:35:55 +0200 Subject: [PATCH 354/723] docs: include formal model for TCG exclusive sections Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- docs/tcg-exclusive.promela | 177 +++++++++++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 docs/tcg-exclusive.promela diff --git a/docs/tcg-exclusive.promela b/docs/tcg-exclusive.promela new file mode 100644 index 00000000000..5889b406388 --- /dev/null +++ b/docs/tcg-exclusive.promela @@ -0,0 +1,177 @@ +/* + * This model describes the implementation of exclusive sections in + * cpus-common.c (start_exclusive, end_exclusive, cpu_exec_start, + * cpu_exec_end). + * + * Author: Paolo Bonzini + * + * This file is in the public domain. If you really want a license, + * the WTFPL will do. + * + * To verify it: + * spin -a docs/tcg-exclusive.promela + * gcc pan.c -O2 + * ./a.out -a + * + * Tunable processor macros: N_CPUS, N_EXCLUSIVE, N_CYCLES, TEST_EXPENSIVE. + */ + +// Define the missing parameters for the model +#ifndef N_CPUS +#define N_CPUS 2 +#warning defaulting to 2 CPU processes +#endif + +// the expensive test is not so expensive for <= 3 CPUs +#if N_CPUS <= 3 +#define TEST_EXPENSIVE +#endif + +#ifndef N_EXCLUSIVE +# if !defined N_CYCLES || N_CYCLES <= 1 || defined TEST_EXPENSIVE +# define N_EXCLUSIVE 2 +# warning defaulting to 2 concurrent exclusive sections +# else +# define N_EXCLUSIVE 1 +# warning defaulting to 1 concurrent exclusive sections +# endif +#endif +#ifndef N_CYCLES +# if N_EXCLUSIVE <= 1 || defined TEST_EXPENSIVE +# define N_CYCLES 2 +# warning defaulting to 2 CPU cycles +# else +# define N_CYCLES 1 +# warning defaulting to 1 CPU cycles +# endif +#endif + + +// synchronization primitives. condition variables require a +// process-local "cond_t saved;" variable. + +#define mutex_t byte +#define MUTEX_LOCK(m) atomic { m == 0 -> m = 1 } +#define MUTEX_UNLOCK(m) m = 0 + +#define cond_t int +#define COND_WAIT(c, m) { \ + saved = c; \ + MUTEX_UNLOCK(m); \ + c != saved -> MUTEX_LOCK(m); \ + } +#define COND_BROADCAST(c) c++ + +// this is the logic from cpus-common.c + +mutex_t mutex; +cond_t exclusive_cond; +cond_t exclusive_resume; +byte pending_cpus; + +byte running[N_CPUS]; +byte has_waiter[N_CPUS]; + +#define exclusive_idle() \ + do \ + :: pending_cpus -> COND_WAIT(exclusive_resume, mutex); \ + :: else -> break; \ + od + +#define start_exclusive() \ + MUTEX_LOCK(mutex); \ + exclusive_idle(); \ + pending_cpus = 1; \ + \ + i = 0; \ + do \ + :: i < N_CPUS -> { \ + if \ + :: running[i] -> has_waiter[i] = 1; pending_cpus++; \ + :: else -> skip; \ + fi; \ + i++; \ + } \ + :: else -> break; \ + od; \ + \ + do \ + :: pending_cpus > 1 -> COND_WAIT(exclusive_cond, mutex); \ + :: else -> break; \ + od + +#define end_exclusive() \ + pending_cpus = 0; \ + COND_BROADCAST(exclusive_resume); \ + MUTEX_UNLOCK(mutex); + +#define cpu_exec_start(id) \ + MUTEX_LOCK(mutex); \ + exclusive_idle(); \ + running[id] = 1; \ + MUTEX_UNLOCK(mutex); + +#define cpu_exec_end(id) \ + MUTEX_LOCK(mutex); \ + running[id] = 0; \ + if \ + :: pending_cpus -> { \ + pending_cpus--; \ + if \ + :: pending_cpus == 1 -> COND_BROADCAST(exclusive_cond); \ + :: else -> skip; \ + fi; \ + } \ + :: else -> skip; \ + fi; \ + exclusive_idle(); \ + MUTEX_UNLOCK(mutex); + +// Promela processes + +byte done_cpu; +byte in_cpu; +active[N_CPUS] proctype cpu() +{ + byte id = _pid % N_CPUS; + byte cycles = 0; + cond_t saved; + + do + :: cycles == N_CYCLES -> break; + :: else -> { + cycles++; + cpu_exec_start(id) + in_cpu++; + done_cpu++; + in_cpu--; + cpu_exec_end(id) + } + od; +} + +byte done_exclusive; +byte in_exclusive; +active[N_EXCLUSIVE] proctype exclusive() +{ + cond_t saved; + byte i; + + start_exclusive(); + in_exclusive = 1; + done_exclusive++; + in_exclusive = 0; + end_exclusive(); +} + +#define LIVENESS (done_cpu == N_CPUS * N_CYCLES && done_exclusive == N_EXCLUSIVE) +#define SAFETY !(in_exclusive && in_cpu) + +never { /* ! ([] SAFETY && <> [] LIVENESS) */ + do + // once the liveness property is satisfied, this is not executable + // and the never clause is not accepted + :: ! LIVENESS -> accept_liveness: skip + :: 1 -> assert(SAFETY) + od; +} From c978b3168727d3a76ffcb18462ea972f50b53634 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 31 Aug 2016 18:03:39 +0200 Subject: [PATCH 355/723] cpus-common: always defer async_run_on_cpu work items MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit async_run_on_cpu is only called from the I/O thread, not from CPU threads, so it doesn't make any difference. It will make a difference however for async_safe_run_on_cpu. Reviewed-by: Alex Bennée Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- cpus-common.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/cpus-common.c b/cpus-common.c index 7d935fd3dd9..115f3d45df6 100644 --- a/cpus-common.c +++ b/cpus-common.c @@ -153,11 +153,6 @@ void async_run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data) { struct qemu_work_item *wi; - if (qemu_cpu_is_self(cpu)) { - func(cpu, data); - return; - } - wi = g_malloc0(sizeof(struct qemu_work_item)); wi->func = func; wi->data = data; From cf07da65f335b9a74e62f5413078f67280572f36 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 2 Sep 2016 21:02:10 +0200 Subject: [PATCH 356/723] cpus-common: remove redundant call to exclusive_idle() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No need to call exclusive_idle() from cpu_exec_end since it is done immediately afterwards in cpu_exec_start. Any exclusive section could run as soon as cpu_exec_end leaves, because cpu->running is false and the mutex is not taken, so the call does not add any protection either. Reviewed-by: Richard Henderson Reviewed-by: Alex Bennée Signed-off-by: Paolo Bonzini --- cpus-common.c | 1 - docs/tcg-exclusive.promela | 1 - 2 files changed, 2 deletions(-) diff --git a/cpus-common.c b/cpus-common.c index 115f3d45df6..80aaf9b42d3 100644 --- a/cpus-common.c +++ b/cpus-common.c @@ -221,7 +221,6 @@ void cpu_exec_end(CPUState *cpu) qemu_cond_signal(&exclusive_cond); } } - exclusive_idle(); qemu_mutex_unlock(&qemu_cpu_list_lock); } diff --git a/docs/tcg-exclusive.promela b/docs/tcg-exclusive.promela index 5889b406388..8bb0967df6b 100644 --- a/docs/tcg-exclusive.promela +++ b/docs/tcg-exclusive.promela @@ -124,7 +124,6 @@ byte has_waiter[N_CPUS]; } \ :: else -> skip; \ fi; \ - exclusive_idle(); \ MUTEX_UNLOCK(mutex); // Promela processes From 758e1b2b622d7c177dc2d95e887a11aa069b7e68 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 2 Sep 2016 23:33:38 +0200 Subject: [PATCH 357/723] cpus-common: simplify locking for start_exclusive/end_exclusive MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is not necessary to hold qemu_cpu_list_mutex throughout the exclusive section, because no other exclusive section can run while pending_cpus != 0. exclusive_idle() is called in cpu_exec_start(), and that prevents any CPUs created after start_exclusive() from entering cpu_exec() during an exclusive section. Reviewed-by: Richard Henderson Reviewed-by: Alex Bennée Signed-off-by: Paolo Bonzini --- cpus-common.c | 11 ++++++++--- docs/tcg-exclusive.promela | 4 +++- include/qom/cpu.h | 4 ---- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/cpus-common.c b/cpus-common.c index 80aaf9b42d3..429652c7fd2 100644 --- a/cpus-common.c +++ b/cpus-common.c @@ -171,8 +171,7 @@ static inline void exclusive_idle(void) } /* Start an exclusive operation. - Must only be called from outside cpu_exec, takes - qemu_cpu_list_lock. */ + Must only be called from outside cpu_exec. */ void start_exclusive(void) { CPUState *other_cpu; @@ -191,11 +190,17 @@ void start_exclusive(void) while (pending_cpus > 1) { qemu_cond_wait(&exclusive_cond, &qemu_cpu_list_lock); } + + /* Can release mutex, no one will enter another exclusive + * section until end_exclusive resets pending_cpus to 0. + */ + qemu_mutex_unlock(&qemu_cpu_list_lock); } -/* Finish an exclusive operation. Releases qemu_cpu_list_lock. */ +/* Finish an exclusive operation. */ void end_exclusive(void) { + qemu_mutex_lock(&qemu_cpu_list_lock); pending_cpus = 0; qemu_cond_broadcast(&exclusive_resume); qemu_mutex_unlock(&qemu_cpu_list_lock); diff --git a/docs/tcg-exclusive.promela b/docs/tcg-exclusive.promela index 8bb0967df6b..feac679b9a8 100644 --- a/docs/tcg-exclusive.promela +++ b/docs/tcg-exclusive.promela @@ -98,9 +98,11 @@ byte has_waiter[N_CPUS]; do \ :: pending_cpus > 1 -> COND_WAIT(exclusive_cond, mutex); \ :: else -> break; \ - od + od; \ + MUTEX_UNLOCK(mutex); #define end_exclusive() \ + MUTEX_LOCK(mutex); \ pending_cpus = 0; \ COND_BROADCAST(exclusive_resume); \ MUTEX_UNLOCK(mutex); diff --git a/include/qom/cpu.h b/include/qom/cpu.h index f8726140f63..934c07afbf6 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -846,9 +846,6 @@ void cpu_exec_end(CPUState *cpu); * cpu_exec are exited immediately. CPUs that call cpu_exec_start * during the exclusive section go to sleep until this CPU calls * end_exclusive. - * - * Returns with the CPU list lock taken (which nests outside all - * other locks except the BQL). */ void start_exclusive(void); @@ -856,7 +853,6 @@ void start_exclusive(void); * end_exclusive: * * Concludes an exclusive execution section started by start_exclusive. - * Releases the CPU list lock. */ void end_exclusive(void); From 53f5ed95064fe6807890cd5535445a05d3361bd2 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sun, 28 Aug 2016 05:38:24 +0200 Subject: [PATCH 358/723] cpus-common: Introduce async_safe_run_on_cpu() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Richard Henderson Reviewed-by: Alex Bennée Signed-off-by: Paolo Bonzini --- cpus-common.c | 33 +++++++++++++++++++++++++++++++-- include/qom/cpu.h | 14 ++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/cpus-common.c b/cpus-common.c index 429652c7fd2..38b1d553fbc 100644 --- a/cpus-common.c +++ b/cpus-common.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" +#include "qemu/main-loop.h" #include "exec/cpu-common.h" #include "qom/cpu.h" #include "sysemu/cpus.h" @@ -106,7 +107,7 @@ struct qemu_work_item { struct qemu_work_item *next; run_on_cpu_func func; void *data; - bool free, done; + bool free, exclusive, done; }; static void queue_work_on_cpu(CPUState *cpu, struct qemu_work_item *wi) @@ -139,6 +140,7 @@ void do_run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data, wi.data = data; wi.done = false; wi.free = false; + wi.exclusive = false; queue_work_on_cpu(cpu, &wi); while (!atomic_mb_read(&wi.done)) { @@ -229,6 +231,19 @@ void cpu_exec_end(CPUState *cpu) qemu_mutex_unlock(&qemu_cpu_list_lock); } +void async_safe_run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data) +{ + struct qemu_work_item *wi; + + wi = g_malloc0(sizeof(struct qemu_work_item)); + wi->func = func; + wi->data = data; + wi->free = true; + wi->exclusive = true; + + queue_work_on_cpu(cpu, wi); +} + void process_queued_cpu_work(CPUState *cpu) { struct qemu_work_item *wi; @@ -245,7 +260,21 @@ void process_queued_cpu_work(CPUState *cpu) cpu->queued_work_last = NULL; } qemu_mutex_unlock(&cpu->work_mutex); - wi->func(cpu, wi->data); + if (wi->exclusive) { + /* Running work items outside the BQL avoids the following deadlock: + * 1) start_exclusive() is called with the BQL taken while another + * CPU is running; 2) cpu_exec in the other CPU tries to takes the + * BQL, so it goes to sleep; start_exclusive() is sleeping too, so + * neither CPU can proceed. + */ + qemu_mutex_unlock_iothread(); + start_exclusive(); + wi->func(cpu, wi->data); + end_exclusive(); + qemu_mutex_lock_iothread(); + } else { + wi->func(cpu, wi->data); + } qemu_mutex_lock(&cpu->work_mutex); if (wi->free) { g_free(wi); diff --git a/include/qom/cpu.h b/include/qom/cpu.h index 934c07afbf6..4092dd919b1 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -655,6 +655,20 @@ void run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data); */ void async_run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data); +/** + * async_safe_run_on_cpu: + * @cpu: The vCPU to run on. + * @func: The function to be executed. + * @data: Data to pass to the function. + * + * Schedules the function @func for execution on the vCPU @cpu asynchronously, + * while all other vCPUs are sleeping. + * + * Unlike run_on_cpu and async_run_on_cpu, the function is run outside the + * BQL. + */ +void async_safe_run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data); + /** * qemu_get_cpu: * @index: The CPUState@cpu_index value of the CPU to obtain. From 3359baad36889b83df40b637ed993a4b816c4906 Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Tue, 2 Aug 2016 18:27:43 +0100 Subject: [PATCH 359/723] tcg: Make tb_flush() thread safe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use async_safe_run_on_cpu() to make tb_flush() thread safe. This is possible now that code generation does not happen in the middle of execution. It can happen that multiple threads schedule a safe work to flush the translation buffer. To keep statistics and debugging output sane, always check if the translation buffer has already been flushed. Signed-off-by: Sergey Fedorov Signed-off-by: Sergey Fedorov [AJB: minor re-base fixes] Signed-off-by: Alex Bennée Message-Id: <1470158864-17651-13-git-send-email-alex.bennee@linaro.org> Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- cpu-exec.c | 12 ++---------- include/exec/tb-context.h | 2 +- include/qom/cpu.h | 2 -- translate-all.c | 38 ++++++++++++++++++++++++++++---------- 4 files changed, 31 insertions(+), 23 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 9f4bd0b6dd8..8823d23df7e 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -204,20 +204,16 @@ static void cpu_exec_nocache(CPUState *cpu, int max_cycles, TranslationBlock *orig_tb, bool ignore_icount) { TranslationBlock *tb; - bool old_tb_flushed; /* Should never happen. We only end up here when an existing TB is too long. */ if (max_cycles > CF_COUNT_MASK) max_cycles = CF_COUNT_MASK; - old_tb_flushed = cpu->tb_flushed; - cpu->tb_flushed = false; tb = tb_gen_code(cpu, orig_tb->pc, orig_tb->cs_base, orig_tb->flags, max_cycles | CF_NOCACHE | (ignore_icount ? CF_IGNORE_ICOUNT : 0)); - tb->orig_tb = cpu->tb_flushed ? NULL : orig_tb; - cpu->tb_flushed |= old_tb_flushed; + tb->orig_tb = orig_tb; /* execute the generated code */ trace_exec_tb_nocache(tb, tb->pc); cpu_tb_exec(cpu, tb); @@ -338,10 +334,7 @@ static inline TranslationBlock *tb_find(CPUState *cpu, tb_lock(); have_tb_lock = true; } - /* Check if translation buffer has been flushed */ - if (cpu->tb_flushed) { - cpu->tb_flushed = false; - } else if (!tb->invalid) { + if (!tb->invalid) { tb_add_jump(last_tb, tb_exit, tb); } } @@ -606,7 +599,6 @@ int cpu_exec(CPUState *cpu) break; } - atomic_mb_set(&cpu->tb_flushed, false); /* reset before first TB lookup */ for(;;) { cpu_handle_interrupt(cpu, &last_tb); tb = tb_find(cpu, last_tb, tb_exit); diff --git a/include/exec/tb-context.h b/include/exec/tb-context.h index dce95d92d63..c7f17f26e07 100644 --- a/include/exec/tb-context.h +++ b/include/exec/tb-context.h @@ -38,7 +38,7 @@ struct TBContext { QemuMutex tb_lock; /* statistics */ - int tb_flush_count; + unsigned tb_flush_count; int tb_phys_invalidate_count; }; diff --git a/include/qom/cpu.h b/include/qom/cpu.h index 4092dd919b1..5dfe74a0e70 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -253,7 +253,6 @@ struct qemu_work_item; * @crash_occurred: Indicates the OS reported a crash (panic) for this CPU * @tcg_exit_req: Set to force TCG to stop executing linked TBs for this * CPU and return to its top level loop. - * @tb_flushed: Indicates the translation buffer has been flushed. * @singlestep_enabled: Flags for single-stepping. * @icount_extra: Instructions until next timer event. * @icount_decr: Number of cycles left, with interrupt flag in high bit. @@ -306,7 +305,6 @@ struct CPUState { bool unplug; bool crash_occurred; bool exit_request; - bool tb_flushed; uint32_t interrupt_request; int singlestep_enabled; int64_t icount_extra; diff --git a/translate-all.c b/translate-all.c index e9bc90c6543..8ca393c9d0a 100644 --- a/translate-all.c +++ b/translate-all.c @@ -834,12 +834,19 @@ static void page_flush_tb(void) } /* flush all the translation blocks */ -/* XXX: tb_flush is currently not thread safe */ -void tb_flush(CPUState *cpu) +static void do_tb_flush(CPUState *cpu, void *data) { - if (!tcg_enabled()) { - return; + unsigned tb_flush_req = (unsigned) (uintptr_t) data; + + tb_lock(); + + /* If it's already been done on request of another CPU, + * just retry. + */ + if (tcg_ctx.tb_ctx.tb_flush_count != tb_flush_req) { + goto done; } + #if defined(DEBUG_FLUSH) printf("qemu: flush code_size=%ld nb_tbs=%d avg_tb_size=%ld\n", (unsigned long)(tcg_ctx.code_gen_ptr - tcg_ctx.code_gen_buffer), @@ -858,7 +865,6 @@ void tb_flush(CPUState *cpu) for (i = 0; i < TB_JMP_CACHE_SIZE; ++i) { atomic_set(&cpu->tb_jmp_cache[i], NULL); } - atomic_mb_set(&cpu->tb_flushed, true); } tcg_ctx.tb_ctx.nb_tbs = 0; @@ -868,7 +874,19 @@ void tb_flush(CPUState *cpu) tcg_ctx.code_gen_ptr = tcg_ctx.code_gen_buffer; /* XXX: flush processor icache at this point if cache flush is expensive */ - tcg_ctx.tb_ctx.tb_flush_count++; + atomic_mb_set(&tcg_ctx.tb_ctx.tb_flush_count, + tcg_ctx.tb_ctx.tb_flush_count + 1); + +done: + tb_unlock(); +} + +void tb_flush(CPUState *cpu) +{ + if (tcg_enabled()) { + uintptr_t tb_flush_req = atomic_mb_read(&tcg_ctx.tb_ctx.tb_flush_count); + async_safe_run_on_cpu(cpu, do_tb_flush, (void *) tb_flush_req); + } } #ifdef DEBUG_TB_CHECK @@ -1175,9 +1193,8 @@ TranslationBlock *tb_gen_code(CPUState *cpu, buffer_overflow: /* flush must be done */ tb_flush(cpu); - /* cannot fail at this point */ - tb = tb_alloc(pc); - assert(tb != NULL); + mmap_unlock(); + cpu_loop_exit(cpu); } gen_code_buf = tcg_ctx.code_gen_ptr; @@ -1775,7 +1792,8 @@ void dump_exec_info(FILE *f, fprintf_function cpu_fprintf) qht_statistics_destroy(&hst); cpu_fprintf(f, "\nStatistics:\n"); - cpu_fprintf(f, "TB flush count %d\n", tcg_ctx.tb_ctx.tb_flush_count); + cpu_fprintf(f, "TB flush count %u\n", + atomic_read(&tcg_ctx.tb_ctx.tb_flush_count)); cpu_fprintf(f, "TB invalidate count %d\n", tcg_ctx.tb_ctx.tb_phys_invalidate_count); cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count); From c265e976f4669fd65f5b47e6865f50d1cb66bd02 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 31 Aug 2016 21:33:58 +0200 Subject: [PATCH 360/723] cpus-common: lock-free fast path for cpu_exec_start/end Set cpu->running without taking the cpu_list lock, only requiring it if there is a concurrent exclusive section. This requires adding a new field to CPUState, which records whether a running CPU is being counted in pending_cpus. When an exclusive section is started concurrently with cpu_exec_start, cpu_exec_start can use the new field to determine if it has to wait for the end of the exclusive section. Likewise, cpu_exec_end can use it to see if start_exclusive is waiting for that CPU. This a separate patch for easier bisection of issues. Signed-off-by: Paolo Bonzini --- cpus-common.c | 95 ++++++++++++++++++++++++++++++++------ docs/tcg-exclusive.promela | 53 +++++++++++++++++++-- include/qom/cpu.h | 5 +- 3 files changed, 133 insertions(+), 20 deletions(-) diff --git a/cpus-common.c b/cpus-common.c index 38b1d553fbc..3e114529c91 100644 --- a/cpus-common.c +++ b/cpus-common.c @@ -28,6 +28,9 @@ static QemuCond exclusive_cond; static QemuCond exclusive_resume; static QemuCond qemu_work_cond; +/* >= 1 if a thread is inside start_exclusive/end_exclusive. Written + * under qemu_cpu_list_lock, read with atomic operations. + */ static int pending_cpus; void qemu_init_cpu_list(void) @@ -177,18 +180,26 @@ static inline void exclusive_idle(void) void start_exclusive(void) { CPUState *other_cpu; + int running_cpus; qemu_mutex_lock(&qemu_cpu_list_lock); exclusive_idle(); /* Make all other cpus stop executing. */ - pending_cpus = 1; + atomic_set(&pending_cpus, 1); + + /* Write pending_cpus before reading other_cpu->running. */ + smp_mb(); + running_cpus = 0; CPU_FOREACH(other_cpu) { - if (other_cpu->running) { - pending_cpus++; + if (atomic_read(&other_cpu->running)) { + other_cpu->has_waiter = true; + running_cpus++; qemu_cpu_kick(other_cpu); } } + + atomic_set(&pending_cpus, running_cpus + 1); while (pending_cpus > 1) { qemu_cond_wait(&exclusive_cond, &qemu_cpu_list_lock); } @@ -203,7 +214,7 @@ void start_exclusive(void) void end_exclusive(void) { qemu_mutex_lock(&qemu_cpu_list_lock); - pending_cpus = 0; + atomic_set(&pending_cpus, 0); qemu_cond_broadcast(&exclusive_resume); qemu_mutex_unlock(&qemu_cpu_list_lock); } @@ -211,24 +222,78 @@ void end_exclusive(void) /* Wait for exclusive ops to finish, and begin cpu execution. */ void cpu_exec_start(CPUState *cpu) { - qemu_mutex_lock(&qemu_cpu_list_lock); - exclusive_idle(); - cpu->running = true; - qemu_mutex_unlock(&qemu_cpu_list_lock); + atomic_set(&cpu->running, true); + + /* Write cpu->running before reading pending_cpus. */ + smp_mb(); + + /* 1. start_exclusive saw cpu->running == true and pending_cpus >= 1. + * After taking the lock we'll see cpu->has_waiter == true and run---not + * for long because start_exclusive kicked us. cpu_exec_end will + * decrement pending_cpus and signal the waiter. + * + * 2. start_exclusive saw cpu->running == false but pending_cpus >= 1. + * This includes the case when an exclusive item is running now. + * Then we'll see cpu->has_waiter == false and wait for the item to + * complete. + * + * 3. pending_cpus == 0. Then start_exclusive is definitely going to + * see cpu->running == true, and it will kick the CPU. + */ + if (unlikely(atomic_read(&pending_cpus))) { + qemu_mutex_lock(&qemu_cpu_list_lock); + if (!cpu->has_waiter) { + /* Not counted in pending_cpus, let the exclusive item + * run. Since we have the lock, just set cpu->running to true + * while holding it; no need to check pending_cpus again. + */ + atomic_set(&cpu->running, false); + exclusive_idle(); + /* Now pending_cpus is zero. */ + atomic_set(&cpu->running, true); + } else { + /* Counted in pending_cpus, go ahead and release the + * waiter at cpu_exec_end. + */ + } + qemu_mutex_unlock(&qemu_cpu_list_lock); + } } /* Mark cpu as not executing, and release pending exclusive ops. */ void cpu_exec_end(CPUState *cpu) { - qemu_mutex_lock(&qemu_cpu_list_lock); - cpu->running = false; - if (pending_cpus > 1) { - pending_cpus--; - if (pending_cpus == 1) { - qemu_cond_signal(&exclusive_cond); + atomic_set(&cpu->running, false); + + /* Write cpu->running before reading pending_cpus. */ + smp_mb(); + + /* 1. start_exclusive saw cpu->running == true. Then it will increment + * pending_cpus and wait for exclusive_cond. After taking the lock + * we'll see cpu->has_waiter == true. + * + * 2. start_exclusive saw cpu->running == false but here pending_cpus >= 1. + * This includes the case when an exclusive item started after setting + * cpu->running to false and before we read pending_cpus. Then we'll see + * cpu->has_waiter == false and not touch pending_cpus. The next call to + * cpu_exec_start will run exclusive_idle if still necessary, thus waiting + * for the item to complete. + * + * 3. pending_cpus == 0. Then start_exclusive is definitely going to + * see cpu->running == false, and it can ignore this CPU until the + * next cpu_exec_start. + */ + if (unlikely(atomic_read(&pending_cpus))) { + qemu_mutex_lock(&qemu_cpu_list_lock); + if (cpu->has_waiter) { + cpu->has_waiter = false; + atomic_set(&pending_cpus, pending_cpus - 1); + if (pending_cpus == 1) { + qemu_cond_signal(&exclusive_cond); + } } + qemu_mutex_unlock(&qemu_cpu_list_lock); } - qemu_mutex_unlock(&qemu_cpu_list_lock); } void async_safe_run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data) diff --git a/docs/tcg-exclusive.promela b/docs/tcg-exclusive.promela index feac679b9a8..c91cfca9f73 100644 --- a/docs/tcg-exclusive.promela +++ b/docs/tcg-exclusive.promela @@ -13,7 +13,8 @@ * gcc pan.c -O2 * ./a.out -a * - * Tunable processor macros: N_CPUS, N_EXCLUSIVE, N_CYCLES, TEST_EXPENSIVE. + * Tunable processor macros: N_CPUS, N_EXCLUSIVE, N_CYCLES, USE_MUTEX, + * TEST_EXPENSIVE. */ // Define the missing parameters for the model @@ -22,8 +23,10 @@ #warning defaulting to 2 CPU processes #endif -// the expensive test is not so expensive for <= 3 CPUs -#if N_CPUS <= 3 +// the expensive test is not so expensive for <= 2 CPUs +// If the mutex is used, it's also cheap (300 MB / 4 seconds) for 3 CPUs +// For 3 CPUs and the lock-free option it needs 1.5 GB of RAM +#if N_CPUS <= 2 || (N_CPUS <= 3 && defined USE_MUTEX) #define TEST_EXPENSIVE #endif @@ -107,6 +110,8 @@ byte has_waiter[N_CPUS]; COND_BROADCAST(exclusive_resume); \ MUTEX_UNLOCK(mutex); +#ifdef USE_MUTEX +// Simple version using mutexes #define cpu_exec_start(id) \ MUTEX_LOCK(mutex); \ exclusive_idle(); \ @@ -127,6 +132,48 @@ byte has_waiter[N_CPUS]; :: else -> skip; \ fi; \ MUTEX_UNLOCK(mutex); +#else +// Wait-free fast path, only needs mutex when concurrent with +// an exclusive section +#define cpu_exec_start(id) \ + running[id] = 1; \ + if \ + :: pending_cpus -> { \ + MUTEX_LOCK(mutex); \ + if \ + :: !has_waiter[id] -> { \ + running[id] = 0; \ + exclusive_idle(); \ + running[id] = 1; \ + } \ + :: else -> skip; \ + fi; \ + MUTEX_UNLOCK(mutex); \ + } \ + :: else -> skip; \ + fi; + +#define cpu_exec_end(id) \ + running[id] = 0; \ + if \ + :: pending_cpus -> { \ + MUTEX_LOCK(mutex); \ + if \ + :: has_waiter[id] -> { \ + has_waiter[id] = 0; \ + pending_cpus--; \ + if \ + :: pending_cpus == 1 -> COND_BROADCAST(exclusive_cond); \ + :: else -> skip; \ + fi; \ + } \ + :: else -> skip; \ + fi; \ + MUTEX_UNLOCK(mutex); \ + } \ + :: else -> skip; \ + fi +#endif // Promela processes diff --git a/include/qom/cpu.h b/include/qom/cpu.h index 5dfe74a0e70..22b54d6d937 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -242,7 +242,8 @@ struct qemu_work_item; * @nr_threads: Number of threads within this CPU. * @numa_node: NUMA node this CPU is belonging to. * @host_tid: Host thread ID. - * @running: #true if CPU is currently running; + * @running: #true if CPU is currently running (lockless). + * @has_waiter: #true if a CPU is currently waiting for the cpu_exec_end; * valid under cpu_list_lock. * @created: Indicates whether the CPU thread has been successfully created. * @interrupt_request: Indicates a pending interrupt request. @@ -296,7 +297,7 @@ struct CPUState { #endif int thread_id; uint32_t host_tid; - bool running; + bool running, has_waiter; struct QemuCond *halt_cond; bool thread_kicked; bool created; From f186d64d8fda4bb22c15beb8e45b7814fbd8b51e Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Mon, 26 Sep 2016 11:08:04 +0300 Subject: [PATCH 361/723] replay: move internal data to the structure This patch moves replay static variables into the structure to allow saving and loading them with savevm/loadvm. Reviewed-by: Paolo Bonzini Signed-off-by: Pavel Dovgalyuk Message-Id: <20160926080804.6992.87687.stgit@PASHA-ISP> Signed-off-by: Paolo Bonzini --- replay/replay-events.c | 2 +- replay/replay-internal.c | 20 +++++++++----------- replay/replay-internal.h | 8 +++++--- replay/replay-time.c | 2 +- replay/replay.c | 15 ++++++++------- 5 files changed, 24 insertions(+), 23 deletions(-) diff --git a/replay/replay-events.c b/replay/replay-events.c index 3807245ae78..4eb2ea3604e 100644 --- a/replay/replay-events.c +++ b/replay/replay-events.c @@ -279,7 +279,7 @@ static Event *replay_read_event(int checkpoint) /* Called with replay mutex locked */ void replay_read_events(int checkpoint) { - while (replay_data_kind == EVENT_ASYNC) { + while (replay_state.data_kind == EVENT_ASYNC) { Event *event = replay_read_event(checkpoint); if (!event) { break; diff --git a/replay/replay-internal.c b/replay/replay-internal.c index 5835e8def3b..bea7b4aa6b1 100644 --- a/replay/replay-internal.c +++ b/replay/replay-internal.c @@ -16,11 +16,8 @@ #include "qemu/error-report.h" #include "sysemu/sysemu.h" -unsigned int replay_data_kind = -1; -static unsigned int replay_has_unread_data; - /* Mutex to protect reading and writing events to the log. - replay_data_kind and replay_has_unread_data are also protected + data_kind and has_unread_data are also protected by this mutex. It also protects replay events queue which stores events to be written or read to the log. */ @@ -150,15 +147,16 @@ void replay_check_error(void) void replay_fetch_data_kind(void) { if (replay_file) { - if (!replay_has_unread_data) { - replay_data_kind = replay_get_byte(); - if (replay_data_kind == EVENT_INSTRUCTION) { + if (!replay_state.has_unread_data) { + replay_state.data_kind = replay_get_byte(); + if (replay_state.data_kind == EVENT_INSTRUCTION) { replay_state.instructions_count = replay_get_dword(); } replay_check_error(); - replay_has_unread_data = 1; - if (replay_data_kind >= EVENT_COUNT) { - error_report("Replay: unknown event kind %d", replay_data_kind); + replay_state.has_unread_data = 1; + if (replay_state.data_kind >= EVENT_COUNT) { + error_report("Replay: unknown event kind %d", + replay_state.data_kind); exit(1); } } @@ -167,7 +165,7 @@ void replay_fetch_data_kind(void) void replay_finish_event(void) { - replay_has_unread_data = 0; + replay_state.has_unread_data = 0; replay_fetch_data_kind(); } diff --git a/replay/replay-internal.h b/replay/replay-internal.h index efbf14c8a77..9b02d7d6aa2 100644 --- a/replay/replay-internal.h +++ b/replay/replay-internal.h @@ -62,11 +62,13 @@ typedef struct ReplayState { uint64_t current_step; /*! Number of instructions to be executed before other events happen. */ int instructions_count; + /*! Type of the currently executed event. */ + unsigned int data_kind; + /*! Flag which indicates that event is not processed yet. */ + unsigned int has_unread_data; } ReplayState; extern ReplayState replay_state; -extern unsigned int replay_data_kind; - /* File for replay writing */ extern FILE *replay_file; @@ -98,7 +100,7 @@ void replay_check_error(void); the next event from the log. */ void replay_finish_event(void); /*! Reads data type from the file and stores it in the - replay_data_kind variable. */ + data_kind variable. */ void replay_fetch_data_kind(void); /*! Saves queued events (like instructions and sound). */ diff --git a/replay/replay-time.c b/replay/replay-time.c index fffe072c555..f70382a88f3 100644 --- a/replay/replay-time.c +++ b/replay/replay-time.c @@ -31,7 +31,7 @@ int64_t replay_save_clock(ReplayClockKind kind, int64_t clock) void replay_read_next_clock(ReplayClockKind kind) { - unsigned int read_kind = replay_data_kind - EVENT_CLOCK; + unsigned int read_kind = replay_state.data_kind - EVENT_CLOCK; assert(read_kind == kind); diff --git a/replay/replay.c b/replay/replay.c index 167fd2942d6..cc2238d0772 100644 --- a/replay/replay.c +++ b/replay/replay.c @@ -38,15 +38,15 @@ bool replay_next_event_is(int event) /* nothing to skip - not all instructions used */ if (replay_state.instructions_count != 0) { - assert(replay_data_kind == EVENT_INSTRUCTION); + assert(replay_state.data_kind == EVENT_INSTRUCTION); return event == EVENT_INSTRUCTION; } while (true) { - if (event == replay_data_kind) { + if (event == replay_state.data_kind) { res = true; } - switch (replay_data_kind) { + switch (replay_state.data_kind) { case EVENT_SHUTDOWN: replay_finish_event(); qemu_system_shutdown_request(); @@ -85,7 +85,7 @@ void replay_account_executed_instructions(void) replay_state.instructions_count -= count; replay_state.current_step += count; if (replay_state.instructions_count == 0) { - assert(replay_data_kind == EVENT_INSTRUCTION); + assert(replay_state.data_kind == EVENT_INSTRUCTION); replay_finish_event(); /* Wake up iothread. This is required because timers will not expire until clock counters @@ -188,7 +188,7 @@ bool replay_checkpoint(ReplayCheckpoint checkpoint) if (replay_mode == REPLAY_MODE_PLAY) { if (replay_next_event_is(EVENT_CHECKPOINT + checkpoint)) { replay_finish_event(); - } else if (replay_data_kind != EVENT_ASYNC) { + } else if (replay_state.data_kind != EVENT_ASYNC) { res = false; goto out; } @@ -196,7 +196,7 @@ bool replay_checkpoint(ReplayCheckpoint checkpoint) /* replay_read_events may leave some unread events. Return false if not all of the events associated with checkpoint were processed */ - res = replay_data_kind != EVENT_ASYNC; + res = replay_state.data_kind != EVENT_ASYNC; } else if (replay_mode == REPLAY_MODE_RECORD) { replay_put_event(EVENT_CHECKPOINT + checkpoint); replay_save_events(checkpoint); @@ -237,9 +237,10 @@ static void replay_enable(const char *fname, int mode) replay_filename = g_strdup(fname); replay_mode = mode; - replay_data_kind = -1; + replay_state.data_kind = -1; replay_state.instructions_count = 0; replay_state.current_step = 0; + replay_state.has_unread_data = 0; /* skip file header for RECORD and check it for PLAY */ if (replay_mode == REPLAY_MODE_RECORD) { From 306e196fa24c46d384577fb9c16e7cdb80f26d17 Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Mon, 26 Sep 2016 11:08:10 +0300 Subject: [PATCH 362/723] replay: vmstate for replay module This patch introduces vmstate for replay data structures. It allows saving and loading vmstate while replaying. Signed-off-by: Pavel Dovgalyuk Message-Id: <20160926080810.6992.68420.stgit@PASHA-ISP> Signed-off-by: Paolo Bonzini --- replay/Makefile.objs | 1 + replay/replay-internal.h | 9 ++++++ replay/replay-snapshot.c | 60 ++++++++++++++++++++++++++++++++++++++++ replay/replay.c | 1 + 4 files changed, 71 insertions(+) create mode 100644 replay/replay-snapshot.c diff --git a/replay/Makefile.objs b/replay/Makefile.objs index fcb3f74d602..c8ad3ebb89d 100644 --- a/replay/Makefile.objs +++ b/replay/Makefile.objs @@ -4,3 +4,4 @@ common-obj-y += replay-events.o common-obj-y += replay-time.o common-obj-y += replay-input.o common-obj-y += replay-char.o +common-obj-y += replay-snapshot.o diff --git a/replay/replay-internal.h b/replay/replay-internal.h index 9b02d7d6aa2..e07eb7d45d1 100644 --- a/replay/replay-internal.h +++ b/replay/replay-internal.h @@ -66,6 +66,8 @@ typedef struct ReplayState { unsigned int data_kind; /*! Flag which indicates that event is not processed yet. */ unsigned int has_unread_data; + /*! Temporary variable for saving current log offset. */ + uint64_t file_offset; } ReplayState; extern ReplayState replay_state; @@ -157,4 +159,11 @@ void replay_event_char_read_save(void *opaque); /*! Reads char event read from the file. */ void *replay_event_char_read_load(void); +/* VMState-related functions */ + +/* Registers replay VMState. + Should be called before virtual devices initialization + to make cached timers available for post_load functions. */ +void replay_vmstate_register(void); + #endif diff --git a/replay/replay-snapshot.c b/replay/replay-snapshot.c new file mode 100644 index 00000000000..a17e80e26cb --- /dev/null +++ b/replay/replay-snapshot.c @@ -0,0 +1,60 @@ +/* + * replay-snapshot.c + * + * Copyright (c) 2010-2016 Institute for System Programming + * of the Russian Academy of Sciences. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "sysemu/replay.h" +#include "replay-internal.h" +#include "sysemu/sysemu.h" +#include "monitor/monitor.h" +#include "qapi/qmp/qstring.h" +#include "qemu/error-report.h" +#include "migration/vmstate.h" + +static void replay_pre_save(void *opaque) +{ + ReplayState *state = opaque; + state->file_offset = ftell(replay_file); +} + +static int replay_post_load(void *opaque, int version_id) +{ + ReplayState *state = opaque; + fseek(replay_file, state->file_offset, SEEK_SET); + /* If this was a vmstate, saved in recording mode, + we need to initialize replay data fields. */ + replay_fetch_data_kind(); + + return 0; +} + +static const VMStateDescription vmstate_replay = { + .name = "replay", + .version_id = 1, + .minimum_version_id = 1, + .pre_save = replay_pre_save, + .post_load = replay_post_load, + .fields = (VMStateField[]) { + VMSTATE_INT64_ARRAY(cached_clock, ReplayState, REPLAY_CLOCK_COUNT), + VMSTATE_UINT64(current_step, ReplayState), + VMSTATE_INT32(instructions_count, ReplayState), + VMSTATE_UINT32(data_kind, ReplayState), + VMSTATE_UINT32(has_unread_data, ReplayState), + VMSTATE_UINT64(file_offset, ReplayState), + VMSTATE_END_OF_LIST() + }, +}; + +void replay_vmstate_register(void) +{ + vmstate_register(NULL, 0, &vmstate_replay, &replay_state); +} diff --git a/replay/replay.c b/replay/replay.c index cc2238d0772..c797aeae8ae 100644 --- a/replay/replay.c +++ b/replay/replay.c @@ -292,6 +292,7 @@ void replay_configure(QemuOpts *opts) exit(1); } + replay_vmstate_register(); replay_enable(fname, mode); out: From 6d0ceb80ffe18ad4b28aab7356f440636c0be7be Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Mon, 26 Sep 2016 11:08:16 +0300 Subject: [PATCH 363/723] replay: allow replay stopping and restarting This patch fixes bug with stopping and restarting replay through monitor. Signed-off-by: Pavel Dovgalyuk Message-Id: <20160926080815.6992.71818.stgit@PASHA-ISP> Signed-off-by: Paolo Bonzini --- block/blkreplay.c | 15 +++++---------- cpus.c | 1 + include/sysemu/replay.h | 4 ++++ replay/replay-events.c | 8 ++++++++ replay/replay-internal.h | 6 ++++-- replay/replay-snapshot.c | 1 + stubs/replay.c | 5 +++++ vl.c | 1 + 8 files changed, 29 insertions(+), 12 deletions(-) diff --git a/block/blkreplay.c b/block/blkreplay.c index 30f9d5ff6c5..a741654d353 100755 --- a/block/blkreplay.c +++ b/block/blkreplay.c @@ -20,11 +20,6 @@ typedef struct Request { QEMUBH *bh; } Request; -/* Next request id. - This counter is global, because requests from different - block devices should not get overlapping ids. */ -static uint64_t request_id; - static int blkreplay_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) { @@ -84,7 +79,7 @@ static void block_request_create(uint64_t reqid, BlockDriverState *bs, static int coroutine_fn blkreplay_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags) { - uint64_t reqid = request_id++; + uint64_t reqid = blkreplay_next_id(); int ret = bdrv_co_preadv(bs->file, offset, bytes, qiov, flags); block_request_create(reqid, bs, qemu_coroutine_self()); qemu_coroutine_yield(); @@ -95,7 +90,7 @@ static int coroutine_fn blkreplay_co_preadv(BlockDriverState *bs, static int coroutine_fn blkreplay_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags) { - uint64_t reqid = request_id++; + uint64_t reqid = blkreplay_next_id(); int ret = bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags); block_request_create(reqid, bs, qemu_coroutine_self()); qemu_coroutine_yield(); @@ -106,7 +101,7 @@ static int coroutine_fn blkreplay_co_pwritev(BlockDriverState *bs, static int coroutine_fn blkreplay_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int count, BdrvRequestFlags flags) { - uint64_t reqid = request_id++; + uint64_t reqid = blkreplay_next_id(); int ret = bdrv_co_pwrite_zeroes(bs->file, offset, count, flags); block_request_create(reqid, bs, qemu_coroutine_self()); qemu_coroutine_yield(); @@ -117,7 +112,7 @@ static int coroutine_fn blkreplay_co_pwrite_zeroes(BlockDriverState *bs, static int coroutine_fn blkreplay_co_pdiscard(BlockDriverState *bs, int64_t offset, int count) { - uint64_t reqid = request_id++; + uint64_t reqid = blkreplay_next_id(); int ret = bdrv_co_pdiscard(bs->file->bs, offset, count); block_request_create(reqid, bs, qemu_coroutine_self()); qemu_coroutine_yield(); @@ -127,7 +122,7 @@ static int coroutine_fn blkreplay_co_pdiscard(BlockDriverState *bs, static int coroutine_fn blkreplay_co_flush(BlockDriverState *bs) { - uint64_t reqid = request_id++; + uint64_t reqid = blkreplay_next_id(); int ret = bdrv_co_flush(bs->file->bs); block_request_create(reqid, bs, qemu_coroutine_self()); qemu_coroutine_yield(); diff --git a/cpus.c b/cpus.c index fbd70f59f74..b2fbe333040 100644 --- a/cpus.c +++ b/cpus.c @@ -750,6 +750,7 @@ static int do_vm_stop(RunState state) } bdrv_drain_all(); + replay_disable_events(); ret = blk_flush_all(); return ret; diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h index 0a88393d2b1..f80d6d28e86 100644 --- a/include/sysemu/replay.h +++ b/include/sysemu/replay.h @@ -105,6 +105,8 @@ bool replay_checkpoint(ReplayCheckpoint checkpoint); /*! Disables storing events in the queue */ void replay_disable_events(void); +/*! Enables storing events in the queue */ +void replay_enable_events(void); /*! Returns true when saving events is enabled */ bool replay_events_enabled(void); /*! Adds bottom half event to the queue */ @@ -115,6 +117,8 @@ void replay_input_event(QemuConsole *src, InputEvent *evt); void replay_input_sync_event(void); /*! Adds block layer event to the queue */ void replay_block_event(QEMUBH *bh, uint64_t id); +/*! Returns ID for the next block event */ +uint64_t blkreplay_next_id(void); /* Character device */ diff --git a/replay/replay-events.c b/replay/replay-events.c index 4eb2ea3604e..c5139136714 100644 --- a/replay/replay-events.c +++ b/replay/replay-events.c @@ -309,3 +309,11 @@ bool replay_events_enabled(void) { return events_enabled; } + +uint64_t blkreplay_next_id(void) +{ + if (replay_events_enabled()) { + return replay_state.block_request_id++; + } + return 0; +} diff --git a/replay/replay-internal.h b/replay/replay-internal.h index e07eb7d45d1..9117e442d01 100644 --- a/replay/replay-internal.h +++ b/replay/replay-internal.h @@ -68,6 +68,10 @@ typedef struct ReplayState { unsigned int has_unread_data; /*! Temporary variable for saving current log offset. */ uint64_t file_offset; + /*! Next block operation id. + This counter is global, because requests from different + block devices should not get overlapping ids. */ + uint64_t block_request_id; } ReplayState; extern ReplayState replay_state; @@ -123,8 +127,6 @@ void replay_read_next_clock(unsigned int kind); void replay_init_events(void); /*! Clears internal data structures for events handling */ void replay_finish_events(void); -/*! Enables storing events in the queue */ -void replay_enable_events(void); /*! Flushes events queue */ void replay_flush_events(void); /*! Clears events list before loading new VM state */ diff --git a/replay/replay-snapshot.c b/replay/replay-snapshot.c index a17e80e26cb..498059734d1 100644 --- a/replay/replay-snapshot.c +++ b/replay/replay-snapshot.c @@ -50,6 +50,7 @@ static const VMStateDescription vmstate_replay = { VMSTATE_UINT32(data_kind, ReplayState), VMSTATE_UINT32(has_unread_data, ReplayState), VMSTATE_UINT64(file_offset, ReplayState), + VMSTATE_UINT64(block_request_id, ReplayState), VMSTATE_END_OF_LIST() }, }; diff --git a/stubs/replay.c b/stubs/replay.c index de9fa1ec987..d9a6da99d27 100644 --- a/stubs/replay.c +++ b/stubs/replay.c @@ -67,3 +67,8 @@ void replay_char_read_all_save_buf(uint8_t *buf, int offset) void replay_block_event(QEMUBH *bh, uint64_t id) { } + +uint64_t blkreplay_next_id(void) +{ + return 0; +} diff --git a/vl.c b/vl.c index eda83fa93d0..5759e0ad51c 100644 --- a/vl.c +++ b/vl.c @@ -784,6 +784,7 @@ void vm_start(void) if (runstate_is_running()) { qapi_event_send_stop(&error_abort); } else { + replay_enable_events(); cpu_enable_ticks(); runstate_set(RUN_STATE_RUNNING); vm_state_notify(1, RUN_STATE_RUNNING); From 0456441b5eb6694a561ad5bb8dad52483e6a08d0 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Tue, 20 Sep 2016 18:57:40 -0300 Subject: [PATCH 364/723] target-i386: Remove unused X86CPUDefinition::xlevel2 field No CPU model in builtin_x86_defs has xlevel2 set, so it is always zero. Delete the field. Note that this is not an user-visible change. It doesn't remove the ability to set xlevel2 on the command-line, it just removes an unused field in builtin_x86_defs. Reviewed-by: Richard Henderson Signed-off-by: Eduardo Habkost --- target-i386/cpu.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index db12728abf8..920b78fb309 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -761,7 +761,6 @@ struct X86CPUDefinition { const char *name; uint32_t level; uint32_t xlevel; - uint32_t xlevel2; /* vendor is zero-terminated, 12 character ASCII string */ char vendor[CPUID_VENDOR_SZ + 1]; int family; @@ -2214,7 +2213,6 @@ static void x86_cpu_load_def(X86CPU *cpu, X86CPUDefinition *def, Error **errp) object_property_set_int(OBJECT(cpu), def->model, "model", errp); object_property_set_int(OBJECT(cpu), def->stepping, "stepping", errp); object_property_set_int(OBJECT(cpu), def->xlevel, "xlevel", errp); - object_property_set_int(OBJECT(cpu), def->xlevel2, "xlevel2", errp); object_property_set_str(OBJECT(cpu), def->model_id, "model-id", errp); for (w = 0; w < FEATURE_WORDS; w++) { env->features[w] = def->features[w]; From 5e992a8e337e710ea2d02f35668ac55a80e15f99 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 24 Apr 2015 15:49:15 -0300 Subject: [PATCH 365/723] target-i386: Add a marker to end of the region zeroed on reset Instead of using cpuid_level, use an empty struct as a marker (like we already did with {start,end}_init_save). This will avoid accidentaly resetting the wrong fields if we change the field ordering on CPUX86State. Reviewed-by: Richard Henderson Signed-off-by: Eduardo Habkost --- target-i386/cpu.c | 2 +- target-i386/cpu.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 920b78fb309..26f0e59ab9b 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -2714,7 +2714,7 @@ static void x86_cpu_reset(CPUState *s) xcc->parent_reset(s); - memset(env, 0, offsetof(CPUX86State, cpuid_level)); + memset(env, 0, offsetof(CPUX86State, end_reset_fields)); tlb_flush(s, 1); diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 27af9c3f9ab..604d5918291 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -1108,6 +1108,7 @@ typedef struct CPUX86State { CPU_COMMON /* Fields from here on are preserved across CPU reset. */ + struct {} end_reset_fields; /* processor features (e.g. for CPUID insn) */ uint32_t cpuid_level; From 6efef58ed151f75bca29561bde6b8a65db43d4a2 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Tue, 20 Sep 2016 17:11:39 -0300 Subject: [PATCH 366/723] tests: Add test code for CPUID level/xlevel handling Add test code that will check if the automatic CPUID level changes are working as expected. Reviewed-by: Richard Henderson Signed-off-by: Eduardo Habkost --- tests/.gitignore | 1 + tests/Makefile.include | 2 + tests/test-x86-cpuid-compat.c | 108 ++++++++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+) create mode 100644 tests/test-x86-cpuid-compat.c diff --git a/tests/.gitignore b/tests/.gitignore index 24ac6cfa77a..0f0c79b1a9c 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -75,6 +75,7 @@ test-visitor-serialization test-vmstate test-write-threshold test-x86-cpuid +test-x86-cpuid-compat test-xbzrle test-netfilter test-filter-mirror diff --git a/tests/Makefile.include b/tests/Makefile.include index 2aa78c18201..8162f6f7357 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -243,6 +243,7 @@ check-qtest-i386-y += tests/test-netfilter$(EXESUF) check-qtest-i386-y += tests/test-filter-mirror$(EXESUF) check-qtest-i386-y += tests/test-filter-redirector$(EXESUF) check-qtest-i386-y += tests/postcopy-test$(EXESUF) +check-qtest-i386-y += tests/test-x86-cpuid-compat$(EXESUF) check-qtest-x86_64-y += $(check-qtest-i386-y) gcov-files-i386-y += i386-softmmu/hw/timer/mc146818rtc.c gcov-files-x86_64-y = $(subst i386-softmmu/,x86_64-softmmu/,$(gcov-files-i386-y)) @@ -663,6 +664,7 @@ tests/test-write-threshold$(EXESUF): tests/test-write-threshold.o $(test-block-o tests/test-netfilter$(EXESUF): tests/test-netfilter.o $(qtest-obj-y) tests/test-filter-mirror$(EXESUF): tests/test-filter-mirror.o $(qtest-obj-y) tests/test-filter-redirector$(EXESUF): tests/test-filter-redirector.o $(qtest-obj-y) +tests/test-x86-cpuid-compat$(EXESUF): tests/test-x86-cpuid-compat.o $(qtest-obj-y) tests/ivshmem-test$(EXESUF): tests/ivshmem-test.o contrib/ivshmem-server/ivshmem-server.o $(libqos-pc-obj-y) tests/vhost-user-bridge$(EXESUF): tests/vhost-user-bridge.o tests/ptimer-test$(EXESUF): tests/ptimer-test.o tests/ptimer-test-stubs.o hw/core/ptimer.o diff --git a/tests/test-x86-cpuid-compat.c b/tests/test-x86-cpuid-compat.c new file mode 100644 index 00000000000..b81cfeb25e4 --- /dev/null +++ b/tests/test-x86-cpuid-compat.c @@ -0,0 +1,108 @@ +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "qapi/qmp/qlist.h" +#include "qapi/qmp/qdict.h" +#include "qapi/qmp/qint.h" +#include "libqtest.h" + +static char *get_cpu0_qom_path(void) +{ + QDict *resp; + QList *ret; + QDict *cpu0; + char *path; + + resp = qmp("{'execute': 'query-cpus', 'arguments': {}}"); + g_assert(qdict_haskey(resp, "return")); + ret = qdict_get_qlist(resp, "return"); + + cpu0 = qobject_to_qdict(qlist_peek(ret)); + path = g_strdup(qdict_get_str(cpu0, "qom_path")); + QDECREF(resp); + return path; +} + +static QObject *qom_get(const char *path, const char *prop) +{ + QDict *resp = qmp("{ 'execute': 'qom-get'," + " 'arguments': { 'path': %s," + " 'property': %s } }", + path, prop); + QObject *ret = qdict_get(resp, "return"); + qobject_incref(ret); + QDECREF(resp); + return ret; +} + +typedef struct CpuidTestArgs { + const char *cmdline; + const char *property; + int64_t expected_value; +} CpuidTestArgs; + +static void test_cpuid_prop(const void *data) +{ + const CpuidTestArgs *args = data; + char *path; + QInt *value; + + qtest_start(args->cmdline); + path = get_cpu0_qom_path(); + value = qobject_to_qint(qom_get(path, args->property)); + g_assert_cmpint(qint_get_int(value), ==, args->expected_value); + qtest_end(); + + QDECREF(value); + g_free(path); +} + +static void add_cpuid_test(const char *name, const char *cmdline, + const char *property, int64_t expected_value) +{ + CpuidTestArgs *args = g_new0(CpuidTestArgs, 1); + args->cmdline = cmdline; + args->property = property; + args->expected_value = expected_value; + qtest_add_data_func(name, args, test_cpuid_prop); +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + /* Original level values for CPU models: */ + add_cpuid_test("x86/cpuid/phenom/level", + "-cpu phenom", "level", 5); + add_cpuid_test("x86/cpuid/Conroe/level", + "-cpu Conroe", "level", 10); + add_cpuid_test("x86/cpuid/SandyBridge/level", + "-cpu SandyBridge", "level", 0xd); + add_cpuid_test("x86/cpuid/486/xlevel", + "-cpu 486", "xlevel", 0); + add_cpuid_test("x86/cpuid/core2duo/xlevel", + "-cpu core2duo", "xlevel", 0x80000008); + add_cpuid_test("x86/cpuid/phenom/xlevel", + "-cpu phenom", "xlevel", 0x8000001A); + + /* If level is not large enough, it should increase automatically: */ + /* CPUID[EAX=7,ECX=0].EBX: */ + add_cpuid_test("x86/cpuid/auto-level/phenom/fsgsbase", + "-cpu phenom,+fsgsbase", "level", 7); + + /* If level is already large enough, it shouldn't change: */ + add_cpuid_test("x86/cpuid/auto-level/SandyBridge/multiple", + "-cpu SandyBridge,+arat,+fsgsbase,+avx512vbmi", + "level", 0xd); + + /* if xlevel is already large enough, it shouldn't change: */ + add_cpuid_test("x86/cpuid/auto-xlevel/phenom/3dnow", + "-cpu phenom,+3dnow,+sse4a,+invtsc,+npt", + "xlevel", 0x8000001A); + + /* if xlevel2 is already large enough, it shouldn't change: */ + add_cpuid_test("x86/cpuid/auto-xlevel2/486/fixed", + "-cpu 486,xlevel2=0xC0000002,+xstore", + "xlevel2", 0xC0000002); + + return g_test_run(); +} From df3e9af8fd02f22d03871975daa23ecbfcd48490 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Tue, 20 Sep 2016 20:57:00 -0300 Subject: [PATCH 367/723] tests: Test CPUID level handling for old machines We're going to change the way level/xlevel/xlevel2 are handled when enabling features, but we need to keep the old behavior on existing machine types. Add test cases for that. Reviewed-by: Richard Henderson Signed-off-by: Eduardo Habkost --- tests/test-x86-cpuid-compat.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/test-x86-cpuid-compat.c b/tests/test-x86-cpuid-compat.c index b81cfeb25e4..f7003ee39d1 100644 --- a/tests/test-x86-cpuid-compat.c +++ b/tests/test-x86-cpuid-compat.c @@ -104,5 +104,18 @@ int main(int argc, char **argv) "-cpu 486,xlevel2=0xC0000002,+xstore", "xlevel2", 0xC0000002); + /* Check compatibility of old machine-types that didn't + * auto-increase level/xlevel/xlevel2: */ + + add_cpuid_test("x86/cpuid/auto-level/pc-2.7", + "-machine pc-i440fx-2.7 -cpu 486,+arat,+avx512vbmi,+xsaveopt", + "level", 1); + add_cpuid_test("x86/cpuid/auto-xlevel/pc-2.7", + "-machine pc-i440fx-2.7 -cpu 486,+3dnow,+sse4a,+invtsc,+npt", + "xlevel", 0); + add_cpuid_test("x86/cpuid/auto-xlevel2/pc-2.7", + "-machine pc-i440fx-2.7 -cpu 486,+xstore", + "xlevel2", 0); + return g_test_run(); } From c39c0edf9bb3b968ba95484465a50c7b19f4aa3a Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Wed, 21 Sep 2016 13:30:12 -0300 Subject: [PATCH 368/723] target-i386: Automatically set level/xlevel/xlevel2 when needed Instead of requiring users and management software to be aware of required CPUID level/xlevel/xlevel2 values for each feature, automatically increase those values when features need them. This was already done for CPUID[7].EBX, and is now made generic for all CPUID feature flags. Unit test included, to make sure we don't break ABI on older machine-types and don't mess with the CPUID level values if they are explicitly set by the user. Reviewed-by: Richard Henderson Signed-off-by: Eduardo Habkost --- include/hw/i386/pc.h | 5 +++ target-i386/cpu.c | 84 ++++++++++++++++++++++++++++++----- target-i386/cpu.h | 12 +++-- tests/test-x86-cpuid-compat.c | 45 +++++++++++++++++++ 4 files changed, 133 insertions(+), 13 deletions(-) diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 29a6c9b60b6..47bdf10cfd9 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -374,6 +374,11 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *); .driver = TYPE_X86_CPU,\ .property = "l3-cache",\ .value = "off",\ + },\ + {\ + .driver = TYPE_X86_CPU,\ + .property = "full-cpuid-auto-level",\ + .value = "off",\ }, #define PC_COMPAT_2_6 \ diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 26f0e59ab9b..24893d2d891 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -1643,9 +1643,12 @@ static void host_x86_cpu_initfn(Object *obj) /* If KVM is disabled, x86_cpu_realizefn() will report an error later */ if (kvm_enabled()) { - env->cpuid_level = kvm_arch_get_supported_cpuid(s, 0x0, 0, R_EAX); - env->cpuid_xlevel = kvm_arch_get_supported_cpuid(s, 0x80000000, 0, R_EAX); - env->cpuid_xlevel2 = kvm_arch_get_supported_cpuid(s, 0xC0000000, 0, R_EAX); + env->cpuid_min_level = + kvm_arch_get_supported_cpuid(s, 0x0, 0, R_EAX); + env->cpuid_min_xlevel = + kvm_arch_get_supported_cpuid(s, 0x80000000, 0, R_EAX); + env->cpuid_min_xlevel2 = + kvm_arch_get_supported_cpuid(s, 0xC0000000, 0, R_EAX); if (lmce_supported()) { object_property_set_bool(OBJECT(cpu), true, "lmce", &error_abort); @@ -2208,11 +2211,13 @@ static void x86_cpu_load_def(X86CPU *cpu, X86CPUDefinition *def, Error **errp) char host_vendor[CPUID_VENDOR_SZ + 1]; FeatureWord w; - object_property_set_int(OBJECT(cpu), def->level, "level", errp); + /* CPU models only set _minimum_ values for level/xlevel: */ + object_property_set_int(OBJECT(cpu), def->level, "min-level", errp); + object_property_set_int(OBJECT(cpu), def->xlevel, "min-xlevel", errp); + object_property_set_int(OBJECT(cpu), def->family, "family", errp); object_property_set_int(OBJECT(cpu), def->model, "model", errp); object_property_set_int(OBJECT(cpu), def->stepping, "stepping", errp); - object_property_set_int(OBJECT(cpu), def->xlevel, "xlevel", errp); object_property_set_str(OBJECT(cpu), def->model_id, "model-id", errp); for (w = 0; w < FEATURE_WORDS; w++) { env->features[w] = def->features[w]; @@ -2951,6 +2956,38 @@ static uint32_t x86_host_phys_bits(void) return host_phys_bits; } +static void x86_cpu_adjust_level(X86CPU *cpu, uint32_t *min, uint32_t value) +{ + if (*min < value) { + *min = value; + } +} + +/* Increase cpuid_min_{level,xlevel,xlevel2} automatically, if appropriate */ +static void x86_cpu_adjust_feat_level(X86CPU *cpu, FeatureWord w) +{ + CPUX86State *env = &cpu->env; + FeatureWordInfo *fi = &feature_word_info[w]; + uint32_t eax = fi->cpuid_eax; + uint32_t region = eax & 0xF0000000; + + if (!env->features[w]) { + return; + } + + switch (region) { + case 0x00000000: + x86_cpu_adjust_level(cpu, &env->cpuid_min_level, eax); + break; + case 0x80000000: + x86_cpu_adjust_level(cpu, &env->cpuid_min_xlevel, eax); + break; + case 0xC0000000: + x86_cpu_adjust_level(cpu, &env->cpuid_min_xlevel2, eax); + break; + } +} + #define IS_INTEL_CPU(env) ((env)->cpuid_vendor1 == CPUID_VENDOR_INTEL_1 && \ (env)->cpuid_vendor2 == CPUID_VENDOR_INTEL_2 && \ (env)->cpuid_vendor3 == CPUID_VENDOR_INTEL_3) @@ -2996,8 +3033,31 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) cpu->env.features[w] &= ~minus_features[w]; } - if (env->features[FEAT_7_0_EBX] && env->cpuid_level < 7) { - env->cpuid_level = 7; + + /* CPUID[EAX=7,ECX=0].EBX always increased level automatically: */ + x86_cpu_adjust_feat_level(cpu, FEAT_7_0_EBX); + if (cpu->full_cpuid_auto_level) { + x86_cpu_adjust_feat_level(cpu, FEAT_1_EDX); + x86_cpu_adjust_feat_level(cpu, FEAT_1_ECX); + x86_cpu_adjust_feat_level(cpu, FEAT_6_EAX); + x86_cpu_adjust_feat_level(cpu, FEAT_7_0_ECX); + x86_cpu_adjust_feat_level(cpu, FEAT_8000_0001_EDX); + x86_cpu_adjust_feat_level(cpu, FEAT_8000_0001_ECX); + x86_cpu_adjust_feat_level(cpu, FEAT_8000_0007_EDX); + x86_cpu_adjust_feat_level(cpu, FEAT_C000_0001_EDX); + x86_cpu_adjust_feat_level(cpu, FEAT_SVM); + x86_cpu_adjust_feat_level(cpu, FEAT_XSAVE); + } + + /* Set cpuid_*level* based on cpuid_min_*level, if not explicitly set */ + if (env->cpuid_level == UINT32_MAX) { + env->cpuid_level = env->cpuid_min_level; + } + if (env->cpuid_xlevel == UINT32_MAX) { + env->cpuid_xlevel = env->cpuid_min_xlevel; + } + if (env->cpuid_xlevel2 == UINT32_MAX) { + env->cpuid_xlevel2 = env->cpuid_min_xlevel2; } if (x86_cpu_filter_features(cpu) && cpu->enforce_cpuid) { @@ -3403,9 +3463,13 @@ static Property x86_cpu_properties[] = { DEFINE_PROP_UINT32("phys-bits", X86CPU, phys_bits, 0), DEFINE_PROP_BOOL("host-phys-bits", X86CPU, host_phys_bits, false), DEFINE_PROP_BOOL("fill-mtrr-mask", X86CPU, fill_mtrr_mask, true), - DEFINE_PROP_UINT32("level", X86CPU, env.cpuid_level, 0), - DEFINE_PROP_UINT32("xlevel", X86CPU, env.cpuid_xlevel, 0), - DEFINE_PROP_UINT32("xlevel2", X86CPU, env.cpuid_xlevel2, 0), + DEFINE_PROP_UINT32("level", X86CPU, env.cpuid_level, UINT32_MAX), + DEFINE_PROP_UINT32("xlevel", X86CPU, env.cpuid_xlevel, UINT32_MAX), + DEFINE_PROP_UINT32("xlevel2", X86CPU, env.cpuid_xlevel2, UINT32_MAX), + DEFINE_PROP_UINT32("min-level", X86CPU, env.cpuid_min_level, 0), + DEFINE_PROP_UINT32("min-xlevel", X86CPU, env.cpuid_min_xlevel, 0), + DEFINE_PROP_UINT32("min-xlevel2", X86CPU, env.cpuid_min_xlevel2, 0), + DEFINE_PROP_BOOL("full-cpuid-auto-level", X86CPU, full_cpuid_auto_level, true), DEFINE_PROP_STRING("hv-vendor-id", X86CPU, hyperv_vendor_id), DEFINE_PROP_BOOL("cpuid-0xb", X86CPU, enable_cpuid_0xb, true), DEFINE_PROP_BOOL("lmce", X86CPU, enable_lmce, false), diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 604d5918291..aaa45f03d0e 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -1111,9 +1111,12 @@ typedef struct CPUX86State { struct {} end_reset_fields; /* processor features (e.g. for CPUID insn) */ - uint32_t cpuid_level; - uint32_t cpuid_xlevel; - uint32_t cpuid_xlevel2; + /* Minimum level/xlevel/xlevel2, based on CPU model + features */ + uint32_t cpuid_min_level, cpuid_min_xlevel, cpuid_min_xlevel2; + /* Maximum level/xlevel/xlevel2 value for auto-assignment: */ + uint32_t cpuid_max_level, cpuid_max_xlevel, cpuid_max_xlevel2; + /* Actual level/xlevel/xlevel2 value: */ + uint32_t cpuid_level, cpuid_xlevel, cpuid_xlevel2; uint32_t cpuid_vendor1; uint32_t cpuid_vendor2; uint32_t cpuid_vendor3; @@ -1218,6 +1221,9 @@ struct X86CPU { /* Compatibility bits for old machine types: */ bool enable_cpuid_0xb; + /* Enable auto level-increase for all CPUID leaves */ + bool full_cpuid_auto_level; + /* if true fill the top bits of the MTRR_PHYSMASKn variable range */ bool fill_mtrr_mask; diff --git a/tests/test-x86-cpuid-compat.c b/tests/test-x86-cpuid-compat.c index f7003ee39d1..83f1c80868f 100644 --- a/tests/test-x86-cpuid-compat.c +++ b/tests/test-x86-cpuid-compat.c @@ -85,19 +85,64 @@ int main(int argc, char **argv) "-cpu phenom", "xlevel", 0x8000001A); /* If level is not large enough, it should increase automatically: */ + /* CPUID[6].EAX: */ + add_cpuid_test("x86/cpuid/auto-level/phenom/arat", + "-cpu 486,+arat", "level", 6); /* CPUID[EAX=7,ECX=0].EBX: */ add_cpuid_test("x86/cpuid/auto-level/phenom/fsgsbase", "-cpu phenom,+fsgsbase", "level", 7); + /* CPUID[EAX=7,ECX=0].ECX: */ + add_cpuid_test("x86/cpuid/auto-level/phenom/avx512vbmi", + "-cpu phenom,+avx512vbmi", "level", 7); + /* CPUID[EAX=0xd,ECX=1].EAX: */ + add_cpuid_test("x86/cpuid/auto-level/phenom/xsaveopt", + "-cpu phenom,+xsaveopt", "level", 0xd); + /* CPUID[8000_0001].EDX: */ + add_cpuid_test("x86/cpuid/auto-xlevel/486/3dnow", + "-cpu 486,+3dnow", "xlevel", 0x80000001); + /* CPUID[8000_0001].ECX: */ + add_cpuid_test("x86/cpuid/auto-xlevel/486/sse4a", + "-cpu 486,+sse4a", "xlevel", 0x80000001); + /* CPUID[8000_0007].EDX: */ + add_cpuid_test("x86/cpuid/auto-xlevel/486/invtsc", + "-cpu 486,+invtsc", "xlevel", 0x80000007); + /* CPUID[8000_000A].EDX: */ + add_cpuid_test("x86/cpuid/auto-xlevel/486/npt", + "-cpu 486,+npt", "xlevel", 0x8000000A); + /* CPUID[C000_0001].EDX: */ + add_cpuid_test("x86/cpuid/auto-xlevel2/phenom/xstore", + "-cpu phenom,+xstore", "xlevel2", 0xC0000001); + /* If level is already large enough, it shouldn't change: */ add_cpuid_test("x86/cpuid/auto-level/SandyBridge/multiple", "-cpu SandyBridge,+arat,+fsgsbase,+avx512vbmi", "level", 0xd); + /* If level is explicitly set, it shouldn't change: */ + add_cpuid_test("x86/cpuid/auto-level/486/fixed/0xF", + "-cpu 486,level=0xF,+arat,+fsgsbase,+avx512vbmi,+xsaveopt", + "level", 0xF); + add_cpuid_test("x86/cpuid/auto-level/486/fixed/2", + "-cpu 486,level=2,+arat,+fsgsbase,+avx512vbmi,+xsaveopt", + "level", 2); + add_cpuid_test("x86/cpuid/auto-level/486/fixed/0", + "-cpu 486,level=0,+arat,+fsgsbase,+avx512vbmi,+xsaveopt", + "level", 0); /* if xlevel is already large enough, it shouldn't change: */ add_cpuid_test("x86/cpuid/auto-xlevel/phenom/3dnow", "-cpu phenom,+3dnow,+sse4a,+invtsc,+npt", "xlevel", 0x8000001A); + /* If xlevel is explicitly set, it shouldn't change: */ + add_cpuid_test("x86/cpuid/auto-xlevel/486/fixed/80000002", + "-cpu 486,xlevel=0x80000002,+3dnow,+sse4a,+invtsc,+npt", + "xlevel", 0x80000002); + add_cpuid_test("x86/cpuid/auto-xlevel/486/fixed/8000001A", + "-cpu 486,xlevel=0x8000001A,+3dnow,+sse4a,+invtsc,+npt", + "xlevel", 0x8000001A); + add_cpuid_test("x86/cpuid/auto-xlevel/phenom/fixed/0", + "-cpu 486,xlevel=0,+3dnow,+sse4a,+invtsc,+npt", + "xlevel", 0); /* if xlevel2 is already large enough, it shouldn't change: */ add_cpuid_test("x86/cpuid/auto-xlevel2/486/fixed", From 0c3d7c0051576d220e6da0a8ac08f2d8482e2f0b Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Wed, 21 Sep 2016 15:01:35 -0300 Subject: [PATCH 369/723] target-i386: Enable CPUID[0x8000000A] if SVM is enabled SVM needs CPUID[0x8000000A] to be available. So if SVM is enabled in a CPU model or explicitly in the command-line, adjust CPUID xlevel to expose the CPUID[0x8000000A] leaf. Reviewed-by: Richard Henderson Signed-off-by: Eduardo Habkost --- target-i386/cpu.c | 4 ++++ tests/test-x86-cpuid-compat.c | 15 ++++++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 24893d2d891..7a5da99222e 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -3047,6 +3047,10 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) x86_cpu_adjust_feat_level(cpu, FEAT_C000_0001_EDX); x86_cpu_adjust_feat_level(cpu, FEAT_SVM); x86_cpu_adjust_feat_level(cpu, FEAT_XSAVE); + /* SVM requires CPUID[0x8000000A] */ + if (env->features[FEAT_8000_0001_ECX] & CPUID_EXT3_SVM) { + x86_cpu_adjust_level(cpu, &env->cpuid_min_xlevel, 0x8000000A); + } } /* Set cpuid_*level* based on cpuid_min_*level, if not explicitly set */ diff --git a/tests/test-x86-cpuid-compat.c b/tests/test-x86-cpuid-compat.c index 83f1c80868f..83162a44c08 100644 --- a/tests/test-x86-cpuid-compat.c +++ b/tests/test-x86-cpuid-compat.c @@ -83,6 +83,8 @@ int main(int argc, char **argv) "-cpu core2duo", "xlevel", 0x80000008); add_cpuid_test("x86/cpuid/phenom/xlevel", "-cpu phenom", "xlevel", 0x8000001A); + add_cpuid_test("x86/cpuid/athlon/xlevel", + "-cpu athlon", "xlevel", 0x80000008); /* If level is not large enough, it should increase automatically: */ /* CPUID[6].EAX: */ @@ -112,6 +114,9 @@ int main(int argc, char **argv) /* CPUID[C000_0001].EDX: */ add_cpuid_test("x86/cpuid/auto-xlevel2/phenom/xstore", "-cpu phenom,+xstore", "xlevel2", 0xC0000001); + /* SVM needs CPUID[0x8000000A] */ + add_cpuid_test("x86/cpuid/auto-xlevel/athlon/svm", + "-cpu athlon,+svm", "xlevel", 0x8000000A); /* If level is already large enough, it shouldn't change: */ @@ -131,17 +136,17 @@ int main(int argc, char **argv) /* if xlevel is already large enough, it shouldn't change: */ add_cpuid_test("x86/cpuid/auto-xlevel/phenom/3dnow", - "-cpu phenom,+3dnow,+sse4a,+invtsc,+npt", + "-cpu phenom,+3dnow,+sse4a,+invtsc,+npt,+svm", "xlevel", 0x8000001A); /* If xlevel is explicitly set, it shouldn't change: */ add_cpuid_test("x86/cpuid/auto-xlevel/486/fixed/80000002", - "-cpu 486,xlevel=0x80000002,+3dnow,+sse4a,+invtsc,+npt", + "-cpu 486,xlevel=0x80000002,+3dnow,+sse4a,+invtsc,+npt,+svm", "xlevel", 0x80000002); add_cpuid_test("x86/cpuid/auto-xlevel/486/fixed/8000001A", - "-cpu 486,xlevel=0x8000001A,+3dnow,+sse4a,+invtsc,+npt", + "-cpu 486,xlevel=0x8000001A,+3dnow,+sse4a,+invtsc,+npt,+svm", "xlevel", 0x8000001A); add_cpuid_test("x86/cpuid/auto-xlevel/phenom/fixed/0", - "-cpu 486,xlevel=0,+3dnow,+sse4a,+invtsc,+npt", + "-cpu 486,xlevel=0,+3dnow,+sse4a,+invtsc,+npt,+svm", "xlevel", 0); /* if xlevel2 is already large enough, it shouldn't change: */ @@ -156,7 +161,7 @@ int main(int argc, char **argv) "-machine pc-i440fx-2.7 -cpu 486,+arat,+avx512vbmi,+xsaveopt", "level", 1); add_cpuid_test("x86/cpuid/auto-xlevel/pc-2.7", - "-machine pc-i440fx-2.7 -cpu 486,+3dnow,+sse4a,+invtsc,+npt", + "-machine pc-i440fx-2.7 -cpu 486,+3dnow,+sse4a,+invtsc,+npt,+svm", "xlevel", 0); add_cpuid_test("x86/cpuid/auto-xlevel2/pc-2.7", "-machine pc-i440fx-2.7 -cpu 486,+xstore", From eab60fb9f5e7bb6738b0619cfd0057d3a9d21330 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Fri, 16 Sep 2016 19:50:24 +0400 Subject: [PATCH 370/723] linux-user: remove #define smp_{cores, threads} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Those are unneeded now that CPUState nr_{cores,threads} is always initialized. Signed-off-by: Marc-André Lureau Reviewed-by: Eduardo Habkost Acked-by: David Gibson Signed-off-by: Eduardo Habkost --- include/sysemu/cpus.h | 5 +---- target-i386/cpu.c | 8 ++++---- target-ppc/translate_init.c | 3 ++- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/include/sysemu/cpus.h b/include/sysemu/cpus.h index fe992a8946e..3728a1ea7e4 100644 --- a/include/sysemu/cpus.h +++ b/include/sysemu/cpus.h @@ -29,12 +29,9 @@ void qtest_clock_warp(int64_t dest); #ifndef CONFIG_USER_ONLY /* vl.c */ +/* *-user doesn't have configurable SMP topology */ extern int smp_cores; extern int smp_threads; -#else -/* *-user doesn't have configurable SMP topology */ -#define smp_cores 1 -#define smp_threads 1 #endif void list_cpus(FILE *f, fprintf_function cpu_fprintf, const char *optarg); diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 7a5da99222e..a5d3b1af757 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -2498,13 +2498,13 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, switch (count) { case 0: - *eax = apicid_core_offset(smp_cores, smp_threads); - *ebx = smp_threads; + *eax = apicid_core_offset(cs->nr_cores, cs->nr_threads); + *ebx = cs->nr_threads; *ecx |= CPUID_TOPOLOGY_LEVEL_SMT; break; case 1: - *eax = apicid_pkg_offset(smp_cores, smp_threads); - *ebx = smp_cores * smp_threads; + *eax = apicid_pkg_offset(cs->nr_cores, cs->nr_threads); + *ebx = cs->nr_cores * cs->nr_threads; *ecx |= CPUID_TOPOLOGY_LEVEL_CORE; break; default: diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 407ccb93a3e..b66b40b82f0 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -9943,7 +9943,8 @@ static void ppc_cpu_unrealizefn(DeviceState *dev, Error **errp) int ppc_get_compat_smt_threads(PowerPCCPU *cpu) { - int ret = MIN(smp_threads, kvmppc_smt_threads()); + CPUState *cs = CPU(cpu); + int ret = MIN(cs->nr_threads, kvmppc_smt_threads()); switch (cpu->cpu_version) { case CPU_POWERPC_LOGICAL_2_05: From 2d5312da566e4424a807d078da05f92ee7be3eec Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Thu, 12 May 2016 11:24:04 -0300 Subject: [PATCH 371/723] target-i386: Move feature name arrays inside FeatureWordInfo It makes it easier to guarantee the arrays are the right size, and to find information when looking at the code. Reviewed-by: Richard Henderson Signed-off-by: Eduardo Habkost --- target-i386/cpu.c | 370 +++++++++++++++++++++------------------------- 1 file changed, 170 insertions(+), 200 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index a5d3b1af757..cc07fdbf8b6 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -181,185 +181,6 @@ static void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, dst[CPUID_VENDOR_SZ] = '\0'; } -/* feature flags taken from "Intel Processor Identification and the CPUID - * Instruction" and AMD's "CPUID Specification". In cases of disagreement - * between feature naming conventions, aliases may be added. - */ -static const char *feature_name[] = { - "fpu", "vme", "de", "pse", - "tsc", "msr", "pae", "mce", - "cx8", "apic", NULL, "sep", - "mtrr", "pge", "mca", "cmov", - "pat", "pse36", "pn" /* Intel psn */, "clflush" /* Intel clfsh */, - NULL, "ds" /* Intel dts */, "acpi", "mmx", - "fxsr", "sse", "sse2", "ss", - "ht" /* Intel htt */, "tm", "ia64", "pbe", -}; -static const char *ext_feature_name[] = { - "pni|sse3" /* Intel,AMD sse3 */, "pclmulqdq|pclmuldq", "dtes64", "monitor", - "ds_cpl", "vmx", "smx", "est", - "tm2", "ssse3", "cid", NULL, - "fma", "cx16", "xtpr", "pdcm", - NULL, "pcid", "dca", "sse4.1|sse4_1", - "sse4.2|sse4_2", "x2apic", "movbe", "popcnt", - "tsc-deadline", "aes", "xsave", "osxsave", - "avx", "f16c", "rdrand", "hypervisor", -}; -/* Feature names that are already defined on feature_name[] but are set on - * CPUID[8000_0001].EDX on AMD CPUs don't have their names on - * ext2_feature_name[]. They are copied automatically to cpuid_ext2_features - * if and only if CPU vendor is AMD. - */ -static const char *ext2_feature_name[] = { - NULL /* fpu */, NULL /* vme */, NULL /* de */, NULL /* pse */, - NULL /* tsc */, NULL /* msr */, NULL /* pae */, NULL /* mce */, - NULL /* cx8 */ /* AMD CMPXCHG8B */, NULL /* apic */, NULL, "syscall", - NULL /* mtrr */, NULL /* pge */, NULL /* mca */, NULL /* cmov */, - NULL /* pat */, NULL /* pse36 */, NULL, NULL /* Linux mp */, - "nx|xd", NULL, "mmxext", NULL /* mmx */, - NULL /* fxsr */, "fxsr_opt|ffxsr", "pdpe1gb" /* AMD Page1GB */, "rdtscp", - NULL, "lm|i64", "3dnowext", "3dnow", -}; -static const char *ext3_feature_name[] = { - "lahf_lm" /* AMD LahfSahf */, "cmp_legacy", "svm", "extapic" /* AMD ExtApicSpace */, - "cr8legacy" /* AMD AltMovCr8 */, "abm", "sse4a", "misalignsse", - "3dnowprefetch", "osvw", "ibs", "xop", - "skinit", "wdt", NULL, "lwp", - "fma4", "tce", NULL, "nodeid_msr", - NULL, "tbm", "topoext", "perfctr_core", - "perfctr_nb", NULL, NULL, NULL, - NULL, NULL, NULL, NULL, -}; - -static const char *ext4_feature_name[] = { - NULL, NULL, "xstore", "xstore-en", - NULL, NULL, "xcrypt", "xcrypt-en", - "ace2", "ace2-en", "phe", "phe-en", - "pmm", "pmm-en", NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, -}; - -static const char *kvm_feature_name[] = { - "kvmclock", "kvm_nopiodelay", "kvm_mmu", "kvmclock", - "kvm_asyncpf", "kvm_steal_time", "kvm_pv_eoi", "kvm_pv_unhalt", - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - "kvmclock-stable-bit", NULL, NULL, NULL, - NULL, NULL, NULL, NULL, -}; - -static const char *hyperv_priv_feature_name[] = { - NULL /* hv_msr_vp_runtime_access */, NULL /* hv_msr_time_refcount_access */, - NULL /* hv_msr_synic_access */, NULL /* hv_msr_stimer_access */, - NULL /* hv_msr_apic_access */, NULL /* hv_msr_hypercall_access */, - NULL /* hv_vpindex_access */, NULL /* hv_msr_reset_access */, - NULL /* hv_msr_stats_access */, NULL /* hv_reftsc_access */, - NULL /* hv_msr_idle_access */, NULL /* hv_msr_frequency_access */, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, -}; - -static const char *hyperv_ident_feature_name[] = { - NULL /* hv_create_partitions */, NULL /* hv_access_partition_id */, - NULL /* hv_access_memory_pool */, NULL /* hv_adjust_message_buffers */, - NULL /* hv_post_messages */, NULL /* hv_signal_events */, - NULL /* hv_create_port */, NULL /* hv_connect_port */, - NULL /* hv_access_stats */, NULL, NULL, NULL /* hv_debugging */, - NULL /* hv_cpu_power_management */, NULL /* hv_configure_profiler */, - NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, -}; - -static const char *hyperv_misc_feature_name[] = { - NULL /* hv_mwait */, NULL /* hv_guest_debugging */, - NULL /* hv_perf_monitor */, NULL /* hv_cpu_dynamic_part */, - NULL /* hv_hypercall_params_xmm */, NULL /* hv_guest_idle_state */, - NULL, NULL, - NULL, NULL, NULL /* hv_guest_crash_msr */, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, -}; - -static const char *svm_feature_name[] = { - "npt", "lbrv", "svm_lock", "nrip_save", - "tsc_scale", "vmcb_clean", "flushbyasid", "decodeassists", - NULL, NULL, "pause_filter", NULL, - "pfthreshold", NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, -}; - -static const char *cpuid_7_0_ebx_feature_name[] = { - "fsgsbase", "tsc_adjust", NULL, "bmi1", - "hle", "avx2", NULL, "smep", - "bmi2", "erms", "invpcid", "rtm", - NULL, NULL, "mpx", NULL, - "avx512f", "avx512dq", "rdseed", "adx", - "smap", "avx512ifma", "pcommit", "clflushopt", - "clwb", NULL, "avx512pf", "avx512er", - "avx512cd", NULL, "avx512bw", "avx512vl", -}; - -static const char *cpuid_7_0_ecx_feature_name[] = { - NULL, "avx512vbmi", "umip", "pku", - "ospke", NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, "rdpid", NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, -}; - -static const char *cpuid_apm_edx_feature_name[] = { - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - "invtsc", NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, -}; - -static const char *cpuid_xsave_feature_name[] = { - "xsaveopt", "xsavec", "xgetbv1", "xsaves", - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, -}; - -static const char *cpuid_6_feature_name[] = { - NULL, NULL, "arat", NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, -}; - #define I486_FEATURES (CPUID_FP87 | CPUID_VME | CPUID_PSE) #define PENTIUM_FEATURES (I486_FEATURES | CPUID_DE | CPUID_TSC | \ CPUID_MSR | CPUID_MCE | CPUID_CX8 | CPUID_MMX | CPUID_APIC) @@ -425,7 +246,12 @@ static const char *cpuid_6_feature_name[] = { CPUID_XSAVE_XSAVEC, CPUID_XSAVE_XSAVES */ typedef struct FeatureWordInfo { - const char **feat_names; + /* feature flags names are taken from "Intel Processor Identification and + * the CPUID Instruction" and AMD's "CPUID Specification". + * In cases of disagreement between feature naming conventions, + * aliases may be added. + */ + const char *feat_names[32]; uint32_t cpuid_eax; /* Input EAX for CPUID */ bool cpuid_needs_ecx; /* CPUID instruction uses ECX as input */ uint32_t cpuid_ecx; /* Input ECX value for CPUID */ @@ -436,82 +262,230 @@ typedef struct FeatureWordInfo { static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { [FEAT_1_EDX] = { - .feat_names = feature_name, + .feat_names = { + "fpu", "vme", "de", "pse", + "tsc", "msr", "pae", "mce", + "cx8", "apic", NULL, "sep", + "mtrr", "pge", "mca", "cmov", + "pat", "pse36", "pn" /* Intel psn */, "clflush" /* Intel clfsh */, + NULL, "ds" /* Intel dts */, "acpi", "mmx", + "fxsr", "sse", "sse2", "ss", + "ht" /* Intel htt */, "tm", "ia64", "pbe", + }, .cpuid_eax = 1, .cpuid_reg = R_EDX, .tcg_features = TCG_FEATURES, }, [FEAT_1_ECX] = { - .feat_names = ext_feature_name, + .feat_names = { + "pni|sse3" /* Intel,AMD sse3 */, "pclmulqdq|pclmuldq", "dtes64", "monitor", + "ds_cpl", "vmx", "smx", "est", + "tm2", "ssse3", "cid", NULL, + "fma", "cx16", "xtpr", "pdcm", + NULL, "pcid", "dca", "sse4.1|sse4_1", + "sse4.2|sse4_2", "x2apic", "movbe", "popcnt", + "tsc-deadline", "aes", "xsave", "osxsave", + "avx", "f16c", "rdrand", "hypervisor", + }, .cpuid_eax = 1, .cpuid_reg = R_ECX, .tcg_features = TCG_EXT_FEATURES, }, + /* Feature names that are already defined on feature_name[] but + * are set on CPUID[8000_0001].EDX on AMD CPUs don't have their + * names on feat_names below. They are copied automatically + * to features[FEAT_8000_0001_EDX] if and only if CPU vendor is AMD. + */ [FEAT_8000_0001_EDX] = { - .feat_names = ext2_feature_name, + .feat_names = { + NULL /* fpu */, NULL /* vme */, NULL /* de */, NULL /* pse */, + NULL /* tsc */, NULL /* msr */, NULL /* pae */, NULL /* mce */, + NULL /* cx8 */, NULL /* apic */, NULL, "syscall", + NULL /* mtrr */, NULL /* pge */, NULL /* mca */, NULL /* cmov */, + NULL /* pat */, NULL /* pse36 */, NULL, NULL /* Linux mp */, + "nx|xd", NULL, "mmxext", NULL /* mmx */, + NULL /* fxsr */, "fxsr_opt|ffxsr", "pdpe1gb", "rdtscp", + NULL, "lm|i64", "3dnowext", "3dnow", + }, .cpuid_eax = 0x80000001, .cpuid_reg = R_EDX, .tcg_features = TCG_EXT2_FEATURES, }, [FEAT_8000_0001_ECX] = { - .feat_names = ext3_feature_name, + .feat_names = { + "lahf_lm", "cmp_legacy", "svm", "extapic", + "cr8legacy", "abm", "sse4a", "misalignsse", + "3dnowprefetch", "osvw", "ibs", "xop", + "skinit", "wdt", NULL, "lwp", + "fma4", "tce", NULL, "nodeid_msr", + NULL, "tbm", "topoext", "perfctr_core", + "perfctr_nb", NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + }, .cpuid_eax = 0x80000001, .cpuid_reg = R_ECX, .tcg_features = TCG_EXT3_FEATURES, }, [FEAT_C000_0001_EDX] = { - .feat_names = ext4_feature_name, + .feat_names = { + NULL, NULL, "xstore", "xstore-en", + NULL, NULL, "xcrypt", "xcrypt-en", + "ace2", "ace2-en", "phe", "phe-en", + "pmm", "pmm-en", NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + }, .cpuid_eax = 0xC0000001, .cpuid_reg = R_EDX, .tcg_features = TCG_EXT4_FEATURES, }, [FEAT_KVM] = { - .feat_names = kvm_feature_name, + .feat_names = { + "kvmclock", "kvm_nopiodelay", "kvm_mmu", "kvmclock", + "kvm_asyncpf", "kvm_steal_time", "kvm_pv_eoi", "kvm_pv_unhalt", + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + "kvmclock-stable-bit", NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + }, .cpuid_eax = KVM_CPUID_FEATURES, .cpuid_reg = R_EAX, .tcg_features = TCG_KVM_FEATURES, }, [FEAT_HYPERV_EAX] = { - .feat_names = hyperv_priv_feature_name, + .feat_names = { + NULL /* hv_msr_vp_runtime_access */, NULL /* hv_msr_time_refcount_access */, + NULL /* hv_msr_synic_access */, NULL /* hv_msr_stimer_access */, + NULL /* hv_msr_apic_access */, NULL /* hv_msr_hypercall_access */, + NULL /* hv_vpindex_access */, NULL /* hv_msr_reset_access */, + NULL /* hv_msr_stats_access */, NULL /* hv_reftsc_access */, + NULL /* hv_msr_idle_access */, NULL /* hv_msr_frequency_access */, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + }, .cpuid_eax = 0x40000003, .cpuid_reg = R_EAX, }, [FEAT_HYPERV_EBX] = { - .feat_names = hyperv_ident_feature_name, + .feat_names = { + NULL /* hv_create_partitions */, NULL /* hv_access_partition_id */, + NULL /* hv_access_memory_pool */, NULL /* hv_adjust_message_buffers */, + NULL /* hv_post_messages */, NULL /* hv_signal_events */, + NULL /* hv_create_port */, NULL /* hv_connect_port */, + NULL /* hv_access_stats */, NULL, NULL, NULL /* hv_debugging */, + NULL /* hv_cpu_power_management */, NULL /* hv_configure_profiler */, + NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + }, .cpuid_eax = 0x40000003, .cpuid_reg = R_EBX, }, [FEAT_HYPERV_EDX] = { - .feat_names = hyperv_misc_feature_name, + .feat_names = { + NULL /* hv_mwait */, NULL /* hv_guest_debugging */, + NULL /* hv_perf_monitor */, NULL /* hv_cpu_dynamic_part */, + NULL /* hv_hypercall_params_xmm */, NULL /* hv_guest_idle_state */, + NULL, NULL, + NULL, NULL, NULL /* hv_guest_crash_msr */, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + }, .cpuid_eax = 0x40000003, .cpuid_reg = R_EDX, }, [FEAT_SVM] = { - .feat_names = svm_feature_name, + .feat_names = { + "npt", "lbrv", "svm_lock", "nrip_save", + "tsc_scale", "vmcb_clean", "flushbyasid", "decodeassists", + NULL, NULL, "pause_filter", NULL, + "pfthreshold", NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + }, .cpuid_eax = 0x8000000A, .cpuid_reg = R_EDX, .tcg_features = TCG_SVM_FEATURES, }, [FEAT_7_0_EBX] = { - .feat_names = cpuid_7_0_ebx_feature_name, + .feat_names = { + "fsgsbase", "tsc_adjust", NULL, "bmi1", + "hle", "avx2", NULL, "smep", + "bmi2", "erms", "invpcid", "rtm", + NULL, NULL, "mpx", NULL, + "avx512f", "avx512dq", "rdseed", "adx", + "smap", "avx512ifma", "pcommit", "clflushopt", + "clwb", NULL, "avx512pf", "avx512er", + "avx512cd", NULL, "avx512bw", "avx512vl", + }, .cpuid_eax = 7, .cpuid_needs_ecx = true, .cpuid_ecx = 0, .cpuid_reg = R_EBX, .tcg_features = TCG_7_0_EBX_FEATURES, }, [FEAT_7_0_ECX] = { - .feat_names = cpuid_7_0_ecx_feature_name, + .feat_names = { + NULL, "avx512vbmi", "umip", "pku", + "ospke", NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, "rdpid", NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + }, .cpuid_eax = 7, .cpuid_needs_ecx = true, .cpuid_ecx = 0, .cpuid_reg = R_ECX, .tcg_features = TCG_7_0_ECX_FEATURES, }, [FEAT_8000_0007_EDX] = { - .feat_names = cpuid_apm_edx_feature_name, + .feat_names = { + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + "invtsc", NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + }, .cpuid_eax = 0x80000007, .cpuid_reg = R_EDX, .tcg_features = TCG_APM_FEATURES, .unmigratable_flags = CPUID_APM_INVTSC, }, [FEAT_XSAVE] = { - .feat_names = cpuid_xsave_feature_name, + .feat_names = { + "xsaveopt", "xsavec", "xgetbv1", "xsaves", + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + }, .cpuid_eax = 0xd, .cpuid_needs_ecx = true, .cpuid_ecx = 1, .cpuid_reg = R_EAX, .tcg_features = TCG_XSAVE_FEATURES, }, [FEAT_6_EAX] = { - .feat_names = cpuid_6_feature_name, + .feat_names = { + NULL, NULL, "arat", NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + }, .cpuid_eax = 6, .cpuid_reg = R_EAX, .tcg_features = TCG_6_EAX_FEATURES, }, @@ -711,8 +685,7 @@ static void add_flagname_to_bitmaps(const char *flagname, FeatureWord w; for (w = 0; w < FEATURE_WORDS; w++) { FeatureWordInfo *wi = &feature_word_info[w]; - if (wi->feat_names && - lookup_feature(&words[w], flagname, NULL, wi->feat_names)) { + if (lookup_feature(&words[w], flagname, NULL, wi->feat_names)) { break; } } @@ -3324,9 +3297,6 @@ static void x86_cpu_register_feature_bit_props(X86CPU *cpu, char **names; FeatureWordInfo *fi = &feature_word_info[w]; - if (!fi->feat_names) { - return; - } if (!fi->feat_names[bitnr]) { return; } From 9646f4927faf68e8690588c2fd6dc9834c440b58 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Thu, 22 Sep 2016 18:58:39 -0300 Subject: [PATCH 372/723] target-i386: Don't try to enable PT State xsave component The code that calculates the set of supported XSAVE components on CPUID looks at ext_save_areas to find out which components should be enabled. However, if there are zeroed entries in the ext_save_areas array, the ((env->features[esa->feature] & esa->bits) == esa->bits) check will always succeed and QEMU will unconditionally try to enable the component. Luckily this never caused any problems because the only missing entry in ext_save_areas is the PT State component (bit 8), and KVM currently doesn't support it (so it was cleared on ena_mask). But the code was still incorrect and would break if KVM starts returning CPUID[EAX=0xD,ECX=0].EAX[bit 8] as supported on GET_SUPPORTED_CPUID. Fix the problem by changing the code to not enable a XSAVE component if ExtSaveArea::bits is zero. Reviewed-by: Richard Henderson Signed-off-by: Eduardo Habkost --- target-i386/cpu.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index cc07fdbf8b6..25ab4f8b418 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -2514,7 +2514,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, *ecx = 0x240; for (i = 2; i < ARRAY_SIZE(x86_ext_save_areas); i++) { const ExtSaveArea *esa = &x86_ext_save_areas[i]; - if ((env->features[esa->feature] & esa->bits) == esa->bits + if ((env->features[esa->feature] & esa->bits) && ((ena_mask >> i) & 1) != 0) { if (i < 32) { *eax |= 1u << i; @@ -2530,7 +2530,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, *eax = env->features[FEAT_XSAVE]; } else if (count < ARRAY_SIZE(x86_ext_save_areas)) { const ExtSaveArea *esa = &x86_ext_save_areas[count]; - if ((env->features[esa->feature] & esa->bits) == esa->bits + if ((env->features[esa->feature] & esa->bits) && ((ena_mask >> count) & 1) != 0) { *eax = esa->size; *ebx = esa->offset; @@ -2766,7 +2766,7 @@ static void x86_cpu_reset(CPUState *s) } for (i = 2; i < ARRAY_SIZE(x86_ext_save_areas); i++) { const ExtSaveArea *esa = &x86_ext_save_areas[i]; - if ((env->features[esa->feature] & esa->bits) == esa->bits) { + if (env->features[esa->feature] & esa->bits) { xcr0 |= 1ull << i; } } From 4928cd6de6b4211a79f98c8dc39115be1e815c2b Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Thu, 22 Sep 2016 14:33:01 -0300 Subject: [PATCH 373/723] target-i386: xsave: Calculate enabled components only once Instead of checking both env->features and ena_mask at two different places in the CPUID code, initialize ena_mask based on the features that are enabled for the CPU, and then clear unsupported bits based on kvm_arch_get_supported_cpuid(). The results should be exactly the same, but it will make it easier to move the mask calculation elsewhare, and reuse x86_cpu_filter_features() for the kvm_arch_get_supported_cpuid() check. Reviewed-by: Richard Henderson Signed-off-by: Eduardo Habkost --- target-i386/cpu.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 25ab4f8b418..99685812adf 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -2490,7 +2490,6 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, *ebx &= 0xffff; /* The count doesn't need to be reliable. */ break; case 0xD: { - KVMState *s = cs->kvm_state; uint64_t ena_mask; int i; @@ -2502,20 +2501,28 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, if (!(env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE)) { break; } + + ena_mask = (XSTATE_FP_MASK | XSTATE_SSE_MASK); + for (i = 2; i < ARRAY_SIZE(x86_ext_save_areas); i++) { + const ExtSaveArea *esa = &x86_ext_save_areas[i]; + if (env->features[esa->feature] & esa->bits) { + ena_mask |= (1ULL << i); + } + } + if (kvm_enabled()) { - ena_mask = kvm_arch_get_supported_cpuid(s, 0xd, 0, R_EDX); - ena_mask <<= 32; - ena_mask |= kvm_arch_get_supported_cpuid(s, 0xd, 0, R_EAX); - } else { - ena_mask = -1; + KVMState *s = cs->kvm_state; + uint64_t kvm_mask = kvm_arch_get_supported_cpuid(s, 0xd, 0, R_EDX); + kvm_mask <<= 32; + kvm_mask |= kvm_arch_get_supported_cpuid(s, 0xd, 0, R_EAX); + ena_mask &= kvm_mask; } if (count == 0) { *ecx = 0x240; for (i = 2; i < ARRAY_SIZE(x86_ext_save_areas); i++) { const ExtSaveArea *esa = &x86_ext_save_areas[i]; - if ((env->features[esa->feature] & esa->bits) - && ((ena_mask >> i) & 1) != 0) { + if ((ena_mask >> i) & 1) { if (i < 32) { *eax |= 1u << i; } else { @@ -2530,8 +2537,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, *eax = env->features[FEAT_XSAVE]; } else if (count < ARRAY_SIZE(x86_ext_save_areas)) { const ExtSaveArea *esa = &x86_ext_save_areas[count]; - if ((env->features[esa->feature] & esa->bits) - && ((ena_mask >> count) & 1) != 0) { + if ((ena_mask >> count) & 1) { *eax = esa->size; *ebx = esa->offset; } From 8057c621b1b17cbcb35fe67d1a09ada9055873a9 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Thu, 22 Sep 2016 14:58:32 -0300 Subject: [PATCH 374/723] target-i386: xsave: Simplify CPUID[0xD,0].{EAX,EDX} calculation Instead of assigning individual bits in a loop, just copy the values from ena_mask. Reviewed-by: Richard Henderson Signed-off-by: Eduardo Habkost --- target-i386/cpu.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 99685812adf..7e66003204c 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -2523,15 +2523,11 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, for (i = 2; i < ARRAY_SIZE(x86_ext_save_areas); i++) { const ExtSaveArea *esa = &x86_ext_save_areas[i]; if ((ena_mask >> i) & 1) { - if (i < 32) { - *eax |= 1u << i; - } else { - *edx |= 1u << (i - 32); - } *ecx = MAX(*ecx, esa->offset + esa->size); } } - *eax |= ena_mask & (XSTATE_FP_MASK | XSTATE_SSE_MASK); + *eax = ena_mask; + *edx = ena_mask >> 32; *ebx = *ecx; } else if (count == 1) { *eax = env->features[FEAT_XSAVE]; From 1fda6198e4126af9988754c8824cfc9928649890 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Thu, 22 Sep 2016 17:14:07 -0300 Subject: [PATCH 375/723] target-i386: xsave: Helper function to calculate xsave area size Move the xsave area size calculation from cpu_x86_cpuid() inside its own function. While doing it, change it to use the XSAVE area struct sizes for the initial size, instead of the magic 0x240 number. Reviewed-by: Richard Henderson Signed-off-by: Eduardo Habkost --- target-i386/cpu.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 7e66003204c..9034d8ee15f 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -548,6 +548,20 @@ static const ExtSaveArea x86_ext_save_areas[] = { .size = sizeof(XSavePKRU) }, }; +static uint32_t xsave_area_size(uint64_t mask) +{ + int i; + uint64_t ret = sizeof(X86LegacyXSaveArea) + sizeof(X86XSaveHeader); + + for (i = 2; i < ARRAY_SIZE(x86_ext_save_areas); i++) { + const ExtSaveArea *esa = &x86_ext_save_areas[i]; + if ((mask >> i) & 1) { + ret = MAX(ret, esa->offset + esa->size); + } + } + return ret; +} + const char *get_register_name_32(unsigned int reg) { if (reg >= CPU_NB_REGS32) { @@ -2519,13 +2533,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, } if (count == 0) { - *ecx = 0x240; - for (i = 2; i < ARRAY_SIZE(x86_ext_save_areas); i++) { - const ExtSaveArea *esa = &x86_ext_save_areas[i]; - if ((ena_mask >> i) & 1) { - *ecx = MAX(*ecx, esa->offset + esa->size); - } - } + *ecx = xsave_area_size(ena_mask);; *eax = ena_mask; *edx = ena_mask >> 32; *ebx = *ecx; From 2ca8a8becc2eeb5262e478ce502f5daa53f3d0bc Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Thu, 22 Sep 2016 17:27:56 -0300 Subject: [PATCH 376/723] target-i386: xsave: Calculate set of xsave components on realize Instead of doing complex calculations and calling kvm_arch_get_supported_cpuid() inside cpu_x86_cpuid(), calculate the set of required XSAVE components earlier, at realize time. Signed-off-by: Eduardo Habkost Reviewed-by: Richard Henderson Signed-off-by: Eduardo Habkost --- target-i386/cpu.c | 55 +++++++++++++++++++++++++++-------------------- target-i386/cpu.h | 1 + 2 files changed, 33 insertions(+), 23 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 9034d8ee15f..8bef3cf8214 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -2504,9 +2504,6 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, *ebx &= 0xffff; /* The count doesn't need to be reliable. */ break; case 0xD: { - uint64_t ena_mask; - int i; - /* Processor Extended State */ *eax = 0; *ebx = 0; @@ -2516,32 +2513,16 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, break; } - ena_mask = (XSTATE_FP_MASK | XSTATE_SSE_MASK); - for (i = 2; i < ARRAY_SIZE(x86_ext_save_areas); i++) { - const ExtSaveArea *esa = &x86_ext_save_areas[i]; - if (env->features[esa->feature] & esa->bits) { - ena_mask |= (1ULL << i); - } - } - - if (kvm_enabled()) { - KVMState *s = cs->kvm_state; - uint64_t kvm_mask = kvm_arch_get_supported_cpuid(s, 0xd, 0, R_EDX); - kvm_mask <<= 32; - kvm_mask |= kvm_arch_get_supported_cpuid(s, 0xd, 0, R_EAX); - ena_mask &= kvm_mask; - } - if (count == 0) { - *ecx = xsave_area_size(ena_mask);; - *eax = ena_mask; - *edx = ena_mask >> 32; + *ecx = xsave_area_size(env->xsave_components); + *eax = env->xsave_components; + *edx = env->xsave_components >> 32; *ebx = *ecx; } else if (count == 1) { *eax = env->features[FEAT_XSAVE]; } else if (count < ARRAY_SIZE(x86_ext_save_areas)) { const ExtSaveArea *esa = &x86_ext_save_areas[count]; - if ((ena_mask >> count) & 1) { + if ((env->xsave_components >> count) & 1) { *eax = esa->size; *ebx = esa->offset; } @@ -2971,6 +2952,33 @@ static void x86_cpu_adjust_feat_level(X86CPU *cpu, FeatureWord w) } } +/* Calculate XSAVE components based on the configured CPU feature flags */ +static void x86_cpu_enable_xsave_components(X86CPU *cpu) +{ + CPUX86State *env = &cpu->env; + int i; + + if (!(env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE)) { + return; + } + + env->xsave_components = (XSTATE_FP_MASK | XSTATE_SSE_MASK); + for (i = 2; i < ARRAY_SIZE(x86_ext_save_areas); i++) { + const ExtSaveArea *esa = &x86_ext_save_areas[i]; + if (env->features[esa->feature] & esa->bits) { + env->xsave_components |= (1ULL << i); + } + } + + if (kvm_enabled()) { + KVMState *s = kvm_state; + uint64_t kvm_mask = kvm_arch_get_supported_cpuid(s, 0xd, 0, R_EDX); + kvm_mask <<= 32; + kvm_mask |= kvm_arch_get_supported_cpuid(s, 0xd, 0, R_EAX); + env->xsave_components &= kvm_mask; + } +} + #define IS_INTEL_CPU(env) ((env)->cpuid_vendor1 == CPUID_VENDOR_INTEL_1 && \ (env)->cpuid_vendor2 == CPUID_VENDOR_INTEL_2 && \ (env)->cpuid_vendor3 == CPUID_VENDOR_INTEL_3) @@ -3016,6 +3024,7 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) cpu->env.features[w] &= ~minus_features[w]; } + x86_cpu_enable_xsave_components(cpu); /* CPUID[EAX=7,ECX=0].EBX always increased level automatically: */ x86_cpu_adjust_feat_level(cpu, FEAT_7_0_EBX); diff --git a/target-i386/cpu.h b/target-i386/cpu.h index aaa45f03d0e..6c457edacbb 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -1122,6 +1122,7 @@ typedef struct CPUX86State { uint32_t cpuid_vendor3; uint32_t cpuid_version; FeatureWordArray features; + uint64_t xsave_components; uint32_t cpuid_model[12]; /* MTRRs */ From 96193c22ab39ea24f81e386ad7883260ff24f5fd Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Thu, 22 Sep 2016 17:41:35 -0300 Subject: [PATCH 377/723] target-i386: Move xsave component mask to features array This will reuse the existing check/enforce logic in x86_cpu_filter_features() to check the xsave component bits against GET_SUPPORTED_CPUID. Reviewed-by: Richard Henderson Signed-off-by: Eduardo Habkost --- target-i386/cpu.c | 42 ++++++++++++++++++++++++++++-------------- target-i386/cpu.h | 3 ++- 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 8bef3cf8214..ad09246d590 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -489,6 +489,18 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { .cpuid_eax = 6, .cpuid_reg = R_EAX, .tcg_features = TCG_6_EAX_FEATURES, }, + [FEAT_XSAVE_COMP_LO] = { + .cpuid_eax = 0xD, + .cpuid_needs_ecx = true, .cpuid_ecx = 0, + .cpuid_reg = R_EAX, + .tcg_features = ~0U, + }, + [FEAT_XSAVE_COMP_HI] = { + .cpuid_eax = 0xD, + .cpuid_needs_ecx = true, .cpuid_ecx = 0, + .cpuid_reg = R_EDX, + .tcg_features = ~0U, + }, }; typedef struct X86RegisterInfo32 { @@ -562,6 +574,12 @@ static uint32_t xsave_area_size(uint64_t mask) return ret; } +static inline uint64_t x86_cpu_xsave_components(X86CPU *cpu) +{ + return ((uint64_t)cpu->env.features[FEAT_XSAVE_COMP_HI]) << 32 | + cpu->env.features[FEAT_XSAVE_COMP_LO]; +} + const char *get_register_name_32(unsigned int reg) { if (reg >= CPU_NB_REGS32) { @@ -2514,15 +2532,15 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, } if (count == 0) { - *ecx = xsave_area_size(env->xsave_components); - *eax = env->xsave_components; - *edx = env->xsave_components >> 32; + *ecx = xsave_area_size(x86_cpu_xsave_components(cpu)); + *eax = env->features[FEAT_XSAVE_COMP_LO]; + *edx = env->features[FEAT_XSAVE_COMP_HI]; *ebx = *ecx; } else if (count == 1) { *eax = env->features[FEAT_XSAVE]; } else if (count < ARRAY_SIZE(x86_ext_save_areas)) { - const ExtSaveArea *esa = &x86_ext_save_areas[count]; - if ((env->xsave_components >> count) & 1) { + if ((x86_cpu_xsave_components(cpu) >> count) & 1) { + const ExtSaveArea *esa = &x86_ext_save_areas[count]; *eax = esa->size; *ebx = esa->offset; } @@ -2957,26 +2975,22 @@ static void x86_cpu_enable_xsave_components(X86CPU *cpu) { CPUX86State *env = &cpu->env; int i; + uint64_t mask; if (!(env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE)) { return; } - env->xsave_components = (XSTATE_FP_MASK | XSTATE_SSE_MASK); + mask = (XSTATE_FP_MASK | XSTATE_SSE_MASK); for (i = 2; i < ARRAY_SIZE(x86_ext_save_areas); i++) { const ExtSaveArea *esa = &x86_ext_save_areas[i]; if (env->features[esa->feature] & esa->bits) { - env->xsave_components |= (1ULL << i); + mask |= (1ULL << i); } } - if (kvm_enabled()) { - KVMState *s = kvm_state; - uint64_t kvm_mask = kvm_arch_get_supported_cpuid(s, 0xd, 0, R_EDX); - kvm_mask <<= 32; - kvm_mask |= kvm_arch_get_supported_cpuid(s, 0xd, 0, R_EAX); - env->xsave_components &= kvm_mask; - } + env->features[FEAT_XSAVE_COMP_LO] = mask; + env->features[FEAT_XSAVE_COMP_HI] = mask >> 32; } #define IS_INTEL_CPU(env) ((env)->cpuid_vendor1 == CPUID_VENDOR_INTEL_1 && \ diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 6c457edacbb..1cb32ae456c 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -453,6 +453,8 @@ typedef enum FeatureWord { FEAT_SVM, /* CPUID[8000_000A].EDX */ FEAT_XSAVE, /* CPUID[EAX=0xd,ECX=1].EAX */ FEAT_6_EAX, /* CPUID[6].EAX */ + FEAT_XSAVE_COMP_LO, /* CPUID[EAX=0xd,ECX=0].EAX */ + FEAT_XSAVE_COMP_HI, /* CPUID[EAX=0xd,ECX=0].EDX */ FEATURE_WORDS, } FeatureWord; @@ -1122,7 +1124,6 @@ typedef struct CPUX86State { uint32_t cpuid_vendor3; uint32_t cpuid_version; FeatureWordArray features; - uint64_t xsave_components; uint32_t cpuid_model[12]; /* MTRRs */ From 1eabfce6d53cb02066dbb0ac8471f8593ff24a24 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Mon, 26 Sep 2016 19:03:29 -0300 Subject: [PATCH 378/723] target-i386: Remove has_msr_mtrr global variable The global variable is not necessary because we can check the CPU feature flags directly. Reviewed-by: Paolo Bonzini Signed-off-by: Eduardo Habkost --- target-i386/kvm.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/target-i386/kvm.c b/target-i386/kvm.c index a0e42b2c4ed..5118562e1d3 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -99,7 +99,6 @@ static bool has_msr_hv_vpindex; static bool has_msr_hv_runtime; static bool has_msr_hv_synic; static bool has_msr_hv_stimer; -static bool has_msr_mtrr; static bool has_msr_xss; static bool has_msr_architectural_pmu; @@ -975,9 +974,6 @@ int kvm_arch_init_vcpu(CPUState *cs) } cpu->kvm_msr_buf = g_malloc0(MSR_BUF_SIZE); - if (env->features[FEAT_1_EDX] & CPUID_MTRR) { - has_msr_mtrr = true; - } if (!(env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_RDTSCP)) { has_msr_tsc_aux = false; } @@ -1735,7 +1731,7 @@ static int kvm_put_msrs(X86CPU *cpu, int level) env->msr_hv_stimer_count[j]); } } - if (has_msr_mtrr) { + if (env->features[FEAT_1_EDX] & CPUID_MTRR) { uint64_t phys_mask = MAKE_64BIT_MASK(0, cpu->phys_bits); kvm_msr_entry_add(cpu, MSR_MTRRdefType, env->mtrr_deftype); @@ -2125,7 +2121,7 @@ static int kvm_get_msrs(X86CPU *cpu) kvm_msr_entry_add(cpu, msr, 0); } } - if (has_msr_mtrr) { + if (env->features[FEAT_1_EDX] & CPUID_MTRR) { kvm_msr_entry_add(cpu, MSR_MTRRdefType, 0); kvm_msr_entry_add(cpu, MSR_MTRRfix64K_00000, 0); kvm_msr_entry_add(cpu, MSR_MTRRfix16K_80000, 0); From 2d5aa8728bc7d98baceffcfa62c23e13abcec4eb Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Thu, 14 Jul 2016 15:55:37 -0300 Subject: [PATCH 379/723] target-i386: Remove has_msr_hv_apic global variable The global variable is not necessary because we can check cpu->hyperv_vapic directly. Reviewed-by: Paolo Bonzini Signed-off-by: Eduardo Habkost --- target-i386/kvm.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 5118562e1d3..031ae903f84 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -91,7 +91,6 @@ static bool has_msr_bndcfgs; static bool has_msr_kvm_steal_time; static int lm_capable_kernel; static bool has_msr_hv_hypercall; -static bool has_msr_hv_vapic; static bool has_msr_hv_tsc; static bool has_msr_hv_crash; static bool has_msr_hv_reset; @@ -609,7 +608,6 @@ static int hyperv_handle_properties(CPUState *cs) if (cpu->hyperv_vapic) { env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_HYPERCALL_AVAILABLE; env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_APIC_ACCESS_AVAILABLE; - has_msr_hv_vapic = true; } if (cpu->hyperv_time && kvm_check_extension(cs->kvm_state, KVM_CAP_HYPERV_TIME) > 0) { @@ -728,7 +726,7 @@ int kvm_arch_init_vcpu(CPUState *cs) if (cpu->hyperv_relaxed_timing) { c->eax |= HV_X64_RELAXED_TIMING_RECOMMENDED; } - if (has_msr_hv_vapic) { + if (cpu->hyperv_vapic) { c->eax |= HV_X64_APIC_ACCESS_RECOMMENDED; } c->ebx = cpu->hyperv_spinlock_attempts; @@ -1681,7 +1679,7 @@ static int kvm_put_msrs(X86CPU *cpu, int level) kvm_msr_entry_add(cpu, HV_X64_MSR_HYPERCALL, env->msr_hv_hypercall); } - if (has_msr_hv_vapic) { + if (cpu->hyperv_vapic) { kvm_msr_entry_add(cpu, HV_X64_MSR_APIC_ASSIST_PAGE, env->msr_hv_vapic); } @@ -2086,7 +2084,7 @@ static int kvm_get_msrs(X86CPU *cpu) kvm_msr_entry_add(cpu, HV_X64_MSR_HYPERCALL, 0); kvm_msr_entry_add(cpu, HV_X64_MSR_GUEST_OS_ID, 0); } - if (has_msr_hv_vapic) { + if (cpu->hyperv_vapic) { kvm_msr_entry_add(cpu, HV_X64_MSR_APIC_ASSIST_PAGE, 0); } if (has_msr_hv_tsc) { From 3ddcd2edc8ca708ccd808a78424b9aadebd4f7c4 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 15 Jul 2016 14:05:36 -0300 Subject: [PATCH 380/723] target-i386: Remove has_msr_hv_tsc global variable The global variable is not necessary because we can check cpu->hyperv_time directly. We just need to ensure cpu->hyperv_time will be cleared if the feature is not really being exposed to the guest due to missing KVM_CAP_HYPERV_TIME capability. Reviewed-by: Paolo Bonzini Signed-off-by: Eduardo Habkost --- target-i386/kvm.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 031ae903f84..40460309496 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -91,7 +91,6 @@ static bool has_msr_bndcfgs; static bool has_msr_kvm_steal_time; static int lm_capable_kernel; static bool has_msr_hv_hypercall; -static bool has_msr_hv_tsc; static bool has_msr_hv_crash; static bool has_msr_hv_reset; static bool has_msr_hv_vpindex; @@ -602,6 +601,11 @@ static int hyperv_handle_properties(CPUState *cs) X86CPU *cpu = X86_CPU(cs); CPUX86State *env = &cpu->env; + if (cpu->hyperv_time && + kvm_check_extension(cs->kvm_state, KVM_CAP_HYPERV_TIME) <= 0) { + cpu->hyperv_time = false; + } + if (cpu->hyperv_relaxed_timing) { env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_HYPERCALL_AVAILABLE; } @@ -609,12 +613,10 @@ static int hyperv_handle_properties(CPUState *cs) env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_HYPERCALL_AVAILABLE; env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_APIC_ACCESS_AVAILABLE; } - if (cpu->hyperv_time && - kvm_check_extension(cs->kvm_state, KVM_CAP_HYPERV_TIME) > 0) { + if (cpu->hyperv_time) { env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_HYPERCALL_AVAILABLE; env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_TIME_REF_COUNT_AVAILABLE; env->features[FEAT_HYPERV_EAX] |= 0x200; - has_msr_hv_tsc = true; } if (cpu->hyperv_crash && has_msr_hv_crash) { env->features[FEAT_HYPERV_EDX] |= HV_X64_GUEST_CRASH_MSR_AVAILABLE; @@ -1683,7 +1685,7 @@ static int kvm_put_msrs(X86CPU *cpu, int level) kvm_msr_entry_add(cpu, HV_X64_MSR_APIC_ASSIST_PAGE, env->msr_hv_vapic); } - if (has_msr_hv_tsc) { + if (cpu->hyperv_time) { kvm_msr_entry_add(cpu, HV_X64_MSR_REFERENCE_TSC, env->msr_hv_tsc); } if (has_msr_hv_crash) { @@ -2087,7 +2089,7 @@ static int kvm_get_msrs(X86CPU *cpu) if (cpu->hyperv_vapic) { kvm_msr_entry_add(cpu, HV_X64_MSR_APIC_ASSIST_PAGE, 0); } - if (has_msr_hv_tsc) { + if (cpu->hyperv_time) { kvm_msr_entry_add(cpu, HV_X64_MSR_REFERENCE_TSC, 0); } if (has_msr_hv_crash) { From aec661de86894e914d2d82431d9cefa9a9a40213 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Mon, 26 Sep 2016 19:11:14 -0300 Subject: [PATCH 381/723] target-i386: Clear KVM CPUID features if KVM is disabled This will ensure all checks for features[FEAT_KVM] in the code will be correct in case the KVM CPUID leaf is completely disabled. Reviewed-by: Paolo Bonzini Signed-off-by: Eduardo Habkost --- target-i386/cpu.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index ad09246d590..333309b9a70 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -3038,6 +3038,10 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) cpu->env.features[w] &= ~minus_features[w]; } + if (!kvm_enabled() || !cpu->expose_kvm) { + env->features[FEAT_KVM] = 0; + } + x86_cpu_enable_xsave_components(cpu); /* CPUID[EAX=7,ECX=0].EBX always increased level automatically: */ From 55c911a58069e3742d35462d8c4e961dd6a2ba93 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Mon, 26 Sep 2016 19:03:24 -0300 Subject: [PATCH 382/723] target-i386: Remove has_msr_* global vars for KVM features The global variables are not necessary because we can check KVM feature flags in X86CPU directly. Reviewed-by: Paolo Bonzini Signed-off-by: Eduardo Habkost --- target-i386/kvm.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 40460309496..30b63b7a75d 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -83,12 +83,9 @@ static bool has_msr_tsc_aux; static bool has_msr_tsc_adjust; static bool has_msr_tsc_deadline; static bool has_msr_feature_control; -static bool has_msr_async_pf_en; -static bool has_msr_pv_eoi_en; static bool has_msr_misc_enable; static bool has_msr_smbase; static bool has_msr_bndcfgs; -static bool has_msr_kvm_steal_time; static int lm_capable_kernel; static bool has_msr_hv_hypercall; static bool has_msr_hv_crash; @@ -754,12 +751,6 @@ int kvm_arch_init_vcpu(CPUState *cs) c = &cpuid_data.entries[cpuid_i++]; c->function = KVM_CPUID_FEATURES | kvm_base; c->eax = env->features[FEAT_KVM]; - - has_msr_async_pf_en = c->eax & (1 << KVM_FEATURE_ASYNC_PF); - - has_msr_pv_eoi_en = c->eax & (1 << KVM_FEATURE_PV_EOI); - - has_msr_kvm_steal_time = c->eax & (1 << KVM_FEATURE_STEAL_TIME); } cpu_x86_cpuid(env, 0, 0, &limit, &unused, &unused, &unused); @@ -1639,13 +1630,13 @@ static int kvm_put_msrs(X86CPU *cpu, int level) kvm_msr_entry_add(cpu, MSR_IA32_TSC, env->tsc); kvm_msr_entry_add(cpu, MSR_KVM_SYSTEM_TIME, env->system_time_msr); kvm_msr_entry_add(cpu, MSR_KVM_WALL_CLOCK, env->wall_clock_msr); - if (has_msr_async_pf_en) { + if (env->features[FEAT_KVM] & (1 << KVM_FEATURE_ASYNC_PF)) { kvm_msr_entry_add(cpu, MSR_KVM_ASYNC_PF_EN, env->async_pf_en_msr); } - if (has_msr_pv_eoi_en) { + if (env->features[FEAT_KVM] & (1 << KVM_FEATURE_PV_EOI)) { kvm_msr_entry_add(cpu, MSR_KVM_PV_EOI_EN, env->pv_eoi_en_msr); } - if (has_msr_kvm_steal_time) { + if (env->features[FEAT_KVM] & (1 << KVM_FEATURE_STEAL_TIME)) { kvm_msr_entry_add(cpu, MSR_KVM_STEAL_TIME, env->steal_time_msr); } if (has_msr_architectural_pmu) { @@ -2048,13 +2039,13 @@ static int kvm_get_msrs(X86CPU *cpu) #endif kvm_msr_entry_add(cpu, MSR_KVM_SYSTEM_TIME, 0); kvm_msr_entry_add(cpu, MSR_KVM_WALL_CLOCK, 0); - if (has_msr_async_pf_en) { + if (env->features[FEAT_KVM] & (1 << KVM_FEATURE_ASYNC_PF)) { kvm_msr_entry_add(cpu, MSR_KVM_ASYNC_PF_EN, 0); } - if (has_msr_pv_eoi_en) { + if (env->features[FEAT_KVM] & (1 << KVM_FEATURE_PV_EOI)) { kvm_msr_entry_add(cpu, MSR_KVM_PV_EOI_EN, 0); } - if (has_msr_kvm_steal_time) { + if (env->features[FEAT_KVM] & (1 << KVM_FEATURE_STEAL_TIME)) { kvm_msr_entry_add(cpu, MSR_KVM_STEAL_TIME, 0); } if (has_msr_architectural_pmu) { From 4f01a637795af77f1c191230b9f6e3a2547b0c28 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 21 Sep 2016 15:23:53 +1000 Subject: [PATCH 383/723] sysbus: Remove ignored return value of FindSysbusDeviceFunc Functions of type FindSysbusDeviceFunc currently return an integer. However, this return value is always ignored by the caller in find_sysbus_device(). This changes the function type to return void, to avoid confusion over the function semantics. Signed-off-by: David Gibson Reviewed-by: Eduardo Habkost Signed-off-by: Eduardo Habkost --- hw/arm/sysbus-fdt.c | 4 ++-- hw/core/machine.c | 2 +- hw/core/platform-bus.c | 8 ++------ hw/ppc/e500.c | 4 +--- hw/ppc/spapr.c | 4 +--- include/hw/sysbus.h | 2 +- 6 files changed, 8 insertions(+), 16 deletions(-) diff --git a/hw/arm/sysbus-fdt.c b/hw/arm/sysbus-fdt.c index 5debb3348cd..d68e3dcdbd2 100644 --- a/hw/arm/sysbus-fdt.c +++ b/hw/arm/sysbus-fdt.c @@ -436,7 +436,7 @@ static const NodeCreationPair add_fdt_node_functions[] = { * are dynamically instantiable and if so call the node creation * function. */ -static int add_fdt_node(SysBusDevice *sbdev, void *opaque) +static void add_fdt_node(SysBusDevice *sbdev, void *opaque) { int i, ret; @@ -445,7 +445,7 @@ static int add_fdt_node(SysBusDevice *sbdev, void *opaque) add_fdt_node_functions[i].typename)) { ret = add_fdt_node_functions[i].add_fdt_node_fn(sbdev, opaque); assert(!ret); - return 0; + return; } } error_report("Device %s can not be dynamically instantiated", diff --git a/hw/core/machine.c b/hw/core/machine.c index 00fbe3e880f..afd84accbf2 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -332,7 +332,7 @@ static bool machine_get_enforce_config_section(Object *obj, Error **errp) return ms->enforce_config_section; } -static int error_on_sysbus_device(SysBusDevice *sbdev, void *opaque) +static void error_on_sysbus_device(SysBusDevice *sbdev, void *opaque) { error_report("Option '-device %s' cannot be handled by this machine", object_class_get_name(object_get_class(OBJECT(sbdev)))); diff --git a/hw/core/platform-bus.c b/hw/core/platform-bus.c index 36f84ab72f7..329ac670c0d 100644 --- a/hw/core/platform-bus.c +++ b/hw/core/platform-bus.c @@ -74,7 +74,7 @@ hwaddr platform_bus_get_mmio_addr(PlatformBusDevice *pbus, SysBusDevice *sbdev, return object_property_get_int(OBJECT(sbdev_mr), "addr", NULL); } -static int platform_bus_count_irqs(SysBusDevice *sbdev, void *opaque) +static void platform_bus_count_irqs(SysBusDevice *sbdev, void *opaque) { PlatformBusDevice *pbus = opaque; qemu_irq sbirq; @@ -93,8 +93,6 @@ static int platform_bus_count_irqs(SysBusDevice *sbdev, void *opaque) } } } - - return 0; } /* @@ -168,7 +166,7 @@ static void platform_bus_map_mmio(PlatformBusDevice *pbus, SysBusDevice *sbdev, * For each sysbus device, look for unassigned IRQ lines as well as * unassociated MMIO regions. Connect them to the platform bus if available. */ -static int link_sysbus_device(SysBusDevice *sbdev, void *opaque) +static void link_sysbus_device(SysBusDevice *sbdev, void *opaque) { PlatformBusDevice *pbus = opaque; int i; @@ -180,8 +178,6 @@ static int link_sysbus_device(SysBusDevice *sbdev, void *opaque) for (i = 0; sysbus_has_mmio(sbdev, i); i++) { platform_bus_map_mmio(pbus, sbdev, i); } - - return 0; } static void platform_bus_init_notify(Notifier *notifier, void *data) diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 0cd534df55f..cf8b122afe0 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -196,7 +196,7 @@ static int create_devtree_etsec(SysBusDevice *sbdev, PlatformDevtreeData *data) return 0; } -static int sysbus_device_create_devtree(SysBusDevice *sbdev, void *opaque) +static void sysbus_device_create_devtree(SysBusDevice *sbdev, void *opaque) { PlatformDevtreeData *data = opaque; bool matched = false; @@ -211,8 +211,6 @@ static int sysbus_device_create_devtree(SysBusDevice *sbdev, void *opaque) qdev_fw_name(DEVICE(sbdev))); exit(1); } - - return 0; } static void platform_bus_create_devtree(PPCE500Params *params, void *fdt, diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 9b506d5d3af..648576e6bd9 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1110,7 +1110,7 @@ static void spapr_reallocate_hpt(sPAPRMachineState *spapr, int shift, } } -static int find_unknown_sysbus_device(SysBusDevice *sbdev, void *opaque) +static void find_unknown_sysbus_device(SysBusDevice *sbdev, void *opaque) { bool matched = false; @@ -1123,8 +1123,6 @@ static int find_unknown_sysbus_device(SysBusDevice *sbdev, void *opaque) qdev_fw_name(DEVICE(sbdev))); exit(1); } - - return 0; } static void ppc_spapr_reset(void) diff --git a/include/hw/sysbus.h b/include/hw/sysbus.h index e73a5b21ac5..e88bb6dae0c 100644 --- a/include/hw/sysbus.h +++ b/include/hw/sysbus.h @@ -75,7 +75,7 @@ struct SysBusDevice { uint32_t pio[QDEV_MAX_PIO]; }; -typedef int FindSysbusDeviceFunc(SysBusDevice *sbdev, void *opaque); +typedef void FindSysbusDeviceFunc(SysBusDevice *sbdev, void *opaque); void sysbus_init_mmio(SysBusDevice *dev, MemoryRegion *memory); MemoryRegion *sysbus_mmio_get_region(SysBusDevice *dev, int n); From b6eb9b45f7307638ff166401721ae6d0401e1d67 Mon Sep 17 00:00:00 2001 From: Paulina Szubarczyk Date: Wed, 14 Sep 2016 21:10:03 +0200 Subject: [PATCH 384/723] qdisk - hw/block/xen_disk: grant copy implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Copy data operated on during request from/to local buffers to/from the grant references. Before grant copy operation local buffers must be allocated what is done by calling ioreq_init_copy_buffers. For the 'read' operation, first, the qemu device invokes the read operation on local buffers and on the completion grant copy is called and buffers are freed. For the 'write' operation grant copy is performed before invoking write by qemu device. A new value 'feature_grant_copy' is added to recognize when the grant copy operation is supported by a guest. Signed-off-by: Paulina Szubarczyk Reviewed-by: Stefano Stabellini Acked-by: Anthony PERARD Acked-by: Roger Pau Monné --- configure | 55 +++++++++++++ hw/block/xen_disk.c | 153 ++++++++++++++++++++++++++++++++++-- include/hw/xen/xen_common.h | 14 ++++ 3 files changed, 217 insertions(+), 5 deletions(-) diff --git a/configure b/configure index 8fa62ade57b..1fb343ded3d 100755 --- a/configure +++ b/configure @@ -1952,6 +1952,61 @@ EOF # Xen unstable elif cat > $TMPC < +#include +#include +#include +#include +#include +#include +#if !defined(HVM_MAX_VCPUS) +# error HVM_MAX_VCPUS not defined +#endif +int main(void) { + xc_interface *xc = NULL; + xenforeignmemory_handle *xfmem; + xenevtchn_handle *xe; + xengnttab_handle *xg; + xen_domain_handle_t handle; + xengnttab_grant_copy_segment_t* seg = NULL; + + xs_daemon_open(); + + xc = xc_interface_open(0, 0, 0); + xc_hvm_set_mem_type(0, 0, HVMMEM_ram_ro, 0, 0); + xc_domain_add_to_physmap(0, 0, XENMAPSPACE_gmfn, 0, 0); + xc_hvm_inject_msi(xc, 0, 0xf0000000, 0x00000000); + xc_hvm_create_ioreq_server(xc, 0, HVM_IOREQSRV_BUFIOREQ_ATOMIC, NULL); + xc_domain_create(xc, 0, handle, 0, NULL, NULL); + + xfmem = xenforeignmemory_open(0, 0); + xenforeignmemory_map(xfmem, 0, 0, 0, 0, 0); + + xe = xenevtchn_open(0, 0); + xenevtchn_fd(xe); + + xg = xengnttab_open(0, 0); + xengnttab_grant_copy(xg, 0, seg); + + return 0; +} +EOF + compile_prog "" "$xen_libs $xen_stable_libs" + then + xen_ctrl_version=480 + xen=yes + elif + cat > $TMPC <= 480 + +static void ioreq_free_copy_buffers(struct ioreq *ioreq) +{ + int i; + + for (i = 0; i < ioreq->v.niov; i++) { + ioreq->page[i] = NULL; + } + + qemu_vfree(ioreq->pages); +} + +static int ioreq_init_copy_buffers(struct ioreq *ioreq) +{ + int i; + + if (ioreq->v.niov == 0) { + return 0; + } + + ioreq->pages = qemu_memalign(XC_PAGE_SIZE, ioreq->v.niov * XC_PAGE_SIZE); + + for (i = 0; i < ioreq->v.niov; i++) { + ioreq->page[i] = ioreq->pages + i * XC_PAGE_SIZE; + ioreq->v.iov[i].iov_base = ioreq->page[i]; + } + + return 0; +} + +static int ioreq_grant_copy(struct ioreq *ioreq) +{ + xengnttab_handle *gnt = ioreq->blkdev->xendev.gnttabdev; + xengnttab_grant_copy_segment_t segs[BLKIF_MAX_SEGMENTS_PER_REQUEST]; + int i, count, rc; + int64_t file_blk = ioreq->blkdev->file_blk; + + if (ioreq->v.niov == 0) { + return 0; + } + + count = ioreq->v.niov; + + for (i = 0; i < count; i++) { + if (ioreq->req.operation == BLKIF_OP_READ) { + segs[i].flags = GNTCOPY_dest_gref; + segs[i].dest.foreign.ref = ioreq->refs[i]; + segs[i].dest.foreign.domid = ioreq->domids[i]; + segs[i].dest.foreign.offset = ioreq->req.seg[i].first_sect * file_blk; + segs[i].source.virt = ioreq->v.iov[i].iov_base; + } else { + segs[i].flags = GNTCOPY_source_gref; + segs[i].source.foreign.ref = ioreq->refs[i]; + segs[i].source.foreign.domid = ioreq->domids[i]; + segs[i].source.foreign.offset = ioreq->req.seg[i].first_sect * file_blk; + segs[i].dest.virt = ioreq->v.iov[i].iov_base; + } + segs[i].len = (ioreq->req.seg[i].last_sect + - ioreq->req.seg[i].first_sect + 1) * file_blk; + } + + rc = xengnttab_grant_copy(gnt, count, segs); + + if (rc) { + xen_be_printf(&ioreq->blkdev->xendev, 0, + "failed to copy data %d\n", rc); + ioreq->aio_errors++; + return -1; + } + + for (i = 0; i < count; i++) { + if (segs[i].status != GNTST_okay) { + xen_be_printf(&ioreq->blkdev->xendev, 3, + "failed to copy data %d for gref %d, domid %d\n", + segs[i].status, ioreq->refs[i], ioreq->domids[i]); + ioreq->aio_errors++; + rc = -1; + } + } + + return rc; +} +#else +static void ioreq_free_copy_buffers(struct ioreq *ioreq) +{ + abort(); +} + +static int ioreq_init_copy_buffers(struct ioreq *ioreq) +{ + abort(); +} + +static int ioreq_grant_copy(struct ioreq *ioreq) +{ + abort(); +} +#endif + static int ioreq_runio_qemu_aio(struct ioreq *ioreq); static void qemu_aio_complete(void *opaque, int ret) @@ -511,8 +614,31 @@ static void qemu_aio_complete(void *opaque, int ret) return; } + if (ioreq->blkdev->feature_grant_copy) { + switch (ioreq->req.operation) { + case BLKIF_OP_READ: + /* in case of failure ioreq->aio_errors is increased */ + if (ret == 0) { + ioreq_grant_copy(ioreq); + } + ioreq_free_copy_buffers(ioreq); + break; + case BLKIF_OP_WRITE: + case BLKIF_OP_FLUSH_DISKCACHE: + if (!ioreq->req.nr_segments) { + break; + } + ioreq_free_copy_buffers(ioreq); + break; + default: + break; + } + } + ioreq->status = ioreq->aio_errors ? BLKIF_RSP_ERROR : BLKIF_RSP_OKAY; - ioreq_unmap(ioreq); + if (!ioreq->blkdev->feature_grant_copy) { + ioreq_unmap(ioreq); + } ioreq_finish(ioreq); switch (ioreq->req.operation) { case BLKIF_OP_WRITE: @@ -538,8 +664,18 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq) { struct XenBlkDev *blkdev = ioreq->blkdev; - if (ioreq->req.nr_segments && ioreq_map(ioreq) == -1) { - goto err_no_map; + if (ioreq->blkdev->feature_grant_copy) { + ioreq_init_copy_buffers(ioreq); + if (ioreq->req.nr_segments && (ioreq->req.operation == BLKIF_OP_WRITE || + ioreq->req.operation == BLKIF_OP_FLUSH_DISKCACHE) && + ioreq_grant_copy(ioreq)) { + ioreq_free_copy_buffers(ioreq); + goto err; + } + } else { + if (ioreq->req.nr_segments && ioreq_map(ioreq)) { + goto err; + } } ioreq->aio_inflight++; @@ -582,6 +718,9 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq) } default: /* unknown operation (shouldn't happen -- parse catches this) */ + if (!ioreq->blkdev->feature_grant_copy) { + ioreq_unmap(ioreq); + } goto err; } @@ -590,8 +729,6 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq) return 0; err: - ioreq_unmap(ioreq); -err_no_map: ioreq_finish(ioreq); ioreq->status = BLKIF_RSP_ERROR; return -1; @@ -1034,6 +1171,12 @@ static int blk_connect(struct XenDevice *xendev) xen_be_bind_evtchn(&blkdev->xendev); + blkdev->feature_grant_copy = + (xengnttab_grant_copy(blkdev->xendev.gnttabdev, 0, NULL) == 0); + + xen_be_printf(&blkdev->xendev, 3, "grant copy operation %s\n", + blkdev->feature_grant_copy ? "enabled" : "disabled"); + xen_be_printf(&blkdev->xendev, 1, "ok: proto %s, ring-ref %d, " "remote port %d, local port %d\n", blkdev->xendev.protocol, blkdev->ring_ref, diff --git a/include/hw/xen/xen_common.h b/include/hw/xen/xen_common.h index bd39287b8f6..8e1580d5266 100644 --- a/include/hw/xen/xen_common.h +++ b/include/hw/xen/xen_common.h @@ -424,4 +424,18 @@ static inline int xen_domain_create(xc_interface *xc, uint32_t ssidref, #endif #endif +/* Xen before 4.8 */ + +#if CONFIG_XEN_CTRL_INTERFACE_VERSION < 480 + + +typedef void *xengnttab_grant_copy_segment_t; + +static inline int xengnttab_grant_copy(xengnttab_handle *xgt, uint32_t count, + xengnttab_grant_copy_segment_t *segs) +{ + return -ENOSYS; +} +#endif + #endif /* QEMU_HW_XEN_COMMON_H */ From 21ce148c7ec71ee32834061355a5ecfd1a11f90f Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 23 Aug 2016 16:34:59 +0200 Subject: [PATCH 385/723] tests: cris: force inlining The CRIS tests expect that functions marked inline are always inline. With newer versions of GCC, building them results warnings like the following and spurious failures when they are run. In file included from tests/tcg/cris/check_moveq.c:5:0: tests/tcg/cris/crisutils.h:66:20: warning: inlining failed in call to 'cris_tst_cc.constprop.0': call is unlikely and code size would grow [-Winline] tests/tcg/cris/check_moveq.c:28:13: warning: called from here [-Winline] Use the always_inline attribute when building them to fix this. Reviewed-by: Edgar E. Iglesias Signed-off-by: Rabin Vincent Signed-off-by: Edgar E. Iglesias --- tests/tcg/cris/check_abs.c | 4 ++-- tests/tcg/cris/check_addc.c | 2 +- tests/tcg/cris/check_addcm.c | 4 ++-- tests/tcg/cris/check_bound.c | 6 +++--- tests/tcg/cris/check_ftag.c | 8 ++++---- tests/tcg/cris/check_int64.c | 4 ++-- tests/tcg/cris/check_lz.c | 2 +- tests/tcg/cris/check_swap.c | 2 +- tests/tcg/cris/crisutils.h | 20 ++++++++++---------- tests/tcg/cris/sys.h | 2 ++ 10 files changed, 28 insertions(+), 26 deletions(-) diff --git a/tests/tcg/cris/check_abs.c b/tests/tcg/cris/check_abs.c index 9770a8d9ef4..08b67b6ef0c 100644 --- a/tests/tcg/cris/check_abs.c +++ b/tests/tcg/cris/check_abs.c @@ -4,14 +4,14 @@ #include "sys.h" #include "crisutils.h" -static inline int cris_abs(int n) +static always_inline int cris_abs(int n) { int r; asm ("abs\t%1, %0\n" : "=r" (r) : "r" (n)); return r; } -static inline void +static always_inline void verify_abs(int val, int res, const int n, const int z, const int v, const int c) { diff --git a/tests/tcg/cris/check_addc.c b/tests/tcg/cris/check_addc.c index facd1bea2dc..fc3fb1faa80 100644 --- a/tests/tcg/cris/check_addc.c +++ b/tests/tcg/cris/check_addc.c @@ -4,7 +4,7 @@ #include "sys.h" #include "crisutils.h" -static inline int cris_addc(int a, const int b) +static always_inline int cris_addc(int a, const int b) { asm ("addc\t%1, %0\n" : "+r" (a) : "r" (b)); return a; diff --git a/tests/tcg/cris/check_addcm.c b/tests/tcg/cris/check_addcm.c index 7928bc9999b..b355ba164fb 100644 --- a/tests/tcg/cris/check_addcm.c +++ b/tests/tcg/cris/check_addcm.c @@ -5,14 +5,14 @@ #include "crisutils.h" /* need to avoid acr as source here. */ -static inline int cris_addc_m(int a, const int *b) +static always_inline int cris_addc_m(int a, const int *b) { asm volatile ("addc [%1], %0\n" : "+r" (a) : "r" (b)); return a; } /* 'b' is a crisv32 constrain to avoid postinc with $acr. */ -static inline int cris_addc_pi_m(int a, int **b) +static always_inline int cris_addc_pi_m(int a, int **b) { asm volatile ("addc [%1+], %0\n" : "+r" (a), "+b" (*b)); return a; diff --git a/tests/tcg/cris/check_bound.c b/tests/tcg/cris/check_bound.c index e8831754ece..d956ab9adec 100644 --- a/tests/tcg/cris/check_bound.c +++ b/tests/tcg/cris/check_bound.c @@ -4,21 +4,21 @@ #include "sys.h" #include "crisutils.h" -static inline int cris_bound_b(int v, int b) +static always_inline int cris_bound_b(int v, int b) { int r = v; asm ("bound.b\t%1, %0\n" : "+r" (r) : "ri" (b)); return r; } -static inline int cris_bound_w(int v, int b) +static always_inline int cris_bound_w(int v, int b) { int r = v; asm ("bound.w\t%1, %0\n" : "+r" (r) : "ri" (b)); return r; } -static inline int cris_bound_d(int v, int b) +static always_inline int cris_bound_d(int v, int b) { int r = v; asm ("bound.d\t%1, %0\n" : "+r" (r) : "ri" (b)); diff --git a/tests/tcg/cris/check_ftag.c b/tests/tcg/cris/check_ftag.c index 908773a38a8..aaa5c971159 100644 --- a/tests/tcg/cris/check_ftag.c +++ b/tests/tcg/cris/check_ftag.c @@ -4,22 +4,22 @@ #include "sys.h" #include "crisutils.h" -static inline void cris_ftag_i(unsigned int x) +static always_inline void cris_ftag_i(unsigned int x) { register unsigned int v asm("$r10") = x; asm ("ftagi\t[%0]\n" : : "r" (v) ); } -static inline void cris_ftag_d(unsigned int x) +static always_inline void cris_ftag_d(unsigned int x) { register unsigned int v asm("$r10") = x; asm ("ftagd\t[%0]\n" : : "r" (v) ); } -static inline void cris_fidx_i(unsigned int x) +static always_inline void cris_fidx_i(unsigned int x) { register unsigned int v asm("$r10") = x; asm ("fidxi\t[%0]\n" : : "r" (v) ); } -static inline void cris_fidx_d(unsigned int x) +static always_inline void cris_fidx_d(unsigned int x) { register unsigned int v asm("$r10") = x; asm ("fidxd\t[%0]\n" : : "r" (v) ); diff --git a/tests/tcg/cris/check_int64.c b/tests/tcg/cris/check_int64.c index fc600176e23..69caec1bb24 100644 --- a/tests/tcg/cris/check_int64.c +++ b/tests/tcg/cris/check_int64.c @@ -5,12 +5,12 @@ #include "crisutils.h" -static inline int64_t add64(const int64_t a, const int64_t b) +static always_inline int64_t add64(const int64_t a, const int64_t b) { return a + b; } -static inline int64_t sub64(const int64_t a, const int64_t b) +static always_inline int64_t sub64(const int64_t a, const int64_t b) { return a - b; } diff --git a/tests/tcg/cris/check_lz.c b/tests/tcg/cris/check_lz.c index 69c2e6d4eca..bf051a6b550 100644 --- a/tests/tcg/cris/check_lz.c +++ b/tests/tcg/cris/check_lz.c @@ -3,7 +3,7 @@ #include #include "sys.h" -static inline int cris_lz(int x) +static always_inline int cris_lz(int x) { int r; asm ("lz\t%1, %0\n" : "=r" (r) : "r" (x)); diff --git a/tests/tcg/cris/check_swap.c b/tests/tcg/cris/check_swap.c index f851cbcef1f..9a68c1e5d76 100644 --- a/tests/tcg/cris/check_swap.c +++ b/tests/tcg/cris/check_swap.c @@ -9,7 +9,7 @@ #define B 2 #define R 1 -static inline int cris_swap(const int mode, int x) +static always_inline int cris_swap(const int mode, int x) { switch (mode) { diff --git a/tests/tcg/cris/crisutils.h b/tests/tcg/cris/crisutils.h index 3456b9d50da..bbbe6c55405 100644 --- a/tests/tcg/cris/crisutils.h +++ b/tests/tcg/cris/crisutils.h @@ -13,57 +13,57 @@ void _err(void) { _fail(tst_cc_loc); } -static inline void cris_tst_cc_n1(void) +static always_inline void cris_tst_cc_n1(void) { asm volatile ("bpl _err\n" "nop\n"); } -static inline void cris_tst_cc_n0(void) +static always_inline void cris_tst_cc_n0(void) { asm volatile ("bmi _err\n" "nop\n"); } -static inline void cris_tst_cc_z1(void) +static always_inline void cris_tst_cc_z1(void) { asm volatile ("bne _err\n" "nop\n"); } -static inline void cris_tst_cc_z0(void) +static always_inline void cris_tst_cc_z0(void) { asm volatile ("beq _err\n" "nop\n"); } -static inline void cris_tst_cc_v1(void) +static always_inline void cris_tst_cc_v1(void) { asm volatile ("bvc _err\n" "nop\n"); } -static inline void cris_tst_cc_v0(void) +static always_inline void cris_tst_cc_v0(void) { asm volatile ("bvs _err\n" "nop\n"); } -static inline void cris_tst_cc_c1(void) +static always_inline void cris_tst_cc_c1(void) { asm volatile ("bcc _err\n" "nop\n"); } -static inline void cris_tst_cc_c0(void) +static always_inline void cris_tst_cc_c0(void) { asm volatile ("bcs _err\n" "nop\n"); } -static inline void cris_tst_mov_cc(int n, int z) +static always_inline void cris_tst_mov_cc(int n, int z) { if (n) cris_tst_cc_n1(); else cris_tst_cc_n0(); if (z) cris_tst_cc_z1(); else cris_tst_cc_z0(); asm volatile ("" : : "g" (_err)); } -static inline void cris_tst_cc(const int n, const int z, +static always_inline void cris_tst_cc(const int n, const int z, const int v, const int c) { if (n) cris_tst_cc_n1(); else cris_tst_cc_n0(); diff --git a/tests/tcg/cris/sys.h b/tests/tcg/cris/sys.h index c5f88e1a294..3dd47bb6730 100644 --- a/tests/tcg/cris/sys.h +++ b/tests/tcg/cris/sys.h @@ -3,6 +3,8 @@ #define STRINGIFY(x) #x #define TOSTRING(x) STRINGIFY(x) +#define always_inline inline __attribute__((always_inline)) + #define CURRENT_LOCATION __FILE__ ":" TOSTRING(__LINE__) #define err() \ From f278d5cbe59bc022ee67ead5f608fe0530c4e96b Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Wed, 24 Aug 2016 09:08:21 +0200 Subject: [PATCH 386/723] tests: cris: fix syscall inline asm Add the appropriate register constraints for the inline asm for the write and exit system calls. Without the correct constraints for the write() function, correct failure messages are not printed succesfully on newer version of GCC. Reviewed-by: Edgar E. Iglesias Reviewed-by: Richard Henderson Signed-off-by: Rabin Vincent Signed-off-by: Edgar E. Iglesias --- tests/tcg/cris/sys.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/tests/tcg/cris/sys.c b/tests/tcg/cris/sys.c index 551c5dd7cb9..21f08c07474 100644 --- a/tests/tcg/cris/sys.c +++ b/tests/tcg/cris/sys.c @@ -33,19 +33,27 @@ void *memset (void *s, int c, size_t n) { } void exit (int status) { - asm volatile ("moveq 1, $r9\n" /* NR_exit. */ - "break 13\n"); + register unsigned int callno asm ("r9") = 1; /* NR_exit */ + + asm volatile ("break 13\n" + : + : "r" (callno) + : "memory" ); while(1) ; } ssize_t write (int fd, const void *buf, size_t count) { - int r; - asm ("move.d %0, $r10\n" - "move.d %1, $r11\n" - "move.d %2, $r12\n" - "moveq 4, $r9\n" /* NR_write. */ - "break 13\n" : : "r" (fd), "r" (buf), "r" (count) : "memory"); - asm ("move.d $r10, %0\n" : "=r" (r)); + register unsigned int callno asm ("r9") = 4; /* NR_write */ + register unsigned int r10 asm ("r10") = fd; + register const void *r11 asm ("r11") = buf; + register size_t r12 asm ("r12") = count; + register unsigned int r asm ("r10"); + + asm volatile ("break 13\n" + : "=r" (r) + : "r" (callno), "0" (r10), "r" (r11), "r" (r12) + : "memory"); + return r; } From d10a0102b33e5bedf2bb92152beceea51245ae84 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 23 Aug 2016 16:44:15 +0200 Subject: [PATCH 387/723] tests: cris: remove openpf4 test This test, borrowed from the GDB simulator test suite, is meant to test the GDB simulator's --sysroot feature and always fails in QEMU. Remove it. openpf3 tests the same sequence of system calls (without assuming the precence of --sysroot). Reviewed-by: Edgar E. Iglesias Signed-off-by: Rabin Vincent Signed-off-by: Edgar E. Iglesias --- tests/tcg/cris/Makefile | 1 - tests/tcg/cris/check_openpf4.c | 5 ----- 2 files changed, 6 deletions(-) delete mode 100644 tests/tcg/cris/check_openpf4.c diff --git a/tests/tcg/cris/Makefile b/tests/tcg/cris/Makefile index d34bfd8f7a3..f5230fcabaa 100644 --- a/tests/tcg/cris/Makefile +++ b/tests/tcg/cris/Makefile @@ -108,7 +108,6 @@ TESTCASES += check_stat4.ctst TESTCASES += check_openpf1.ctst TESTCASES += check_openpf2.ctst TESTCASES += check_openpf3.ctst -TESTCASES += check_openpf4.ctst TESTCASES += check_openpf5.ctst TESTCASES += check_mapbrk.ctst TESTCASES += check_mmap1.ctst diff --git a/tests/tcg/cris/check_openpf4.c b/tests/tcg/cris/check_openpf4.c deleted file mode 100644 index 8bbee41a649..00000000000 --- a/tests/tcg/cris/check_openpf4.c +++ /dev/null @@ -1,5 +0,0 @@ -/* Basic file operations, now *with* sysroot. -#sim: --sysroot=@exedir@ -*/ -#define PREFIX "/" -#include "check_openpf3.c" From 85b3ed1db5e50b66016ef59ca2afce10e753cbc6 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 23 Aug 2016 16:50:18 +0200 Subject: [PATCH 388/723] tests: cris: remove check_time1 This test, borrowed from the GDB simulator test suite, checks that every syscall increments the time returned by gettimeofday() by exactly 1 ms. This is not guaranteed or even desirable on QEMU so remove this test. Reviewed-by: Edgar E. Iglesias Signed-off-by: Rabin Vincent Signed-off-by: Edgar E. Iglesias --- tests/tcg/cris/Makefile | 1 - tests/tcg/cris/check_time1.c | 46 ------------------------------------ 2 files changed, 47 deletions(-) delete mode 100644 tests/tcg/cris/check_time1.c diff --git a/tests/tcg/cris/Makefile b/tests/tcg/cris/Makefile index f5230fcabaa..14a9eb5b572 100644 --- a/tests/tcg/cris/Makefile +++ b/tests/tcg/cris/Makefile @@ -114,7 +114,6 @@ TESTCASES += check_mmap1.ctst TESTCASES += check_mmap2.ctst TESTCASES += check_mmap3.ctst TESTCASES += check_sigalrm.ctst -TESTCASES += check_time1.ctst TESTCASES += check_time2.ctst TESTCASES += check_settls1.ctst diff --git a/tests/tcg/cris/check_time1.c b/tests/tcg/cris/check_time1.c deleted file mode 100644 index 3fcf0e15352..00000000000 --- a/tests/tcg/cris/check_time1.c +++ /dev/null @@ -1,46 +0,0 @@ -/* Basic time functionality test: check that milliseconds are - incremented for each syscall (does not work on host). */ -#include -#include -#include -#include -#include - -void err (const char *s) -{ - perror (s); - abort (); -} - -int -main (void) -{ - struct timeval t_m = {0, 0}; - struct timezone t_z = {0, 0}; - struct timeval t_m1 = {0, 0}; - int i; - - if (gettimeofday (&t_m, &t_z) != 0) - err ("gettimeofday"); - - for (i = 1; i < 10000; i++) - if (gettimeofday (&t_m1, NULL) != 0) - err ("gettimeofday 1"); - else - if (t_m1.tv_sec * 1000000 + t_m1.tv_usec - != (t_m.tv_sec * 1000000 + t_m.tv_usec + i * 1000)) - { - fprintf (stderr, "t0 (%ld, %ld), i %d, t1 (%ld, %ld)\n", - t_m.tv_sec, t_m.tv_usec, i, t_m1.tv_sec, t_m1.tv_usec); - abort (); - } - - if (time (NULL) != t_m1.tv_sec) - { - fprintf (stderr, "time != gettod\n"); - abort (); - } - - printf ("pass\n"); - exit (0); -} From 17bc37b75ea4c33a6f36f073a67df687bef840c9 Mon Sep 17 00:00:00 2001 From: Hans-Peter Nilsson Date: Mon, 15 Aug 2016 13:44:46 +0200 Subject: [PATCH 389/723] target-cris: reduce v32isms from v10 log dumps Use the correct register names for v10 and don't dump support function registers for pre-v32. Reviewed-by: Edgar E. Iglesias Signed-off-by: Hans-Peter Nilsson Signed-off-by: Rabin Vincent Signed-off-by: Edgar E. Iglesias --- target-cris/translate.c | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/target-cris/translate.c b/target-cris/translate.c index f4a8d7d000f..b5ab0a5fb2a 100644 --- a/target-cris/translate.c +++ b/target-cris/translate.c @@ -140,14 +140,14 @@ static void gen_BUG(DisasContext *dc, const char *file, int line) cpu_abort(CPU(dc->cpu), "%s:%d\n", file, line); } -static const char *regnames[] = +static const char *regnames_v32[] = { "$r0", "$r1", "$r2", "$r3", "$r4", "$r5", "$r6", "$r7", "$r8", "$r9", "$r10", "$r11", "$r12", "$r13", "$sp", "$acr", }; -static const char *pregnames[] = +static const char *pregnames_v32[] = { "$bz", "$vr", "$pid", "$srs", "$wz", "$exs", "$eda", "$mof", @@ -3327,12 +3327,20 @@ void cris_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, { CRISCPU *cpu = CRIS_CPU(cs); CPUCRISState *env = &cpu->env; + const char **regnames; + const char **pregnames; int i; - uint32_t srs; if (!env || !f) { return; } + if (env->pregs[PR_VR] < 32) { + pregnames = pregnames_v10; + regnames = regnames_v10; + } else { + pregnames = pregnames_v32; + regnames = regnames_v32; + } cpu_fprintf(f, "PC=%x CCS=%x btaken=%d btarget=%x\n" "cc_op=%d cc_src=%d cc_dest=%d cc_result=%x cc_mask=%x\n", @@ -3354,14 +3362,16 @@ void cris_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, cpu_fprintf(f, "\n"); } } - srs = env->pregs[PR_SRS]; - cpu_fprintf(f, "\nsupport function regs bank %x:\n", srs); - if (srs < ARRAY_SIZE(env->sregs)) { - for (i = 0; i < 16; i++) { - cpu_fprintf(f, "s%2.2d=%8.8x ", - i, env->sregs[srs][i]); - if ((i + 1) % 4 == 0) { - cpu_fprintf(f, "\n"); + if (env->pregs[PR_VR] >= 32) { + uint32_t srs = env->pregs[PR_SRS]; + cpu_fprintf(f, "\nsupport function regs bank %x:\n", srs); + if (srs < ARRAY_SIZE(env->sregs)) { + for (i = 0; i < 16; i++) { + cpu_fprintf(f, "s%2.2d=%8.8x ", + i, env->sregs[srs][i]); + if ((i + 1) % 4 == 0) { + cpu_fprintf(f, "\n"); + } } } } @@ -3406,12 +3416,12 @@ void cris_initialize_tcg(void) for (i = 0; i < 16; i++) { cpu_R[i] = tcg_global_mem_new(cpu_env, offsetof(CPUCRISState, regs[i]), - regnames[i]); + regnames_v32[i]); } for (i = 0; i < 16; i++) { cpu_PR[i] = tcg_global_mem_new(cpu_env, offsetof(CPUCRISState, pregs[i]), - pregnames[i]); + pregnames_v32[i]); } } From ceffd34e8589a9a4f18849a21ae1fecaef3af02e Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Mon, 15 Aug 2016 13:59:32 +0200 Subject: [PATCH 390/723] target-cris: add v17 CPU In the CRIS v17 CPU an ADDC (add with carry) instruction has been added compared to the v10 instruction set. Assembler syntax: ADDC [Rs],Rd ADDC [Rs+],Rd Size: Dword Description: The source data is added together with the carry flag to the destination register. The size of the operation is dword. Operation: Rd += s + C-flag; Flags affected: S R P U I X N Z V C - - - - - 0 * * * * Instruction format: ADDC [Rs],Rd +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ |Destination(Rd)| 1 0 0 1 1 0 1 0 | Source(Rs) | +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ Instruction format: ADDC [Rs+],Rd +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ |Destination(Rd)| 1 1 0 1 1 0 1 0 | Source(Rs) | +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ [EI: Shorten 80+ lines] Reviewed-by: Edgar E. Iglesias Signed-off-by: Rabin Vincent Signed-off-by: Edgar E. Iglesias --- target-cris/cpu.c | 14 ++++++++++++++ target-cris/crisv10-decode.h | 1 + target-cris/translate_v10.c | 23 +++++++++++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/target-cris/cpu.c b/target-cris/cpu.c index c5a656bb623..d680cfb52b3 100644 --- a/target-cris/cpu.c +++ b/target-cris/cpu.c @@ -246,6 +246,16 @@ static void crisv11_cpu_class_init(ObjectClass *oc, void *data) cc->gdb_read_register = crisv10_cpu_gdb_read_register; } +static void crisv17_cpu_class_init(ObjectClass *oc, void *data) +{ + CPUClass *cc = CPU_CLASS(oc); + CRISCPUClass *ccc = CRIS_CPU_CLASS(oc); + + ccc->vr = 17; + cc->do_interrupt = crisv10_cpu_do_interrupt; + cc->gdb_read_register = crisv10_cpu_gdb_read_register; +} + static void crisv32_cpu_class_init(ObjectClass *oc, void *data) { CRISCPUClass *ccc = CRIS_CPU_CLASS(oc); @@ -272,6 +282,10 @@ static const TypeInfo cris_cpu_model_type_infos[] = { .name = TYPE("crisv11"), .parent = TYPE_CRIS_CPU, .class_init = crisv11_cpu_class_init, + }, { + .name = TYPE("crisv17"), + .parent = TYPE_CRIS_CPU, + .class_init = crisv17_cpu_class_init, }, { .name = TYPE("crisv32"), .parent = TYPE_CRIS_CPU, diff --git a/target-cris/crisv10-decode.h b/target-cris/crisv10-decode.h index 587fbdd278e..bdb4b6d3184 100644 --- a/target-cris/crisv10-decode.h +++ b/target-cris/crisv10-decode.h @@ -92,6 +92,7 @@ #define CRISV10_IND_JUMP_M 4 #define CRISV10_IND_DIP 5 #define CRISV10_IND_JUMP_R 6 +#define CRISV17_IND_ADDC 6 #define CRISV10_IND_BOUND 7 #define CRISV10_IND_BCC_M 7 #define CRISV10_IND_MOVE_M_SPR 8 diff --git a/target-cris/translate_v10.c b/target-cris/translate_v10.c index 4707a18e775..4a0b485d8e3 100644 --- a/target-cris/translate_v10.c +++ b/target-cris/translate_v10.c @@ -1094,6 +1094,29 @@ static unsigned int dec10_ind(CPUCRISState *env, DisasContext *dc) insn_len = dec10_bdap_m(env, dc, size); break; default: + /* + * ADDC for v17: + * + * Instruction format: ADDC [Rs],Rd + * + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+-+ + * |Destination(Rd)| 1 0 0 1 1 0 1 0 | Source(Rs)| + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+--+--+ + * + * Instruction format: ADDC [Rs+],Rd + * + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+-+ + * |Destination(Rd)| 1 1 0 1 1 0 1 0 | Source(Rs)| + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+-+ + */ + if (dc->opcode == CRISV17_IND_ADDC && dc->size == 2 && + env->pregs[PR_VR] == 17) { + LOG_DIS("addc op=%d %d\n", dc->src, dc->dst); + cris_cc_mask(dc, CC_MASK_NZVC); + insn_len += dec10_ind_alu(env, dc, CC_OP_ADDC, size); + break; + } + LOG_DIS("pc=%x var-ind.%d %d r%d r%d\n", dc->pc, size, dc->opcode, dc->src, dc->dst); cpu_abort(CPU(dc->cpu), "Unhandled opcode"); From 4a58f35b793d5d09d6cef921bf6ed7ffc39669fd Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Wed, 24 Aug 2016 10:42:16 +0200 Subject: [PATCH 391/723] tests: cris: add v17 ADDC test Add a test for the newly implemented ADDC instruction in the v17 CRIS CPU. Acked-by: Edgar E. Iglesias Signed-off-by: Rabin Vincent Signed-off-by: Edgar E. Iglesias --- tests/tcg/cris/Makefile | 19 ++++++++-- tests/tcg/cris/check_addcv17.s | 65 ++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 tests/tcg/cris/check_addcv17.s diff --git a/tests/tcg/cris/Makefile b/tests/tcg/cris/Makefile index 14a9eb5b572..6b3dba446cd 100644 --- a/tests/tcg/cris/Makefile +++ b/tests/tcg/cris/Makefile @@ -23,6 +23,7 @@ SYS = sys.o TESTCASES += check_abs.tst TESTCASES += check_addc.tst TESTCASES += check_addcm.tst +TESTCASES += check_addcv17.tst TESTCASES += check_addo.tst TESTCASES += check_addoq.tst TESTCASES += check_addi.tst @@ -134,13 +135,27 @@ all: build %.ctst: %.o $(CC) $(CFLAGS) $(LDLIBS) $< -o $@ + +sysv10.o: sys.c + $(CC) $(CFLAGS) -mcpu=v10 -c $< -o $@ + +crtv10.o: crt.s + $(AS) $(ASFLAGS) -mcpu=v10 -c $< -o $@ + +check_addcv17.tst: ASFLAGS += -mcpu=v10 +check_addcv17.tst: CRT := crtv10.o +check_addcv17.tst: SYS := sysv10.o +check_addcv17.tst: crtv10.o sysv10.o + build: $(CRT) $(SYS) $(TESTCASES) check: $(CRT) $(SYS) $(TESTCASES) @echo -e "\nQEMU simulator." for case in $(TESTCASES); do \ echo -n "$$case "; \ - $(SIM) ./$$case; \ + SIMARGS=; \ + case $$case in *v17*) SIMARGS="-cpu crisv17";; esac; \ + $(SIM) $$SIMARGS ./$$case; \ done check-g: $(CRT) $(SYS) $(TESTCASES) @echo -e "\nGDB simulator." @@ -150,4 +165,4 @@ check-g: $(CRT) $(SYS) $(TESTCASES) done clean: - $(RM) -fr $(TESTCASES) $(CRT) $(SYS) + $(RM) -fr $(TESTCASES) *.o diff --git a/tests/tcg/cris/check_addcv17.s b/tests/tcg/cris/check_addcv17.s new file mode 100644 index 00000000000..52ef7a97169 --- /dev/null +++ b/tests/tcg/cris/check_addcv17.s @@ -0,0 +1,65 @@ +# mach: crisv17 + + .include "testutils.inc" + + .macro addc Rs Rd inc=0 +# Create the instruction manually since there is no assembler support yet + .word (\Rd << 12) | \Rs | (\inc << 10) | 0x09a0 + .endm + + start + + .data +mem1: + .dword 0x0 +mem2: + .dword 0x12345678 + + .text + move.d mem1,r4 + clearf nzvc + addc 4 3 + test_cc 0 1 0 0 + checkr3 0 + + move.d mem1,r4 + clearf nzvc + ax + addc 4 3 + test_cc 0 0 0 0 + checkr3 0 + + move.d mem1,r4 + clearf nzvc + setf c + addc 4 3 + test_cc 0 0 0 0 + checkr3 1 + + move.d mem2,r4 + moveq 2, r3 + clearf nzvc + setf c + addc 4 3 + test_cc 0 0 0 0 + checkr3 1234567b + + move.d mem2,r5 + clearf nzvc + cmp.d r4,r5 + test_cc 0 1 0 0 + + move.d mem2,r4 + moveq 2, r3 + clearf nzvc + addc 4 3 inc=1 + test_cc 0 0 0 0 + checkr3 1234567a + + move.d mem2,r5 + clearf nzvc + addq 4,r5 + cmp.d r4,r5 + test_cc 0 1 0 0 + + quit From e7e4f9f950253ce5fb03f569868a21d6d7e3f8a2 Mon Sep 17 00:00:00 2001 From: Yaowei Bai Date: Wed, 14 Sep 2016 07:03:38 -0400 Subject: [PATCH 392/723] block: mirror: fix wrong comment of mirror_start Obviously, we should write to '@target'. Signed-off-by: Yaowei Bai Reviewed-by: Xiubo Li Reviewed-by: Eric Blake Message-id: 1473851019-7005-2-git-send-email-baiyaowei@cmss.chinamobile.com Signed-off-by: Stefan Hajnoczi --- include/block/block_int.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/block/block_int.h b/include/block/block_int.h index ef3c047cb37..3e79228eb00 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -722,7 +722,7 @@ void commit_active_start(const char *job_id, BlockDriverState *bs, * @errp: Error object. * * Start a mirroring operation on @bs. Clusters that are allocated - * in @bs will be written to @bs until the job is cancelled or + * in @bs will be written to @target until the job is cancelled or * manually completed. At the end of a successful mirroring job, * @bs will be switched to read from @target. */ From 6b9424689a32bb76942ec39f6d5c60b72eb002e0 Mon Sep 17 00:00:00 2001 From: Yaowei Bai Date: Wed, 14 Sep 2016 07:03:39 -0400 Subject: [PATCH 393/723] aio-posix: avoid unnecessary aio_epoll_enabled() calls As epoll whether enabled or not is a global setting, we can just check it only once rather than checking it with every node iteration. Through this we can avoid a lot of checks when epoll is not enabled. Signed-off-by: Yaowei Bai Reviewed-by: Xiubo Li Message-id: 1473851019-7005-3-git-send-email-baiyaowei@cmss.chinamobile.com Signed-off-by: Stefan Hajnoczi --- aio-posix.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/aio-posix.c b/aio-posix.c index 43162a9f291..4ef34dd1750 100644 --- a/aio-posix.c +++ b/aio-posix.c @@ -431,11 +431,13 @@ bool aio_poll(AioContext *ctx, bool blocking) assert(npfd == 0); /* fill pollfds */ - QLIST_FOREACH(node, &ctx->aio_handlers, node) { - if (!node->deleted && node->pfd.events - && !aio_epoll_enabled(ctx) - && aio_node_check(ctx, node->is_external)) { - add_pollfd(node); + + if (!aio_epoll_enabled(ctx)) { + QLIST_FOREACH(node, &ctx->aio_handlers, node) { + if (!node->deleted && node->pfd.events + && aio_node_check(ctx, node->is_external)) { + add_pollfd(node); + } } } From eb7b5c35117bfb90dcfa881a0e3b23368c73fba6 Mon Sep 17 00:00:00 2001 From: Lin Ma Date: Mon, 26 Sep 2016 13:29:58 +0800 Subject: [PATCH 394/723] iothread: check iothread->ctx before aio_context_unref to avoid assertion if iothread->ctx is set to NULL, aio_context_unref triggers the assertion: g_source_unref: assertion 'source != NULL' failed. The patch fixes it. Signed-off-by: Lin Ma Reviewed-by: Paolo Bonzini Message-id: 20160926052958.10716-1-lma@suse.com Signed-off-by: Stefan Hajnoczi --- iothread.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/iothread.c b/iothread.c index fb08a60b4b9..fbeb8deb385 100644 --- a/iothread.c +++ b/iothread.c @@ -75,6 +75,9 @@ static void iothread_instance_finalize(Object *obj) iothread_stop(obj, NULL); qemu_cond_destroy(&iothread->init_done_cond); qemu_mutex_destroy(&iothread->init_done_lock); + if (!iothread->ctx) { + return; + } aio_context_unref(iothread->ctx); } From 844c82296f8bd6ceff8d170f3740740f3ce84b73 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Mon, 26 Sep 2016 17:24:10 +0200 Subject: [PATCH 395/723] libqos: fix qvring_init() "vq->desc[i].addr" is a 64bit value, so write it with writeq(), not writew(). struct vring_desc { __virtio64 addr; __virtio32 len; __virtio16 flags; __virtio16 next; }; Signed-off-by: Laurent Vivier Message-id: 1474903450-9605-1-git-send-email-lvivier@redhat.com Signed-off-by: Stefan Hajnoczi --- tests/libqos/virtio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/libqos/virtio.c b/tests/libqos/virtio.c index 37ff860c168..105bccecaaa 100644 --- a/tests/libqos/virtio.c +++ b/tests/libqos/virtio.c @@ -147,7 +147,7 @@ void qvring_init(const QGuestAllocator *alloc, QVirtQueue *vq, uint64_t addr) for (i = 0; i < vq->size - 1; i++) { /* vq->desc[i].addr */ - writew(vq->desc + (16 * i), 0); + writeq(vq->desc + (16 * i), 0); /* vq->desc[i].next */ writew(vq->desc + (16 * i) + 14, i + 1); } From cd958edb1fae85d0c7d1e1acbff82d22724e8d64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Fri, 26 Aug 2016 13:47:11 +0400 Subject: [PATCH 396/723] console: skip same-size resize MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit virtio-gpu does a set-scanout at each frame (it might be a driver regression). qemu_console_resize() recreate a surface even if the size didn't change, and this shows up in profiling reports because the surface is cleared. With this patch, I get a +15-20% glmark2 improvement. Signed-off-by: Marc-André Lureau Message-id: 20160826094711.14470-1-marcandre.lureau@redhat.com Signed-off-by: Gerd Hoffmann --- ui/console.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ui/console.c b/ui/console.c index 3940762851a..394786b3c79 100644 --- a/ui/console.c +++ b/ui/console.c @@ -2101,6 +2101,13 @@ void qemu_console_resize(QemuConsole *s, int width, int height) DisplaySurface *surface; assert(s->console_type == GRAPHIC_CONSOLE); + + if (s->surface && + pixman_image_get_width(s->surface->image) == width && + pixman_image_get_height(s->surface->image) == height) { + return; + } + surface = qemu_create_displaysurface(width, height); dpy_gfx_replace_surface(s, surface); } From f607867cefdbf1bcb2bd4449ba96cae4994f6224 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 23 Sep 2016 09:50:27 +0200 Subject: [PATCH 397/723] console: track gl_block state in QemuConsole MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Keep track of gl_block state (added in bba19b8 console: block rendering until client is done) in QemuConsole and allow to query it. This way we can avoid state inconsistencies in case different code paths make use of this. Signed-off-by: Gerd Hoffmann Reviewed-by: Marc-André Lureau Message-id: 1474617028-3979-2-git-send-email-kraxel@redhat.com --- include/ui/console.h | 1 + ui/console.c | 15 +++++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/include/ui/console.h b/include/ui/console.h index d9c13d20b15..e2589e2134d 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -387,6 +387,7 @@ QemuConsole *qemu_console_lookup_by_device_name(const char *device_id, bool qemu_console_is_visible(QemuConsole *con); bool qemu_console_is_graphic(QemuConsole *con); bool qemu_console_is_fixedsize(QemuConsole *con); +bool qemu_console_is_gl_blocked(QemuConsole *con); char *qemu_console_get_label(QemuConsole *con); int qemu_console_get_index(QemuConsole *con); uint32_t qemu_console_get_head(QemuConsole *con); diff --git a/ui/console.c b/ui/console.c index 394786b3c79..fa3e658eddf 100644 --- a/ui/console.c +++ b/ui/console.c @@ -123,6 +123,7 @@ struct QemuConsole { DisplaySurface *surface; int dcls; DisplayChangeListener *gl; + bool gl_block; /* Graphic console state. */ Object *device; @@ -264,10 +265,10 @@ void graphic_hw_update(QemuConsole *con) void graphic_hw_gl_block(QemuConsole *con, bool block) { - if (!con) { - con = active_console; - } - if (con && con->hw_ops->gl_block) { + assert(con != NULL); + + con->gl_block = block; + if (con->hw_ops->gl_block) { con->hw_ops->gl_block(con->hw, block); } } @@ -1879,6 +1880,12 @@ bool qemu_console_is_fixedsize(QemuConsole *con) return con && (con->console_type != TEXT_CONSOLE); } +bool qemu_console_is_gl_blocked(QemuConsole *con) +{ + assert(con != NULL); + return con->gl_block; +} + char *qemu_console_get_label(QemuConsole *con) { if (con->console_type == GRAPHIC_CONSOLE) { From 4423184376dc85849b2d7b4660e7feeb2b38bf6f Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 23 Sep 2016 09:50:28 +0200 Subject: [PATCH 398/723] spice/gl: render DisplaySurface via opengl This switches over spice (in opengl mode) to render DisplaySurface updates into a opengl texture, using the helper functions in ui/console-gl.c. With this patch applied spice (with gl=on) will stop using qxl rendering ops, it will use dma-buf passing all the time, i.e. for bios/bootloader (before virtio-gpu driver is loaded) too. This should improve performance even using spice (with gl=on) with non-accelerated stdvga because we stop squeezing all display updates through a unix/tcp socket and basically using a shared memory transport instead. Signed-off-by: Gerd Hoffmann Message-id: 1474617028-3979-3-git-send-email-kraxel@redhat.com --- include/ui/spice-display.h | 5 ++- ui/spice-display.c | 92 ++++++++++++++++++++++++++++++++++---- 2 files changed, 88 insertions(+), 9 deletions(-) diff --git a/include/ui/spice-display.h b/include/ui/spice-display.h index 42e0fdf775d..184d4c373a2 100644 --- a/include/ui/spice-display.h +++ b/include/ui/spice-display.h @@ -119,7 +119,10 @@ struct SimpleSpiceDisplay { /* opengl rendering */ QEMUBH *gl_unblock_bh; QEMUTimer *gl_unblock_timer; - int dmabuf_fd; + ConsoleGLState *gls; + int gl_updates; + bool have_scanout; + bool have_surface; #endif }; diff --git a/ui/spice-display.c b/ui/spice-display.c index 99132b69b65..5e6f78a2191 100644 --- a/ui/spice-display.c +++ b/ui/spice-display.c @@ -850,6 +850,74 @@ static void qemu_spice_gl_block_timer(void *opaque) fprintf(stderr, "WARNING: spice: no gl-draw-done within one second\n"); } +static void spice_gl_refresh(DisplayChangeListener *dcl) +{ + SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); + uint64_t cookie; + + if (!ssd->ds || qemu_console_is_gl_blocked(ssd->dcl.con)) { + return; + } + + graphic_hw_update(dcl->con); + if (ssd->gl_updates && ssd->have_surface) { + qemu_spice_gl_block(ssd, true); + cookie = (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_GL_DRAW_DONE, 0); + spice_qxl_gl_draw_async(&ssd->qxl, 0, 0, + surface_width(ssd->ds), + surface_height(ssd->ds), + cookie); + ssd->gl_updates = 0; + } +} + +static void spice_gl_update(DisplayChangeListener *dcl, + int x, int y, int w, int h) +{ + SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); + + surface_gl_update_texture(ssd->gls, ssd->ds, x, y, w, h); + ssd->gl_updates++; +} + +static void spice_gl_switch(DisplayChangeListener *dcl, + struct DisplaySurface *new_surface) +{ + SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); + EGLint stride, fourcc; + int fd; + + if (ssd->ds) { + surface_gl_destroy_texture(ssd->gls, ssd->ds); + } + ssd->ds = new_surface; + if (ssd->ds) { + surface_gl_create_texture(ssd->gls, ssd->ds); + fd = egl_get_fd_for_texture(ssd->ds->texture, + &stride, &fourcc); + if (fd < 0) { + surface_gl_destroy_texture(ssd->gls, ssd->ds); + return; + } + + dprint(1, "%s: %dx%d (stride %d/%d, fourcc 0x%x)\n", __func__, + surface_width(ssd->ds), surface_height(ssd->ds), + surface_stride(ssd->ds), stride, fourcc); + + /* note: spice server will close the fd */ + spice_qxl_gl_scanout(&ssd->qxl, fd, + surface_width(ssd->ds), + surface_height(ssd->ds), + stride, fourcc, false); + ssd->have_surface = true; + ssd->have_scanout = false; + + qemu_spice_gl_monitor_config(ssd, 0, 0, + surface_width(ssd->ds), + surface_height(ssd->ds)); + } +} + static QEMUGLContext qemu_spice_gl_create_context(DisplayChangeListener *dcl, QEMUGLParams *params) { @@ -887,6 +955,8 @@ static void qemu_spice_gl_scanout(DisplayChangeListener *dcl, /* note: spice server will close the fd */ spice_qxl_gl_scanout(&ssd->qxl, fd, backing_width, backing_height, stride, fourcc, y_0_top); + ssd->have_surface = false; + ssd->have_scanout = (tex_id != 0); qemu_spice_gl_monitor_config(ssd, x, y, w, h); } @@ -897,6 +967,10 @@ static void qemu_spice_gl_update(DisplayChangeListener *dcl, SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); uint64_t cookie; + if (!ssd->have_scanout) { + return; + } + dprint(2, "%s: %dx%d+%d+%d\n", __func__, w, h, x, y); qemu_spice_gl_block(ssd, true); cookie = (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_GL_DRAW_DONE, 0); @@ -904,13 +978,13 @@ static void qemu_spice_gl_update(DisplayChangeListener *dcl, } static const DisplayChangeListenerOps display_listener_gl_ops = { - .dpy_name = "spice-egl", - .dpy_gfx_update = display_update, - .dpy_gfx_switch = display_switch, - .dpy_gfx_check_format = qemu_pixman_check_format, - .dpy_refresh = display_refresh, - .dpy_mouse_set = display_mouse_set, - .dpy_cursor_define = display_mouse_define, + .dpy_name = "spice-egl", + .dpy_gfx_update = spice_gl_update, + .dpy_gfx_switch = spice_gl_switch, + .dpy_gfx_check_format = console_gl_check_format, + .dpy_refresh = spice_gl_refresh, + .dpy_mouse_set = display_mouse_set, + .dpy_cursor_define = display_mouse_define, .dpy_gl_ctx_create = qemu_spice_gl_create_context, .dpy_gl_ctx_destroy = qemu_egl_destroy_context, @@ -933,10 +1007,12 @@ static void qemu_spice_display_init_one(QemuConsole *con) #ifdef HAVE_SPICE_GL if (display_opengl) { ssd->dcl.ops = &display_listener_gl_ops; - ssd->dmabuf_fd = -1; ssd->gl_unblock_bh = qemu_bh_new(qemu_spice_gl_unblock_bh, ssd); ssd->gl_unblock_timer = timer_new_ms(QEMU_CLOCK_REALTIME, qemu_spice_gl_block_timer, ssd); + ssd->gls = console_gl_init_context(); + ssd->have_surface = false; + ssd->have_scanout = false; } #endif ssd->dcl.con = con; From d9d2663c336b4ff7af9528f2cd3736791f4c0da5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Thu, 22 Sep 2016 11:13:08 +0100 Subject: [PATCH 399/723] ui/vnc-enc-tight: remove switch and have single return MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When enabling the sanitizer build it will complain about control reaching a non-void function. Normally the compiler should detect that there is only one possible exit given a static VNC_SERVER_FB_BYTES. As we always expect a static VNC_SERVER_FB_BYTES I've added a compile time assert and just called the sub-function directly. Signed-off-by: Alex Bennée Reviewed-by: Marc-André Lureau Signed-off-by: Gerd Hoffmann --- ui/vnc-enc-tight.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ui/vnc-enc-tight.c b/ui/vnc-enc-tight.c index 49df85e7632..1e53b1cf847 100644 --- a/ui/vnc-enc-tight.c +++ b/ui/vnc-enc-tight.c @@ -707,10 +707,8 @@ check_solid_tile32(VncState *vs, int x, int y, int w, int h, static bool check_solid_tile(VncState *vs, int x, int y, int w, int h, uint32_t* color, bool samecolor) { - switch (VNC_SERVER_FB_BYTES) { - case 4: - return check_solid_tile32(vs, x, y, w, h, color, samecolor); - } + QEMU_BUILD_BUG_ON(VNC_SERVER_FB_BYTES != 4); + return check_solid_tile32(vs, x, y, w, h, color, samecolor); } static void find_best_solid_area(VncState *vs, int x, int y, int w, int h, From 205e5de4251f4c18e1f17f2e7aaa42ff92c3e05f Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Wed, 24 Aug 2016 12:46:34 +0200 Subject: [PATCH 400/723] s390x/pci: re-arrange variable declarations Pull mr variable declarations at the top of the functions instead of mixing them up with the code. This is in preparation for followup patches. Signed-off-by: Pierre Morel Reviewed-by: Cornelia Huck Signed-off-by: Christian Borntraeger --- hw/s390x/s390-pci-inst.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index f069b110b49..80a51049cad 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -315,6 +315,7 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) S390PCIBusDevice *pbdev; uint64_t offset; uint64_t data; + MemoryRegion *mr; uint8_t len; uint32_t fh; uint8_t pcias; @@ -363,7 +364,7 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) program_interrupt(env, PGM_OPERAND, 4); return 0; } - MemoryRegion *mr = pbdev->pdev->io_regions[pcias].memory; + mr = pbdev->pdev->io_regions[pcias].memory; memory_region_dispatch_read(mr, offset, &data, len, MEMTXATTRS_UNSPECIFIED); } else if (pcias == 15) { @@ -442,6 +443,7 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) CPUS390XState *env = &cpu->env; uint64_t offset, data; S390PCIBusDevice *pbdev; + MemoryRegion *mr; uint8_t len; uint32_t fh; uint8_t pcias; @@ -491,7 +493,7 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) program_interrupt(env, PGM_OPERAND, 4); return 0; } - MemoryRegion *mr; + if (trap_msix(pbdev, offset, pcias)) { offset = offset - pbdev->msix.table_offset; mr = &pbdev->pdev->msix_table_mmio; From 8f95595072c3d91645c21d27cd02dd0b8d920f77 Mon Sep 17 00:00:00 2001 From: Yi Min Zhao Date: Tue, 6 Sep 2016 14:00:44 +0800 Subject: [PATCH 401/723] s390x/pci: assign msix io region for each pci device For efficiency we now assign one msix io region for each pci device and provide it with the pointer to the zPCI device as opaque parameter. In addition, we remove msix address space and add msix io region as a subregion to the root memory region of pci device. Signed-off-by: Yi Min Zhao Reviewed-by: Pierre Morel Signed-off-by: Christian Borntraeger --- hw/s390x/s390-pci-bus.c | 37 ++++++++++++++++++++++++++----------- hw/s390x/s390-pci-bus.h | 4 ++-- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index ac8f06d9e7a..fe5fc4eb16b 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -383,7 +383,6 @@ static IOMMUTLBEntry s390_translate_iommu(MemoryRegion *iommu, hwaddr addr, uint64_t pte; uint32_t flags; S390PCIBusDevice *pbdev = container_of(iommu, S390PCIBusDevice, iommu_mr); - S390pciState *s; IOMMUTLBEntry ret = { .target_as = &address_space_memory, .iova = 0, @@ -405,12 +404,10 @@ static IOMMUTLBEntry s390_translate_iommu(MemoryRegion *iommu, hwaddr addr, DPRINTF("iommu trans addr 0x%" PRIx64 "\n", addr); - s = S390_PCI_HOST_BRIDGE(pci_device_root_bus(pbdev->pdev)->qbus.parent); /* s390 does not have an APIC mapped to main storage so we use * a separate AddressSpace only for msix notifications */ if (addr == ZPCI_MSI_ADDR) { - ret.target_as = &s->msix_notify_as; ret.iova = addr; ret.translated_addr = addr; ret.addr_mask = 0xfff; @@ -476,7 +473,7 @@ static uint8_t set_ind_atomic(uint64_t ind_loc, uint8_t to_be_set) static void s390_msi_ctrl_write(void *opaque, hwaddr addr, uint64_t data, unsigned int size) { - S390PCIBusDevice *pbdev; + S390PCIBusDevice *pbdev = opaque; uint32_t io_int_word; uint32_t idx = data >> ZPCI_MSI_VEC_BITS; uint32_t vec = data & ZPCI_MSI_VEC_MASK; @@ -486,7 +483,6 @@ static void s390_msi_ctrl_write(void *opaque, hwaddr addr, uint64_t data, DPRINTF("write_msix data 0x%" PRIx64 " idx %d vec 0x%x\n", data, idx, vec); - pbdev = s390_pci_find_dev_by_idx(idx); if (!pbdev) { e |= (vec << ERR_EVENT_MVN_OFFSET); s390_pci_generate_error_event(ERR_EVENT_NOMSI, idx, 0, addr, e); @@ -548,10 +544,6 @@ static void s390_pcihost_init_as(S390pciState *s) s->iommu[i] = iommu; } - - memory_region_init_io(&s->msix_notify_mr, OBJECT(s), - &s390_msi_ctrl_ops, s, "msix-s390", UINT64_MAX); - address_space_init(&s->msix_notify_as, &s->msix_notify_mr, "msix-pci"); } static int s390_pcihost_init(SysBusDevice *dev) @@ -581,7 +573,7 @@ static int s390_pcihost_init(SysBusDevice *dev) return 0; } -static int s390_pcihost_setup_msix(S390PCIBusDevice *pbdev) +static int s390_pci_setup_msix(S390PCIBusDevice *pbdev) { uint8_t pos; uint16_t ctrl; @@ -609,6 +601,26 @@ static int s390_pcihost_setup_msix(S390PCIBusDevice *pbdev) return 0; } +static void s390_pci_msix_init(S390PCIBusDevice *pbdev) +{ + char *name; + + name = g_strdup_printf("msix-s390-%04x", pbdev->uid); + + memory_region_init_io(&pbdev->msix_notify_mr, OBJECT(pbdev), + &s390_msi_ctrl_ops, pbdev, name, PAGE_SIZE); + memory_region_add_subregion(&pbdev->iommu->mr, ZPCI_MSI_ADDR, + &pbdev->msix_notify_mr); + + g_free(name); +} + +static void s390_pci_msix_free(S390PCIBusDevice *pbdev) +{ + memory_region_del_subregion(&pbdev->iommu->mr, &pbdev->msix_notify_mr); + object_unparent(OBJECT(&pbdev->msix_notify_mr)); +} + static S390PCIBusDevice *s390_pci_device_new(const char *target) { DeviceState *dev = NULL; @@ -662,7 +674,9 @@ static void s390_pcihost_hot_plug(HotplugHandler *hotplug_dev, pbdev->pdev = pdev; pbdev->iommu = s->iommu[PCI_SLOT(pdev->devfn)]; pbdev->state = ZPCI_FS_STANDBY; - s390_pcihost_setup_msix(pbdev); + + s390_pci_msix_init(pbdev); + s390_pci_setup_msix(pbdev); if (dev->hotplugged) { s390_pci_generate_plug_event(HP_EVENT_RESERVED_TO_STANDBY, @@ -749,6 +763,7 @@ static void s390_pcihost_hot_unplug(HotplugHandler *hotplug_dev, s390_pci_generate_plug_event(HP_EVENT_STANDBY_TO_RESERVED, pbdev->fh, pbdev->fid); object_unparent(OBJECT(pci_dev)); + s390_pci_msix_free(pbdev); pbdev->pdev = NULL; pbdev->state = ZPCI_FS_RESERVED; out: diff --git a/hw/s390x/s390-pci-bus.h b/hw/s390x/s390-pci-bus.h index 4f564e02f2a..7f2701301e1 100644 --- a/hw/s390x/s390-pci-bus.h +++ b/hw/s390x/s390-pci-bus.h @@ -82,6 +82,7 @@ #define ZPCI_EDMA_ADDR 0x1ffffffffffffffULL #define PAGE_SHIFT 12 +#define PAGE_SIZE (1 << PAGE_SHIFT) #define PAGE_MASK (~(PAGE_SIZE-1)) #define PAGE_DEFAULT_ACC 0 #define PAGE_DEFAULT_KEY (PAGE_DEFAULT_ACC << 4) @@ -283,6 +284,7 @@ typedef struct S390PCIBusDevice { AdapterRoutes routes; S390PCIIOMMU *iommu; MemoryRegion iommu_mr; + MemoryRegion msix_notify_mr; IndAddr *summary_ind; IndAddr *indicator; QEMUTimer *release_timer; @@ -297,8 +299,6 @@ typedef struct S390pciState { S390PCIBus *bus; S390PCIBusDevice *pbdev[PCI_SLOT_MAX]; S390PCIIOMMU *iommu[PCI_SLOT_MAX]; - AddressSpace msix_notify_as; - MemoryRegion msix_notify_mr; QTAILQ_HEAD(, SeiContainer) pending_sei; } S390pciState; From bfcec59a23f42dcac18a434bd48bd60d6fc0e563 Mon Sep 17 00:00:00 2001 From: Yi Min Zhao Date: Tue, 6 Sep 2016 14:01:29 +0800 Subject: [PATCH 402/723] s390x/pci: code cleanup Now that each S390 PCI device uses an IO region as MSIX region. The code in s390_translate_iommu() will never be triggered. Let's remove it. Signed-off-by: Yi Min Zhao Reviewed-by: Pierre Morel Signed-off-by: Christian Borntraeger --- hw/s390x/s390-pci-bus.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index fe5fc4eb16b..b7f8bca1fd0 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -404,17 +404,6 @@ static IOMMUTLBEntry s390_translate_iommu(MemoryRegion *iommu, hwaddr addr, DPRINTF("iommu trans addr 0x%" PRIx64 "\n", addr); - /* s390 does not have an APIC mapped to main storage so we use - * a separate AddressSpace only for msix notifications - */ - if (addr == ZPCI_MSI_ADDR) { - ret.iova = addr; - ret.translated_addr = addr; - ret.addr_mask = 0xfff; - ret.perm = IOMMU_RW; - return ret; - } - if (addr < pbdev->pba || addr > pbdev->pal) { return ret; } From f9530c32420fff941b7bc8bb5d90310eecab5a96 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Mon, 19 Sep 2016 13:39:42 +0200 Subject: [PATCH 403/723] s390x/kvm: Fix potential deadlock in sigp handling If two VCPUs exit at the same time and target each other with a sigp, both could run into a deadlock as run_on_cpu on CPU0 will free the BQL when starting the CPU1 target routine. CPU1 will run its sigp initiater for CPU0 before handling the run_on_cpu requests, thus resulting in a dead lock. As all qemu SIGPs are slow path anway we can use a big sigp lock and allow only one SIGP for the guest at a time. We will return condition code 2 (BUSY) on contention to the guest. Reported-by: Paolo Bonzini Reviewed-by: Cornelia Huck Signed-off-by: Christian Borntraeger --- target-s390x/kvm.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 4b847a3be48..a95d3da0f81 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -132,6 +132,8 @@ const KVMCapabilityInfo kvm_arch_required_capabilities[] = { KVM_CAP_LAST_INFO }; +static QemuMutex qemu_sigp_mutex; + static int cap_sync_regs; static int cap_async_pf; static int cap_mem_op; @@ -287,6 +289,8 @@ int kvm_arch_init(MachineState *ms, KVMState *s) } } + qemu_mutex_init(&qemu_sigp_mutex); + return 0; } @@ -1774,6 +1778,11 @@ static int handle_sigp(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1) status_reg = &env->regs[r1]; param = (r1 % 2) ? env->regs[r1] : env->regs[r1 + 1]; + if (qemu_mutex_trylock(&qemu_sigp_mutex)) { + ret = SIGP_CC_BUSY; + goto out; + } + switch (order) { case SIGP_SET_ARCH: ret = sigp_set_architecture(cpu, param, status_reg); @@ -1783,7 +1792,9 @@ static int handle_sigp(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1) dst_cpu = s390_cpu_addr2state(env->regs[r3]); ret = handle_sigp_single_dst(dst_cpu, order, param, status_reg); } + qemu_mutex_unlock(&qemu_sigp_mutex); +out: trace_kvm_sigp_finished(order, CPU(cpu)->cpu_index, dst_cpu ? CPU(dst_cpu)->cpu_index : -1, ret); From 9c9f5f311a4b391c2dba57cf06b63d62b790e891 Mon Sep 17 00:00:00 2001 From: Dong Jia Shi Date: Thu, 22 Sep 2016 10:36:39 +0200 Subject: [PATCH 404/723] pc-bios/s390-ccw: enable subchannel for IPL I/O devices IPL should cause the IPL I/O device to become enabled. So when handling the IPL program, we should set the E (Enable) bit. However, virtio-ccw does not know whether it's dealing with an IPL device or not. Since trying to perform I/O on a disabled device doesn't make any sense, let's just always enable it. At the same time we can remove the SCSW_FCTL_START_FUNC flag as it is ignored for msch anyway and did not enable the device as intended. Reported-by: Farhan Ali Signed-off-by: Dong Jia Shi Reviewed-by: Cornelia Huck Reviewed-by: Sascha Silbe Signed-off-by: Halil Pasic [remove superfluous flag] Signed-off-by: Christian Borntraeger --- pc-bios/s390-ccw/virtio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c index 1d34e8c1aad..b3337349558 100644 --- a/pc-bios/s390-ccw/virtio.c +++ b/pc-bios/s390-ccw/virtio.c @@ -97,7 +97,8 @@ static int run_ccw(VDev *vdev, int cmd, void *ptr, int len) /* start command processing */ stsch_err(vdev->schid, &schib); - schib.scsw.ctrl = SCSW_FCTL_START_FUNC; + /* enable the subchannel for IPL device */ + schib.pmcw.ena = 1; msch(vdev->schid, &schib); /* start subchannel command */ From 6b5ffb14b78f8bb4835d0cd8e3d2826720acfa43 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Tue, 27 Sep 2016 13:41:21 +0200 Subject: [PATCH 405/723] pc-bios/s390-ccw.img: rebuild image Contains: - pc-bios/s390-ccw: enable subchannel for IPL I/O devices Signed-off-by: Christian Borntraeger --- pc-bios/s390-ccw.img | Bin 26440 -> 26392 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/pc-bios/s390-ccw.img b/pc-bios/s390-ccw.img index 089f6ba5e924c17796cccac4ecbfa7a78b00ba22..cf05bf0be2299ec6512375ef4b38179f22558ddc 100644 GIT binary patch literal 26392 zcmeHwdwf*Ywf~++GD8x=$&(2noPj9e6(@iQsAVP(Od!BOf(EOFKn9W$GBKGbP+Ozs zwrI76XuN%RbyV$Jf%-(13wbx$nz4qRRaBW5PQmfS>;vbvHN8M;h2^;NRS#CVerB^HzV}w^^2?fuo z_@>Byw8_t?(sD{Ro278#*@mxOwp$mTxfJ7Md%PsN=xferbdN4-`(%q*5}7=XXvJr} zEJScrX=6ZPeRh}Z;72R!|BrE|{LGU1Bi>B@DkVPas8STl_IPP;2>r#M7`LoT_Kz+t z*T{CW6f|x%+8na|EB`7Ow+7G#onIywlP|LrmUEk%HlEwuuwZ_1d$72K=OY}s_}VUB zxmG-L{<{aRsQvM4Z=U$^Coep$6`e?F{|7@!y^~A{S?U<7sD6?+wJ{xkJ6chCO;7Y! zlj^QKe$9`6G#2gu^aDdO__p;Y0a~CvV{98M(&)>@Lnha4a}7Q7lQZ5fM!*+j#o;{$ z3Tu~GA84o#)rJKD>iY|X@HqYEm-J!Q1^HTm5L%H) zjS4*4Z?M{&+7w~Yy2KK+ioOV7oW5{ukE=&>30s{S5xE6>&(S}*Q4v}B*?uJ=v_-mp z&@N^YR`EghR4pVLTm{+$VX0O6h0Bd`dTzEhS=h9Y{>MI5h)MS{9Y5y!U0m;>`jmU9 zZdn*rh!)`77gdxD(T%ZIP_zQ24(wY9YTR{|p2%dc$K3_|7Qf=|#PcLPe;?x})_Ec> zzsJ3c=s)iPw7BcM5dm!5MEBmM`X@vgbC4VLs4ZeQ@!?ZrdkC}W1`l2OFNs%r&bfwu zvn!}ooJ;le-!bKvGxXb0B?7FNy@jyyj6uRpGtyl7xqBA~#(pqY%%hoj+!fl8{xain z^7B(%&!hU-bgrMp^%Sa4$z_;d^u>gw*MpIHeF`X@zJI?W21HDVv+uCRQn_|6_hdyC z%j3{IK@}cxSR#txdVXTW?Vp991npX%BB=l6^KQ-x=jM@-Vb0c+?Inc6pW z9c9{XOMeP9o25Mg+q+*sLADq54l1yMTrm~19v61U5Xm6>3f9iwv#-|5g)^%3r;6PL z<6&8U#u&>N$2j;yywBfLrzpa&h{s_uR6gk#9(X_2D)}MY8LRsKqU-uvZ3rQRKT!p- zJD)UAz4u7E5UOwtQpdobVvR|17%$%9k-wvPs=JS*li2$d;Cjd3FPxamPBnQyUQ`Lg z57#RF8Cszp%g(~cY6D}1@48k8S={6ez^(TAF~9bduamGZHn7i%w#LGuFsk}57L(at zetR%qOpSAKD{+t+W)3Q&Dq!u*#|^y}Re-9?STmPOsz@`#|5N7c7CbY}7v%Z6^cN8o zAsOwb!b132LiLQhjd7>AW`LV(2-^gXz3G#=zJXxUT~t47I$6%}(+s(VdvmyV4A;NK zbsIxwGvv>c=$*y%hV%z}t%?Pby1#d=G8w*bZ|{T36qI)z%2BK+e@eQkDeT)I#HCr# z&UZ+DXGOH1izRs4-@B`oxE`l{N2r>nf66nLC2=1F)c9V}3Ln+q2To{CABd{0PBEGI zH+jD#>g#OfXf~GCfi96tm6VK@!NjOSTCG%Dt$sCjII48Q2>eRy(WugjDByDMg15p0ocY-lf$(HS zZ=b34HMg6#JNCXL>Ntw0tzk;vVd|=xx^EJ7pMSt}+7UVK?Zb47+emVYukCBa@6Fl+ z6h~S`v@?cSOHn1-9eY3&`azjr=@y{*z`+S(AMCeF1mSbW+9LL7lbs~-F#Omm?CZR- zN3|}?&I#Fwc8jAP;&NafV)9sjPPeGb=@b*Q{rKH&jTB(iUE0IK0r+pg5*`qCZ6Q|h z2cd;rF+oZQeokXcRN?o5Iu+E}=}Gb;dqLa2x~y&iA9HGl^@oUO*XzXpn3q@H&xO3^!kQN&CqP*@7ja?nDKR0( zpWP`aj_B8F4riG^a-lcgxys( zaoS~w5RmEuXncOu<3ZoVX%otzO_DzP{B94$wk0fSH*-Cn>o0LVizTg+1WrH3Gl%s5 z;{Nx!-%_W<4wGHGO4!alu=AX#H`XU|2TG8j1$G=A{&Ob3e ztW~JLLG=kIdA@6-sB^}ZjTIGZ2CU3+a6BR!QFHU&Vqr-{gVSA%rIWE7fK7nELsOJV zT4?wcQ<}AZM09Y8e0WGI!KMF|b=C!6Pn9+b2|j_$39=*a&~MQuICSvEnU8A=`7PuB zJ|y-pSa0L&(Zm_rXYUL0KmS8M&mgS3l~z~cw}IxcY&vS|cMg(war7DA%y>33%|GD! z<;?k3=FQqG2JIL%-v>T?or5adcp;u%K`nwcMClxFWS}8&l2!>~%7v?2mwVwxknfS+TxS#bYVUL9*P$G58tnNjpU10Ew3QJCtEU25u=e>@`$g}Aep*2lxq|8+G9Ejmf45KZ zDpF^l`I}LX7ugCZ7d-cVwC&fkRFpc4!fL}bxaGYg1QW=h; zg+oxiU>w8U54c;B{i0wm@-#oK^Q%;{xM+k{B53D=WZNUFS;d&sUQR@Zyx$WYsr@|H z#aw@p>aI6={e?c~Y6h^io~ar%}k z@L(@_@Lcxb>G~lpA{k!+UdgGPP`{`LntHZKiw&Q?3lmO4ty5 z_5`BSRJI~y_Me<(&>c~*Bcics57nyu&b(P#xn3gsdWB+#l=y_hageyx7f2m2{vuGx z(I)L#sabtGWR=4*ox{{jqk7(}TtAB`1C_dd>RG^Xgvu@8zHtn9C)YXuAMawgN8s)E zkxu{~t0DY8ey%fqANf5|pcV6;dUMZ`*q)x^*xsJB*!?{srlB2i&ceAy-T}gG{{zp% zG~17oSFA|I4vtQ7cEcxEiSArCMtL!62Fed0=OLVJ*nxTP-ig9fs>JrtX$j7S9$S#dOlVKUH|x3(Mb1qWyEpJNkp8SG#g9SVU|%n*WaPv(;t74?`&jx823kl&3%UJ$C(PmZs7PHENf%W+}IwJERo#1VRHin zk^LKneuhV$;QFt4Bw{N@)?-9B!#&1*zht=opze6|52D%f^aNM9+>wYdEoM?|I`ETCmwQGU)H0h2U>ak&*7EZ`XX9+W&G?F*b;Id zXe=h|GS|ss?OGpaNu@A7`?(Igf~4x8Y4(n+hq-SL_bui6U0nYq!<7T>DtgZPDfh7z z<&Nk2O$_%FhNJV&iz(_M?#0i?@-CutDT-aW4M)z2-GlQ@$R(x6m95Rh5uVzgs}+h> zh*Hl+ML$9w_<08_3Y~tG4D1t2MB2gcV~w$kQf+|GuYVB@1FrMn7_4k##4_GbrVW$} zD+Sp##0h1YKzpQTMhTQ*iX#KIF6)R((*v&*qA^ke662w01;61MRqu-6T z>>l-mpxI~_0Lt#^3k$KV3O!FS&kAZY&t&h*&Nm}niacLm0Q*pogLR2Y2@lKqMZ)@) zO);%6<@aoTi|YVQx#6bCdO8U710XGm7sJ2>tt%RU!oP$iH^m>9R3?~Tg32# zEEVZ-kH~XYI#C?r>@VkEsdwlQj|wOC@;Yt1f$2EH@>;~$cA}+AKMomlo;L1trg1v; zi5O$yxG4Tg_3Td=d$++sNWX_$KV|4Q(CUm}?<-bC)v$t`nz*$Re$hhms60(@cFuRi z>bMkmbr=Uv$BeA!oNTV|W88f_ql~04`KE^X)}iuU#`hY0!mS+^mmGEU3y*?%RulB8 zTyRs%<2c{UMivH{oQKvKjPoJJe;wBmIWX^cxPBAYI{?Rgjk}tkw{ahPl-R=cs~F!{ zz_I;}V?By>+{c;{HC*3FaR2xOCpwS@ps%IYan+2qlp!>(U&!_44E+vc1x?mBP(!u{ z${Vo44Rg41P(;oNf2bYl9cs|2TCnKX0bM6bs$dW7HF zGr^yRGM)QU(dwjCqA?q10CXyLSj;N3siM^8m8TT>`lod`2LdH|phVrJib+fX-%@<= zB4%a$TL!#1y&(K(Nu@dP?4)@hi?`8cL3xxU5sk&RgMN~R8-6K#IO9CFK87_5_d@4+ z=w3*{>CYrS3p&*+Vn2sn;+6t?Se&q7*!2f(xCffbaT_;6(b(X2#HV4c2+?#%KQ-_R zx;N2QTWAO5ibhmKuV@(R%f}g$RqWQr;H>Zmh~zjw8&D{cR|+-NYl&bFs@idamL=@i zV_-LhaU~H!=RQg89%}ddJWf~M-toga?hNtl@+HG~eV&Xuk7|#4sShhnj>PFL@n$B& zp^j7PN{^CBXOysk%sR|OI`mVy8Zrxs^r%W4R4S^Kdb}u^LvSqZO5VefJ!F5E@~8bN zu`o`La55wJC6H8x$bf~c=?e=neHPX_AD-wu;L3sPMK;cwIw2nCp(%)LhsAc@Tl^Td z>C}}p3$38V>rpc%?8aGuS4$I?bpqJ-VC|!GB7fM) zr(4Lsv8R9z))CH-{u;6s8%7sFHy-~&ksE~v;O4n71*d4J72Y63In7O2f!oAeuD?z_ z**}4Nrc(q7tB8d6Fz37Arx@guyAI&h@w(xtZ<uv_*G} zC&;1<`Es5?c@?DV;$2{&=G1lQN*qg%JrH}q7l}RU3h$pEA=?e_3X4g1bjA+upUcmY zT@f(}5GPAv=h_qc<9=^!5Bh)UkHjK9ow0|#{@A@PkIx%>VE;UC{8luZcK6OYRmCcV zm9)_{7nDuIDp!a6>k+yqlecpYM;}c49Is=zPeFNMR8{7QZlYb@OOjn=?MSiqKlf@%~}2aEFQ>Ve}L!g2vJ~ zv}TyCB2U(s(!vpxDF$VbpY#OBFz9O_pKuIEJz15ao9Mk!^{}6i^vv@ISVko@d>dgc z`~!2>nEb05XGHo-z`*druYnt|U0SVK?deuq2|bN)NN_u|X9ar#*U zIEfJ%1#U<;U7NuYg&)ZrQfBUB>jr)$RFSdw0OHsav}4BE`di?Scw7!lI0J;7CTVVd zuVySg4G%&Fvv5*JZ+FZAU9VHD8P`jF?{CHP`%D+V|3GnO+zO(OEMVFx$`RpnbgR!1 z$?(uD!$Zd#a-q0G5trY4a18C81KQOrujq`bK!~U=En3EfWJsp(o=b5$C;Jow2krQf zqf8-KM?Vk-Ai-pf?Z#H~3++|*up%$Ls^RkF%(qFHPwU%L>iWr5*; zbJ_nw*t5aY5DjzA%%9=i#C-{K*lBQfy>Lqz@EaJE+hj-%07)l(11M=XMQ>NQQAS}8 zN$;ybb8?@OMcnB(nvs+wG4MV|ca{f6lQo)B=bm_c_2WH=YgjG?BXo9_p)=*E%`aG5 zxxk}iors@ebCeY$Tgud|(vdA}#+(OdR?|FF|MC^)Suzp_X8z(lWg}taJR{}v`45c< za1liSvg4`uL&90e-w>sY2sOosQ1Bt#jIo@g^c+J`zq=JXfhx`&eTEF};_Re;&p+!o zJo{Pbjn`H3m$5IK{xWq#p9d6mz|Zz!t(vVBSg^(*hd1sC5pe`%=~Ek!rT>|!zk)RV z*`v%A@?&nh=%^)9(oeRT58m7c2fUIxhA5AU>)tKbSMa4W|8gIjDmAS~DXW8({fYfM ze&0Hl@`%bFd+a{iA5Km6s}VlC)_+2=&hjzM;8*sQbL{>r40=@H?Hk=KC-pi4L zL*CTl{%`p%pXGNbXc?Yrv=DG=3rt%n$&7Up8d?E42LsKHiSS{&v zR(Rzv@CJ*}8gUQOiqq&$tO!Hm+DavMzgLMJpu2K;*NVvdDBce#fu!+Oo9ahKs<=d9oj(>qhT{~SITgNnsvWzCa@_Kt zr(J-PqfWZ*M_O1&nKANVIfgQ0D@LoZkA;-ybGv*ZC@Wi=svzH`tQucCa-!Kxo!vhZ z9=A@=c~B*!zvp-$vfO0W#SmuG3ufej8}*rn^7VjCVuq zQGEB1Jn+3ASm`9}Vql%ivYpRZe@MF21JvSpjap9e{a?mmt{e#Unv)ibW+`W=jWFXO%txcMH; z(PMJPFkK9PJJ-L*@V790p_Br1U#{Ok>pC*(`!GM>w5m8M#r$UxZ-P%Pa2rg#UC#LU zRN&Mlj4wd#1E&*qs`f}b6}4=qAyI}^BiCIX$K+#7=QF0QT<1B{yo~7>pp|``e-kF5xvi(COWRwpSxVyMe_gm#7=oI~N1{eS59 z^gOZ>o&DzYce&1frXIqM#@!>JIpdy`pg*k}i49t{K%>|LvW8(%(D2akc{G3OfAK7Q z{+G_@G#~#5wU1#-8Th6)^!XRc@9r> zieN>Vx_`a!B%KK0t%Rsjh#e%qD?uj#Sp#nKBp`kU@EOOgU(z`M#o6?u*!fx()q>-B zu=po>1boD}vyKYYhIcLmg6-J7PK%%&INlz^ewc3lG~h<0Dc_rd_0G-fUAAyxZN84^ z2qV=6zFci0eBX+lD&Af#b9+RoJDfvpcsJuy@NHT6HfE+9>JfbR=$0Gh6hfE2Z#^sM)%GVUYRpswJXBO^L5Cohx7vjx5m5%pLjoWIED!KIGz>o zeJggWeN5x^h}f2e|3Gnypa-n z9?@fw7>C&Ap+3Cdc3c#qZwx#n4LA1pXj$SJ+}Ib8hMjNYeUcNv;Xk5=Fn78 zRvyy`V#=$fUXKG%CxN#LTz3i|^`VvCHn&0opD>jQ?idOY*)0o8InLu9tf;3OZ-6sr zILpEQu&~zCpNp@8b(`+^zQcVvQDqRCky!9PExiFld#dkf_i%1|H*CBUzI5v#$#qE5 z7xfZu#OG^s=Ywt`I+Emy-Mmp4RHjD9iX^EQmmxNu}6fG5rZFgXHrgYj+K2F zJ2vX?c2Q4v0W7VTCF5tPwcy*YTzj=Rtcf3)+d^M~(33cDbqT--uD4jZGJ>U$7dd4Kfbah&@C6fhJmKB94s z6Xf6TU0oKAq_O0TRl)uOwSRah3Ey!8-#&Pi#24W=^hV-)TuPkwH1AcDEu>*jG5j8J zU=PERo#eI1k2v3;%m`Rt!q-U*-yF##7y8vov0WNjF?ZU>vuN-;&y!h1K%6)y%#&6TeK#DTQ{s0 zO;}CCqVU+5*n!vqM5uXKVV|cMiSi|s%_xu4o(XlVim^9QpMyHRd-^xjp8~Iz^A*&N z`1@lg>0Mbr-WP?(VvY7jVow1-yr-uqM(@(~u~%Cb{3p&^;h&&pna>|P;Pc>pIOt~# zub}$YUeTWpPE%2)LBISa`52sKV>kMtk;iTz2@I+v0aLyd7sp(oefIfrij50SM8j^Z z+?ZoOZb&+T$5W@cclnjDy;5~|d0`!u%D(S=m9SNFBeI2Ttxx6bTd5V=x{lhy_I-ZT z=$#tNf_p$YVg}a($i+_KIU?{D-Cz-Fh)mj$#m&7p8<6nv`7dz`-M3m6ER!Q33vkWj zx=9w=F3#-;AFzPZ9&ab8Y2vfZOK}o+3UjG|l;>MG*%++EDC`%AdYt|svx?Da&^*67 z=s}4Spuzbln^AgE+L#`k=M0v^pNeQKjT!W#&x*2^>9T7xtcZ&^fx`@>x1Mn9RF5_G zDJWWwxb`?~i?qWQGkm8U6IB$%T%2elPU2kv(o^+-OJL2x$uM^AfI1Fd{WA8BxyGjs z&OVYih!Y&jrR+Ol)z0V%<_)Lph$8hIMd*~5;_E4|C`*lwn<(gH%8L7U+Qd&|;Zy!+V_ANm%JD-iFKv?~Pa=rZahg z-644pox7?y#kEonXPGxZIWMwjjHlCVEgx|7ROoWixph?Cw-R~xb(D$cW#cX5X*}<3 zH1E3=$koRq4{;heyYv%~=IzKJv5w+>(=36T)@W8Y{+$C^B-zS&=i_}+8@(4ciQYEC zJjYVV0**`>Eb0`-?jsdg&d1D%6|fWfw<(tM_+6^chCmxMMbQEGNr@ZzCSDopU^L{FS)-?3c)ykZl3l zGVd7PBFZ%~>xXE({b_>v;5Mo|aLWGpiuvT$seuz6xX0TuAEdBs_-t-aXW3*D=D+O4I{I|&2FSBT zq{3RB!86`jh9J8kWd%}B0se`-tC78j^eZScqV+em7jhgI^?5AF<7$1raMn|+y>xF_ zO*Lk1eD4;n8e=X&w;~;C8;B9$Zq1wUF1q!>2pB{aZYqPdifBw+H8N`-R*--B>3NpKgKV9)s0Vq(saF zjkiEoP8r+q)Wd0zqq?a*G^e4dEwCvRXi%&C)oM#Hq_%gowg%g%Wk(?7P7`TvRjdrE zS2eYTnu2OW;Hsug0d;e*1OMKX+v}T~vJ26e5t!Z-; zb)TtsQ?R4CfwjId8FVyn38d~MohM6I3JPK=t8XDAVnsAUX94I3vfW9Fg~XdSsZA}a z(NPMO%BmXL(Ham8#HP|7*s=`@P&cy$;op(91zWbLQYBZ_H+KXGXGL8_nQW6IB`}#A z&tB?ZQ=`_0RL}OyMty|vl+2ws|GWj~FI-f=aZ^KJvlv15iqbVBo=eG$R@AquHEeQ% zG4mWIeH+2arpAtzt?I_+;HIr=J4BCLGNNEpuqD*g(!r{hgc*Z21sej!pb@y%wrp() zUfrTf`!<+n`6OnkC|h2x);Bb?iLwiqqmcYj4^@8Y2-@0n*R}Ys#1r*W|vMaHc zQ9NO;xkfiBTcRsT*qn(B$df>ezrx%jz(IY>9G1EfAoe`!z&}Q@|&tmEr@*}mJLH~2b+V&=R6LZtPsWE_PT9l-Q zne>@4Tjh9cpaxe`ZxlpibQ$IA#=HjZnzEWI7%<_6Eg`O7>RYq2YURa?fz`Bcc$wN< zza!WYGHrLZTHoH@v5kl`tyyZ)-xh?yZc}S1JPT3L)&@HwryZjD)~;GpRl7>9@mG{pEv+i^)mE)qnS@4G zi~m1AYSQ=%i)LMOPW;(jICI7Y#dFS$H_SeJ{Wq4xpEfL>=AC}g)M6Qow=^~xJ>TBi zysahJdS#ml*&gb+>gw$~cAC$lN?&PNdBxI;E31t5Wy`BqtX$<^y~c#Asa<=?rFH8r zlh27&Kt7A@_?H{>xymS|SmfWyK)r0@AFn@lVE!M>5<3bBA@n7(0u3bed=cuTR{D%6 z7tWQ9^0!kK7JV2M72gf`(#Hb7fjN_%b6S#QiIjg-ox4h9PZ0hJ@~TAMHX>D{co|>i zw*<@(X_z!tr_D`UI@*j(tYsg)sZd%1cM}jKI{ssl7>hE##FX zruwUpKd|gbVCLsqR1AG_6Zs!~$Uk*_sXzHc{ZsIzlKU2eTN$&3XhGh{g!5lynT;f} z4H0UISPZ?jw+4wNK^iP7@nA=3a8C3trq=b_>RWb*)fFq&s%7PK)~s5g(uc6N%-I=e z3nD*2K85w7EpR156_Rox@aJBj#%XF})0Rg3yOgynjcQwf(ss4EqorMN{6%<@sTj8d zu$`!-Qm(^{CppR^b*YEal87`TABiuic`=mU(YhE5zFJeUvZg|1=8fE-YUS#+RcqEI z_{X9TZL$=QjJMWrY6|T*6Sg?Lh{0#*Z)&-+qX|9Cn;|W8uR(V7MfzC6@fjB*6Eq@f zyuj;z6Kxm3)wV;o#kgZZT(;)oPh;GPw%c|6$y$_eqHIQq^V}zIM*oE<_n@prc^c(4 zy8cub%7=9Qa4yWKP}hGw8)bv8|E3V-9$kO=&nW+<>;01uGthtJLX_x#?Io1xKZ!xZUH=pCI37aT zj1qMH3G_LJbp6DIIO)qkiDxJ9zukqh3+DufQT`dHPt<=J=Wc~Kr!2&2{18gu`)dPA z(2KhWF$QysTzrLP=Nf1r(=st*T-XSdrYVkezEiiV|QiTn0`~*569f>yv6aO z)LT=^GyAO8wzS{<_T`s;^WqE7|2i{lDNS$t_46;h_?wqr{_XGZNJANa1Msw>?&22t z1HQyHM*9S@)WjHv0NvtFU4IN`7?ysqbmZL2GEZ@!2Mp1F7K_&1IAIi%x(MSra1QaCo$?<#wa=YgCnhwQ9oLS+7rf*&Kv6*dfKCe$b7)qMH0B zY_l#+BL_)HMdG0 zouM84zgCI%2)^cr;7_Cd1R7x5@z3Rm+y@LNme1f}WUO5+)lDvS_(r9%J5 zX`Y9~(u93+6gQ$Vi={TrT%eNu4|;cGU_AWGe&LtJ$K!~P*BhF^k|zUuUD|WWt6pik zwR&_5Xac{qp1(=_hL~dc1OIV!VclPd$CC-YTc1xOKTc2x8>KwpEzoCuQ7j$38ZXO? z*ld>KIBm?S&C;6Oz)`6hc%c6iotUrr%zX07?vIZ&*jy$9g~7HY9>0(~?RU_(KV8Z8b)v$kIkRIek)PVSPZB@qOE5W1~iHe?0AUuC!^c!>;Pyc5Ht_{xgv3alsj&~$#*6w&CS1gM8EbrG6kY@YW zB+wXKM$zo80&pxGR^o}*VOn|UQ}17F0WWeMcJzI3MyAuFI|HYe;c^g zSG%@`s+ZKLYbt8|+$zMyWo3)iBK!sa8R~h(^NLH3@wobJO`Cu+2xtk5 zKf*7HHwCxR8!KN)(q93HeA?87an@{ID94#){Qspe(V6h{oP)37_re@sDFLlUNoQvx zKK7)ibKv(M8PDc;BR<9B6wXTG7oY@ch7791d4(C5%<&IU2h77L1vxUs6r(>rp5hSk zD*ZX$Z^lEj6lVMbD1Vaq_oBt*$G~sKKeNPbZvuu8nDo>9%kVYv8S&TFPe35cC>KTK zbNtsFPYr&2&GE+k7j;sH5N0{nq)#>{=BMX6d`FG{vj2y}93JPF8t_Kb=)tpcKFVYUS>i_@% literal 26440 zcmeHwdw5jU)%QL#lVnIjIJp2xKsX6e145ht(tuiLa=~yB4kYN%T1iL(NexL%CJ0`m zq!#Thq+n~cHC5nH>LpO>3tCJ3O1)A|K@?h4+Cj_P(ASAli~>2|Z>@dKWD?{1`aJLV z-{(Bf%-(13wbov1?X}ikd+$TIyJ+EDheHwJk5i06-D-%=w%Wb2T=_DWUXdq82(L&I ziFl62H%j)SO@4-yN}p`DOX0?|6JM8XcjOIUiczvXToPaOwa2r%hZf7M@$6D10Ky|) z@mV1YQ9q<~rgDShK&R|rJO}Fk1D>TWTWx~nBiU^EiX}bAkWysH_HgN{47{%o;4L^P z`-hgw9kSgn1>r40Ta0Y~(!VP3mIB)1^NaNIIr)^!Yim|sURyb9W=>OmPA-o}G*a+& zUb|?Sc;UfokLN9T<&zI@``)ag!p!&eTgUyCq2v$EJ$-C`?PrUR|7m_DGJdUj5j02k zhiK6=&$nAqMU>|KzSTx{6J0p6^Jk}z6y@L19(-=R|CVE__L`Icox^=Vkn9y7SA#71 zHx1TdwMSnS(T)*Cf_!e2_9P!t&@S!SIioWI-W_figW#tmh3Utvv*6RkimJ-;K)G14 zVr5g)il#t$V*pKcm7=1)uBmxV)rzKy+J+T1bpg>(URP6Lp*7fi#LEVo-v-SBu-ff$ z8uA9UJ8iHA%YKD~S2`@PTe_@@Y}d3Ra2|D zoa%9(F}Ke#^hrsXd6`ADX$+!GV~j~D27RKwZI%$MmlQFB@yd)d=AW3(YJTqGdVuO9 z=Wv}R8#$Be6Ypi1r(*ci6%wNLH1IRJRPcN0?%k^B5oo;lK}RT>YnO9RVo+7~VulGS z>rjl+sS2)-8Nk?l!N!Q`ho>qn0JT5PA4-ENvOwfTVaM$^!s%YpI)?Yyh!P}k|9L55G_432qLI;xI~+!DYsDf#fxO)GSkGE zA?VvJGGfm3)Q3EB{0T>lbN|)X)gr{hojy;mJE*l-a*R4bzODR#q!{Q~bnO<=8xP!X`qa=TK{eDVvV0=c6%?Tz(CTDy%$FGwK`jIe zHfoe?-zq$*Wn-;45Kvq^<_$ru3_1&TmZb{Up`6e$*mwhYsQ_jdxc7kP>y0$8Xy54( z#+9(FvF3T7H`GO=8ncD_kQ#cqK?HTL5N$o%u=>UaF;SwWU}xy%{0>zVypQsPsu&A^ zI}Q=(Yvw7YdKpPHs*K}8GRc^}g=PFE{QVf$uBX^cGN zMi~#mW>17Vz^yLC&rD+;qVBJRxj(4K!XGkuWJKbgLU1<{JgdIK76CnV2$%0~Ua@88 z2?4k`aHoK~J|4q`_^^RtvVtBR_C!=+H{WEgN0J2@m$TnZf$l*msHp?|xx^BS$E##7 zXscYyBD;lsq#1^Y36Hc0^ycBa38QXjU5uh}VvlgWn(J?{HZEdq%=>S~445xt46iXc z(d|nt6J!PZGDHSE-Qz1O(;{r3)f89@XjNi+OFP2jJj`Pja(xTc#|L@LQLq%)2-hz* z&Lz5oUiiI>t(@WtAk+5H2#mRosibnfk*RbM<^_to9IMlQ!F`pC_aWDBVz?(5?x=C5 zpGQx7fctcY`#)Tt&u~9wxC4Nzka1?f-!964ujj!BRI;>(&SLHq!W?-gd7H>4%YUc` zu?`WQyrruHb~c^#PwUV{9@K8(wR^URDp=AXe7*+d`6XVml32@1&TdiKqM^AFhyi)5 zg+2i-1l2b9!7{Zw-pDe~BqahP-=d@yD4oK$q#@>cMHgLOaIh1-Gc0-^2OEf!pys_+ zOyKBzWZxK($^1VU=Kmt*-v_(dftesFHf~WgiWnvIl)H&ElkT_TV10;q>NPeBCH-Ee zbPLh6sl}gVYEh}#n3D$xGnKQK5kF&H-%J`Cv6<@Q{?58iV8~{M+|Rw=VaOV;-_4MJ zBFOWfMsWBw<}hIH+TuVI$TFYYvP_+TwdPk_cB&ImZreXYb)ftu>HZ<-dz!4e3$(|875&>}3GunfcOWnIKEZ&wf21@Ke$jSypv z$>vF4Vhg-O60r#X^-lRBH^ zcbha`>RGOT%DT9gb^j<9SiKe@GzBdWklAOfWKS~UoSEo(029gp7nriF*vM)v1ouUE7`!Vq>RpFm?+d zyM{tS?mc2mPpGFvawm_7C-~UC5xhLa6jm@Vr@6kIc`=BW&khH{7uHwGzFhlS zcn=e^Z!BUX^`6+4BNRk_M7pjscs?5RbiyM2@G$5%R=Cm&#!bTP&VtR(40g*8ttoA26*anC?wn=S(9NI|9(sf*$gPpyv6SXiH5pE{C22N&{t7 z53ZtopLLR@tMKZ5h-VE#+;yA8>3I%k93wH;&{?peGY>OC6bm5vV>H@btBf=a`6Ht0 zWw2@FkLZ~~yx+B)_=vp;Tn5B;+6BQ%9`1QaAW!oxx9uL#7c<3lqA0U2#cBLr!LG;r zGjt2z3bv?GSiM1Q#Okzr;a!~3jAs9jX8#{^j%8;5Pi6oAbUXM5ZgGpp5p3y35G07W z8FD|szw!Gr#J$LzzDIJ5E@BG2u8fW0dK9&%mJoNJ-YuyGy`C7+hU~8pGU>kA4Jxny zlZD%d$iHQ$PFX~u74F3T@Xp|AJ(=3{e%!89!qF$l;n4fd~56nX%^Kdn6 z@g{ms;fyNkw+z?Ja8FZx>;;CK47m9;3qG$`K{<;c-2cV%kZ){dNyfS&laBYBf^PV#{6@1jatn7LuS+Ldj)V$`8}aM(o-o`VvXEmd=ps!`EC~M z=r=v%*e<1APf`c$y0w2BcBd|~dlYy29>IQ=_nYu}9dhk9a(H*Xy8W8a*7lsxw)WW2_I436(2k5-NhivqLtQYt z&D&`#*L&Q;vDkGisC6%f_F1FI(Y?UPLHQAQ{S>XEKy_P6(zbEJldp!hA|u#Jc|J~* zIG(unan7M*zB#UKz7@Nk=%5cnwiOiWBHz~`*aE+1egd9&tsK3Jxp;)Ef@?ovetyk$ z>`O!x^Qx2IZoY14%mD|S<81a4yt|n!R{CJ_PNvYn)b8W@x2Zm6FKP9Ylg95^Pj^tn zOg`?%4t}}X-4Mq99%C$F>=g_PJitD^MRYgA z_tv6Zi}EJm-WtZef#EM=+;v8e)A9MY8^n1P+y9Et)^K>sJ9DAlt$h`81v%8^_GJubnj+^Nm<&(iP=I!m%F~4U_ zmHJZN!b)|DYDs)D==>vNjAe}dR3C#g1IRiX80`$#!+pD`p7JTzf6X|k1MXtL-PWE< zBlN##otFS|bQ-MK-_-%`{fx7TtU}KDKorNED`X8no=Y$>w-3yDQYT}v{3)CfJLUZU zo<=?UPnzqb4~{rHZd55_&j0<4_1i6?V`Q~qvPZ#R6)mT4+MIzD2o<6J+@SaTR_6<`q`E%`aCbR1{cqYV2N z!%D7o@@QXosDoDI(QGO0KOE}S-H~3+t9$Z`OlcRSoyIj@|C778z8$TX5hv%i!7fwD zE_uhud-=rI8HV?NDT}!NLt73=?1tssVC}oZ=isB8Sr5OW-S?qOLchdW66BBiMXJM? zf+Il)&*Y*r{=Y3nfF#kRQVCrtlf1btqOm6wQSGTXfJ0@KHt5$In@ z^ppQav1QZx@F+Qa9#1`QFDGeRaZWs0I0@tYcKYpiS|=Hg_Tp?ZhW4u99lbvZ!?n}% zg%3Xm2YvvzfkuE;yunb%QQI=qK2p}eGRjCEXJG%tj52uUcWDp0>0*)|TAm!4C1PBu zVfKuu1p^vTTUe`eSpyt56ff6*NMoOQ*5BF2C-v$cn#H!W%R5=(8+qg_u>w0F|7?_Q zaF9u@u7ySp?_Q5FomZJYkL&yg(d=&{t!Dp?dyiRX3Xg_PK~p@pY9wTcxbY;h&QGEU*`1~h%Cd0D- zC;gpa6R5@cA0%VjjlN9im`1!7xm$*DK=_WtbPJCPS{Mbo*Z}V5@ks1NqMqx2VX8G; z{|~NL0FFl-wS}L*$$jr~o%6q>$BEv@Z%8Qt{R8TAe1h7ysOM}nYL^h!r~qTliJ&l( z>-RE+rvSGnCWazt@|!qk7*CQs{SU7P)`4u!ujvBySk%3`M@_{y9^Vvv)!mxNz`cuS zqeo(0dQ{FX-DCv2=^lf!qvR*~EU8uaV9QB9RaH`R$4y5TOso56MltScQblxnL3%Rr z@bpfvR~PNr)3>MVu_)ubs_w>~{(u<8`I{Foj}|DJ$XC2Fvd=O<^Q*W4(!^+RqixhI zZjhgV2b>&1AhJlJemllWzzIS$sPZUYp}Xyopow>aq0l;cW}dtZektBw5$Xta_^>C! zJ<}B)x@S_c>mN@iJ!an)5&9J@FPZnUZ9&i!_wI9w#GVX}+qhv0hI-dw^nN27k@Sq& z*Yj(-e=(LQwBtz)c4}B*f*qKqF+mk4M4OBei2UD0B**yzPFoPki-i{LRXQPu273mE z3wJNi3G4=gS3)wJ#8Zpx#aRN{^#awMS`^v7?b?1*_IV4`c)zN-&d|HZ22pdK$umJjmE`#hTeq~B8B zv^y%)fjc!fB#`GmnYd$)hea$Uuf60Y-sj#Yd~~{l`&Ej2Kg0eL@Tg_=G>RnLp)^2I z?lc9fRq_TQ3UT@n5Ow5X9U5x0{B$x0d_Zh9dm)?NvrI%oPkM(NH+mXw=PZ?3^TC$Tlc{rXhPK032ud@&M2RB+ zox2IQU(*D|mHwMjr-ScF;MLE$eI9X-I0I9^xErT}Fx`s}1~qktXp8B$?>)(061PRz z3p{tIz2GL3EEl#ipljG0?=yQIr}_4)UU$&r1+HKB#v8|Q6X_CreD5G$V5Nn(!5V0O zv40zdp67!e4C_J+ar<@LQ53^B|0>imrRbXi8J6MeW0|rxDV?JbwdCrz$**-}Q~QNe ziJ6cSTs@$PiQpu}o|Vb+lAM0XiFqeES#Dj*ZLPU+)|wk_WIJGqiIo&Bgi{9&wX}=G zVziQNC@8CmibZGY7twKlj*dH$j%x@VH;p0btJ%~yi0&24U#l41J}NQaPn_hqXmuQm zyfxj(aZn_i0PNg+EwLb`--4=So(VEw{tLYsve(Ke#uzz>|E;)rgq2%8*{UF1#>*D* zcB>dIYcg*l{bh9y;!m~siy>O%D>41xvQpN9p2T9De1hxyHILOxl;nFVu!mx%_+89( zdr*)yqV_nxdyE9mh^C^XSdmPYt77ME;u@TyIc7Xt&U4SBy|AB{Gr*$rBRaw1^*W1l ztC+OULlURB!`Kn*#^MBOqN3*=vRt%1fi~DDjbnZvxjNxz!o`l%=B+;j{A9JakFX@-$cNp<7zK`MiTjuqm zp6diozKt}~Ov{3XmxncPc5qX3N}Mfm=d~uF+fIAH$6RJ_>L$CjD|2R-J6i&ouTk-0p%W zyq^IMTP)7*MSe=}W@I8$iI;qmbdh}Hc{KR^!18g#Cy|TicTv)w<}WBSP`<@-M7-~U z*)QRo9=S2BTikgHppLyZ@izv zzwsO|#o(3#Eir#^i?l}`hxMEJgD)}8HG^r8jEbIV^$U|}7lLb4`uxlt50+}er z0=CQR)g0VTnJY4MjoLNYPTIlf$SP@mz=0cIm*3ktRdT4$SEVj9po3)CQ!#X@k`_LD zm$gvOXHjnB*EnVWwosOrK_^?qJw(k&RfQK^5mQ z)x}hQLvv|X(G0n9{)f8(KK~oZd-^^;|BK`EztgK=AxkjlPDtgzUIUucRLolz;cBnY z?Ah~{!Ry**-(lL9P``||eFvx>j~zC~`90O+;;DW*544jQ?w__~48!Mt@u#`Io%&<> z{_nIVwZPIBnj5G`+lbL~ecsUHv<4H#XGJu=JgD|Tj4pP0RZ@^Bq zMV5DzO79Q_wDx2ahABP7*ejUQAGprGFo)Y8Cg@3~uVI{~vizzck=ITi-VGRN=qNKGy|hQ+b-Zs&p~qB`38mN#2bPFdCfw9m#u@P@dCV9UZXXn8>`hppq*oy#;{PPTHc0wXiaDPvpgIVerKPrH}!R4b;qro=P2F^k5P8osNiPfwJ*^7uTxIbhB z8@iEw7W^b+kWWt7p5LNJORW4hJu2AXO~7n75Kh5&L&hPY$K#jh34N*XlAjPIV2!k( zK$EBed$a}T^`?n7K&13+=DGGVwL-vn^@|E7qtx{Akg!P3RKzR=%*#njvFjkqG}686 zFQ|<`{=|6-7^5jKjVxeSk}8xaCGdaGb`GCEWldf;Mhg$ zUx43>R58c(ux89LAg0JV?U?#&*l+CdRDX9yH6XU)y9M73`0mE8<_AWNh$WhRcf#sB zMAq9QLeGSrLC<7Ftr;kPj&=BD^ugx!me5|>3AJZqy>1IV4;l-w3+(dgjByA#MiM-1 z2kesntwZP_%39zbMd?I&93@ua&}qFpbPCp_+_hPHFFaeh%a0RQ_$6s>#0SKac{6rF z@ITxp$3fm`SQfnz=Vl0;a%1H_%h;&nJ@aC9SF0E2gvHvf`@C9*!$_oevz!~BpR{X{k>z{@cRa3LI%-c* z47_VLGO#Xiste`L3qG|s54T-?cq^ilqY+|~uZ7+~r&wd0QSt}^a-yBF(~%1*cYF)+ z?G)Y4Nm@h!^BY2je3fqo-ZNN+9+k9i?aEb*^^&m;xnr0%Fpr{NC#^xMP2PqMz!T2T@P<)u0*{JwTfA9IS=|g>>-EwKs(X41fl;gLy?T2` zue;sR8yjpx6rnlA9QKxC%|-s#TgDlcr?=8r4!ZQlhMc*pKzT1>25bXgKkSRMrT*{W zy6NjWKw+n=J$SQ_{xRNUsjO)DX^;D`yt)lt| z?es4U=q*cn`u8MA&TG`aC+y1*?a=U8iD>(!)vp@1#xz{lpLo>^e@9^ zkX1vHE_j7b*6vk%@BrzoA#=JsRS-;yFCdW&3-`fx#{)JW!?yj= zjifsx8>hPJF6`ZRRZG3UD)I6I=1BigTG-ql@|LGMR9 zXvO%bT42Q}$n`3=CTU+OH3my+CO*VDqTl-h)uS(P{W+?;Mo|5Iod5N2EG@&V)xoO* z{olj$!`#pB3iNJcypI^~QK~!t#r20kzi3G03(3eAGX;?kucQm1ERm6qqaLj%ct@B0 zPDA7$@xP0J(d(IyWdjkgck%FEb^ZwUM^7>D+Zg9cmWfY%d#~Vjo`c@Yi?Md{nt9-S zHMjqO;U_WtB(C%OU(TDkKGs@S51i-skes|H?2TvWWQK_D@(AU&dzjV|wzDj14}E5w zIiC+pN#lsy#ya7+2u=g=8#gj=YK46wCZ4&lma>AFn1wY>foYXBja3zas!DC1zEG>H z4`@xz4Gr~;)Uv)RkP$0lGc>WNURzt!7^tb&Dy!DkR8(oJ>YMTJX1Tq*wnidbU6oY< zCMd+*@|s$Z3Dj$~_2re?;u39DWBnSfy1cPctE_3dIaY)}PO4!fVxqAs(A-$pq+#rW z@;YLvu?pzb_^E0X;x@qW$W+nRl&`L-&}!=J?))&M7Fgd<#n5v2rmEFzs_FvTD&|Uv z8yf5DR%>W!T(7MyuWha(X^Q+s1+q&E9#qTE7@jOMuHBNZGdP-gvCZ` zSDNz>d%G@w=^*>dr|Gz^yg@7BsS|7qJY}{;t%U7WR5#b%tgWoAuee!jf(Y2^ zC`e&Vm=#T2zj$Fu(bB8GDa5y++ekl>ym`o`S2vcgv~*s#sy;`E=DOPQl~v@lpq3L$ zcEw)SRI{3Vj8rfWke2Uomo*|T*nK61T1^wr$0}GQxoKn@aZCD#2ckDn4bbw&ifTa~ zJD@KbMh*$vCQ0g70k%rZZK5zxQQugZgIspu5ScL6bgP@(Q8>w+`b7V_qF15yGjAY7pIu7d$Ic ztYKlAsv51{$g%91hTt?2;+3~)jL$<%7k_y3@8~&vMPI$Wk^{R97KdWk*cU z6#7h_s&TZoNI_aTpX8*{dx!Xv#fe3`q@ZLT44Y`f#t`*y@GV_5Z_%}LK-IQ;c%N2V zzP`RWVB7Rmt-J|;rGc2Utvpwdh3bv#I=Iue=kThbmx`h_ z4T1GT;G_;#H&-<^!57$yS69`qslr+zIkwp((IagEa>q`Q%BU!>)9R|gDi*wkhN?Pk z3XC@L6Z!X9losxB(=V@uC`T#WCd4ZFSuK?NeqlA)h2p?J2PwlbFUo2vz19cwTEfmHN*8M-dQri=x$_EqrSldqvhl-Z&j0eGMc`kRec2tCgr76ArcAyvXWHfA zhN%~?`1&>Br?NSdyq8{`nIjj?)zvjt&$n-`T~k-za7&{N*%WAAd+WOOx7p7_N?(3K zVbR=ci|1MG^A{|h7kUx-%|PBZC{?3K8D1w>SJ}bQGFq%lt7=v^H(G1?e*<~_5?aI} zfGy{50!j4M(6SIQ(yd5gC}AiMG&j*wQ(fN_uw#qlZ`#V*o8e5rA*yqb%+xgjgO>d@ zHBD>E16UjEzJkL1AwAMVElN!lO*PUlp|1!vm9Isv$GRhh*`K>nvF44N?7yR9`y=@u z!3_OS|3rMLX3o40Q?tbrXn3{L@c^S%)$IMHQ?{dRB3`{GCS9U{bdB- zbEtL2n)15!VoA|;%d~>RX-gMhr_qO~)=j&us<9p!0y1H&7>!l8ASfX@7Xp922Gco7 ztFBpHEyTiQi>zv66{YW5ZF60d;7E%=B$H@v2VfI%OQl?inNDOpNAgmR$%|mpj&Y>M zh~_z%{N{!^Sn{=!qD3V|8Vhe_2lEy!SvGI!@&Wm=>|<703rK4l$}4ID>xZKj<`>a+ znEsl&TbgUo!?Ic0viBThPoL+HH5?vs4zhPEqJ|5+d^pZ|C0q_CiXz7}_in`*O^Rtg zdmL?>P4l_UD37Cj0wvCqpF4>Dt5BXqS!$ZUD@1t*$^$5$z`4y#l&4Me#XSfIm8SVB zm0L~oPXUym^9Ja+K>yF6IZ+vFkUp^j{z?FD%1Q+JWBBSmr|6#|EmjSE6Rl^LFf2Z zl;=?bF9v+QgZ7w0ly9O8nC82WpxlEJM;lz|Vwz zs<5YTi@EnDd|os26Lw5;I=W+lvoNfl7xUvV0)hwdF|W^iG4FSL5&o$`ntc(3^5Y!s z1G<(iP9^qpP0r(ko94<ucn&jOKy~1 zgY{IH(Cu(KF0lq?W=T@{Aw10gD{UyJi-nQ;ElhaX;Z*vD$14Op=KnRqgMAF1e?8$8 zFn@20%0sS-9k4u0*TezQISK!-M)|{`bmr3xzdi`Dau88V2o$h0C**&F>^L%sgB?2y z(S8c;d&$lmt+9V9wzbZ7NO7pU1^s1WA^A;*(=j)e93+BGL3F+kxV?ZoCH3n#@!G3+ zk{`(7d;)Q+1@l-poIlQIZG!M1hb$fHkg#{>8Phzp17x?0`GeSO!9vyr}wPL;Lz!TQc@CW*#b>_%V(el&5`k}~c2i~w1 z5&S`{S45z7K<{0S0I|nlWwA0Yb4)-yh&m5=Kj05U!Z%p(bK@E<_|mxfk(e|B$4y$_ z-a3K$*9YSFH-L@7=Euz+SON%~{D;=Rw?e3|^>ZK+5I>u- z{$t)9FAnGDdP1kusbmju!@}5-g;!#GT%vap`GJat+TrEnm0TYnD8-vE1A!&3O^((P z_e{|9pykXL(Q9)$P7ROF_yORb0-dDc@vl!f8s&^uhcXmq;j7A58u&^BUuobg4Sc16 zuQc$L2L8X*fJ;j5XrQv*?Ekm*+$~G{EZx~@Jx9yZ>9(Hj{RZW7^s#rXsq#^bwo1FO z&TE|~tOlD-oAo@xDjB~Xe<;g(w#K!d{+|^%_8#_Q|DACBU2y9#3t$5^r#2W%>9C*W z{m%fT-Tqbir8K}ta$jD1^6#zB0BMQioI&7t@tj)~H%eew4%T3jIg#xc> zh#dTt`KrbSk%N=@s+`qz%{eQZYicW})l>?8sxEJ;7CDvc>zdZDk!7G!4V z0g=zzI_C+1`tl^EU0Q#?e}J3~Pc6y#+V?Ovez62~SS6pO$|m`1#T|Z_f?s)ehk<3c zj7NBEkk5RtX2VdE9XF`F1aac51!v=T%V&pG;@^l2j6q#CKGi+=+HuRmx8s{#iXDKV z7-aQ_@hMIbZRz*nemh>;C658H@F!A#UbNc!u*W|kA;WR94bQ{LPvg(W*QRI1N&Ek6 zu**5Rq!<2;l%M)+d~5u#cS%UQ92p%yV&M Date: Mon, 19 Sep 2016 21:12:03 +0200 Subject: [PATCH 406/723] s390x/css: {c,h,t,r,x}sch: require enable AND device number valid According to the PoP, subchannels are only considered operational if they are enabled _and_ the device number is valid. With the current checks being enabled _or_ having a valid device number was sufficient. This caused qemu to allow IO on subchannels that were not enabled. Fix the checks to require both bits to be set. Signed-off-by: Sascha Silbe Reviewed-by: Cornelia Huck Reviewed-by: Halil Pasic Signed-off-by: Christian Borntraeger --- hw/s390x/css.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hw/s390x/css.c b/hw/s390x/css.c index b0e81efc271..0f2580d644c 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -775,7 +775,7 @@ int css_do_xsch(SubchDev *sch) PMCW *p = &sch->curr_status.pmcw; int ret; - if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) { + if (~(p->flags) & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA)) { ret = -ENODEV; goto out; } @@ -815,7 +815,7 @@ int css_do_csch(SubchDev *sch) PMCW *p = &sch->curr_status.pmcw; int ret; - if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) { + if (~(p->flags) & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA)) { ret = -ENODEV; goto out; } @@ -837,7 +837,7 @@ int css_do_hsch(SubchDev *sch) PMCW *p = &sch->curr_status.pmcw; int ret; - if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) { + if (~(p->flags) & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA)) { ret = -ENODEV; goto out; } @@ -913,7 +913,7 @@ int css_do_ssch(SubchDev *sch, ORB *orb) PMCW *p = &sch->curr_status.pmcw; int ret; - if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) { + if (~(p->flags) & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA)) { ret = -ENODEV; goto out; } @@ -990,7 +990,7 @@ int css_do_tsch_get_irb(SubchDev *sch, IRB *target_irb, int *irb_len) uint16_t stctl; IRB irb; - if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) { + if (~(p->flags) & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA)) { return 3; } @@ -1196,7 +1196,7 @@ int css_do_rsch(SubchDev *sch) PMCW *p = &sch->curr_status.pmcw; int ret; - if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) { + if (~(p->flags) & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA)) { ret = -ENODEV; goto out; } From 794afd7096f1ef3ea632b5cf75998562a2f8029a Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Tue, 27 Sep 2016 10:08:50 +0200 Subject: [PATCH 407/723] s390x/kvm: fix build against qemu_uuid commit 9c5ce8db2e5c ("vl: Switch qemu_uuid to QemuUUID") changed most users of qemu_uuid but not all. Fix a build error on s390/kvm. Reviewed-by: Fam Zheng Signed-off-by: Christian Borntraeger --- target-s390x/kvm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index a95d3da0f81..495905cf8eb 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -1999,7 +1999,7 @@ static void insert_stsi_3_2_2(S390CPU *cpu, __u64 addr, uint8_t ar) strcpy((char *)sysib.ext_names[0], "KVMguest"); } /* Insert UUID */ - memcpy(sysib.vm[0].uuid, qemu_uuid, sizeof(sysib.vm[0].uuid)); + memcpy(sysib.vm[0].uuid, &qemu_uuid, sizeof(sysib.vm[0].uuid)); s390_cpu_virt_mem_write(cpu, addr, ar, &sysib, sizeof(sysib)); } From 06b3611fc2a3001d3940fa3bfa404c679b7d2b13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herv=C3=A9=20Poussineau?= Date: Thu, 15 Sep 2016 22:06:23 +0200 Subject: [PATCH 408/723] ps2: reject unknown commands, instead of blindly accepting them MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Hervé Poussineau Message-id: 1473969987-5890-2-git-send-email-hpoussin@reactos.org Signed-off-by: Gerd Hoffmann --- hw/input/ps2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/input/ps2.c b/hw/input/ps2.c index a8aa36f5c04..00a1792228b 100644 --- a/hw/input/ps2.c +++ b/hw/input/ps2.c @@ -290,7 +290,7 @@ void ps2_write_keyboard(void *opaque, int val) ps2_queue(&s->common, KBD_REPLY_POR); break; default: - ps2_queue(&s->common, KBD_REPLY_ACK); + ps2_queue(&s->common, KBD_REPLY_RESEND); break; } break; From 4df23b64c51cc830d19eb29801070d31aa1e81cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herv=C3=A9=20Poussineau?= Date: Thu, 15 Sep 2016 22:06:24 +0200 Subject: [PATCH 409/723] ps2: correctly handle 'get/set scancode' command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When getting scancode, current scancode must be preceded from reply ack. When setting scancode, we must reject invalid scancodes. Signed-off-by: Hervé Poussineau Message-id: 1473969987-5890-3-git-send-email-hpoussin@reactos.org Signed-off-by: Gerd Hoffmann --- hw/input/ps2.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/hw/input/ps2.c b/hw/input/ps2.c index 00a1792228b..2105e51f0b1 100644 --- a/hw/input/ps2.c +++ b/hw/input/ps2.c @@ -296,16 +296,18 @@ void ps2_write_keyboard(void *opaque, int val) break; case KBD_CMD_SCANCODE: if (val == 0) { + ps2_queue(&s->common, KBD_REPLY_ACK); if (s->scancode_set == 1) ps2_put_keycode(s, 0x43); else if (s->scancode_set == 2) ps2_put_keycode(s, 0x41); else if (s->scancode_set == 3) ps2_put_keycode(s, 0x3f); - } else { - if (val >= 1 && val <= 3) - s->scancode_set = val; + } else if (val >= 1 && val <= 3) { + s->scancode_set = val; ps2_queue(&s->common, KBD_REPLY_ACK); + } else { + ps2_queue(&s->common, KBD_REPLY_RESEND); } s->common.write_cmd = -1; break; From 57d5c005d35dc6d6d7e15a6b8c4d9ea16a7c738d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herv=C3=A9=20Poussineau?= Date: Thu, 15 Sep 2016 22:06:25 +0200 Subject: [PATCH 410/723] ps2: allow keycode translation for all scancode sets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change ps2_put_keycode to get an untranslated scancode, which is translated if needed. As qemu_input_key_value_to_scancode() gives translated scancodes, untranslate them in ps2_keyboard_event first before giving them to ps2_put_keycode. Results are not changed, except for some keys in translated set 3. Translation table is available at https://www.win.tue.nl/~aeb/linux/kbd/scancodes-10.html Signed-off-by: Hervé Poussineau Message-id: 1473969987-5890-4-git-send-email-hpoussin@reactos.org Signed-off-by: Gerd Hoffmann --- hw/input/ps2.c | 123 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 97 insertions(+), 26 deletions(-) diff --git a/hw/input/ps2.c b/hw/input/ps2.c index 2105e51f0b1..3636dfb686f 100644 --- a/hw/input/ps2.c +++ b/hw/input/ps2.c @@ -94,12 +94,10 @@ typedef struct { typedef struct { PS2State common; int scan_enabled; - /* QEMU uses translated PC scancodes internally. To avoid multiple - conversions we do the translation (if any) in the PS/2 emulation - not the keyboard controller. */ int translate; int scancode_set; /* 1=XT, 2=AT, 3=PS/2 */ int ledstate; + bool need_high_bit; } PS2KbdState; typedef struct { @@ -138,6 +136,41 @@ static const unsigned char ps2_raw_keycode_set3[128] = { 19, 25, 57, 81, 83, 92, 95, 98, 99, 100, 101, 103, 104, 106, 109, 110 }; +static uint8_t translate_table[256] = { + 0xff, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x3c, 0x58, + 0x64, 0x44, 0x42, 0x40, 0x3e, 0x0f, 0x29, 0x59, + 0x65, 0x38, 0x2a, 0x70, 0x1d, 0x10, 0x02, 0x5a, + 0x66, 0x71, 0x2c, 0x1f, 0x1e, 0x11, 0x03, 0x5b, + 0x67, 0x2e, 0x2d, 0x20, 0x12, 0x05, 0x04, 0x5c, + 0x68, 0x39, 0x2f, 0x21, 0x14, 0x13, 0x06, 0x5d, + 0x69, 0x31, 0x30, 0x23, 0x22, 0x15, 0x07, 0x5e, + 0x6a, 0x72, 0x32, 0x24, 0x16, 0x08, 0x09, 0x5f, + 0x6b, 0x33, 0x25, 0x17, 0x18, 0x0b, 0x0a, 0x60, + 0x6c, 0x34, 0x35, 0x26, 0x27, 0x19, 0x0c, 0x61, + 0x6d, 0x73, 0x28, 0x74, 0x1a, 0x0d, 0x62, 0x6e, + 0x3a, 0x36, 0x1c, 0x1b, 0x75, 0x2b, 0x63, 0x76, + 0x55, 0x56, 0x77, 0x78, 0x79, 0x7a, 0x0e, 0x7b, + 0x7c, 0x4f, 0x7d, 0x4b, 0x47, 0x7e, 0x7f, 0x6f, + 0x52, 0x53, 0x50, 0x4c, 0x4d, 0x48, 0x01, 0x45, + 0x57, 0x4e, 0x51, 0x4a, 0x37, 0x49, 0x46, 0x54, + 0x80, 0x81, 0x82, 0x41, 0x54, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, +}; + void ps2_queue(void *opaque, int b) { PS2State *s = (PS2State *)opaque; @@ -152,29 +185,26 @@ void ps2_queue(void *opaque, int b) s->update_irq(s->update_arg, 1); } -/* - keycode is expressed as follow: - bit 7 - 0 key pressed, 1 = key released - bits 6-0 - translated scancode set 2 - */ +/* keycode is the untranslated scancode in the current scancode set. */ static void ps2_put_keycode(void *opaque, int keycode) { PS2KbdState *s = opaque; trace_ps2_put_keycode(opaque, keycode); qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); - /* XXX: add support for scancode set 1 */ - if (!s->translate && keycode < 0xe0 && s->scancode_set > 1) { - if (keycode & 0x80) { - ps2_queue(&s->common, 0xf0); - } - if (s->scancode_set == 2) { - keycode = ps2_raw_keycode[keycode & 0x7f]; - } else if (s->scancode_set == 3) { - keycode = ps2_raw_keycode_set3[keycode & 0x7f]; + + if (s->translate) { + if (keycode == 0xf0) { + s->need_high_bit = true; + } else if (s->need_high_bit) { + ps2_queue(&s->common, translate_table[keycode] | 0x80); + s->need_high_bit = false; + } else { + ps2_queue(&s->common, translate_table[keycode]); } - } - ps2_queue(&s->common, keycode); + } else { + ps2_queue(&s->common, keycode); + } } static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src, @@ -183,13 +213,41 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src, PS2KbdState *s = (PS2KbdState *)dev; int scancodes[3], i, count; InputKeyEvent *key = evt->u.key.data; + int keycode; qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); count = qemu_input_key_value_to_scancode(key->key, key->down, scancodes); + + /* handle invalid key */ + if (count == 1 && scancodes[0] == 0x00) { + ps2_queue(&s->common, 0x00); + return; + } else if (count == 1 && scancodes[0] == 0x80) { + if (s->translate || s->scancode_set == 1) { + ps2_queue(&s->common, 0x80); + } else { + ps2_queue(&s->common, 0xf0); + ps2_queue(&s->common, 0x00); + } + return; + } + for (i = 0; i < count; i++) { - ps2_put_keycode(s, scancodes[i]); + /* XXX: add support for scancode set 1 */ + keycode = scancodes[i]; + if (keycode < 0xe0 && (s->scancode_set > 1 || s->translate)) { + if (keycode & 0x80) { + ps2_put_keycode(&s->common, 0xf0); + } + if (s->scancode_set == 1 || s->scancode_set == 2) { + keycode = ps2_raw_keycode[keycode & 0x7f]; + } else if (s->scancode_set == 3) { + keycode = ps2_raw_keycode_set3[keycode & 0x7f]; + } + } + ps2_put_keycode(s, keycode); } } @@ -297,12 +355,7 @@ void ps2_write_keyboard(void *opaque, int val) case KBD_CMD_SCANCODE: if (val == 0) { ps2_queue(&s->common, KBD_REPLY_ACK); - if (s->scancode_set == 1) - ps2_put_keycode(s, 0x43); - else if (s->scancode_set == 2) - ps2_put_keycode(s, 0x41); - else if (s->scancode_set == 3) - ps2_put_keycode(s, 0x3f); + ps2_put_keycode(s, s->scancode_set); } else if (val >= 1 && val <= 3) { s->scancode_set = val; ps2_queue(&s->common, KBD_REPLY_ACK); @@ -692,6 +745,23 @@ static const VMStateDescription vmstate_ps2_keyboard_ledstate = { } }; +static bool ps2_keyboard_need_high_bit_needed(void *opaque) +{ + PS2KbdState *s = opaque; + return s->need_high_bit != 0; /* 0 is the usual state */ +} + +static const VMStateDescription vmstate_ps2_keyboard_need_high_bit = { + .name = "ps2kbd/need_high_bit", + .version_id = 1, + .minimum_version_id = 1, + .needed = ps2_keyboard_need_high_bit_needed, + .fields = (VMStateField[]) { + VMSTATE_BOOL(need_high_bit, PS2KbdState), + VMSTATE_END_OF_LIST() + } +}; + static int ps2_kbd_post_load(void* opaque, int version_id) { PS2KbdState *s = (PS2KbdState*)opaque; @@ -728,6 +798,7 @@ static const VMStateDescription vmstate_ps2_keyboard = { }, .subsections = (const VMStateDescription*[]) { &vmstate_ps2_keyboard_ledstate, + &vmstate_ps2_keyboard_need_high_bit, NULL } }; From 8c10e0baf0260b59a4e984744462a18016662e3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herv=C3=A9=20Poussineau?= Date: Thu, 15 Sep 2016 22:06:26 +0200 Subject: [PATCH 411/723] ps2: use QEMU qcodes instead of scancodes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes problems with translated set 1, where most make code were wrong. This fixes problems with set 3 for extended keys (like arrows) and lot of other keys. Added a FIXME for set 3, where most keys must not (by default) deliver a break code. Detailed list of changes on untranslated set 2: - change of ALTGR break code from 0xe4 to 0xf0 0x08 - change of ALTGR_R break code from 0xe0 0xe4 to 0xe0 0xf0 0x08 - change of F7 make code from 0x02 to 0x83 - change of F7 break code from 0xf0 0x02 to 0xf0 0x83 - change of PRINT make code from 0xe0 0x7c to 0xe0 0x12 0xe0 0x7c - change of PRINT break code from 0xe0 0xf0 0x7c to 0xe0 0xf0 0x7c 0xe0 0xf0 0x12 - change of PAUSE key: new make code = old make code + old break code, no more break code - change on RO break code from 0xf3 to 0xf0 0x51 - change on KP_COMMA break code from 0xfe to 0xf0 0x6d Detailed list of changes on translated set 2 (the most commonly used): - change of PRINT make code from 0xe0 0x37 to 0xe0 0x2a 0xe0 0x37 - change of PRINT break code from 0xe0 0xb7 to 0xe0 0xb7 0xe0 0xaa - change of PAUSE key: new make code = old make code + old break code, no more break code Reference: http://www.computer-engineering.org/ps2keyboard/scancodes1.html http://www.computer-engineering.org/ps2keyboard/scancodes2.html http://www.computer-engineering.org/ps2keyboard/scancodes3.html Signed-off-by: Hervé Poussineau Message-id: 1473969987-5890-5-git-send-email-hpoussin@reactos.org Signed-off-by: Gerd Hoffmann --- hw/input/ps2.c | 533 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 485 insertions(+), 48 deletions(-) diff --git a/hw/input/ps2.c b/hw/input/ps2.c index 3636dfb686f..98da984384f 100644 --- a/hw/input/ps2.c +++ b/hw/input/ps2.c @@ -114,26 +114,395 @@ typedef struct { uint8_t mouse_buttons; } PS2MouseState; -/* Table to convert from PC scancodes to raw scancodes. */ -static const unsigned char ps2_raw_keycode[128] = { - 0, 118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85, 102, 13, - 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27, - 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42, - 50, 49, 58, 65, 73, 74, 89, 124, 17, 41, 88, 5, 6, 4, 12, 3, - 11, 2, 10, 1, 9, 119, 126, 108, 117, 125, 123, 107, 115, 116, 121, 105, -114, 122, 112, 113, 127, 96, 97, 120, 7, 15, 23, 31, 39, 47, 55, 63, - 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87, 111, - 19, 25, 57, 81, 83, 92, 95, 98, 99, 100, 101, 103, 104, 106, 109, 110 +/* Table to convert from QEMU codes to scancodes. */ +static const uint16_t qcode_to_keycode_set1[Q_KEY_CODE__MAX] = { + [0 ... Q_KEY_CODE__MAX - 1] = 0, + + [Q_KEY_CODE_A] = 0x1e, + [Q_KEY_CODE_B] = 0x30, + [Q_KEY_CODE_C] = 0x2e, + [Q_KEY_CODE_D] = 0x20, + [Q_KEY_CODE_E] = 0x12, + [Q_KEY_CODE_F] = 0x21, + [Q_KEY_CODE_G] = 0x22, + [Q_KEY_CODE_H] = 0x23, + [Q_KEY_CODE_I] = 0x17, + [Q_KEY_CODE_J] = 0x24, + [Q_KEY_CODE_K] = 0x25, + [Q_KEY_CODE_L] = 0x26, + [Q_KEY_CODE_M] = 0x32, + [Q_KEY_CODE_N] = 0x31, + [Q_KEY_CODE_O] = 0x18, + [Q_KEY_CODE_P] = 0x19, + [Q_KEY_CODE_Q] = 0x10, + [Q_KEY_CODE_R] = 0x13, + [Q_KEY_CODE_S] = 0x1f, + [Q_KEY_CODE_T] = 0x14, + [Q_KEY_CODE_U] = 0x16, + [Q_KEY_CODE_V] = 0x2f, + [Q_KEY_CODE_W] = 0x11, + [Q_KEY_CODE_X] = 0x2d, + [Q_KEY_CODE_Y] = 0x15, + [Q_KEY_CODE_Z] = 0x2c, + [Q_KEY_CODE_0] = 0x0b, + [Q_KEY_CODE_1] = 0x02, + [Q_KEY_CODE_2] = 0x03, + [Q_KEY_CODE_3] = 0x04, + [Q_KEY_CODE_4] = 0x05, + [Q_KEY_CODE_5] = 0x06, + [Q_KEY_CODE_6] = 0x07, + [Q_KEY_CODE_7] = 0x08, + [Q_KEY_CODE_8] = 0x09, + [Q_KEY_CODE_9] = 0x0a, + [Q_KEY_CODE_GRAVE_ACCENT] = 0x29, + [Q_KEY_CODE_MINUS] = 0x0c, + [Q_KEY_CODE_EQUAL] = 0x0d, + [Q_KEY_CODE_BACKSLASH] = 0x2b, + [Q_KEY_CODE_BACKSPACE] = 0x0e, + [Q_KEY_CODE_SPC] = 0x39, + [Q_KEY_CODE_TAB] = 0x0f, + [Q_KEY_CODE_CAPS_LOCK] = 0x3a, + [Q_KEY_CODE_SHIFT] = 0x2a, + [Q_KEY_CODE_CTRL] = 0x1d, + [Q_KEY_CODE_META_L] = 0xe05b, + [Q_KEY_CODE_ALT] = 0x38, + [Q_KEY_CODE_SHIFT_R] = 0x36, + [Q_KEY_CODE_CTRL_R] = 0xe01d, + [Q_KEY_CODE_META_R] = 0xe05c, + [Q_KEY_CODE_ALT_R] = 0xe038, + [Q_KEY_CODE_MENU] = 0xe05d, + [Q_KEY_CODE_RET] = 0x1c, + [Q_KEY_CODE_ESC] = 0x01, + [Q_KEY_CODE_F1] = 0x3b, + [Q_KEY_CODE_F2] = 0x3c, + [Q_KEY_CODE_F3] = 0x3d, + [Q_KEY_CODE_F4] = 0x3e, + [Q_KEY_CODE_F5] = 0x3f, + [Q_KEY_CODE_F6] = 0x40, + [Q_KEY_CODE_F7] = 0x41, + [Q_KEY_CODE_F8] = 0x42, + [Q_KEY_CODE_F9] = 0x43, + [Q_KEY_CODE_F10] = 0x44, + [Q_KEY_CODE_F11] = 0x57, + [Q_KEY_CODE_F12] = 0x58, + /* special handling for Q_KEY_CODE_PRINT */ + [Q_KEY_CODE_SCROLL_LOCK] = 0x46, + /* special handling for Q_KEY_CODE_PAUSE */ + [Q_KEY_CODE_BRACKET_LEFT] = 0x1a, + [Q_KEY_CODE_INSERT] = 0xe052, + [Q_KEY_CODE_HOME] = 0xe047, + [Q_KEY_CODE_PGUP] = 0xe049, + [Q_KEY_CODE_DELETE] = 0xe053, + [Q_KEY_CODE_END] = 0xe04f, + [Q_KEY_CODE_PGDN] = 0xe051, + [Q_KEY_CODE_UP] = 0xe048, + [Q_KEY_CODE_LEFT] = 0xe04b, + [Q_KEY_CODE_DOWN] = 0xe050, + [Q_KEY_CODE_RIGHT] = 0xe04d, + [Q_KEY_CODE_NUM_LOCK] = 0x45, + [Q_KEY_CODE_KP_DIVIDE] = 0xe035, + [Q_KEY_CODE_KP_MULTIPLY] = 0x37, + [Q_KEY_CODE_KP_SUBTRACT] = 0x4a, + [Q_KEY_CODE_KP_ADD] = 0x4e, + [Q_KEY_CODE_KP_ENTER] = 0xe01c, + [Q_KEY_CODE_KP_DECIMAL] = 0x53, + [Q_KEY_CODE_KP_0] = 0x52, + [Q_KEY_CODE_KP_1] = 0x4f, + [Q_KEY_CODE_KP_2] = 0x50, + [Q_KEY_CODE_KP_3] = 0x51, + [Q_KEY_CODE_KP_4] = 0x4b, + [Q_KEY_CODE_KP_5] = 0x4c, + [Q_KEY_CODE_KP_6] = 0x4d, + [Q_KEY_CODE_KP_7] = 0x47, + [Q_KEY_CODE_KP_8] = 0x48, + [Q_KEY_CODE_KP_9] = 0x49, + [Q_KEY_CODE_BRACKET_RIGHT] = 0x1b, + [Q_KEY_CODE_SEMICOLON] = 0x27, + [Q_KEY_CODE_APOSTROPHE] = 0x28, + [Q_KEY_CODE_COMMA] = 0x33, + [Q_KEY_CODE_DOT] = 0x34, + [Q_KEY_CODE_SLASH] = 0x35, + +#if 0 + [Q_KEY_CODE_POWER] = 0x0e5e, + [Q_KEY_CODE_SLEEP] = 0x0e5f, + [Q_KEY_CODE_WAKE] = 0x0e63, + + [Q_KEY_CODE_AUDIONEXT] = 0xe019, + [Q_KEY_CODE_AUDIOPREV] = 0xe010, + [Q_KEY_CODE_AUDIOSTOP] = 0xe024, + [Q_KEY_CODE_AUDIOPLAY] = 0xe022, + [Q_KEY_CODE_AUDIOMUTE] = 0xe020, + [Q_KEY_CODE_VOLUMEUP] = 0xe030, + [Q_KEY_CODE_VOLUMEDOWN] = 0xe02e, + [Q_KEY_CODE_MEDIASELECT] = 0xe06d, + [Q_KEY_CODE_MAIL] = 0xe06c, + [Q_KEY_CODE_CALCULATOR] = 0xe021, + [Q_KEY_CODE_COMPUTER] = 0xe06b, + [Q_KEY_CODE_AC_SEARCH] = 0xe065, + [Q_KEY_CODE_AC_HOME] = 0xe032, + [Q_KEY_CODE_AC_BACK] = 0xe06a, + [Q_KEY_CODE_AC_FORWARD] = 0xe069, + [Q_KEY_CODE_AC_STOP] = 0xe068, + [Q_KEY_CODE_AC_REFRESH] = 0xe067, + [Q_KEY_CODE_AC_BOOKMARKS] = 0xe066, +#endif + + [Q_KEY_CODE_ASTERISK] = 0x37, + [Q_KEY_CODE_LESS] = 0x56, + [Q_KEY_CODE_RO] = 0x73, + [Q_KEY_CODE_KP_COMMA] = 0x7e, }; -static const unsigned char ps2_raw_keycode_set3[128] = { - 0, 8, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85, 102, 13, - 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 17, 28, 27, - 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 92, 26, 34, 33, 42, - 50, 49, 58, 65, 73, 74, 89, 126, 25, 41, 20, 7, 15, 23, 31, 39, - 47, 2, 63, 71, 79, 118, 95, 108, 117, 125, 132, 107, 115, 116, 124, 105, -114, 122, 112, 113, 127, 96, 97, 86, 94, 15, 23, 31, 39, 47, 55, 63, - 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87, 111, - 19, 25, 57, 81, 83, 92, 95, 98, 99, 100, 101, 103, 104, 106, 109, 110 + +static const uint16_t qcode_to_keycode_set2[Q_KEY_CODE__MAX] = { + [0 ... Q_KEY_CODE__MAX - 1] = 0, + + [Q_KEY_CODE_A] = 0x1c, + [Q_KEY_CODE_B] = 0x32, + [Q_KEY_CODE_C] = 0x21, + [Q_KEY_CODE_D] = 0x23, + [Q_KEY_CODE_E] = 0x24, + [Q_KEY_CODE_F] = 0x2b, + [Q_KEY_CODE_G] = 0x34, + [Q_KEY_CODE_H] = 0x33, + [Q_KEY_CODE_I] = 0x43, + [Q_KEY_CODE_J] = 0x3b, + [Q_KEY_CODE_K] = 0x42, + [Q_KEY_CODE_L] = 0x4b, + [Q_KEY_CODE_M] = 0x3a, + [Q_KEY_CODE_N] = 0x31, + [Q_KEY_CODE_O] = 0x44, + [Q_KEY_CODE_P] = 0x4d, + [Q_KEY_CODE_Q] = 0x15, + [Q_KEY_CODE_R] = 0x2d, + [Q_KEY_CODE_S] = 0x1b, + [Q_KEY_CODE_T] = 0x2c, + [Q_KEY_CODE_U] = 0x3c, + [Q_KEY_CODE_V] = 0x2a, + [Q_KEY_CODE_W] = 0x1d, + [Q_KEY_CODE_X] = 0x22, + [Q_KEY_CODE_Y] = 0x35, + [Q_KEY_CODE_Z] = 0x1a, + [Q_KEY_CODE_0] = 0x45, + [Q_KEY_CODE_1] = 0x16, + [Q_KEY_CODE_2] = 0x1e, + [Q_KEY_CODE_3] = 0x26, + [Q_KEY_CODE_4] = 0x25, + [Q_KEY_CODE_5] = 0x2e, + [Q_KEY_CODE_6] = 0x36, + [Q_KEY_CODE_7] = 0x3d, + [Q_KEY_CODE_8] = 0x3e, + [Q_KEY_CODE_9] = 0x46, + [Q_KEY_CODE_GRAVE_ACCENT] = 0x0e, + [Q_KEY_CODE_MINUS] = 0x4e, + [Q_KEY_CODE_EQUAL] = 0x55, + [Q_KEY_CODE_BACKSLASH] = 0x5d, + [Q_KEY_CODE_BACKSPACE] = 0x66, + [Q_KEY_CODE_SPC] = 0x29, + [Q_KEY_CODE_TAB] = 0x0d, + [Q_KEY_CODE_CAPS_LOCK] = 0x58, + [Q_KEY_CODE_SHIFT] = 0x12, + [Q_KEY_CODE_CTRL] = 0x14, + [Q_KEY_CODE_META_L] = 0xe01f, + [Q_KEY_CODE_ALT] = 0x11, + [Q_KEY_CODE_SHIFT_R] = 0x59, + [Q_KEY_CODE_CTRL_R] = 0xe014, + [Q_KEY_CODE_META_R] = 0xe027, + [Q_KEY_CODE_ALT_R] = 0xe011, + [Q_KEY_CODE_MENU] = 0xe02f, + [Q_KEY_CODE_RET] = 0x5a, + [Q_KEY_CODE_ESC] = 0x76, + [Q_KEY_CODE_F1] = 0x05, + [Q_KEY_CODE_F2] = 0x06, + [Q_KEY_CODE_F3] = 0x04, + [Q_KEY_CODE_F4] = 0x0c, + [Q_KEY_CODE_F5] = 0x03, + [Q_KEY_CODE_F6] = 0x0b, + [Q_KEY_CODE_F7] = 0x83, + [Q_KEY_CODE_F8] = 0x0a, + [Q_KEY_CODE_F9] = 0x01, + [Q_KEY_CODE_F10] = 0x09, + [Q_KEY_CODE_F11] = 0x78, + [Q_KEY_CODE_F12] = 0x07, + /* special handling for Q_KEY_CODE_PRINT */ + [Q_KEY_CODE_SCROLL_LOCK] = 0x7e, + /* special handling for Q_KEY_CODE_PAUSE */ + [Q_KEY_CODE_BRACKET_LEFT] = 0x54, + [Q_KEY_CODE_INSERT] = 0xe070, + [Q_KEY_CODE_HOME] = 0xe06c, + [Q_KEY_CODE_PGUP] = 0xe07d, + [Q_KEY_CODE_DELETE] = 0xe071, + [Q_KEY_CODE_END] = 0xe069, + [Q_KEY_CODE_PGDN] = 0xe07a, + [Q_KEY_CODE_UP] = 0xe075, + [Q_KEY_CODE_LEFT] = 0xe06b, + [Q_KEY_CODE_DOWN] = 0xe072, + [Q_KEY_CODE_RIGHT] = 0xe074, + [Q_KEY_CODE_NUM_LOCK] = 0x77, + [Q_KEY_CODE_KP_DIVIDE] = 0xe04a, + [Q_KEY_CODE_KP_MULTIPLY] = 0x7c, + [Q_KEY_CODE_KP_SUBTRACT] = 0x7b, + [Q_KEY_CODE_KP_ADD] = 0x79, + [Q_KEY_CODE_KP_ENTER] = 0xe05a, + [Q_KEY_CODE_KP_DECIMAL] = 0x71, + [Q_KEY_CODE_KP_0] = 0x70, + [Q_KEY_CODE_KP_1] = 0x69, + [Q_KEY_CODE_KP_2] = 0x72, + [Q_KEY_CODE_KP_3] = 0x7a, + [Q_KEY_CODE_KP_4] = 0x6b, + [Q_KEY_CODE_KP_5] = 0x73, + [Q_KEY_CODE_KP_6] = 0x74, + [Q_KEY_CODE_KP_7] = 0x6c, + [Q_KEY_CODE_KP_8] = 0x75, + [Q_KEY_CODE_KP_9] = 0x7d, + [Q_KEY_CODE_BRACKET_RIGHT] = 0x5b, + [Q_KEY_CODE_SEMICOLON] = 0x4c, + [Q_KEY_CODE_APOSTROPHE] = 0x52, + [Q_KEY_CODE_COMMA] = 0x41, + [Q_KEY_CODE_DOT] = 0x49, + [Q_KEY_CODE_SLASH] = 0x4a, + +#if 0 + [Q_KEY_CODE_POWER] = 0x0e37, + [Q_KEY_CODE_SLEEP] = 0x0e3f, + [Q_KEY_CODE_WAKE] = 0x0e5e, + + [Q_KEY_CODE_AUDIONEXT] = 0xe04d, + [Q_KEY_CODE_AUDIOPREV] = 0xe015, + [Q_KEY_CODE_AUDIOSTOP] = 0xe03b, + [Q_KEY_CODE_AUDIOPLAY] = 0xe034, + [Q_KEY_CODE_AUDIOMUTE] = 0xe023, + [Q_KEY_CODE_VOLUMEUP] = 0xe032, + [Q_KEY_CODE_VOLUMEDOWN] = 0xe021, + [Q_KEY_CODE_MEDIASELECT] = 0xe050, + [Q_KEY_CODE_MAIL] = 0xe048, + [Q_KEY_CODE_CALCULATOR] = 0xe02b, + [Q_KEY_CODE_COMPUTER] = 0xe040, + [Q_KEY_CODE_AC_SEARCH] = 0xe010, + [Q_KEY_CODE_AC_HOME] = 0xe03a, + [Q_KEY_CODE_AC_BACK] = 0xe038, + [Q_KEY_CODE_AC_FORWARD] = 0xe030, + [Q_KEY_CODE_AC_STOP] = 0xe028, + [Q_KEY_CODE_AC_REFRESH] = 0xe020, + [Q_KEY_CODE_AC_BOOKMARKS] = 0xe018, +#endif + + [Q_KEY_CODE_ALTGR] = 0x08, + [Q_KEY_CODE_ALTGR_R] = 0xe008, + [Q_KEY_CODE_ASTERISK] = 0x7c, + [Q_KEY_CODE_LESS] = 0x61, + [Q_KEY_CODE_SYSRQ] = 0x7f, + [Q_KEY_CODE_RO] = 0x51, + [Q_KEY_CODE_KP_COMMA] = 0x6d, +}; + +static const uint16_t qcode_to_keycode_set3[Q_KEY_CODE__MAX] = { + [0 ... Q_KEY_CODE__MAX - 1] = 0, + + [Q_KEY_CODE_A] = 0x1c, + [Q_KEY_CODE_B] = 0x32, + [Q_KEY_CODE_C] = 0x21, + [Q_KEY_CODE_D] = 0x23, + [Q_KEY_CODE_E] = 0x24, + [Q_KEY_CODE_F] = 0x2b, + [Q_KEY_CODE_G] = 0x34, + [Q_KEY_CODE_H] = 0x33, + [Q_KEY_CODE_I] = 0x43, + [Q_KEY_CODE_J] = 0x3b, + [Q_KEY_CODE_K] = 0x42, + [Q_KEY_CODE_L] = 0x4b, + [Q_KEY_CODE_M] = 0x3a, + [Q_KEY_CODE_N] = 0x31, + [Q_KEY_CODE_O] = 0x44, + [Q_KEY_CODE_P] = 0x4d, + [Q_KEY_CODE_Q] = 0x15, + [Q_KEY_CODE_R] = 0x2d, + [Q_KEY_CODE_S] = 0x1b, + [Q_KEY_CODE_T] = 0x2c, + [Q_KEY_CODE_U] = 0x3c, + [Q_KEY_CODE_V] = 0x2a, + [Q_KEY_CODE_W] = 0x1d, + [Q_KEY_CODE_X] = 0x22, + [Q_KEY_CODE_Y] = 0x35, + [Q_KEY_CODE_Z] = 0x1a, + [Q_KEY_CODE_0] = 0x45, + [Q_KEY_CODE_1] = 0x16, + [Q_KEY_CODE_2] = 0x1e, + [Q_KEY_CODE_3] = 0x26, + [Q_KEY_CODE_4] = 0x25, + [Q_KEY_CODE_5] = 0x2e, + [Q_KEY_CODE_6] = 0x36, + [Q_KEY_CODE_7] = 0x3d, + [Q_KEY_CODE_8] = 0x3e, + [Q_KEY_CODE_9] = 0x46, + [Q_KEY_CODE_GRAVE_ACCENT] = 0x0e, + [Q_KEY_CODE_MINUS] = 0x4e, + [Q_KEY_CODE_EQUAL] = 0x55, + [Q_KEY_CODE_BACKSLASH] = 0x5c, + [Q_KEY_CODE_BACKSPACE] = 0x66, + [Q_KEY_CODE_SPC] = 0x29, + [Q_KEY_CODE_TAB] = 0x0d, + [Q_KEY_CODE_CAPS_LOCK] = 0x14, + [Q_KEY_CODE_SHIFT] = 0x12, + [Q_KEY_CODE_CTRL] = 0x11, + [Q_KEY_CODE_META_L] = 0x8b, + [Q_KEY_CODE_ALT] = 0x19, + [Q_KEY_CODE_SHIFT_R] = 0x59, + [Q_KEY_CODE_CTRL_R] = 0x58, + [Q_KEY_CODE_META_R] = 0x8c, + [Q_KEY_CODE_ALT_R] = 0x39, + [Q_KEY_CODE_MENU] = 0x8d, + [Q_KEY_CODE_RET] = 0x5a, + [Q_KEY_CODE_ESC] = 0x08, + [Q_KEY_CODE_F1] = 0x07, + [Q_KEY_CODE_F2] = 0x0f, + [Q_KEY_CODE_F3] = 0x17, + [Q_KEY_CODE_F4] = 0x1f, + [Q_KEY_CODE_F5] = 0x27, + [Q_KEY_CODE_F6] = 0x2f, + [Q_KEY_CODE_F7] = 0x37, + [Q_KEY_CODE_F8] = 0x3f, + [Q_KEY_CODE_F9] = 0x47, + [Q_KEY_CODE_F10] = 0x4f, + [Q_KEY_CODE_F11] = 0x56, + [Q_KEY_CODE_F12] = 0x5e, + [Q_KEY_CODE_PRINT] = 0x57, + [Q_KEY_CODE_SCROLL_LOCK] = 0x5f, + [Q_KEY_CODE_PAUSE] = 0x62, + [Q_KEY_CODE_BRACKET_LEFT] = 0x54, + [Q_KEY_CODE_INSERT] = 0x67, + [Q_KEY_CODE_HOME] = 0x6e, + [Q_KEY_CODE_PGUP] = 0x6f, + [Q_KEY_CODE_DELETE] = 0x64, + [Q_KEY_CODE_END] = 0x65, + [Q_KEY_CODE_PGDN] = 0x6d, + [Q_KEY_CODE_UP] = 0x63, + [Q_KEY_CODE_LEFT] = 0x61, + [Q_KEY_CODE_DOWN] = 0x60, + [Q_KEY_CODE_RIGHT] = 0x6a, + [Q_KEY_CODE_NUM_LOCK] = 0x76, + [Q_KEY_CODE_KP_DIVIDE] = 0x4a, + [Q_KEY_CODE_KP_MULTIPLY] = 0x7e, + [Q_KEY_CODE_KP_SUBTRACT] = 0x4e, + [Q_KEY_CODE_KP_ADD] = 0x7c, + [Q_KEY_CODE_KP_ENTER] = 0x79, + [Q_KEY_CODE_KP_DECIMAL] = 0x71, + [Q_KEY_CODE_KP_0] = 0x70, + [Q_KEY_CODE_KP_1] = 0x69, + [Q_KEY_CODE_KP_2] = 0x72, + [Q_KEY_CODE_KP_3] = 0x7a, + [Q_KEY_CODE_KP_4] = 0x6b, + [Q_KEY_CODE_KP_5] = 0x73, + [Q_KEY_CODE_KP_6] = 0x74, + [Q_KEY_CODE_KP_7] = 0x6c, + [Q_KEY_CODE_KP_8] = 0x75, + [Q_KEY_CODE_KP_9] = 0x7d, + [Q_KEY_CODE_BRACKET_RIGHT] = 0x5b, + [Q_KEY_CODE_SEMICOLON] = 0x4c, + [Q_KEY_CODE_APOSTROPHE] = 0x52, + [Q_KEY_CODE_COMMA] = 0x41, + [Q_KEY_CODE_DOT] = 0x49, + [Q_KEY_CODE_SLASH] = 0x4a, }; static uint8_t translate_table[256] = { @@ -211,43 +580,111 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src, InputEvent *evt) { PS2KbdState *s = (PS2KbdState *)dev; - int scancodes[3], i, count; InputKeyEvent *key = evt->u.key.data; - int keycode; + int qcode; + uint16_t keycode; qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); - count = qemu_input_key_value_to_scancode(key->key, - key->down, - scancodes); - - /* handle invalid key */ - if (count == 1 && scancodes[0] == 0x00) { - ps2_queue(&s->common, 0x00); - return; - } else if (count == 1 && scancodes[0] == 0x80) { - if (s->translate || s->scancode_set == 1) { - ps2_queue(&s->common, 0x80); + assert(evt->type == INPUT_EVENT_KIND_KEY); + qcode = qemu_input_key_value_to_qcode(key->key); + + if (s->scancode_set == 1) { + if (qcode == Q_KEY_CODE_PAUSE) { + if (key->down) { + ps2_put_keycode(s, 0xe1); + ps2_put_keycode(s, 0x1d); + ps2_put_keycode(s, 0x45); + ps2_put_keycode(s, 0x91); + ps2_put_keycode(s, 0x9d); + ps2_put_keycode(s, 0xc5); + } + } else if (qcode == Q_KEY_CODE_PRINT) { + if (key->down) { + ps2_put_keycode(s, 0xe0); + ps2_put_keycode(s, 0x2a); + ps2_put_keycode(s, 0xe0); + ps2_put_keycode(s, 0x37); + } else { + ps2_put_keycode(s, 0xe0); + ps2_put_keycode(s, 0xb7); + ps2_put_keycode(s, 0xe0); + ps2_put_keycode(s, 0xaa); + } } else { - ps2_queue(&s->common, 0xf0); - ps2_queue(&s->common, 0x00); + keycode = qcode_to_keycode_set1[qcode]; + if (keycode) { + if (keycode & 0xff00) { + ps2_put_keycode(s, keycode >> 8); + } + if (!key->down) { + keycode |= 0x80; + } + ps2_put_keycode(s, keycode & 0xff); + } else { + ps2_queue(&s->common, key->down ? 0x00 : 0x80); + } } - return; - } - - for (i = 0; i < count; i++) { - /* XXX: add support for scancode set 1 */ - keycode = scancodes[i]; - if (keycode < 0xe0 && (s->scancode_set > 1 || s->translate)) { - if (keycode & 0x80) { - ps2_put_keycode(&s->common, 0xf0); + } else if (s->scancode_set == 2) { + if (qcode == Q_KEY_CODE_PAUSE) { + if (key->down) { + ps2_put_keycode(s, 0xe1); + ps2_put_keycode(s, 0x14); + ps2_put_keycode(s, 0x77); + ps2_put_keycode(s, 0xe1); + ps2_put_keycode(s, 0xf0); + ps2_put_keycode(s, 0x14); + ps2_put_keycode(s, 0xf0); + ps2_put_keycode(s, 0x77); } - if (s->scancode_set == 1 || s->scancode_set == 2) { - keycode = ps2_raw_keycode[keycode & 0x7f]; - } else if (s->scancode_set == 3) { - keycode = ps2_raw_keycode_set3[keycode & 0x7f]; + } else if (qcode == Q_KEY_CODE_PRINT) { + if (key->down) { + ps2_put_keycode(s, 0xe0); + ps2_put_keycode(s, 0x12); + ps2_put_keycode(s, 0xe0); + ps2_put_keycode(s, 0x7c); + } else { + ps2_put_keycode(s, 0xe0); + ps2_put_keycode(s, 0xf0); + ps2_put_keycode(s, 0x7c); + ps2_put_keycode(s, 0xe0); + ps2_put_keycode(s, 0xf0); + ps2_put_keycode(s, 0x12); } + } else { + keycode = qcode_to_keycode_set2[qcode]; + if (keycode) { + if (keycode & 0xff00) { + ps2_put_keycode(s, keycode >> 8); + } + if (!key->down) { + ps2_put_keycode(s, 0xf0); + } + ps2_put_keycode(s, keycode & 0xff); + } else if (key->down) { + ps2_queue(&s->common, 0x00); + } else if (s->translate) { + ps2_queue(&s->common, 0x80); + } else { + ps2_queue(&s->common, 0xf0); + ps2_queue(&s->common, 0x00); + } + } + } else if (s->scancode_set == 3) { + keycode = qcode_to_keycode_set3[qcode]; + if (keycode) { + /* FIXME: break code should be configured on a key by key basis */ + if (!key->down) { + ps2_put_keycode(s, 0xf0); + } + ps2_put_keycode(s, keycode); + } else if (key->down) { + ps2_queue(&s->common, 0x00); + } else if (s->translate) { + ps2_queue(&s->common, 0x80); + } else { + ps2_queue(&s->common, 0xf0); + ps2_queue(&s->common, 0x00); } - ps2_put_keycode(s, keycode); } } From ec044a80e7216ca290ee2dce0afb864256efa956 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herv=C3=A9=20Poussineau?= Date: Thu, 15 Sep 2016 22:06:27 +0200 Subject: [PATCH 412/723] ps2: do not generate invalid key codes for unknown keys MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead, print a warning message. Signed-off-by: Hervé Poussineau Message-id: 1473969987-5890-6-git-send-email-hpoussin@reactos.org Signed-off-by: Gerd Hoffmann --- hw/input/ps2.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/hw/input/ps2.c b/hw/input/ps2.c index 98da984384f..0d14de08a62 100644 --- a/hw/input/ps2.c +++ b/hw/input/ps2.c @@ -22,6 +22,7 @@ * THE SOFTWARE. */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "hw/hw.h" #include "hw/input/ps2.h" #include "ui/console.h" @@ -621,7 +622,8 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src, } ps2_put_keycode(s, keycode & 0xff); } else { - ps2_queue(&s->common, key->down ? 0x00 : 0x80); + qemu_log_mask(LOG_UNIMP, + "ps2: ignoring key with qcode %d\n", qcode); } } } else if (s->scancode_set == 2) { @@ -660,13 +662,9 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src, ps2_put_keycode(s, 0xf0); } ps2_put_keycode(s, keycode & 0xff); - } else if (key->down) { - ps2_queue(&s->common, 0x00); - } else if (s->translate) { - ps2_queue(&s->common, 0x80); } else { - ps2_queue(&s->common, 0xf0); - ps2_queue(&s->common, 0x00); + qemu_log_mask(LOG_UNIMP, + "ps2: ignoring key with qcode %d\n", qcode); } } } else if (s->scancode_set == 3) { @@ -677,13 +675,9 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src, ps2_put_keycode(s, 0xf0); } ps2_put_keycode(s, keycode); - } else if (key->down) { - ps2_queue(&s->common, 0x00); - } else if (s->translate) { - ps2_queue(&s->common, 0x80); } else { - ps2_queue(&s->common, 0xf0); - ps2_queue(&s->common, 0x00); + qemu_log_mask(LOG_UNIMP, + "ps2: ignoring key with qcode %d\n", qcode); } } } From f643e469f31df735fd5c42ab317f96ebfe749871 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 27 Sep 2016 16:18:34 +0100 Subject: [PATCH 413/723] coroutine: add qemu_coroutine_entered() function See the doc comments for a description of this new coroutine API. Signed-off-by: Stefan Hajnoczi Reviewed-by: Fam Zheng Message-id: 1474989516-18255-2-git-send-email-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- include/qemu/coroutine.h | 13 +++++++++++++ util/qemu-coroutine.c | 5 +++++ 2 files changed, 18 insertions(+) diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h index 29a20782f0a..e6a60d55fd5 100644 --- a/include/qemu/coroutine.h +++ b/include/qemu/coroutine.h @@ -92,6 +92,19 @@ Coroutine *coroutine_fn qemu_coroutine_self(void); */ bool qemu_in_coroutine(void); +/** + * Return true if the coroutine is currently entered + * + * A coroutine is "entered" if it has not yielded from the current + * qemu_coroutine_enter() call used to run it. This does not mean that the + * coroutine is currently executing code since it may have transferred control + * to another coroutine using qemu_coroutine_enter(). + * + * When several coroutines enter each other there may be no way to know which + * ones have already been entered. In such situations this function can be + * used to avoid recursively entering coroutines. + */ +bool qemu_coroutine_entered(Coroutine *co); /** diff --git a/util/qemu-coroutine.c b/util/qemu-coroutine.c index 3cbf2254871..737bffa984a 100644 --- a/util/qemu-coroutine.c +++ b/util/qemu-coroutine.c @@ -146,3 +146,8 @@ void coroutine_fn qemu_coroutine_yield(void) self->caller = NULL; qemu_coroutine_switch(self, to, COROUTINE_YIELD); } + +bool qemu_coroutine_entered(Coroutine *co) +{ + return co->caller; +} From afe16f3f477bc656932a640a09769db486446f07 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 27 Sep 2016 16:18:35 +0100 Subject: [PATCH 414/723] test-coroutine: test qemu_coroutine_entered() Signed-off-by: Stefan Hajnoczi Reviewed-by: Fam Zheng Message-id: 1474989516-18255-3-git-send-email-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- tests/test-coroutine.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/tests/test-coroutine.c b/tests/test-coroutine.c index 6431dd6d7cb..abd97c23c12 100644 --- a/tests/test-coroutine.c +++ b/tests/test-coroutine.c @@ -52,6 +52,47 @@ static void test_self(void) qemu_coroutine_enter(coroutine); } +/* + * Check that qemu_coroutine_entered() works + */ + +static void coroutine_fn verify_entered_step_2(void *opaque) +{ + Coroutine *caller = (Coroutine *)opaque; + + g_assert(qemu_coroutine_entered(caller)); + g_assert(qemu_coroutine_entered(qemu_coroutine_self())); + qemu_coroutine_yield(); + + /* Once more to check it still works after yielding */ + g_assert(qemu_coroutine_entered(caller)); + g_assert(qemu_coroutine_entered(qemu_coroutine_self())); + qemu_coroutine_yield(); +} + +static void coroutine_fn verify_entered_step_1(void *opaque) +{ + Coroutine *self = qemu_coroutine_self(); + Coroutine *coroutine; + + g_assert(qemu_coroutine_entered(self)); + + coroutine = qemu_coroutine_create(verify_entered_step_2, self); + g_assert(!qemu_coroutine_entered(coroutine)); + qemu_coroutine_enter(coroutine); + g_assert(!qemu_coroutine_entered(coroutine)); + qemu_coroutine_enter(coroutine); +} + +static void test_entered(void) +{ + Coroutine *coroutine; + + coroutine = qemu_coroutine_create(verify_entered_step_1, NULL); + g_assert(!qemu_coroutine_entered(coroutine)); + qemu_coroutine_enter(coroutine); +} + /* * Check that coroutines may nest multiple levels */ @@ -389,6 +430,7 @@ int main(int argc, char **argv) g_test_add_func("/basic/yield", test_yield); g_test_add_func("/basic/nesting", test_nesting); g_test_add_func("/basic/self", test_self); + g_test_add_func("/basic/entered", test_entered); g_test_add_func("/basic/in_coroutine", test_in_coroutine); g_test_add_func("/basic/order", test_order); if (g_test_perf()) { From fe121b9d3c4258e41f7efa4976bf79151b2d5dbb Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 27 Sep 2016 16:18:36 +0100 Subject: [PATCH 415/723] linux-aio: fix re-entrant completion processing Commit 0ed93d84edabc7656f5c998ae1a346fe8b94ca54 ("linux-aio: process completions from ioq_submit()") added an optimization that processes completions each time ioq_submit() returns with requests in flight. This commit introduces a "Co-routine re-entered recursively" error which can be triggered with -drive format=qcow2,aio=native. Fam Zheng , Kevin Wolf , and I debugged the following backtrace: (gdb) bt #0 0x00007ffff0a046f5 in raise () at /lib64/libc.so.6 #1 0x00007ffff0a062fa in abort () at /lib64/libc.so.6 #2 0x0000555555ac0013 in qemu_coroutine_enter (co=0x5555583464d0) at util/qemu-coroutine.c:113 #3 0x0000555555a4b663 in qemu_laio_process_completions (s=s@entry=0x555557e2f7f0) at block/linux-aio.c:218 #4 0x0000555555a4b874 in ioq_submit (s=s@entry=0x555557e2f7f0) at block/linux-aio.c:331 #5 0x0000555555a4ba12 in laio_do_submit (fd=fd@entry=13, laiocb=laiocb@entry=0x555559d38ae0, offset=offset@entry=2932727808, type=type@entry=1) at block/linux-aio.c:383 #6 0x0000555555a4bbd3 in laio_co_submit (bs=, s=0x555557e2f7f0, fd=13, offset=2932727808, qiov=0x555559d38e20, type=1) at block/linux-aio.c:402 #7 0x0000555555a4fd23 in bdrv_driver_preadv (bs=bs@entry=0x55555663bcb0, offset=offset@entry=2932727808, bytes=bytes@entry=8192, qiov=qiov@entry=0x555559d38e20, flags=0) at block/io.c:804 #8 0x0000555555a52b34 in bdrv_aligned_preadv (bs=bs@entry=0x55555663bcb0, req=req@entry=0x555559d38d20, offset=offset@entry=2932727808, bytes=bytes@entry=8192, align=align@entry=512, qiov=qiov@entry=0x555559d38e20, flags=0) at block/io.c:1041 #9 0x0000555555a52db8 in bdrv_co_preadv (child=, offset=2932727808, bytes=8192, qiov=qiov@entry=0x555559d38e20, flags=flags@entry=0) at block/io.c:1133 #10 0x0000555555a29629 in qcow2_co_preadv (bs=0x555556635890, offset=6178725888, bytes=8192, qiov=0x555557527840, flags=) at block/qcow2.c:1509 #11 0x0000555555a4fd23 in bdrv_driver_preadv (bs=bs@entry=0x555556635890, offset=offset@entry=6178725888, bytes=bytes@entry=8192, qiov=qiov@entry=0x555557527840, flags=0) at block/io.c:804 #12 0x0000555555a52b34 in bdrv_aligned_preadv (bs=bs@entry=0x555556635890, req=req@entry=0x555559d39000, offset=offset@entry=6178725888, bytes=bytes@entry=8192, align=align@entry=1, qiov=qiov@entry=0x555557527840, flags=0) at block/io.c:1041 #13 0x0000555555a52db8 in bdrv_co_preadv (child=, offset=offset@entry=6178725888, bytes=bytes@entry=8192, qiov=qiov@entry=0x555557527840, flags=flags@entry=0) at block/io.c:1133 #14 0x0000555555a4515a in blk_co_preadv (blk=0x5555566356d0, offset=6178725888, bytes=8192, qiov=0x555557527840, flags=0) at block/block-backend.c:783 #15 0x0000555555a45266 in blk_aio_read_entry (opaque=0x5555577025e0) at block/block-backend.c:991 #16 0x0000555555ac0cfa in coroutine_trampoline (i0=, i1=) at util/coroutine-ucontext.c:78 It turned out that re-entrant ioq_submit() and completion processing between three requests caused this error. The following check is not sufficient to prevent recursively entering coroutines: if (laiocb->co != qemu_coroutine_self()) { qemu_coroutine_enter(laiocb->co); } As the following coroutine backtrace shows, not just the current coroutine (self) can be entered. There might also be other coroutines that are currently entered and transferred control due to the qcow2 lock (CoMutex): (gdb) qemu coroutine 0x5555583464d0 #0 0x0000555555ac0c90 in qemu_coroutine_switch (from_=from_@entry=0x5555583464d0, to_=to_@entry=0x5555572f9890, action=action@entry=COROUTINE_ENTER) at util/coroutine-ucontext.c:175 #1 0x0000555555abfe54 in qemu_coroutine_enter (co=0x5555572f9890) at util/qemu-coroutine.c:117 #2 0x0000555555ac031c in qemu_co_queue_run_restart (co=co@entry=0x5555583462c0) at util/qemu-coroutine-lock.c:60 #3 0x0000555555abfe5e in qemu_coroutine_enter (co=0x5555583462c0) at util/qemu-coroutine.c:119 #4 0x0000555555a4b663 in qemu_laio_process_completions (s=s@entry=0x555557e2f7f0) at block/linux-aio.c:218 #5 0x0000555555a4b874 in ioq_submit (s=s@entry=0x555557e2f7f0) at block/linux-aio.c:331 #6 0x0000555555a4ba12 in laio_do_submit (fd=fd@entry=13, laiocb=laiocb@entry=0x55555a338b40, offset=offset@entry=2911477760, type=type@entry=1) at block/linux-aio.c:383 #7 0x0000555555a4bbd3 in laio_co_submit (bs=, s=0x555557e2f7f0, fd=13, offset=2911477760, qiov=0x55555a338e80, type=1) at block/linux-aio.c:402 #8 0x0000555555a4fd23 in bdrv_driver_preadv (bs=bs@entry=0x55555663bcb0, offset=offset@entry=2911477760, bytes=bytes@entry=8192, qiov=qiov@entry=0x55555a338e80, flags=0) at block/io.c:804 #9 0x0000555555a52b34 in bdrv_aligned_preadv (bs=bs@entry=0x55555663bcb0, req=req@entry=0x55555a338d80, offset=offset@entry=2911477760, bytes=bytes@entry=8192, align=align@entry=512, qiov=qiov@entry=0x55555a338e80, flags=0) at block/io.c:1041 #10 0x0000555555a52db8 in bdrv_co_preadv (child=, offset=2911477760, bytes=8192, qiov=qiov@entry=0x55555a338e80, flags=flags@entry=0) at block/io.c:1133 #11 0x0000555555a29629 in qcow2_co_preadv (bs=0x555556635890, offset=6157475840, bytes=8192, qiov=0x5555575df720, flags=) at block/qcow2.c:1509 #12 0x0000555555a4fd23 in bdrv_driver_preadv (bs=bs@entry=0x555556635890, offset=offset@entry=6157475840, bytes=bytes@entry=8192, qiov=qiov@entry=0x5555575df720, flags=0) at block/io.c:804 #13 0x0000555555a52b34 in bdrv_aligned_preadv (bs=bs@entry=0x555556635890, req=req@entry=0x55555a339060, offset=offset@entry=6157475840, bytes=bytes@entry=8192, align=align@entry=1, qiov=qiov@entry=0x5555575df720, flags=0) at block/io.c:1041 #14 0x0000555555a52db8 in bdrv_co_preadv (child=, offset=offset@entry=6157475840, bytes=bytes@entry=8192, qiov=qiov@entry=0x5555575df720, flags=flags@entry=0) at block/io.c:1133 #15 0x0000555555a4515a in blk_co_preadv (blk=0x5555566356d0, offset=6157475840, bytes=8192, qiov=0x5555575df720, flags=0) at block/block-backend.c:783 #16 0x0000555555a45266 in blk_aio_read_entry (opaque=0x555557231aa0) at block/block-backend.c:991 #17 0x0000555555ac0cfa in coroutine_trampoline (i0=, i1=) at util/coroutine-ucontext.c:78 Use the new qemu_coroutine_entered() function instead of comparing against qemu_coroutine_self(). This is correct because: 1. If a coroutine is not entered then it must have yielded to wait for I/O completion. It is therefore safe to enter. 2. If a coroutine is entered then it must be in ioq_submit()/qemu_laio_process_completions() because otherwise it would be yielded while waiting for I/O completion. Therefore it will check laio->ret and return from ioq_submit() instead of yielding, i.e. it's guaranteed not to hang. Reported-by: Fam Zheng Tested-by: Fam Zheng Signed-off-by: Stefan Hajnoczi Reviewed-by: Fam Zheng Message-id: 1474989516-18255-4-git-send-email-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- block/linux-aio.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/block/linux-aio.c b/block/linux-aio.c index d4e19d444cf..1685ec29a3a 100644 --- a/block/linux-aio.c +++ b/block/linux-aio.c @@ -94,9 +94,12 @@ static void qemu_laio_process_completion(struct qemu_laiocb *laiocb) laiocb->ret = ret; if (laiocb->co) { - /* Jump and continue completion for foreign requests, don't do - * anything for current request, it will be completed shortly. */ - if (laiocb->co != qemu_coroutine_self()) { + /* If the coroutine is already entered it must be in ioq_submit() and + * will notice laio->ret has been filled in when it eventually runs + * later. Coroutines cannot be entered recursively so avoid doing + * that! + */ + if (!qemu_coroutine_entered(laiocb->co)) { qemu_coroutine_enter(laiocb->co); } } else { From 2c7c4cf0c446a082acb3f42200936c4a6edaf68e Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Wed, 14 Sep 2016 18:03:41 +0100 Subject: [PATCH 416/723] trace: move util/buffer.c trace points into correct file The trace points for util/buffer.c were mistakenly put in the io/trace-events file, instead of util/trace-events in commit 892bd32ea38bbe9709ff0b6db3053bdf06eec9fb Author: Daniel P. Berrange Date: Thu Jun 16 09:39:50 2016 +0100 trace: split out trace events for io/ directory Move all trace-events for files in the io/ directory to Signed-off-by: Daniel P. Berrange Reviewed-by: Eric Blake Message-id: 1473872624-23285-2-git-send-email-berrange@redhat.com Signed-off-by: Stefan Hajnoczi --- io/trace-events | 6 ------ util/trace-events | 6 ++++++ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/io/trace-events b/io/trace-events index d064665f441..e31b596ca1d 100644 --- a/io/trace-events +++ b/io/trace-events @@ -1,11 +1,5 @@ # See docs/tracing.txt for syntax documentation. -# io/buffer.c -buffer_resize(const char *buf, size_t olen, size_t len) "%s: old %zd, new %zd" -buffer_move_empty(const char *buf, size_t len, const char *from) "%s: %zd bytes from %s" -buffer_move(const char *buf, size_t len, const char *from) "%s: %zd bytes from %s" -buffer_free(const char *buf, size_t len) "%s: capacity %zd" - # io/task.c qio_task_new(void *task, void *source, void *func, void *opaque) "Task new task=%p source=%p func=%p opaque=%p" qio_task_complete(void *task) "Task complete task=%p" diff --git a/util/trace-events b/util/trace-events index 747e6baf75e..9114654810f 100644 --- a/util/trace-events +++ b/util/trace-events @@ -1,5 +1,11 @@ # See docs/tracing.txt for syntax documentation. +# util/buffer.c +buffer_resize(const char *buf, size_t olen, size_t len) "%s: old %zd, new %zd" +buffer_move_empty(const char *buf, size_t len, const char *from) "%s: %zd bytes from %s" +buffer_move(const char *buf, size_t len, const char *from) "%s: %zd bytes from %s" +buffer_free(const char *buf, size_t len) "%s: capacity %zd" + # util/oslib-win32.c # util/oslib-posix.c qemu_memalign(size_t alignment, size_t size, void *ptr) "alignment %zu size %zu ptr %p" From a409aada20212a629b7e6bd8b9abf2773f97c65a Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Wed, 14 Sep 2016 18:03:42 +0100 Subject: [PATCH 417/723] trace: move util/qemu-coroutine*.c trace points into correct file The trace points for util/qemu-coroutine*.c were mistakenly left in the top level trace-events file, instead of util/trace-events in commit 492bb2dd651e780c0723580880acbedb5661e5ad Author: Daniel P. Berrange Date: Thu Jun 16 09:39:48 2016 +0100 trace: split out trace events for util/ directory Signed-off-by: Daniel P. Berrange Reviewed-by: Eric Blake Message-id: 1473872624-23285-3-git-send-email-berrange@redhat.com Signed-off-by: Stefan Hajnoczi --- trace-events | 13 ------------- util/trace-events | 13 +++++++++++++ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/trace-events b/trace-events index 1cb9d37ce4b..55bef8c7708 100644 --- a/trace-events +++ b/trace-events @@ -83,19 +83,6 @@ xen_map_cache(uint64_t phys_addr) "want %#"PRIx64 xen_remap_bucket(uint64_t index) "index %#"PRIx64 xen_map_cache_return(void* ptr) "%p" -# qemu-coroutine.c -qemu_coroutine_enter(void *from, void *to, void *opaque) "from %p to %p opaque %p" -qemu_coroutine_yield(void *from, void *to) "from %p to %p" -qemu_coroutine_terminate(void *co) "self %p" - -# qemu-coroutine-lock.c -qemu_co_queue_run_restart(void *co) "co %p" -qemu_co_queue_next(void *nxt) "next %p" -qemu_co_mutex_lock_entry(void *mutex, void *self) "mutex %p self %p" -qemu_co_mutex_lock_return(void *mutex, void *self) "mutex %p self %p" -qemu_co_mutex_unlock_entry(void *mutex, void *self) "mutex %p self %p" -qemu_co_mutex_unlock_return(void *mutex, void *self) "mutex %p self %p" - # monitor.c handle_qmp_command(void *mon, const char *cmd_name) "mon %p cmd_name \"%s\"" monitor_protocol_event_handler(uint32_t event, void *qdict) "event=%d data=%p" diff --git a/util/trace-events b/util/trace-events index 9114654810f..ed06aee2ec7 100644 --- a/util/trace-events +++ b/util/trace-events @@ -6,6 +6,19 @@ buffer_move_empty(const char *buf, size_t len, const char *from) "%s: %zd bytes buffer_move(const char *buf, size_t len, const char *from) "%s: %zd bytes from %s" buffer_free(const char *buf, size_t len) "%s: capacity %zd" +# util/qemu-coroutine.c +qemu_coroutine_enter(void *from, void *to, void *opaque) "from %p to %p opaque %p" +qemu_coroutine_yield(void *from, void *to) "from %p to %p" +qemu_coroutine_terminate(void *co) "self %p" + +# util/qemu-coroutine-lock.c +qemu_co_queue_run_restart(void *co) "co %p" +qemu_co_queue_next(void *nxt) "next %p" +qemu_co_mutex_lock_entry(void *mutex, void *self) "mutex %p self %p" +qemu_co_mutex_lock_return(void *mutex, void *self) "mutex %p self %p" +qemu_co_mutex_unlock_entry(void *mutex, void *self) "mutex %p self %p" +qemu_co_mutex_unlock_return(void *mutex, void *self) "mutex %p self %p" + # util/oslib-win32.c # util/oslib-posix.c qemu_memalign(size_t alignment, size_t size, void *ptr) "alignment %zu size %zu ptr %p" From e97eb6f7f03282f7e3db19865eb5b4fbd5f69f8b Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Wed, 14 Sep 2016 18:03:43 +0100 Subject: [PATCH 418/723] trace: move hw/mem/pc-dimm.c trace points into correct file The trace points for hw/mem/pc-dimm.c were mistakenly put in the hw/i386/trace-events file, instead of hw/mem/trace-events in commit 5eb76e480b42206d3640c1aab8a376ba350f70bb Author: Daniel P. Berrange Date: Thu Jun 16 09:40:10 2016 +0100 trace: split out trace events for hw/i386/ directory Signed-off-by: Daniel P. Berrange Reviewed-by: Eric Blake Message-id: 1473872624-23285-4-git-send-email-berrange@redhat.com Signed-off-by: Stefan Hajnoczi --- Makefile.objs | 1 + hw/i386/trace-events | 4 ---- hw/mem/trace-events | 5 +++++ 3 files changed, 6 insertions(+), 4 deletions(-) create mode 100644 hw/mem/trace-events diff --git a/Makefile.objs b/Makefile.objs index 7301544cddd..571ac1101de 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -142,6 +142,7 @@ trace-events-y += hw/dma/trace-events trace-events-y += hw/sparc/trace-events trace-events-y += hw/sd/trace-events trace-events-y += hw/isa/trace-events +trace-events-y += hw/mem/trace-events trace-events-y += hw/i386/trace-events trace-events-y += hw/9pfs/trace-events trace-events-y += hw/ppc/trace-events diff --git a/hw/i386/trace-events b/hw/i386/trace-events index 1938b988d99..d2b497327ee 100644 --- a/hw/i386/trace-events +++ b/hw/i386/trace-events @@ -7,10 +7,6 @@ xen_platform_log(char *s) "xen platform: %s" xen_pv_mmio_read(uint64_t addr) "WARNING: read from Xen PV Device MMIO space (address %"PRIx64")" xen_pv_mmio_write(uint64_t addr) "WARNING: write to Xen PV Device MMIO space (address %"PRIx64")" -# hw/i386/pc.c -mhp_pc_dimm_assigned_slot(int slot) "%d" -mhp_pc_dimm_assigned_address(uint64_t addr) "0x%"PRIx64 - # hw/i386/x86-iommu.c x86_iommu_iec_notify(bool global, uint32_t index, uint32_t mask) "Notify IEC invalidation: global=%d index=%" PRIu32 " mask=%" PRIu32 diff --git a/hw/mem/trace-events b/hw/mem/trace-events new file mode 100644 index 00000000000..323c3c10d51 --- /dev/null +++ b/hw/mem/trace-events @@ -0,0 +1,5 @@ +# See docs/trace-events.txt for syntax documentation. + +# hw/mem/pc-dimm.c +mhp_pc_dimm_assigned_slot(int slot) "%d" +mhp_pc_dimm_assigned_address(uint64_t addr) "0x%"PRIx64 From 331f5eb28a6b537558ac595879d2179885df9db5 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Wed, 14 Sep 2016 18:03:44 +0100 Subject: [PATCH 419/723] trace: move hw/virtio/virtio-balloon.c trace points into correct file The trace points for hw/virtio/virtio-balloon.c were mistakenly put in the top level trace-events file, instead of util/trace-events in commit 270ab88f7c1112389a02cee0e3e03b20fcc7547e Author: Daniel P. Berrange Date: Thu Jun 16 09:39:57 2016 +0100 trace: split out trace events for hw/virtio/ directory Signed-off-by: Daniel P. Berrange Reviewed-by: Eric Blake Message-id: 1473872624-23285-5-git-send-email-berrange@redhat.com Signed-off-by: Stefan Hajnoczi --- hw/virtio/trace-events | 5 +++++ trace-events | 4 ---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events index 55184d33b3e..8756cefa79b 100644 --- a/hw/virtio/trace-events +++ b/hw/virtio/trace-events @@ -14,3 +14,8 @@ virtio_rng_guest_not_ready(void *rng) "rng %p: guest not ready" virtio_rng_pushed(void *rng, size_t len) "rng %p: %zd bytes pushed" virtio_rng_request(void *rng, size_t size, unsigned quota) "rng %p: %zd bytes requested, %u bytes quota left" +# hw/virtio/virtio-balloon.c +virtio_balloon_handle_output(const char *name, uint64_t gpa) "section name: %s gpa: %"PRIx64 +virtio_balloon_get_config(uint32_t num_pages, uint32_t actual) "num_pages: %d actual: %d" +virtio_balloon_set_config(uint32_t actual, uint32_t oldactual) "actual: %d oldactual: %d" +virtio_balloon_to_target(uint64_t target, uint32_t num_pages) "balloon target: %"PRIx64" num_pages: %d" diff --git a/trace-events b/trace-events index 55bef8c7708..a45dc562a0f 100644 --- a/trace-events +++ b/trace-events @@ -37,10 +37,6 @@ cpu_out(unsigned int addr, char size, unsigned int val) "addr %#x(%c) value %u" # balloon.c # Since requests are raised via monitor, not many tracepoints are needed. balloon_event(void *opaque, unsigned long addr) "opaque %p addr %lu" -virtio_balloon_handle_output(const char *name, uint64_t gpa) "section name: %s gpa: %"PRIx64 -virtio_balloon_get_config(uint32_t num_pages, uint32_t actual) "num_pages: %d actual: %d" -virtio_balloon_set_config(uint32_t actual, uint32_t oldactual) "actual: %d oldactual: %d" -virtio_balloon_to_target(uint64_t target, uint32_t num_pages) "balloon target: %"PRIx64" num_pages: %d" # vl.c vm_state_notify(int running, int reason) "running %d reason %d" From 2bfe11c8fac96db4f94abbe818fbc964a6744130 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Vilanova?= Date: Mon, 19 Sep 2016 14:55:07 +0200 Subject: [PATCH 420/723] trace: Properly initialize dynamic event states in hot-plugged vCPUs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every time a vCPU is hot-plugged, it will "inherit" its tracing state from the global state array. That is, if *any* existing vCPU has an event enabled, new vCPUs will have too. Signed-off-by: Lluís Vilanova Message-id: 147428970768.15111.7664565956870423529.stgit@fimbulvetr.bsc.es Signed-off-by: Stefan Hajnoczi --- bsd-user/main.c | 1 - linux-user/main.c | 1 - qom/cpu.c | 3 +++ stubs/trace-control.c | 6 ++++++ trace/control-target.c | 37 +++++++++++++++++++++++++++++++++++++ trace/control.c | 19 ------------------- trace/control.h | 19 ++++++++----------- vl.c | 1 - 8 files changed, 54 insertions(+), 33 deletions(-) diff --git a/bsd-user/main.c b/bsd-user/main.c index 0fb08e405d5..f58bb435795 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -1133,7 +1133,6 @@ int main(int argc, char **argv) gdbserver_start (gdbstub_port); gdb_handlesig(cpu, 0); } - trace_init_vcpu_events(); cpu_loop(env); /* never exits */ return 0; diff --git a/linux-user/main.c b/linux-user/main.c index 8daebe07670..424f2b6f7b8 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -4800,7 +4800,6 @@ int main(int argc, char **argv, char **envp) } gdb_handlesig(cpu, 0); } - trace_init_vcpu_events(); cpu_loop(env); /* never exits */ return 0; diff --git a/qom/cpu.c b/qom/cpu.c index f783b5a6bd6..f87fffabd12 100644 --- a/qom/cpu.c +++ b/qom/cpu.c @@ -333,6 +333,9 @@ static void cpu_common_realizefn(DeviceState *dev, Error **errp) cpu_synchronize_post_init(cpu); cpu_resume(cpu); } + + /* NOTE: latest generic point where the cpu is fully realized */ + trace_init_vcpu(cpu); } static void cpu_common_initfn(Object *obj) diff --git a/stubs/trace-control.c b/stubs/trace-control.c index 2dfcd9fb2bd..f765a020188 100644 --- a/stubs/trace-control.c +++ b/stubs/trace-control.c @@ -44,3 +44,9 @@ void trace_event_set_vcpu_state_dynamic(CPUState *vcpu, /* should never be called on non-target binaries */ abort(); } + +void trace_init_vcpu(CPUState *vcpu) +{ + /* should never be called on non-target binaries */ + abort(); +} diff --git a/trace/control-target.c b/trace/control-target.c index 72081e2a34f..3b7d99b44cf 100644 --- a/trace/control-target.c +++ b/trace/control-target.c @@ -81,3 +81,40 @@ void trace_event_set_vcpu_state_dynamic(CPUState *vcpu, } } } + +static bool adding_first_cpu(void) +{ + CPUState *cpu; + size_t count = 0; + CPU_FOREACH(cpu) { + count++; + if (count > 1) { + return false; + } + } + return true; +} + +void trace_init_vcpu(CPUState *vcpu) +{ + TraceEvent *ev = NULL; + + while ((ev = trace_event_pattern("*", ev)) != NULL) { + if (trace_event_is_vcpu(ev) && + trace_event_get_state_static(ev) && + trace_event_get_state_dynamic(ev)) { + TraceEventID id = trace_event_get_id(ev); + if (adding_first_cpu()) { + /* check preconditions */ + assert(trace_events_dstate[id] == 1); + /* disable early-init state ... */ + trace_events_dstate[id] = 0; + trace_events_enabled_count--; + /* ... and properly re-enable */ + trace_event_set_vcpu_state_dynamic(vcpu, ev, true); + } else { + trace_event_set_vcpu_state_dynamic(vcpu, ev, true); + } + } + } +} diff --git a/trace/control.c b/trace/control.c index 05d85accbd7..10b3e9babad 100644 --- a/trace/control.c +++ b/trace/control.c @@ -269,22 +269,3 @@ char *trace_opt_parse(const char *optarg) return trace_file; } - -void trace_init_vcpu_events(void) -{ - TraceEvent *ev = NULL; - while ((ev = trace_event_pattern("*", ev)) != NULL) { - if (trace_event_is_vcpu(ev) && - trace_event_get_state_static(ev) && - trace_event_get_state_dynamic(ev)) { - TraceEventID id = trace_event_get_id(ev); - /* check preconditions */ - assert(trace_events_dstate[id] == 1); - /* disable early-init state ... */ - trace_events_dstate[id] = 0; - trace_events_enabled_count--; - /* ... and properly re-enable */ - trace_event_set_state_dynamic(ev, true); - } - } -} diff --git a/trace/control.h b/trace/control.h index 27a16fc9557..a22d11242e0 100644 --- a/trace/control.h +++ b/trace/control.h @@ -238,6 +238,14 @@ bool trace_init_backends(void); */ void trace_init_file(const char *file); +/** + * trace_init_vcpu: + * @vcpu: Added vCPU. + * + * Set initial dynamic event state for a hot-plugged vCPU. + */ +void trace_init_vcpu(CPUState *vcpu); + /** * trace_list_events: * @@ -269,17 +277,6 @@ extern QemuOptsList qemu_trace_opts; */ char *trace_opt_parse(const char *optarg); -/** - * trace_init_vcpu_events: - * - * Re-synchronize initial event state with vCPUs (which can be created after - * trace_init_events()). - * - * Precondition: event states won't be changed between trace_enable_events() and - * trace_init_vcpu_events() (e.g., through QMP). - */ -void trace_init_vcpu_events(void); - #include "trace/control-internal.h" diff --git a/vl.c b/vl.c index eafda8d7373..04fc1725f32 100644 --- a/vl.c +++ b/vl.c @@ -4658,7 +4658,6 @@ int main(int argc, char **argv, char **envp) os_setup_post(); - trace_init_vcpu_events(); main_loop(); replay_disable_events(); iothread_stop_all(); From b9d72215248789abdd1e2bfce746eff2eddd67fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Vilanova?= Date: Mon, 19 Sep 2016 14:55:13 +0200 Subject: [PATCH 421/723] trace: Add event "guest_cpu_enter" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signals the hot-plugging of a new virtual (guest) CPU. Signed-off-by: Lluís Vilanova Message-id: 147428971313.15111.18023030883528426840.stgit@fimbulvetr.bsc.es Signed-off-by: Stefan Hajnoczi --- trace-events | 8 ++++++++ trace/control-target.c | 3 +++ 2 files changed, 11 insertions(+) diff --git a/trace-events b/trace-events index a45dc562a0f..0492c960dbe 100644 --- a/trace-events +++ b/trace-events @@ -140,6 +140,14 @@ colo_filter_rewriter_conn_offset(uint32_t offset) ": offset=%u\n" ### Guest events, keep at bottom + +## vCPU + +# Hot-plug a new virtual (guest) CPU +# +# Targets: all +vcpu guest_cpu_enter(void) + # @vaddr: Access' virtual address. # @info : Access' information (see below). # diff --git a/trace/control-target.c b/trace/control-target.c index 3b7d99b44cf..52fcce5a005 100644 --- a/trace/control-target.c +++ b/trace/control-target.c @@ -9,6 +9,7 @@ #include "qemu/osdep.h" #include "cpu.h" +#include "trace.h" #include "trace/control.h" #include "translate-all.h" @@ -117,4 +118,6 @@ void trace_init_vcpu(CPUState *vcpu) } } } + + trace_guest_cpu_enter(vcpu); } From 2cc2d082b52ef0aa9bffff512ce552391405ce9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Vilanova?= Date: Mon, 19 Sep 2016 14:55:18 +0200 Subject: [PATCH 422/723] trace: Add event "guest_cpu_reset" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signals the reset of the state a virtual (guest) CPU. Signed-off-by: Lluís Vilanova Message-id: 147428971851.15111.8799439252178273840.stgit@fimbulvetr.bsc.es Signed-off-by: Stefan Hajnoczi --- qom/cpu.c | 3 +++ trace-events | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/qom/cpu.c b/qom/cpu.c index f87fffabd12..484c49388d6 100644 --- a/qom/cpu.c +++ b/qom/cpu.c @@ -29,6 +29,7 @@ #include "qemu/error-report.h" #include "sysemu/sysemu.h" #include "hw/qdev-properties.h" +#include "trace.h" bool cpu_exists(int64_t id) { @@ -245,6 +246,8 @@ void cpu_reset(CPUState *cpu) if (klass->reset != NULL) { (*klass->reset)(cpu); } + + trace_guest_cpu_reset(cpu); } static void cpu_common_reset(CPUState *cpu) diff --git a/trace-events b/trace-events index 0492c960dbe..fb96f6c3331 100644 --- a/trace-events +++ b/trace-events @@ -148,6 +148,11 @@ colo_filter_rewriter_conn_offset(uint32_t offset) ": offset=%u\n" # Targets: all vcpu guest_cpu_enter(void) +# Reset the state of a virtual (guest) CPU +# +# Targets: all +vcpu guest_cpu_reset(void) + # @vaddr: Access' virtual address. # @info : Access' information (see below). # From 43e21e4907a009d87f6aef44663d9e1f7b181b8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Vilanova?= Date: Thu, 22 Sep 2016 20:40:21 +0200 Subject: [PATCH 423/723] trace: Document the execution mode of guest events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Explicitly state in which execution mode (user, softmmu, all) are guest events available for tracing. Signed-off-by: Lluís Vilanova Message-id: 147456962135.11114.6146034359114598596.stgit@fimbulvetr.bsc.es Signed-off-by: Stefan Hajnoczi --- trace-events | 3 +++ 1 file changed, 3 insertions(+) diff --git a/trace-events b/trace-events index fb96f6c3331..1a4e092418d 100644 --- a/trace-events +++ b/trace-events @@ -169,6 +169,7 @@ vcpu guest_cpu_reset(void) # bool store : 1; /* wheter it's a store operation */ # }; # +# Mode: user, softmmu # Targets: TCG(all) disable vcpu tcg guest_mem_before(TCGv vaddr, uint8_t info) "info=%d", "vaddr=0x%016"PRIx64" info=%d" @@ -177,6 +178,7 @@ disable vcpu tcg guest_mem_before(TCGv vaddr, uint8_t info) "info=%d", "vaddr=0x # # Start executing a guest system call in syscall emulation mode. # +# Mode: user # Targets: TCG(all) disable vcpu guest_user_syscall(uint64_t num, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6, uint64_t arg7, uint64_t arg8) "num=0x%016"PRIx64" arg1=0x%016"PRIx64" arg2=0x%016"PRIx64" arg3=0x%016"PRIx64" arg4=0x%016"PRIx64" arg5=0x%016"PRIx64" arg6=0x%016"PRIx64" arg7=0x%016"PRIx64" arg8=0x%016"PRIx64 @@ -185,5 +187,6 @@ disable vcpu guest_user_syscall(uint64_t num, uint64_t arg1, uint64_t arg2, uint # # Finish executing a guest system call in syscall emulation mode. # +# Mode: user # Targets: TCG(all) disable vcpu guest_user_syscall_ret(uint64_t num, uint64_t ret) "num=0x%016"PRIx64" ret=0x%016"PRIx64 From 84d0984dfe336f24109a6792d06aad0e9ae5e0a6 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Tue, 27 Sep 2016 17:20:11 +0800 Subject: [PATCH 424/723] xenpv: Fix qemu_uuid compiling error 9c5ce8db2 switched the type of qemu_uuid and this should have followed. Fix it. Signed-off-by: Fam Zheng Message-Id: <1474968011-29382-1-git-send-email-famz@redhat.com> Reviewed-by: Eric Blake Acked-by: Stefano Stabellini --- hw/xenpv/xen_domainbuild.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/xenpv/xen_domainbuild.c b/hw/xenpv/xen_domainbuild.c index b439b0ed5d7..457a8976c3f 100644 --- a/hw/xenpv/xen_domainbuild.c +++ b/hw/xenpv/xen_domainbuild.c @@ -232,7 +232,7 @@ int xen_domain_build_pv(const char *kernel, const char *ramdisk, unsigned long xenstore_mfn = 0, console_mfn = 0; int rc; - memcpy(uuid, qemu_uuid, sizeof(uuid)); + memcpy(uuid, &qemu_uuid, sizeof(uuid)); rc = xen_domain_create(xen_xc, ssidref, uuid, flags, &xen_domid); if (rc < 0) { fprintf(stderr, "xen: xc_domain_create() failed\n"); From 664ee76891adce2b1df42d714f4c158a1df4220b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 28 Sep 2016 18:38:10 +0400 Subject: [PATCH 425/723] smbios: fix uuid copy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since 9c5ce8db, the uuid is wrongly copied, as QemuUUID 'in' argument is already a pointer. Fixes ASAN complaining: hw/smbios/smbios.c:489:5: runtime error: load of address 0x7fffcdb91b00 with insufficient space for an object of type '__int128 unsigned' Signed-off-by: Marc-André Lureau Message-Id: <20160928143810.25558-1-marcandre.lureau@redhat.com> Reviewed-by: Laszlo Ersek [Warp the long error message line in commit message. - Fam] Signed-off-by: Fam Zheng --- hw/smbios/smbios.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c index 9a6552aa602..3a96cededdc 100644 --- a/hw/smbios/smbios.c +++ b/hw/smbios/smbios.c @@ -486,7 +486,7 @@ static void smbios_build_type_0_table(void) */ static void smbios_encode_uuid(struct smbios_uuid *uuid, QemuUUID *in) { - memcpy(uuid, &in, 16); + memcpy(uuid, in, 16); if (smbios_uuid_encoded) { uuid->time_low = bswap32(uuid->time_low); uuid->time_mid = bswap16(uuid->time_mid); From 78851fa529a97c7b90c474daf53a4b18d01d20fe Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Thu, 22 Sep 2016 14:34:14 +0100 Subject: [PATCH 426/723] MAINTAINERS: update target-mips maintainers Yongbok Kim takes over the target-mips maintenance from me. Signed-off-by: Leon Alrae Acked-by: Yongbok Kim Signed-off-by: Yongbok Kim --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index f3c1f7f307c..8b18ad006ce 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -145,7 +145,7 @@ F: disas/microblaze.c MIPS M: Aurelien Jarno -M: Leon Alrae +M: Yongbok Kim S: Maintained F: target-mips/ F: hw/mips/ From 73bfa8c0e0295df92d5fe61e0149db7b36cdc0c4 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Wed, 24 Aug 2016 11:40:43 +0100 Subject: [PATCH 427/723] hw/dma: vmstateify rc4030 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert rc4030 to VMState. Now saving the whole 16 entries rather than 15. Signed-off-by: Dr. David Alan Gilbert Reviewed-by: Hervé Poussineau Tested-by: Hervé Poussineau [Yongbok Kim: edited commit message] Signed-off-by: Yongbok Kim --- hw/dma/rc4030.c | 81 +++++++++++++++++-------------------------------- 1 file changed, 27 insertions(+), 54 deletions(-) diff --git a/hw/dma/rc4030.c b/hw/dma/rc4030.c index 2f2576fafb4..17c8518feaf 100644 --- a/hw/dma/rc4030.c +++ b/hw/dma/rc4030.c @@ -616,34 +616,9 @@ static void rc4030_reset(DeviceState *dev) qemu_irq_lower(s->jazz_bus_irq); } -static int rc4030_load(QEMUFile *f, void *opaque, int version_id) +static int rc4030_post_load(void *opaque, int version_id) { rc4030State* s = opaque; - int i, j; - - if (version_id != 2) - return -EINVAL; - - s->config = qemu_get_be32(f); - s->invalid_address_register = qemu_get_be32(f); - for (i = 0; i < 8; i++) - for (j = 0; j < 4; j++) - s->dma_regs[i][j] = qemu_get_be32(f); - s->dma_tl_base = qemu_get_be32(f); - s->dma_tl_limit = qemu_get_be32(f); - s->cache_maint = qemu_get_be32(f); - s->remote_failed_address = qemu_get_be32(f); - s->memory_failed_address = qemu_get_be32(f); - s->cache_ptag = qemu_get_be32(f); - s->cache_ltag = qemu_get_be32(f); - s->cache_bmask = qemu_get_be32(f); - s->memory_refresh_rate = qemu_get_be32(f); - s->nvram_protect = qemu_get_be32(f); - for (i = 0; i < 15; i++) - s->rem_speed[i] = qemu_get_be32(f); - s->imr_jazz = qemu_get_be32(f); - s->isr_jazz = qemu_get_be32(f); - s->itr = qemu_get_be32(f); set_next_tick(s); update_jazz_irq(s); @@ -651,32 +626,31 @@ static int rc4030_load(QEMUFile *f, void *opaque, int version_id) return 0; } -static void rc4030_save(QEMUFile *f, void *opaque) -{ - rc4030State* s = opaque; - int i, j; - - qemu_put_be32(f, s->config); - qemu_put_be32(f, s->invalid_address_register); - for (i = 0; i < 8; i++) - for (j = 0; j < 4; j++) - qemu_put_be32(f, s->dma_regs[i][j]); - qemu_put_be32(f, s->dma_tl_base); - qemu_put_be32(f, s->dma_tl_limit); - qemu_put_be32(f, s->cache_maint); - qemu_put_be32(f, s->remote_failed_address); - qemu_put_be32(f, s->memory_failed_address); - qemu_put_be32(f, s->cache_ptag); - qemu_put_be32(f, s->cache_ltag); - qemu_put_be32(f, s->cache_bmask); - qemu_put_be32(f, s->memory_refresh_rate); - qemu_put_be32(f, s->nvram_protect); - for (i = 0; i < 15; i++) - qemu_put_be32(f, s->rem_speed[i]); - qemu_put_be32(f, s->imr_jazz); - qemu_put_be32(f, s->isr_jazz); - qemu_put_be32(f, s->itr); -} +static const VMStateDescription vmstate_rc4030 = { + .name = "rc4030", + .version_id = 3, + .post_load = rc4030_post_load, + .fields = (VMStateField []) { + VMSTATE_UINT32(config, rc4030State), + VMSTATE_UINT32(invalid_address_register, rc4030State), + VMSTATE_UINT32_2DARRAY(dma_regs, rc4030State, 8, 4), + VMSTATE_UINT32(dma_tl_base, rc4030State), + VMSTATE_UINT32(dma_tl_limit, rc4030State), + VMSTATE_UINT32(cache_maint, rc4030State), + VMSTATE_UINT32(remote_failed_address, rc4030State), + VMSTATE_UINT32(memory_failed_address, rc4030State), + VMSTATE_UINT32(cache_ptag, rc4030State), + VMSTATE_UINT32(cache_ltag, rc4030State), + VMSTATE_UINT32(cache_bmask, rc4030State), + VMSTATE_UINT32(memory_refresh_rate, rc4030State), + VMSTATE_UINT32(nvram_protect, rc4030State), + VMSTATE_UINT32_ARRAY(rem_speed, rc4030State, 16), + VMSTATE_UINT32(imr_jazz, rc4030State), + VMSTATE_UINT32(isr_jazz, rc4030State), + VMSTATE_UINT32(itr, rc4030State), + VMSTATE_END_OF_LIST() + } +}; static void rc4030_do_dma(void *opaque, int n, uint8_t *buf, int len, int is_write) { @@ -753,8 +727,6 @@ static void rc4030_initfn(Object *obj) sysbus_init_irq(sysbus, &s->timer_irq); sysbus_init_irq(sysbus, &s->jazz_bus_irq); - register_savevm(NULL, "rc4030", 0, 2, rc4030_save, rc4030_load, s); - sysbus_init_mmio(sysbus, &s->iomem_chipset); sysbus_init_mmio(sysbus, &s->iomem_jazzio); } @@ -813,6 +785,7 @@ static void rc4030_class_init(ObjectClass *klass, void *class_data) dc->realize = rc4030_realize; dc->unrealize = rc4030_unrealize; dc->reset = rc4030_reset; + dc->vmsd = &vmstate_rc4030; } static const TypeInfo rc4030_info = { From 4085f5c7a239567a292876f46cb59d9b19bcf6ac Mon Sep 17 00:00:00 2001 From: John Snow Date: Thu, 22 Sep 2016 21:45:50 -0400 Subject: [PATCH 428/723] block: reintroduce bdrv_flush_all Commit fe1a9cbc moved the flush_all routine from the bdrv layer to the block-backend layer. In doing so, however, the semantics of the routine changed slightly such that flush_all now used blk_flush instead of bdrv_flush. blk_flush can fail if the attached device model reports that it is not "available," (i.e. the tray is open.) This changed the semantics of flush_all such that it can now fail for e.g. open CDROM drives. Reintroduce bdrv_flush_all to regain the old semantics without having to alter the behavior of blk_flush or blk_flush_all, which are already 'doing the right thing.' Signed-off-by: John Snow Reviewed-by: Kevin Wolf Reviewed-by: Max Reitz Acked-by: Fam Zheng Signed-off-by: Kevin Wolf --- block/io.c | 25 +++++++++++++++++++++++++ include/block/block.h | 1 + 2 files changed, 26 insertions(+) diff --git a/block/io.c b/block/io.c index fdf70807b09..57a2eeb512f 100644 --- a/block/io.c +++ b/block/io.c @@ -1619,6 +1619,31 @@ int coroutine_fn bdrv_co_pwrite_zeroes(BdrvChild *child, int64_t offset, BDRV_REQ_ZERO_WRITE | flags); } +/* + * Flush ALL BDSes regardless of if they are reachable via a BlkBackend or not. + */ +int bdrv_flush_all(void) +{ + BdrvNextIterator it; + BlockDriverState *bs = NULL; + int result = 0; + + for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { + AioContext *aio_context = bdrv_get_aio_context(bs); + int ret; + + aio_context_acquire(aio_context); + ret = bdrv_flush(bs); + if (ret < 0 && !result) { + result = ret; + } + aio_context_release(aio_context); + } + + return result; +} + + typedef struct BdrvCoGetBlockStatusData { BlockDriverState *bs; BlockDriverState *base; diff --git a/include/block/block.h b/include/block/block.h index e18233afe0e..811b060f411 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -333,6 +333,7 @@ int bdrv_inactivate_all(void); /* Ensure contents are flushed to disk. */ int bdrv_flush(BlockDriverState *bs); int coroutine_fn bdrv_co_flush(BlockDriverState *bs); +int bdrv_flush_all(void); void bdrv_close_all(void); void bdrv_drain(BlockDriverState *bs); void coroutine_fn bdrv_co_drain(BlockDriverState *bs); From 22af08eacf6b5aa0e6c0581e547380b3eb4f95e9 Mon Sep 17 00:00:00 2001 From: John Snow Date: Thu, 22 Sep 2016 21:45:51 -0400 Subject: [PATCH 429/723] qemu: use bdrv_flush_all for vm_stop et al Reimplement bdrv_flush_all for vm_stop. In contrast to blk_flush_all, bdrv_flush_all does not have device model restrictions. This allows us to flush and halt unconditionally without error. This allows us to do things like migrate when we have a device with an open tray, but has a node that may need to be flushed, or nodes that aren't currently attached to any device and need to be flushed. Specifically, this allows us to migrate when we have a CDROM with an open tray. Signed-off-by: John Snow Reviewed-by: Kevin Wolf Reviewed-by: Max Reitz Acked-by: Fam Zheng Signed-off-by: Kevin Wolf --- cpus.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpus.c b/cpus.c index b2fbe333040..31204bb4b3d 100644 --- a/cpus.c +++ b/cpus.c @@ -751,7 +751,7 @@ static int do_vm_stop(RunState state) bdrv_drain_all(); replay_disable_events(); - ret = blk_flush_all(); + ret = bdrv_flush_all(); return ret; } @@ -1408,7 +1408,7 @@ int vm_stop_force_state(RunState state) bdrv_drain_all(); /* Make sure to return an error if the flush in a previous vm_stop() * failed. */ - return blk_flush_all(); + return bdrv_flush_all(); } } From 49137bf6845eaecad51a047fc06dd11c56118460 Mon Sep 17 00:00:00 2001 From: John Snow Date: Thu, 22 Sep 2016 21:45:52 -0400 Subject: [PATCH 430/723] block-backend: remove blk_flush_all We can teach Xen to drain and flush each device as it needs to, instead of trying to flush ALL devices. This removes the last user of blk_flush_all. The function is therefore removed under the premise that any new uses of blk_flush_all would be the wrong paradigm: either flush the single device that requires flushing, or use an appropriate flush_all mechanism from outside of the BlkBackend layer. Signed-off-by: John Snow Reviewed-by: Max Reitz Acked-by: Fam Zheng Signed-off-by: Kevin Wolf --- block/block-backend.c | 22 ---------------------- hw/i386/xen/xen_platform.c | 2 -- hw/ide/piix.c | 4 ++++ include/sysemu/block-backend.h | 1 - 4 files changed, 4 insertions(+), 25 deletions(-) diff --git a/block/block-backend.c b/block/block-backend.c index 0bd19abdfb9..f34bad58400 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -1640,28 +1640,6 @@ int blk_commit_all(void) return 0; } -int blk_flush_all(void) -{ - BlockBackend *blk = NULL; - int result = 0; - - while ((blk = blk_all_next(blk)) != NULL) { - AioContext *aio_context = blk_get_aio_context(blk); - int ret; - - aio_context_acquire(aio_context); - if (blk_is_inserted(blk)) { - ret = blk_flush(blk); - if (ret < 0 && !result) { - result = ret; - } - } - aio_context_release(aio_context); - } - - return result; -} - /* throttling disk I/O limits */ void blk_set_io_limits(BlockBackend *blk, ThrottleConfig *cfg) diff --git a/hw/i386/xen/xen_platform.c b/hw/i386/xen/xen_platform.c index aa7839324cd..f85635cc9a4 100644 --- a/hw/i386/xen/xen_platform.c +++ b/hw/i386/xen/xen_platform.c @@ -134,8 +134,6 @@ static void platform_fixed_ioport_writew(void *opaque, uint32_t addr, uint32_t v devices, and bit 2 the non-primary-master IDE devices. */ if (val & UNPLUG_ALL_IDE_DISKS) { DPRINTF("unplug disks\n"); - blk_drain_all(); - blk_flush_all(); pci_unplug_disks(pci_dev->bus); } if (val & UNPLUG_ALL_NICS) { diff --git a/hw/ide/piix.c b/hw/ide/piix.c index c190fcaa3c2..d5777fd0b32 100644 --- a/hw/ide/piix.c +++ b/hw/ide/piix.c @@ -179,6 +179,10 @@ int pci_piix3_xen_ide_unplug(DeviceState *dev) if (di != NULL && !di->media_cd) { BlockBackend *blk = blk_by_legacy_dinfo(di); DeviceState *ds = blk_get_attached_dev(blk); + + blk_drain(blk); + blk_flush(blk); + if (ds) { blk_detach_dev(blk, ds); } diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h index 3b29317349b..24d1d853991 100644 --- a/include/sysemu/block-backend.h +++ b/include/sysemu/block-backend.h @@ -152,7 +152,6 @@ BlockAIOCB *blk_aio_ioctl(BlockBackend *blk, unsigned long int req, void *buf, int blk_co_pdiscard(BlockBackend *blk, int64_t offset, int count); int blk_co_flush(BlockBackend *blk); int blk_flush(BlockBackend *blk); -int blk_flush_all(void); int blk_commit_all(void); void blk_drain(BlockBackend *blk); void blk_drain_all(void); From 24df38b00e23f76558ac12d7055c2df8d4b05150 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Mon, 26 Sep 2016 15:03:00 +0200 Subject: [PATCH 431/723] block: Fix error path in qmp_blockdev_change_medium() Commit 00949bab incorrectly changed one instance of &err into errp while touching the line. Change it back. Signed-off-by: Kevin Wolf Reviewed-by: Max Reitz --- blockdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/blockdev.c b/blockdev.c index 29c6561fd89..62d0dd016f1 100644 --- a/blockdev.c +++ b/blockdev.c @@ -2614,7 +2614,7 @@ void qmp_blockdev_change_medium(bool has_device, const char *device, error_free(err); err = NULL; - qmp_x_blockdev_remove_medium(has_device, device, has_id, id, errp); + qmp_x_blockdev_remove_medium(has_device, device, has_id, id, &err); if (err) { error_propagate(errp, err); goto fail; From 0ffcdd9c06343a3fe0b2b3e1ca93ce8aa5366f98 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Wed, 7 Sep 2016 15:26:42 +0200 Subject: [PATCH 432/723] block: Drop aio/cache consistency check from qmp_blockdev_add() The TODO comment has been addressed a while ago and this is now checked in raw-posix, so we don't have to special case this in blockdev-add any more. Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake Reviewed-by: Max Reitz --- blockdev.c | 15 --------------- tests/qemu-iotests/087.out | 2 +- 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/blockdev.c b/blockdev.c index 62d0dd016f1..7820f422104 100644 --- a/blockdev.c +++ b/blockdev.c @@ -3832,21 +3832,6 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp) QDict *qdict; Error *local_err = NULL; - /* TODO Sort it out in raw-posix and drive_new(): Reject aio=native with - * cache.direct=false instead of silently switching to aio=threads, except - * when called from drive_new(). - * - * For now, simply forbidding the combination for all drivers will do. */ - if (options->has_aio && options->aio == BLOCKDEV_AIO_OPTIONS_NATIVE) { - bool direct = options->has_cache && - options->cache->has_direct && - options->cache->direct; - if (!direct) { - error_setg(errp, "aio=native requires cache.direct=true"); - goto fail; - } - } - visit_type_BlockdevOptions(v, NULL, &options, &local_err); if (local_err) { error_propagate(errp, local_err); diff --git a/tests/qemu-iotests/087.out b/tests/qemu-iotests/087.out index bef68626c8d..cd02eaed4cb 100644 --- a/tests/qemu-iotests/087.out +++ b/tests/qemu-iotests/087.out @@ -27,7 +27,7 @@ QMP_VERSION Testing: QMP_VERSION {"return": {}} -{"error": {"class": "GenericError", "desc": "aio=native requires cache.direct=true"}} +{"error": {"class": "GenericError", "desc": "aio=native was specified, but it requires cache.direct=on, which was not specified."}} {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"} From 685552850bf29ef1cd4bef0e2629cbc3ebf0a23b Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 8 Sep 2016 13:08:20 +0200 Subject: [PATCH 433/723] block/qapi: Use separate options type for curl driver We're going to add an option to the file drivers which doesn't apply to the curl drivers, so give them a separate option type. Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake Reviewed-by: Max Reitz --- qapi/block-core.json | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/qapi/block-core.json b/qapi/block-core.json index 92193ab0a1d..b5fdd426c98 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -1721,8 +1721,7 @@ ## # @BlockdevOptionsFile # -# Driver specific block device options for the file backend and similar -# protocols. +# Driver specific block device options for the file backend. # # @filename: path to the image file # @@ -2210,6 +2209,18 @@ 'data': { 'mode': 'ReplicationMode', '*top-id': 'str' } } +## +# @BlockdevOptionsCurl +# +# Driver specific block device options for the curl backend. +# +# @filename: path to the image file +# +# Since: 1.7 +## +{ 'struct': 'BlockdevOptionsCurl', + 'data': { 'filename': 'str' } } + ## # @BlockdevOptions # @@ -2248,13 +2259,13 @@ 'cloop': 'BlockdevOptionsGenericFormat', 'dmg': 'BlockdevOptionsGenericFormat', 'file': 'BlockdevOptionsFile', - 'ftp': 'BlockdevOptionsFile', - 'ftps': 'BlockdevOptionsFile', + 'ftp': 'BlockdevOptionsCurl', + 'ftps': 'BlockdevOptionsCurl', 'gluster': 'BlockdevOptionsGluster', 'host_cdrom': 'BlockdevOptionsFile', 'host_device':'BlockdevOptionsFile', - 'http': 'BlockdevOptionsFile', - 'https': 'BlockdevOptionsFile', + 'http': 'BlockdevOptionsCurl', + 'https': 'BlockdevOptionsCurl', # TODO iscsi: Wait for structured options 'luks': 'BlockdevOptionsLUKS', # TODO nbd: Should take InetSocketAddress for 'host'? @@ -2271,7 +2282,7 @@ 'replication':'BlockdevOptionsReplication', # TODO sheepdog: Wait for structured options # TODO ssh: Should take InetSocketAddress for 'host'? - 'tftp': 'BlockdevOptionsFile', + 'tftp': 'BlockdevOptionsCurl', 'vdi': 'BlockdevOptionsGenericFormat', 'vhdx': 'BlockdevOptionsGenericFormat', 'vmdk': 'BlockdevOptionsGenericCOWFormat', From 0a4279d97c501254f6164b8abcd89055a11e2dc5 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 8 Sep 2016 15:09:01 +0200 Subject: [PATCH 434/723] block/qapi: Move 'aio' option to file driver The option whether or not to use a native AIO interface really isn't a generic option for all drivers, but only applies to the native file protocols. This patch moves the option in blockdev-add to the appropriate places (raw-posix and raw-win32). We still have to keep the flag BDRV_O_NATIVE_AIO for compatibility because so far the AIO option was usually specified on the wrong layer (the top-level format driver, which didn't even look at it) and then inherited by the protocol driver (where it was actually used). We can't forbid this use except in new interfaces. Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake Reviewed-by: Max Reitz --- block/raw-posix.c | 44 ++++++++++++++++++++------------- block/raw-win32.c | 56 ++++++++++++++++++++++++++++++++++++++---- qapi/block-core.json | 6 ++--- tests/qemu-iotests/087 | 4 +-- 4 files changed, 83 insertions(+), 27 deletions(-) diff --git a/block/raw-posix.c b/block/raw-posix.c index 6ed75473927..166e9d1ad5d 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -143,6 +143,7 @@ typedef struct BDRVRawState { bool has_discard:1; bool has_write_zeroes:1; bool discard_zeroes:1; + bool use_linux_aio:1; bool has_fallocate; bool needs_alignment; } BDRVRawState; @@ -367,18 +368,6 @@ static void raw_parse_flags(int bdrv_flags, int *open_flags) } } -#ifdef CONFIG_LINUX_AIO -static bool raw_use_aio(int bdrv_flags) -{ - /* - * Currently Linux do AIO only for files opened with O_DIRECT - * specified so check NOCACHE flag too - */ - return (bdrv_flags & (BDRV_O_NOCACHE|BDRV_O_NATIVE_AIO)) == - (BDRV_O_NOCACHE|BDRV_O_NATIVE_AIO); -} -#endif - static void raw_parse_filename(const char *filename, QDict *options, Error **errp) { @@ -399,6 +388,11 @@ static QemuOptsList raw_runtime_opts = { .type = QEMU_OPT_STRING, .help = "File name of the image", }, + { + .name = "aio", + .type = QEMU_OPT_STRING, + .help = "host AIO implementation (threads, native)", + }, { /* end of list */ } }, }; @@ -410,6 +404,7 @@ static int raw_open_common(BlockDriverState *bs, QDict *options, QemuOpts *opts; Error *local_err = NULL; const char *filename = NULL; + BlockdevAioOptions aio, aio_default; int fd, ret; struct stat st; @@ -429,6 +424,18 @@ static int raw_open_common(BlockDriverState *bs, QDict *options, goto fail; } + aio_default = (bdrv_flags & BDRV_O_NATIVE_AIO) + ? BLOCKDEV_AIO_OPTIONS_NATIVE + : BLOCKDEV_AIO_OPTIONS_THREADS; + aio = qapi_enum_parse(BlockdevAioOptions_lookup, qemu_opt_get(opts, "aio"), + BLOCKDEV_AIO_OPTIONS__MAX, aio_default, &local_err); + if (local_err) { + error_propagate(errp, local_err); + ret = -EINVAL; + goto fail; + } + s->use_linux_aio = (aio == BLOCKDEV_AIO_OPTIONS_NATIVE); + s->open_flags = open_flags; raw_parse_flags(bdrv_flags, &s->open_flags); @@ -444,14 +451,15 @@ static int raw_open_common(BlockDriverState *bs, QDict *options, s->fd = fd; #ifdef CONFIG_LINUX_AIO - if (!raw_use_aio(bdrv_flags) && (bdrv_flags & BDRV_O_NATIVE_AIO)) { + /* Currently Linux does AIO only for files opened with O_DIRECT */ + if (s->use_linux_aio && !(s->open_flags & O_DIRECT)) { error_setg(errp, "aio=native was specified, but it requires " "cache.direct=on, which was not specified."); ret = -EINVAL; goto fail; } #else - if (bdrv_flags & BDRV_O_NATIVE_AIO) { + if (s->use_linux_aio) { error_setg(errp, "aio=native was specified, but is not supported " "in this build."); ret = -EINVAL; @@ -1256,7 +1264,7 @@ static int coroutine_fn raw_co_prw(BlockDriverState *bs, uint64_t offset, if (!bdrv_qiov_is_aligned(bs, qiov)) { type |= QEMU_AIO_MISALIGNED; #ifdef CONFIG_LINUX_AIO - } else if (bs->open_flags & BDRV_O_NATIVE_AIO) { + } else if (s->use_linux_aio) { LinuxAioState *aio = aio_get_linux_aio(bdrv_get_aio_context(bs)); assert(qiov->size == bytes); return laio_co_submit(bs, aio, s->fd, offset, qiov, type); @@ -1285,7 +1293,8 @@ static int coroutine_fn raw_co_pwritev(BlockDriverState *bs, uint64_t offset, static void raw_aio_plug(BlockDriverState *bs) { #ifdef CONFIG_LINUX_AIO - if (bs->open_flags & BDRV_O_NATIVE_AIO) { + BDRVRawState *s = bs->opaque; + if (s->use_linux_aio) { LinuxAioState *aio = aio_get_linux_aio(bdrv_get_aio_context(bs)); laio_io_plug(bs, aio); } @@ -1295,7 +1304,8 @@ static void raw_aio_plug(BlockDriverState *bs) static void raw_aio_unplug(BlockDriverState *bs) { #ifdef CONFIG_LINUX_AIO - if (bs->open_flags & BDRV_O_NATIVE_AIO) { + BDRVRawState *s = bs->opaque; + if (s->use_linux_aio) { LinuxAioState *aio = aio_get_linux_aio(bdrv_get_aio_context(bs)); laio_io_unplug(bs, aio); } diff --git a/block/raw-win32.c b/block/raw-win32.c index 56f45fea9e7..734bb105bd0 100644 --- a/block/raw-win32.c +++ b/block/raw-win32.c @@ -32,6 +32,7 @@ #include "block/thread-pool.h" #include "qemu/iov.h" #include "qapi/qmp/qstring.h" +#include "qapi/util.h" #include #include @@ -252,7 +253,8 @@ static void raw_probe_alignment(BlockDriverState *bs, Error **errp) } } -static void raw_parse_flags(int flags, int *access_flags, DWORD *overlapped) +static void raw_parse_flags(int flags, bool use_aio, int *access_flags, + DWORD *overlapped) { assert(access_flags != NULL); assert(overlapped != NULL); @@ -264,7 +266,7 @@ static void raw_parse_flags(int flags, int *access_flags, DWORD *overlapped) } *overlapped = FILE_ATTRIBUTE_NORMAL; - if (flags & BDRV_O_NATIVE_AIO) { + if (use_aio) { *overlapped |= FILE_FLAG_OVERLAPPED; } if (flags & BDRV_O_NOCACHE) { @@ -292,10 +294,35 @@ static QemuOptsList raw_runtime_opts = { .type = QEMU_OPT_STRING, .help = "File name of the image", }, + { + .name = "aio", + .type = QEMU_OPT_STRING, + .help = "host AIO implementation (threads, native)", + }, { /* end of list */ } }, }; +static bool get_aio_option(QemuOpts *opts, int flags, Error **errp) +{ + BlockdevAioOptions aio, aio_default; + + aio_default = (flags & BDRV_O_NATIVE_AIO) ? BLOCKDEV_AIO_OPTIONS_NATIVE + : BLOCKDEV_AIO_OPTIONS_THREADS; + aio = qapi_enum_parse(BlockdevAioOptions_lookup, qemu_opt_get(opts, "aio"), + BLOCKDEV_AIO_OPTIONS__MAX, aio_default, errp); + + switch (aio) { + case BLOCKDEV_AIO_OPTIONS_NATIVE: + return true; + case BLOCKDEV_AIO_OPTIONS_THREADS: + return false; + default: + error_setg(errp, "Invalid AIO option"); + } + return false; +} + static int raw_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) { @@ -305,6 +332,7 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags, QemuOpts *opts; Error *local_err = NULL; const char *filename; + bool use_aio; int ret; s->type = FTYPE_FILE; @@ -319,7 +347,14 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags, filename = qemu_opt_get(opts, "filename"); - raw_parse_flags(flags, &access_flags, &overlapped); + use_aio = get_aio_option(opts, flags, &local_err); + if (local_err) { + error_propagate(errp, local_err); + ret = -EINVAL; + goto fail; + } + + raw_parse_flags(flags, use_aio, &access_flags, &overlapped); if (filename[0] && filename[1] == ':') { snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", filename[0]); @@ -346,7 +381,7 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags, goto fail; } - if (flags & BDRV_O_NATIVE_AIO) { + if (use_aio) { s->aio = win32_aio_init(); if (s->aio == NULL) { CloseHandle(s->hfile); @@ -647,6 +682,7 @@ static int hdev_open(BlockDriverState *bs, QDict *options, int flags, Error *local_err = NULL; const char *filename; + bool use_aio; QemuOpts *opts = qemu_opts_create(&raw_runtime_opts, NULL, 0, &error_abort); @@ -659,6 +695,16 @@ static int hdev_open(BlockDriverState *bs, QDict *options, int flags, filename = qemu_opt_get(opts, "filename"); + use_aio = get_aio_option(opts, flags, &local_err); + if (!local_err && use_aio) { + error_setg(&local_err, "AIO is not supported on Windows host devices"); + } + if (local_err) { + error_propagate(errp, local_err); + ret = -EINVAL; + goto done; + } + if (strstart(filename, "/dev/cdrom", NULL)) { if (find_cdrom(device_name, sizeof(device_name)) < 0) { error_setg(errp, "Could not open CD-ROM drive"); @@ -677,7 +723,7 @@ static int hdev_open(BlockDriverState *bs, QDict *options, int flags, } s->type = find_device_type(bs, filename); - raw_parse_flags(flags, &access_flags, &overlapped); + raw_parse_flags(flags, use_aio, &access_flags, &overlapped); create_flags = OPEN_EXISTING; diff --git a/qapi/block-core.json b/qapi/block-core.json index b5fdd426c98..9d797b8fe00 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -1724,11 +1724,13 @@ # Driver specific block device options for the file backend. # # @filename: path to the image file +# @aio: #optional AIO backend (default: threads) (since: 2.8) # # Since: 1.7 ## { 'struct': 'BlockdevOptionsFile', - 'data': { 'filename': 'str' } } + 'data': { 'filename': 'str', + '*aio': 'BlockdevAioOptions' } } ## # @BlockdevOptionsNull @@ -2232,7 +2234,6 @@ # This option is required on the top level of blockdev-add. # @discard: #optional discard-related options (default: ignore) # @cache: #optional cache-related options -# @aio: #optional AIO backend (default: threads) # @read-only: #optional whether the block device should be read-only # (default: false) # @detect-zeroes: #optional detect and optimize zero writes (Since 2.1) @@ -2247,7 +2248,6 @@ '*node-name': 'str', '*discard': 'BlockdevDiscardOptions', '*cache': 'BlockdevCacheOptions', - '*aio': 'BlockdevAioOptions', '*read-only': 'bool', '*detect-zeroes': 'BlockdevDetectZeroesOptions' }, 'discriminator': 'driver', diff --git a/tests/qemu-iotests/087 b/tests/qemu-iotests/087 index 5c04577b366..b1ac71f2b8d 100755 --- a/tests/qemu-iotests/087 +++ b/tests/qemu-iotests/087 @@ -117,10 +117,10 @@ run_qemu < Date: Mon, 12 Sep 2016 21:00:41 +0200 Subject: [PATCH 435/723] block: Parse 'detect-zeroes' in bdrv_open_common() Amongst others, this means that you can now use the 'detect-zeroes' option for non-top-level nodes in blockdev-add, like the QAPI schema promises. Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake Reviewed-by: Max Reitz --- block.c | 33 +++++++++++++++++++++++++++++++++ blockdev.c | 9 +-------- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/block.c b/block.c index 493ecf3137f..1f1045738d6 100644 --- a/block.c +++ b/block.c @@ -42,6 +42,7 @@ #include "qapi-event.h" #include "qemu/cutils.h" #include "qemu/id.h" +#include "qapi/util.h" #ifdef CONFIG_BSD #include @@ -954,6 +955,11 @@ static QemuOptsList bdrv_runtime_opts = { .type = QEMU_OPT_BOOL, .help = "Node is opened in read-only mode", }, + { + .name = "detect-zeroes", + .type = QEMU_OPT_STRING, + .help = "try to optimize zero writes (off, on, unmap)", + }, { /* end of list */ } }, }; @@ -970,6 +976,7 @@ static int bdrv_open_common(BlockDriverState *bs, BdrvChild *file, const char *filename; const char *driver_name = NULL; const char *node_name = NULL; + const char *detect_zeroes; QemuOpts *opts; BlockDriver *drv; Error *local_err = NULL; @@ -1038,6 +1045,32 @@ static int bdrv_open_common(BlockDriverState *bs, BdrvChild *file, } } + detect_zeroes = qemu_opt_get(opts, "detect-zeroes"); + if (detect_zeroes) { + BlockdevDetectZeroesOptions value = + qapi_enum_parse(BlockdevDetectZeroesOptions_lookup, + detect_zeroes, + BLOCKDEV_DETECT_ZEROES_OPTIONS__MAX, + BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF, + &local_err); + if (local_err) { + error_propagate(errp, local_err); + ret = -EINVAL; + goto fail_opts; + } + + if (value == BLOCKDEV_DETECT_ZEROES_OPTIONS_UNMAP && + !(bs->open_flags & BDRV_O_UNMAP)) + { + error_setg(errp, "setting detect-zeroes to unmap is not allowed " + "without setting discard operation to unmap"); + ret = -EINVAL; + goto fail_opts; + } + + bs->detect_zeroes = value; + } + if (filename != NULL) { pstrcpy(bs->filename, sizeof(bs->filename), filename); } else { diff --git a/blockdev.c b/blockdev.c index 7820f422104..511260ce935 100644 --- a/blockdev.c +++ b/blockdev.c @@ -658,7 +658,6 @@ static BlockDriverState *bds_tree_init(QDict *bs_opts, Error **errp) BlockDriverState *bs; QemuOpts *opts; Error *local_error = NULL; - BlockdevDetectZeroesOptions detect_zeroes; int bdrv_flags = 0; opts = qemu_opts_create(&qemu_root_bds_opts, NULL, 1, errp); @@ -673,7 +672,7 @@ static BlockDriverState *bds_tree_init(QDict *bs_opts, Error **errp) } extract_common_blockdev_options(opts, &bdrv_flags, NULL, NULL, - &detect_zeroes, &local_error); + NULL, &local_error); if (local_error) { error_propagate(errp, local_error); goto fail; @@ -695,8 +694,6 @@ static BlockDriverState *bds_tree_init(QDict *bs_opts, Error **errp) goto fail_no_bs_opts; } - bs->detect_zeroes = detect_zeroes; - fail_no_bs_opts: qemu_opts_del(opts); return bs; @@ -4136,10 +4133,6 @@ static QemuOptsList qemu_root_bds_opts = { .name = "copy-on-read", .type = QEMU_OPT_BOOL, .help = "copy read data from backing file into image file", - },{ - .name = "detect-zeroes", - .type = QEMU_OPT_STRING, - .help = "try to optimize zero writes (off, on, unmap)", }, { /* end of list */ } }, From b85114f8cfbede8b153db68875973ef0790bf296 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Mon, 12 Sep 2016 19:08:31 +0200 Subject: [PATCH 436/723] block: Use 'detect-zeroes' option for 'blockdev-change-medium' Instead of modifying the new BDS after it has been opened, use the newly supported 'detect-zeroes' option in bdrv_open_common() so that all requirements are checked (detect-zeroes=unmap requires discard=unmap). Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake Reviewed-by: Max Reitz --- block/block-backend.c | 9 ++++----- blockdev.c | 9 ++++++--- include/sysemu/block-backend.h | 2 +- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/block/block-backend.c b/block/block-backend.c index f34bad58400..639294b8e6b 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -1592,13 +1592,12 @@ void blk_update_root_state(BlockBackend *blk) } /* - * Applies the information in the root state to the given BlockDriverState. This - * does not include the flags which have to be specified for bdrv_open(), use - * blk_get_open_flags_from_root_state() to inquire them. + * Returns the detect-zeroes setting to be used for bdrv_open() of a + * BlockDriverState which is supposed to inherit the root state. */ -void blk_apply_root_state(BlockBackend *blk, BlockDriverState *bs) +bool blk_get_detect_zeroes_from_root_state(BlockBackend *blk) { - bs->detect_zeroes = blk->root_state.detect_zeroes; + return blk->root_state.detect_zeroes; } /* diff --git a/blockdev.c b/blockdev.c index 511260ce935..7b87bd8a710 100644 --- a/blockdev.c +++ b/blockdev.c @@ -2546,6 +2546,7 @@ void qmp_blockdev_change_medium(bool has_device, const char *device, BlockBackend *blk; BlockDriverState *medium_bs = NULL; int bdrv_flags; + bool detect_zeroes; int rc; QDict *options = NULL; Error *err = NULL; @@ -2585,8 +2586,12 @@ void qmp_blockdev_change_medium(bool has_device, const char *device, abort(); } + options = qdict_new(); + detect_zeroes = blk_get_detect_zeroes_from_root_state(blk); + qdict_put(options, "detect-zeroes", + qstring_from_str(detect_zeroes ? "on" : "off")); + if (has_format) { - options = qdict_new(); qdict_put(options, "driver", qstring_from_str(format)); } @@ -2623,8 +2628,6 @@ void qmp_blockdev_change_medium(bool has_device, const char *device, goto fail; } - blk_apply_root_state(blk, medium_bs); - qmp_blockdev_close_tray(has_device, device, has_id, id, errp); fail: diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h index 24d1d853991..a7993afcda6 100644 --- a/include/sysemu/block-backend.h +++ b/include/sysemu/block-backend.h @@ -198,7 +198,7 @@ void blk_io_unplug(BlockBackend *blk); BlockAcctStats *blk_get_stats(BlockBackend *blk); BlockBackendRootState *blk_get_root_state(BlockBackend *blk); void blk_update_root_state(BlockBackend *blk); -void blk_apply_root_state(BlockBackend *blk, BlockDriverState *bs); +bool blk_get_detect_zeroes_from_root_state(BlockBackend *blk); int blk_get_open_flags_from_root_state(BlockBackend *blk); void *blk_aio_get(const AIOCBInfo *aiocb_info, BlockBackend *blk, From 818584a43ab0ef52c131865128ef110f867726cd Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Mon, 12 Sep 2016 18:03:18 +0200 Subject: [PATCH 437/723] block: Move 'discard' option to bdrv_open_common() This enables its use for nested child nodes. The compatibility between the 'discard' and 'detect-zeroes' setting is checked in bdrv_open_common() now as the former setting isn't available before calling bdrv_open() any more. Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake Reviewed-by: Max Reitz --- block.c | 17 ++++++++++++++++- blockdev.c | 25 ------------------------- include/block/block.h | 1 + 3 files changed, 17 insertions(+), 26 deletions(-) diff --git a/block.c b/block.c index 1f1045738d6..bb1f1ec9576 100644 --- a/block.c +++ b/block.c @@ -765,7 +765,7 @@ static void bdrv_inherited_options(int *child_flags, QDict *child_options, /* Our block drivers take care to send flushes and respect unmap policy, * so we can default to enable both on lower layers regardless of the * corresponding parent options. */ - flags |= BDRV_O_UNMAP; + qdict_set_default_str(child_options, BDRV_OPT_DISCARD, "unmap"); /* Clear flags that only apply to the top layer */ flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING | BDRV_O_COPY_ON_READ | @@ -960,6 +960,11 @@ static QemuOptsList bdrv_runtime_opts = { .type = QEMU_OPT_STRING, .help = "try to optimize zero writes (off, on, unmap)", }, + { + .name = "discard", + .type = QEMU_OPT_STRING, + .help = "discard operation (ignore/off, unmap/on)", + }, { /* end of list */ } }, }; @@ -976,6 +981,7 @@ static int bdrv_open_common(BlockDriverState *bs, BdrvChild *file, const char *filename; const char *driver_name = NULL; const char *node_name = NULL; + const char *discard; const char *detect_zeroes; QemuOpts *opts; BlockDriver *drv; @@ -1045,6 +1051,15 @@ static int bdrv_open_common(BlockDriverState *bs, BdrvChild *file, } } + discard = qemu_opt_get(opts, "discard"); + if (discard != NULL) { + if (bdrv_parse_discard_flags(discard, &bs->open_flags) != 0) { + error_setg(errp, "Invalid discard option"); + ret = -EINVAL; + goto fail_opts; + } + } + detect_zeroes = qemu_opt_get(opts, "detect-zeroes"); if (detect_zeroes) { BlockdevDetectZeroesOptions value = diff --git a/blockdev.c b/blockdev.c index 7b87bd8a710..e2ace04346b 100644 --- a/blockdev.c +++ b/blockdev.c @@ -356,7 +356,6 @@ static void extract_common_blockdev_options(QemuOpts *opts, int *bdrv_flags, const char **throttling_group, ThrottleConfig *throttle_cfg, BlockdevDetectZeroesOptions *detect_zeroes, Error **errp) { - const char *discard; Error *local_error = NULL; const char *aio; @@ -365,13 +364,6 @@ static void extract_common_blockdev_options(QemuOpts *opts, int *bdrv_flags, *bdrv_flags |= BDRV_O_COPY_ON_READ; } - if ((discard = qemu_opt_get(opts, "discard")) != NULL) { - if (bdrv_parse_discard_flags(discard, bdrv_flags) != 0) { - error_setg(errp, "Invalid discard option"); - return; - } - } - if ((aio = qemu_opt_get(opts, "aio")) != NULL) { if (!strcmp(aio, "native")) { *bdrv_flags |= BDRV_O_NATIVE_AIO; @@ -449,15 +441,6 @@ static void extract_common_blockdev_options(QemuOpts *opts, int *bdrv_flags, error_propagate(errp, local_error); return; } - - if (bdrv_flags && - *detect_zeroes == BLOCKDEV_DETECT_ZEROES_OPTIONS_UNMAP && - !(*bdrv_flags & BDRV_O_UNMAP)) - { - error_setg(errp, "setting detect-zeroes to unmap is not allowed " - "without setting discard operation to unmap"); - return; - } } } @@ -3989,10 +3972,6 @@ QemuOptsList qemu_common_drive_opts = { .name = "snapshot", .type = QEMU_OPT_BOOL, .help = "enable/disable snapshot mode", - },{ - .name = "discard", - .type = QEMU_OPT_STRING, - .help = "discard operation (ignore/off, unmap/on)", },{ .name = "aio", .type = QEMU_OPT_STRING, @@ -4125,10 +4104,6 @@ static QemuOptsList qemu_root_bds_opts = { .head = QTAILQ_HEAD_INITIALIZER(qemu_root_bds_opts.head), .desc = { { - .name = "discard", - .type = QEMU_OPT_STRING, - .help = "discard operation (ignore/off, unmap/on)", - },{ .name = "aio", .type = QEMU_OPT_STRING, .help = "host AIO implementation (threads, native)", diff --git a/include/block/block.h b/include/block/block.h index 811b060f411..107c6036057 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -108,6 +108,7 @@ typedef struct HDGeometry { #define BDRV_OPT_CACHE_DIRECT "cache.direct" #define BDRV_OPT_CACHE_NO_FLUSH "cache.no-flush" #define BDRV_OPT_READ_ONLY "read-only" +#define BDRV_OPT_DISCARD "discard" #define BDRV_SECTOR_BITS 9 From 74e1ae7c0b66d85d2b04c153ffdf6294e6a40798 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 20 Sep 2016 20:48:52 +0200 Subject: [PATCH 438/723] block: Remove qemu_root_bds_opts The remaining options in qemu_root_bds_opts (aio and copy-on-read) aren't used any more, the QAPI schema doesn't contain them. Therefore all the code processing qemu_root_bds_opts options is dead and can be removed. Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake Reviewed-by: Max Reitz --- blockdev.c | 54 +----------------------------------------------------- 1 file changed, 1 insertion(+), 53 deletions(-) diff --git a/blockdev.c b/blockdev.c index e2ace04346b..07ec733905d 100644 --- a/blockdev.c +++ b/blockdev.c @@ -633,34 +633,11 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, return NULL; } -static QemuOptsList qemu_root_bds_opts; - /* Takes the ownership of bs_opts */ static BlockDriverState *bds_tree_init(QDict *bs_opts, Error **errp) { - BlockDriverState *bs; - QemuOpts *opts; - Error *local_error = NULL; int bdrv_flags = 0; - opts = qemu_opts_create(&qemu_root_bds_opts, NULL, 1, errp); - if (!opts) { - goto fail; - } - - qemu_opts_absorb_qdict(opts, bs_opts, &local_error); - if (local_error) { - error_propagate(errp, local_error); - goto fail; - } - - extract_common_blockdev_options(opts, &bdrv_flags, NULL, NULL, - NULL, &local_error); - if (local_error) { - error_propagate(errp, local_error); - goto fail; - } - /* bdrv_open() defaults to the values in bdrv_flags (for compatibility * with other callers) rather than what we want as the real defaults. * Apply the defaults here instead. */ @@ -672,19 +649,7 @@ static BlockDriverState *bds_tree_init(QDict *bs_opts, Error **errp) bdrv_flags |= BDRV_O_INACTIVE; } - bs = bdrv_open(NULL, NULL, bs_opts, bdrv_flags, errp); - if (!bs) { - goto fail_no_bs_opts; - } - -fail_no_bs_opts: - qemu_opts_del(opts); - return bs; - -fail: - qemu_opts_del(opts); - QDECREF(bs_opts); - return NULL; + return bdrv_open(NULL, NULL, bs_opts, bdrv_flags, errp); } void blockdev_close_all_bdrv_states(void) @@ -4099,23 +4064,6 @@ QemuOptsList qemu_common_drive_opts = { }, }; -static QemuOptsList qemu_root_bds_opts = { - .name = "root-bds", - .head = QTAILQ_HEAD_INITIALIZER(qemu_root_bds_opts.head), - .desc = { - { - .name = "aio", - .type = QEMU_OPT_STRING, - .help = "host AIO implementation (threads, native)", - },{ - .name = "copy-on-read", - .type = QEMU_OPT_BOOL, - .help = "copy read data from backing file into image file", - }, - { /* end of list */ } - }, -}; - QemuOptsList qemu_drive_opts = { .name = "drive", .head = QTAILQ_HEAD_INITIALIZER(qemu_drive_opts.head), From 8737d9e0c4017aaa5ab1fcf1356c8ee4f7caf1df Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Tue, 27 Sep 2016 11:58:40 +0200 Subject: [PATCH 439/723] oslib-posix: add helpers for stack alloc and free the allocated stack will be adjusted to the minimum supported stack size by the OS and rounded up to be a multiple of the system pagesize. Additionally an architecture dependent guard page is added to the stack to catch stack overflows. Signed-off-by: Peter Lieven Signed-off-by: Kevin Wolf --- include/sysemu/os-posix.h | 27 +++++++++++++++++++++++++ util/oslib-posix.c | 42 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/include/sysemu/os-posix.h b/include/sysemu/os-posix.h index 9c7dfdfbec6..3cfedbc28ba 100644 --- a/include/sysemu/os-posix.h +++ b/include/sysemu/os-posix.h @@ -60,4 +60,31 @@ int qemu_utimens(const char *path, const qemu_timespec *times); bool is_daemonized(void); +/** + * qemu_alloc_stack: + * @sz: pointer to a size_t holding the requested usable stack size + * + * Allocate memory that can be used as a stack, for instance for + * coroutines. If the memory cannot be allocated, this function + * will abort (like g_malloc()). This function also inserts an + * additional guard page to catch a potential stack overflow. + * Note that the memory required for the guard page and alignment + * and minimal stack size restrictions will increase the value of sz. + * + * The allocated stack must be freed with qemu_free_stack(). + * + * Returns: pointer to (the lowest address of) the stack memory. + */ +void *qemu_alloc_stack(size_t *sz); + +/** + * qemu_free_stack: + * @stack: stack to free + * @sz: size of stack in bytes + * + * Free a stack allocated via qemu_alloc_stack(). Note that sz must + * be exactly the adjusted stack size returned by qemu_alloc_stack. + */ +void qemu_free_stack(void *stack, size_t sz); + #endif diff --git a/util/oslib-posix.c b/util/oslib-posix.c index f2d4e9e592e..d950c347e26 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -499,3 +499,45 @@ pid_t qemu_fork(Error **errp) } return pid; } + +void *qemu_alloc_stack(size_t *sz) +{ + void *ptr, *guardpage; + size_t pagesz = getpagesize(); +#ifdef _SC_THREAD_STACK_MIN + /* avoid stacks smaller than _SC_THREAD_STACK_MIN */ + long min_stack_sz = sysconf(_SC_THREAD_STACK_MIN); + *sz = MAX(MAX(min_stack_sz, 0), *sz); +#endif + /* adjust stack size to a multiple of the page size */ + *sz = ROUND_UP(*sz, pagesz); + /* allocate one extra page for the guard page */ + *sz += pagesz; + + ptr = mmap(NULL, *sz, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (ptr == MAP_FAILED) { + abort(); + } + +#if defined(HOST_IA64) + /* separate register stack */ + guardpage = ptr + (((*sz - pagesz) / 2) & ~pagesz); +#elif defined(HOST_HPPA) + /* stack grows up */ + guardpage = ptr + *sz - pagesz; +#else + /* stack grows down */ + guardpage = ptr; +#endif + if (mprotect(guardpage, pagesz, PROT_NONE) != 0) { + abort(); + } + + return ptr; +} + +void qemu_free_stack(void *stack, size_t sz) +{ + munmap(stack, sz); +} From be87a393f9aed6f9406a728d4d55199aee0ebbb4 Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Tue, 27 Sep 2016 11:58:41 +0200 Subject: [PATCH 440/723] coroutine-sigaltstack: rename coroutine struct appropriately The name of the sigaltstack coroutine struct was misleading. Signed-off-by: Peter Lieven Signed-off-by: Kevin Wolf --- util/coroutine-sigaltstack.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/util/coroutine-sigaltstack.c b/util/coroutine-sigaltstack.c index a7c33665538..171cd44b7ff 100644 --- a/util/coroutine-sigaltstack.c +++ b/util/coroutine-sigaltstack.c @@ -34,7 +34,7 @@ typedef struct { Coroutine base; void *stack; sigjmp_buf env; -} CoroutineUContext; +} CoroutineSigAltStack; /** * Per-thread coroutine bookkeeping @@ -44,7 +44,7 @@ typedef struct { Coroutine *current; /** The default coroutine */ - CoroutineUContext leader; + CoroutineSigAltStack leader; /** Information for the signal handler (trampoline) */ sigjmp_buf tr_reenter; @@ -89,7 +89,7 @@ static void __attribute__((constructor)) coroutine_init(void) * (from the signal handler when it is not signal handling, read ahead * for more information). */ -static void coroutine_bootstrap(CoroutineUContext *self, Coroutine *co) +static void coroutine_bootstrap(CoroutineSigAltStack *self, Coroutine *co) { /* Initialize longjmp environment and switch back the caller */ if (!sigsetjmp(self->env, 0)) { @@ -109,7 +109,7 @@ static void coroutine_bootstrap(CoroutineUContext *self, Coroutine *co) */ static void coroutine_trampoline(int signal) { - CoroutineUContext *self; + CoroutineSigAltStack *self; Coroutine *co; CoroutineThreadState *coTS; @@ -144,7 +144,7 @@ static void coroutine_trampoline(int signal) Coroutine *qemu_coroutine_new(void) { const size_t stack_size = 1 << 20; - CoroutineUContext *co; + CoroutineSigAltStack *co; CoroutineThreadState *coTS; struct sigaction sa; struct sigaction osa; @@ -251,7 +251,7 @@ Coroutine *qemu_coroutine_new(void) void qemu_coroutine_delete(Coroutine *co_) { - CoroutineUContext *co = DO_UPCAST(CoroutineUContext, base, co_); + CoroutineSigAltStack *co = DO_UPCAST(CoroutineSigAltStack, base, co_); g_free(co->stack); g_free(co); @@ -260,8 +260,8 @@ void qemu_coroutine_delete(Coroutine *co_) CoroutineAction qemu_coroutine_switch(Coroutine *from_, Coroutine *to_, CoroutineAction action) { - CoroutineUContext *from = DO_UPCAST(CoroutineUContext, base, from_); - CoroutineUContext *to = DO_UPCAST(CoroutineUContext, base, to_); + CoroutineSigAltStack *from = DO_UPCAST(CoroutineSigAltStack, base, from_); + CoroutineSigAltStack *to = DO_UPCAST(CoroutineSigAltStack, base, to_); CoroutineThreadState *s = coroutine_get_thread_state(); int ret; From 8adcd6fb6d14ff7fbb47179384dcddbd6dfd95a3 Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Tue, 27 Sep 2016 11:58:42 +0200 Subject: [PATCH 441/723] coroutine: add a macro for the coroutine stack size Signed-off-by: Peter Lieven Reviewed-by: Paolo Bonzini Reviewed-by: Richard Henderson Signed-off-by: Kevin Wolf --- include/qemu/coroutine_int.h | 2 ++ util/coroutine-sigaltstack.c | 2 +- util/coroutine-ucontext.c | 2 +- util/coroutine-win32.c | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/include/qemu/coroutine_int.h b/include/qemu/coroutine_int.h index 6df9d333529..14d4f1d1f28 100644 --- a/include/qemu/coroutine_int.h +++ b/include/qemu/coroutine_int.h @@ -28,6 +28,8 @@ #include "qemu/queue.h" #include "qemu/coroutine.h" +#define COROUTINE_STACK_SIZE (1 << 20) + typedef enum { COROUTINE_YIELD = 1, COROUTINE_TERMINATE = 2, diff --git a/util/coroutine-sigaltstack.c b/util/coroutine-sigaltstack.c index 171cd44b7ff..a5bcb7e19e5 100644 --- a/util/coroutine-sigaltstack.c +++ b/util/coroutine-sigaltstack.c @@ -143,7 +143,7 @@ static void coroutine_trampoline(int signal) Coroutine *qemu_coroutine_new(void) { - const size_t stack_size = 1 << 20; + const size_t stack_size = COROUTINE_STACK_SIZE; CoroutineSigAltStack *co; CoroutineThreadState *coTS; struct sigaction sa; diff --git a/util/coroutine-ucontext.c b/util/coroutine-ucontext.c index 2bb7e10d4bf..31254abd4c4 100644 --- a/util/coroutine-ucontext.c +++ b/util/coroutine-ucontext.c @@ -82,7 +82,7 @@ static void coroutine_trampoline(int i0, int i1) Coroutine *qemu_coroutine_new(void) { - const size_t stack_size = 1 << 20; + const size_t stack_size = COROUTINE_STACK_SIZE; CoroutineUContext *co; ucontext_t old_uc, uc; sigjmp_buf old_env; diff --git a/util/coroutine-win32.c b/util/coroutine-win32.c index 02e28e825fe..de6bd4fd3e4 100644 --- a/util/coroutine-win32.c +++ b/util/coroutine-win32.c @@ -71,7 +71,7 @@ static void CALLBACK coroutine_trampoline(void *co_) Coroutine *qemu_coroutine_new(void) { - const size_t stack_size = 1 << 20; + const size_t stack_size = COROUTINE_STACK_SIZE; CoroutineWin32 *co; co = g_malloc0(sizeof(*co)); From ddba15919bd51b45d0d1425cc2de0c0c0bae3877 Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Tue, 27 Sep 2016 11:58:43 +0200 Subject: [PATCH 442/723] coroutine-ucontext: use helper for allocating stack memory Signed-off-by: Peter Lieven Signed-off-by: Kevin Wolf --- util/coroutine-ucontext.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/util/coroutine-ucontext.c b/util/coroutine-ucontext.c index 31254abd4c4..6621f3f692c 100644 --- a/util/coroutine-ucontext.c +++ b/util/coroutine-ucontext.c @@ -34,6 +34,7 @@ typedef struct { Coroutine base; void *stack; + size_t stack_size; sigjmp_buf env; #ifdef CONFIG_VALGRIND_H @@ -82,7 +83,6 @@ static void coroutine_trampoline(int i0, int i1) Coroutine *qemu_coroutine_new(void) { - const size_t stack_size = COROUTINE_STACK_SIZE; CoroutineUContext *co; ucontext_t old_uc, uc; sigjmp_buf old_env; @@ -101,17 +101,18 @@ Coroutine *qemu_coroutine_new(void) } co = g_malloc0(sizeof(*co)); - co->stack = g_malloc(stack_size); + co->stack_size = COROUTINE_STACK_SIZE; + co->stack = qemu_alloc_stack(&co->stack_size); co->base.entry_arg = &old_env; /* stash away our jmp_buf */ uc.uc_link = &old_uc; uc.uc_stack.ss_sp = co->stack; - uc.uc_stack.ss_size = stack_size; + uc.uc_stack.ss_size = co->stack_size; uc.uc_stack.ss_flags = 0; #ifdef CONFIG_VALGRIND_H co->valgrind_stack_id = - VALGRIND_STACK_REGISTER(co->stack, co->stack + stack_size); + VALGRIND_STACK_REGISTER(co->stack, co->stack + co->stack_size); #endif arg.p = co; @@ -149,7 +150,7 @@ void qemu_coroutine_delete(Coroutine *co_) valgrind_stack_deregister(co); #endif - g_free(co->stack); + qemu_free_stack(co->stack, co->stack_size); g_free(co); } From 2f4aa2329945c741e10fd5b6631e99a4be25ea60 Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Tue, 27 Sep 2016 11:58:44 +0200 Subject: [PATCH 443/723] coroutine-sigaltstack: use helper for allocating stack memory Signed-off-by: Peter Lieven Signed-off-by: Kevin Wolf --- util/coroutine-sigaltstack.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/util/coroutine-sigaltstack.c b/util/coroutine-sigaltstack.c index a5bcb7e19e5..f6fc49a0e51 100644 --- a/util/coroutine-sigaltstack.c +++ b/util/coroutine-sigaltstack.c @@ -33,6 +33,7 @@ typedef struct { Coroutine base; void *stack; + size_t stack_size; sigjmp_buf env; } CoroutineSigAltStack; @@ -143,7 +144,6 @@ static void coroutine_trampoline(int signal) Coroutine *qemu_coroutine_new(void) { - const size_t stack_size = COROUTINE_STACK_SIZE; CoroutineSigAltStack *co; CoroutineThreadState *coTS; struct sigaction sa; @@ -164,7 +164,8 @@ Coroutine *qemu_coroutine_new(void) */ co = g_malloc0(sizeof(*co)); - co->stack = g_malloc(stack_size); + co->stack_size = COROUTINE_STACK_SIZE; + co->stack = qemu_alloc_stack(&co->stack_size); co->base.entry_arg = &old_env; /* stash away our jmp_buf */ coTS = coroutine_get_thread_state(); @@ -189,7 +190,7 @@ Coroutine *qemu_coroutine_new(void) * Set the new stack. */ ss.ss_sp = co->stack; - ss.ss_size = stack_size; + ss.ss_size = co->stack_size; ss.ss_flags = 0; if (sigaltstack(&ss, &oss) < 0) { abort(); @@ -253,7 +254,7 @@ void qemu_coroutine_delete(Coroutine *co_) { CoroutineSigAltStack *co = DO_UPCAST(CoroutineSigAltStack, base, co_); - g_free(co->stack); + qemu_free_stack(co->stack, co->stack_size); g_free(co); } From 7d992e4d5a95d0b21c6c33bd32cef8671805e39b Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Tue, 27 Sep 2016 11:58:45 +0200 Subject: [PATCH 444/723] oslib-posix: add a configure switch to debug stack usage this adds a knob to track the maximum stack usage of stacks created by qemu_alloc_stack. Signed-off-by: Peter Lieven Signed-off-by: Kevin Wolf --- configure | 19 +++++++++++++++++++ util/oslib-posix.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/configure b/configure index df4a247fc21..5751d8ecaa5 100755 --- a/configure +++ b/configure @@ -296,6 +296,7 @@ libiscsi="" libnfs="" coroutine="" coroutine_pool="" +debug_stack_usage="no" seccomp="" glusterfs="" glusterfs_xlator_opt="no" @@ -1004,6 +1005,8 @@ for opt do ;; --enable-coroutine-pool) coroutine_pool="yes" ;; + --enable-debug-stack-usage) debug_stack_usage="yes" + ;; --disable-docs) docs="no" ;; --enable-docs) docs="yes" @@ -4331,6 +4334,17 @@ if test "$coroutine" = "gthread" -a "$coroutine_pool" = "yes"; then error_exit "'gthread' coroutine backend does not support pool (use --disable-coroutine-pool)" fi +if test "$debug_stack_usage" = "yes"; then + if test "$cpu" = "ia64" -o "$cpu" = "hppa"; then + error_exit "stack usage debugging is not supported for $cpu" + fi + if test "$coroutine_pool" = "yes"; then + echo "WARN: disabling coroutine pool for stack usage debugging" + coroutine_pool=no + fi +fi + + ########################################## # check if we have open_by_handle_at @@ -4916,6 +4930,7 @@ echo "QGA MSI support $guest_agent_msi" echo "seccomp support $seccomp" echo "coroutine backend $coroutine" echo "coroutine pool $coroutine_pool" +echo "debug stack usage $debug_stack_usage" echo "GlusterFS support $glusterfs" echo "Archipelago support $archipelago" echo "gcov $gcov_tool" @@ -5384,6 +5399,10 @@ else echo "CONFIG_COROUTINE_POOL=0" >> $config_host_mak fi +if test "$debug_stack_usage" = "yes" ; then + echo "CONFIG_DEBUG_STACK_USAGE=y" >> $config_host_mak +fi + if test "$open_by_handle_at" = "yes" ; then echo "CONFIG_OPEN_BY_HANDLE=y" >> $config_host_mak fi diff --git a/util/oslib-posix.c b/util/oslib-posix.c index d950c347e26..aaec1891f5f 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -50,6 +50,10 @@ #include "qemu/mmap-alloc.h" +#ifdef CONFIG_DEBUG_STACK_USAGE +#include "qemu/error-report.h" +#endif + int qemu_get_thread_id(void) { #if defined(__linux__) @@ -503,6 +507,9 @@ pid_t qemu_fork(Error **errp) void *qemu_alloc_stack(size_t *sz) { void *ptr, *guardpage; +#ifdef CONFIG_DEBUG_STACK_USAGE + void *ptr2; +#endif size_t pagesz = getpagesize(); #ifdef _SC_THREAD_STACK_MIN /* avoid stacks smaller than _SC_THREAD_STACK_MIN */ @@ -534,10 +541,38 @@ void *qemu_alloc_stack(size_t *sz) abort(); } +#ifdef CONFIG_DEBUG_STACK_USAGE + for (ptr2 = ptr + pagesz; ptr2 < ptr + *sz; ptr2 += sizeof(uint32_t)) { + *(uint32_t *)ptr2 = 0xdeadbeaf; + } +#endif + return ptr; } +#ifdef CONFIG_DEBUG_STACK_USAGE +static __thread unsigned int max_stack_usage; +#endif + void qemu_free_stack(void *stack, size_t sz) { +#ifdef CONFIG_DEBUG_STACK_USAGE + unsigned int usage; + void *ptr; + + for (ptr = stack + getpagesize(); ptr < stack + sz; + ptr += sizeof(uint32_t)) { + if (*(uint32_t *)ptr != 0xdeadbeaf) { + break; + } + } + usage = sz - (uintptr_t) (ptr - stack); + if (usage > max_stack_usage) { + error_report("thread %d max stack usage increased from %u to %u", + qemu_get_thread_id(), max_stack_usage, usage); + max_stack_usage = usage; + } +#endif + munmap(stack, sz); } From 9da82227caa74fb6fbea224dad91fe5b7cc115a5 Mon Sep 17 00:00:00 2001 From: John Snow Date: Thu, 29 Sep 2016 14:46:15 -0400 Subject: [PATCH 445/723] ide: fix DMA register transitions ATA8-APT defines the state transitions for both a host controller and for the hardware device during the lifecycle of a DMA transfer, in section 9.7 "DMA command protocol." One of the interesting tidbits here is that when a device transitions from DDMA0 ("Prepare state") to DDMA1 ("Data_Transfer State"), it can choose to set either BSY or DRQ to signal this transition, but not both. as ide_sector_dma_start is the last point in our preparation process before we begin the real data transfer process (for either AHCI or BMDMA), this is the correct transition point for DDMA0 to DDMA1. I have chosen !BSY && DRQ for QEMU to make the transition from DDMA0 the most obvious. Reported-by: Benjamin David Lunt Signed-off-by: John Snow Reviewed-by: Kevin Wolf Tested-by: Stefan Weil Message-id: 1470175541-19344-1-git-send-email-jsnow@redhat.com Signed-off-by: John Snow --- hw/ide/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/ide/core.c b/hw/ide/core.c index b0e42a6562e..1bee18d86ee 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -908,7 +908,7 @@ static void ide_dma_cb(void *opaque, int ret) static void ide_sector_start_dma(IDEState *s, enum ide_dma_cmd dma_cmd) { - s->status = READY_STAT | SEEK_STAT | DRQ_STAT | BUSY_STAT; + s->status = READY_STAT | SEEK_STAT | DRQ_STAT; s->io_buffer_size = 0; s->dma_cmd = dma_cmd; From df403bc58859c893ebd0accda07678e84d15dc5d Mon Sep 17 00:00:00 2001 From: John Snow Date: Mon, 26 Sep 2016 14:33:37 -0400 Subject: [PATCH 446/723] ahci: clear aiocb in ncq_cb Similar to existing fixes for IDE (87ac25fd) and ATAPI (7f951b2d), the AIOCB must be cleared in the callback. Otherwise, we may accidentally try to reset a dangling pointer in bdrv_aio_cancel() from a port reset. Signed-off-by: John Snow Reviewed-by: Stefan Hajnoczi Message-id: 1474575040-32079-2-git-send-email-jsnow@redhat.com Signed-off-by: John Snow --- hw/ide/ahci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index f3438ad78a4..63ead21047f 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -948,6 +948,7 @@ static void ncq_cb(void *opaque, int ret) NCQTransferState *ncq_tfs = (NCQTransferState *)opaque; IDEState *ide_state = &ncq_tfs->drive->port.ifs[0]; + ncq_tfs->aiocb = NULL; if (ret == -ECANCELED) { return; } From c9f7acd57552b919a7b9b1c381383960307c0ada Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 23 Sep 2016 18:09:56 +0200 Subject: [PATCH 447/723] MAINTAINERS: Add some more headers to the IDE section The folder include/hw/ide/ belongs to the IDE section. Signed-off-by: Thomas Huth Reviewed-by: John Snow Message-id: 1474646996-30421-1-git-send-email-thuth@redhat.com Signed-off-by: John Snow --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index f3c1f7f307c..9b7e846ec29 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -772,6 +772,7 @@ M: John Snow L: qemu-block@nongnu.org S: Supported F: include/hw/ide.h +F: include/hw/ide/ F: hw/ide/ F: hw/block/block.c F: hw/block/cdrom.c From ca44141d5fb801dd5903102acefd0f2d8e8bb6a1 Mon Sep 17 00:00:00 2001 From: Ashijeet Acharya Date: Tue, 27 Sep 2016 22:23:32 +0530 Subject: [PATCH 448/723] ide: Fix memory leak in ide_register_restart_cb() Fix a memory leak in ide_register_restart_cb() in hw/ide/core.c and add idebus_unrealize() in hw/ide/qdev.c to have calls to qemu_del_vm_change_state_handler() to deal with the dangling change state handler during hot-unplugging ide devices which might lead to a crash. Signed-off-by: Ashijeet Acharya Reviewed-by: John Snow Message-id: 1474995212-10580-1-git-send-email-ashijeetacharya@gmail.com [Minor whitespace fix --js] Signed-off-by: John Snow --- hw/ide/core.c | 2 +- hw/ide/qdev.c | 11 +++++++++++ include/hw/ide/internal.h | 1 + 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/hw/ide/core.c b/hw/ide/core.c index 1bee18d86ee..72916771093 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -2582,7 +2582,7 @@ static void ide_restart_cb(void *opaque, int running, RunState state) void ide_register_restart_cb(IDEBus *bus) { if (bus->dma->ops->restart_dma) { - qemu_add_vm_change_state_handler(ide_restart_cb, bus); + bus->vmstate = qemu_add_vm_change_state_handler(ide_restart_cb, bus); } } diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c index 2eb055ae704..dbaa75cf595 100644 --- a/hw/ide/qdev.c +++ b/hw/ide/qdev.c @@ -31,6 +31,7 @@ /* --------------------------------- */ static char *idebus_get_fw_dev_path(DeviceState *dev); +static void idebus_unrealize(DeviceState *qdev, Error **errp); static Property ide_props[] = { DEFINE_PROP_UINT32("unit", IDEDevice, unit, -1), @@ -44,6 +45,15 @@ static void ide_bus_class_init(ObjectClass *klass, void *data) k->get_fw_dev_path = idebus_get_fw_dev_path; } +static void idebus_unrealize(DeviceState *qdev, Error **errp) +{ + IDEBus *bus = DO_UPCAST(IDEBus, qbus, qdev->parent_bus); + + if (bus->vmstate) { + qemu_del_vm_change_state_handler(bus->vmstate); + } +} + static const TypeInfo ide_bus_info = { .name = TYPE_IDE_BUS, .parent = TYPE_BUS, @@ -355,6 +365,7 @@ static void ide_device_class_init(ObjectClass *klass, void *data) k->init = ide_qdev_init; set_bit(DEVICE_CATEGORY_STORAGE, k->categories); k->bus_type = TYPE_IDE_BUS; + k->unrealize = idebus_unrealize; k->props = ide_props; } diff --git a/include/hw/ide/internal.h b/include/hw/ide/internal.h index a6dd2c3d301..88dc11808b9 100644 --- a/include/hw/ide/internal.h +++ b/include/hw/ide/internal.h @@ -482,6 +482,7 @@ struct IDEBus { uint32_t retry_nsector; PortioList portio_list; PortioList portio2_list; + VMChangeStateEntry *vmstate; }; #define TYPE_IDE_DEVICE "ide-device" From c16fe84f07a9d3a04c11ce8a139e13a092b384c2 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 28 Sep 2016 15:31:32 +0800 Subject: [PATCH 449/723] docker: Build in a clean directory Currently we configure and build under "$QEMU_SRC/tests/docker" which is dubious. Create a fixed directory (to be friendly to ccache) and change to there before calling build_qemu. Signed-off-by: Fam Zheng Message-Id: <1475047892-11955-1-git-send-email-famz@redhat.com> --- tests/docker/common.rc | 3 +++ tests/docker/test-clang | 2 ++ tests/docker/test-full | 2 ++ tests/docker/test-mingw | 2 ++ tests/docker/test-quick | 2 ++ 5 files changed, 11 insertions(+) diff --git a/tests/docker/common.rc b/tests/docker/common.rc index 510a3ad3f44..21657e87c64 100755 --- a/tests/docker/common.rc +++ b/tests/docker/common.rc @@ -11,6 +11,9 @@ # or (at your option) any later version. See the COPYING file in # the top-level directory. +BUILD_DIR=/var/tmp/qemu-build +mkdir $BUILD_DIR + requires() { for c in $@; do diff --git a/tests/docker/test-clang b/tests/docker/test-clang index 60e4e976b32..16485e6b7e5 100755 --- a/tests/docker/test-clang +++ b/tests/docker/test-clang @@ -15,6 +15,8 @@ requires clang +cd "$BUILD_DIR" + OPTS="--enable-debug --cxx=clang++ --cc=clang --host-cc=clang" # -fsanitize=undefined is broken on Fedora 23, skip it for now # See also: https://bugzilla.redhat.com/show_bug.cgi?id=1263834 diff --git a/tests/docker/test-full b/tests/docker/test-full index fd9b798947c..05f0d491d14 100755 --- a/tests/docker/test-full +++ b/tests/docker/test-full @@ -13,5 +13,7 @@ . common.rc +cd "$BUILD_DIR" + build_qemu make check $MAKEFLAGS diff --git a/tests/docker/test-mingw b/tests/docker/test-mingw index c03757add8a..33968769f88 100755 --- a/tests/docker/test-mingw +++ b/tests/docker/test-mingw @@ -15,6 +15,8 @@ requires mingw dtc +cd "$BUILD_DIR" + for prefix in x86_64-w64-mingw32- i686-w64-mingw32-; do TARGET_LIST=x86_64-softmmu,aarch64-softmmu \ build_qemu --cross-prefix=$prefix \ diff --git a/tests/docker/test-quick b/tests/docker/test-quick index 7885dfafdbe..c465dc06d89 100755 --- a/tests/docker/test-quick +++ b/tests/docker/test-quick @@ -13,6 +13,8 @@ . common.rc +cd "$BUILD_DIR" + DEF_TARGET_LIST="x86_64-softmmu,aarch64-softmmu" TARGET_LIST=${TARGET_LIST:-$DEF_TARGET_LIST} \ build_qemu From 6fb2fff75dceed1716e757882a6dfbadd9042407 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Wed, 28 Sep 2016 12:00:29 -0300 Subject: [PATCH 450/723] target-i386: Report known CPUID[EAX=0xD,ECX=0]:EAX bits as migratable A regression was introduced by commit 96193c22a "target-i386: Move xsave component mask to features array": all CPUID[EAX=0xD,ECX=0]:EAX bits were being reported as unmigratable because they don't have feature names defined. This broke "-cpu host" because it enables only migratable features by default. This adds a new field to FeatureWordInfo: migratable_flags, which will make those features be reported as migratable even if they don't have a property name defined. Reported-by: Wanpeng Li Cc: Paolo Bonzini Reviewed-by: Wanpeng Li Signed-off-by: Eduardo Habkost --- target-i386/cpu.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 333309b9a70..0807e92600e 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -258,6 +258,7 @@ typedef struct FeatureWordInfo { int cpuid_reg; /* output register (R_* constant) */ uint32_t tcg_features; /* Feature flags supported by TCG */ uint32_t unmigratable_flags; /* Feature flags known to be unmigratable */ + uint32_t migratable_flags; /* Feature flags known to be migratable */ } FeatureWordInfo; static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { @@ -494,6 +495,10 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { .cpuid_needs_ecx = true, .cpuid_ecx = 0, .cpuid_reg = R_EAX, .tcg_features = ~0U, + .migratable_flags = XSTATE_FP_MASK | XSTATE_SSE_MASK | + XSTATE_YMM_MASK | XSTATE_BNDREGS_MASK | XSTATE_BNDCSR_MASK | + XSTATE_OPMASK_MASK | XSTATE_ZMM_Hi256_MASK | XSTATE_Hi16_ZMM_MASK | + XSTATE_PKRU_MASK, }, [FEAT_XSAVE_COMP_HI] = { .cpuid_eax = 0xD, @@ -600,15 +605,13 @@ static uint32_t x86_cpu_get_migratable_flags(FeatureWord w) for (i = 0; i < 32; i++) { uint32_t f = 1U << i; - /* If the feature name is unknown, it is not supported by QEMU yet */ - if (!wi->feat_names[i]) { - continue; - } - /* Skip features known to QEMU, but explicitly marked as unmigratable */ - if (wi->unmigratable_flags & f) { - continue; + + /* If the feature name is known, it is implicitly considered migratable, + * unless it is explicitly set in unmigratable_flags */ + if ((wi->migratable_flags & f) || + (wi->feat_names[i] && !(wi->unmigratable_flags & f))) { + r |= f; } - r |= f; } return r; } From 339892d758efb2d0954160d41736a0eac9875d67 Mon Sep 17 00:00:00 2001 From: Evgeny Yakovlev Date: Mon, 3 Oct 2016 14:50:02 +0300 Subject: [PATCH 451/723] target-i386: Correct family/model/stepping for Opteron_G3 Current CPU definition for AMD Opteron third generation includes features like SSE4a and LAHF_LM support in emulated CPUID. These features are present in K8 rev.E or K10 CPUs and later. However, current G3 family and model describe 2nd generation K8 cores instead. This is incorrect but was considered harmless until our tests found a problem with linux kernels >= 3.10 (and maybe earlier) which specifically check for Opteron K8 model when parsing CPUID leaf 0x80000001: http://lxr.free-electrons.com/source/arch/x86/kernel/cpu/amd.c?v=3.16#L552 This code will disable LAHF_LM feature in /proc/cpuinfo if model number is inconsistent. This change sets Opteron_G3 family/model/stepping to 16/2/3 which is a proper Opteron 3rd generation 2350 CPU. Signed-off-by: Evgeny Yakovlev Signed-off-by: Denis V. Lunev CC: Paolo Bonzini CC: Richard Henderson CC: Eduardo Habkost Signed-off-by: Eduardo Habkost --- include/hw/i386/pc.h | 15 +++++++++++++++ target-i386/cpu.c | 6 +++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 47bdf10cfd9..cb2df83b2c1 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -379,6 +379,21 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *); .driver = TYPE_X86_CPU,\ .property = "full-cpuid-auto-level",\ .value = "off",\ + },\ + {\ + .driver = "Opteron_G3" "-" TYPE_X86_CPU,\ + .property = "family",\ + .value = "15",\ + },\ + {\ + .driver = "Opteron_G3" "-" TYPE_X86_CPU,\ + .property = "model",\ + .value = "6",\ + },\ + {\ + .driver = "Opteron_G3" "-" TYPE_X86_CPU,\ + .property = "stepping",\ + .value = "1",\ }, #define PC_COMPAT_2_6 \ diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 0807e92600e..1c57fce81bc 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -1428,9 +1428,9 @@ static X86CPUDefinition builtin_x86_defs[] = { .name = "Opteron_G3", .level = 5, .vendor = CPUID_VENDOR_AMD, - .family = 15, - .model = 6, - .stepping = 1, + .family = 16, + .model = 2, + .stepping = 3, .features[FEAT_1_EDX] = CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | From 1d5b128cbeeab638f772e88674f22e36b1b024e5 Mon Sep 17 00:00:00 2001 From: David Kiarie Date: Tue, 4 Oct 2016 07:03:28 +0300 Subject: [PATCH 452/723] hw/iommu: Fix problems reported by Coverity scan Signed-off-by: David Kiarie Message-Id: <1475553808-13285-2-git-send-email-davidkiarie4@gmail.com> Signed-off-by: Paolo Bonzini --- hw/i386/amd_iommu.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index 023de526f6e..47b79d9112e 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -143,10 +143,10 @@ static void amdvi_assign_andq(AMDVIState *s, hwaddr addr, uint64_t val) static void amdvi_generate_msi_interrupt(AMDVIState *s) { - MSIMessage msg; - MemTxAttrs attrs; - - attrs.requester_id = pci_requester_id(&s->pci.dev); + MSIMessage msg = {}; + MemTxAttrs attrs = { + .requester_id = pci_requester_id(&s->pci.dev) + }; if (msi_enabled(&s->pci.dev)) { msg = msi_get_message(&s->pci.dev, 0); @@ -185,7 +185,7 @@ static void amdvi_setevent_bits(uint64_t *buffer, uint64_t value, int start, int length) { int index = start / 64, bitpos = start % 64; - uint64_t mask = ((1 << length) - 1) << bitpos; + uint64_t mask = MAKE_64BIT_MASK(start, length); buffer[index] &= ~mask; buffer[index] |= (value << bitpos) & mask; } @@ -333,8 +333,8 @@ static void amdvi_update_iotlb(AMDVIState *s, uint16_t devid, uint64_t gpa, IOMMUTLBEntry to_cache, uint16_t domid) { - AMDVIIOTLBEntry *entry = g_malloc(sizeof(*entry)); - uint64_t *key = g_malloc(sizeof(key)); + AMDVIIOTLBEntry *entry = g_new(AMDVIIOTLBEntry, 1); + uint64_t *key = g_new(uint64_t, 1); uint64_t gfn = gpa >> AMDVI_PAGE_SHIFT_4K; /* don't cache erroneous translations */ @@ -1135,6 +1135,7 @@ static void amdvi_reset(DeviceState *dev) static void amdvi_realize(DeviceState *dev, Error **err) { + int ret = 0; AMDVIState *s = AMD_IOMMU_DEVICE(dev); X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(dev); PCIBus *bus = PC_MACHINE(qdev_get_machine())->bus; @@ -1147,8 +1148,11 @@ static void amdvi_realize(DeviceState *dev, Error **err) object_property_set_bool(OBJECT(&s->pci), true, "realized", err); s->capab_offset = pci_add_capability(&s->pci.dev, AMDVI_CAPAB_ID_SEC, 0, AMDVI_CAPAB_SIZE); - pci_add_capability(&s->pci.dev, PCI_CAP_ID_MSI, 0, AMDVI_CAPAB_REG_SIZE); - pci_add_capability(&s->pci.dev, PCI_CAP_ID_HT, 0, AMDVI_CAPAB_REG_SIZE); + assert(s->capab_offset > 0); + ret = pci_add_capability(&s->pci.dev, PCI_CAP_ID_MSI, 0, AMDVI_CAPAB_REG_SIZE); + assert(ret > 0); + ret = pci_add_capability(&s->pci.dev, PCI_CAP_ID_HT, 0, AMDVI_CAPAB_REG_SIZE); + assert(ret > 0); /* set up MMIO */ memory_region_init_io(&s->mmio, OBJECT(s), &mmio_mem_ops, s, "amdvi-mmio", From 3cf294eebc98da6e2ff7976fcdf6a9b41984840e Mon Sep 17 00:00:00 2001 From: Junlian Bell Date: Mon, 26 Sep 2016 20:41:01 +0800 Subject: [PATCH 453/723] MC146818 RTC: coordinate guest clock base to destination host after migration qemu tracks guest time based on vector [base_rtc, last_update], in which last_update stands for a monotonic tick which is actually uptime of the host. according to rtc implementation codes of recent releases and upstream, after migration, the time base vector [base_rtc, last_update] isn't updated to coordinate with the destionation host, ie. qemu doesnt update last_update to uptime of the destination host. what problem have we got because of this bug? after migration, guest time may jump back to several days ago, that will make some critical business applications, such as lotus notes, malfunction. this patch is trying to fix the problem. first, when vmsave in progress, we rtc_update_time to refresh time stamp in cmos array, then during vmrestore, we rtc_set_time to update qemu base_rtc and last_update variable according to time stamp in cmos array. Signed-off-by: Junlian Bell Message-Id: <20160926124101.2364-1-zhongjun@sangfor.com.cn> Signed-off-by: Paolo Bonzini --- hw/timer/mc146818rtc.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c index ea625f25ce1..da209d02f08 100644 --- a/hw/timer/mc146818rtc.c +++ b/hw/timer/mc146818rtc.c @@ -717,11 +717,18 @@ static void rtc_set_date_from_host(ISADevice *dev) rtc_set_cmos(s, &tm); } +static void rtc_pre_save(void *opaque) +{ + RTCState *s = opaque; + + rtc_update_time(s); +} + static int rtc_post_load(void *opaque, int version_id) { RTCState *s = opaque; - if (version_id <= 2) { + if (version_id <= 2 || rtc_clock == QEMU_CLOCK_REALTIME) { rtc_set_time(s); s->offset = 0; check_update_timer(s); @@ -764,6 +771,7 @@ static const VMStateDescription vmstate_rtc = { .name = "mc146818rtc", .version_id = 3, .minimum_version_id = 1, + .pre_save = rtc_pre_save, .post_load = rtc_post_load, .fields = (VMStateField[]) { VMSTATE_BUFFER(cmos_data, RTCState), From eabb5782f70b4a10975b24ccd7129929a05ac932 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Wed, 28 Sep 2016 21:03:39 +0800 Subject: [PATCH 454/723] hw/misc/edu: support MSI interrupt So now edu device can support both line or msi interrupt, depending on how user configures it. Signed-off-by: Peter Xu Message-Id: <1475067819-21413-1-git-send-email-peterx@redhat.com> Signed-off-by: Paolo Bonzini --- docs/specs/edu.txt | 7 ++++++- hw/misc/edu.c | 18 ++++++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/docs/specs/edu.txt b/docs/specs/edu.txt index 7f8146780b4..08763108099 100644 --- a/docs/specs/edu.txt +++ b/docs/specs/edu.txt @@ -52,7 +52,7 @@ size == 8 for the rest. 0x20 (RW) : status register, bitwise OR 0x01 -- computing factorial (RO) - 0x80 -- raise interrupt 0x01 after finishing factorial computation + 0x80 -- raise interrupt after finishing factorial computation 0x24 (RO) : interrupt status register It contains values which raised the interrupt (see interrupt raise @@ -87,6 +87,11 @@ An IRQ is generated when written to the interrupt raise register. The value appears in interrupt status register when the interrupt is raised and has to be written to the interrupt acknowledge register to lower it. +The device supports both INTx and MSI interrupt. By default, INTx is +used. Even if the driver disabled INTx and only uses MSI, it still +needs to update the acknowledge register at the end of the IRQ handler +routine. + DMA controller -------------- One has to specify, source, destination, size, and start the transfer. One diff --git a/hw/misc/edu.c b/hw/misc/edu.c index 888ba49a0e7..401039c100b 100644 --- a/hw/misc/edu.c +++ b/hw/misc/edu.c @@ -24,6 +24,7 @@ #include "qemu/osdep.h" #include "hw/pci/pci.h" +#include "hw/pci/msi.h" #include "qemu/timer.h" #include "qemu/main-loop.h" /* iothread mutex */ #include "qapi/visitor.h" @@ -69,11 +70,20 @@ typedef struct { uint64_t dma_mask; } EduState; +static bool edu_msi_enabled(EduState *edu) +{ + return msi_enabled(&edu->pdev); +} + static void edu_raise_irq(EduState *edu, uint32_t val) { edu->irq_status |= val; if (edu->irq_status) { - pci_set_irq(&edu->pdev, 1); + if (edu_msi_enabled(edu)) { + msi_notify(&edu->pdev, 0); + } else { + pci_set_irq(&edu->pdev, 1); + } } } @@ -81,7 +91,7 @@ static void edu_lower_irq(EduState *edu, uint32_t val) { edu->irq_status &= ~val; - if (!edu->irq_status) { + if (!edu->irq_status && !edu_msi_enabled(edu)) { pci_set_irq(&edu->pdev, 0); } } @@ -342,6 +352,10 @@ static void pci_edu_realize(PCIDevice *pdev, Error **errp) pci_config_set_interrupt_pin(pci_conf, 1); + if (msi_init(pdev, 0, 1, true, false, errp)) { + return; + } + memory_region_init_io(&edu->mmio, OBJECT(edu), &edu_mmio_ops, edu, "edu-mmio", 1 << 20); pci_register_bar(pdev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &edu->mmio); From 120e512b7f753f2e2978b47344f329c2595284de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herv=C3=A9=20Poussineau?= Date: Mon, 26 Sep 2016 22:23:23 +0200 Subject: [PATCH 455/723] intc: add an interface to gather statistics/informations on interrupt controllers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This interface will be used by HMP commands 'info irq' and 'info pic'. Signed-off-by: Hervé Poussineau Message-Id: <1474921408-24710-2-git-send-email-hpoussin@reactos.org> Signed-off-by: Paolo Bonzini --- hw/intc/Makefile.objs | 1 + hw/intc/intc.c | 41 +++++++++++++++++++++++++++++++++++++++++ include/hw/intc/intc.h | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+) create mode 100644 hw/intc/intc.c create mode 100644 include/hw/intc/intc.h diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs index 05ec21b21e0..f24c837118c 100644 --- a/hw/intc/Makefile.objs +++ b/hw/intc/Makefile.objs @@ -17,6 +17,7 @@ common-obj-$(CONFIG_ARM_GIC) += arm_gicv3.o common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_dist.o common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_redist.o common-obj-$(CONFIG_OPENPIC) += openpic.o +common-obj-y += intc.o obj-$(CONFIG_APIC) += apic.o apic_common.o obj-$(CONFIG_ARM_GIC_KVM) += arm_gic_kvm.o diff --git a/hw/intc/intc.c b/hw/intc/intc.c new file mode 100644 index 00000000000..2e1e29e753a --- /dev/null +++ b/hw/intc/intc.c @@ -0,0 +1,41 @@ +/* + * QEMU Generic Interrupt Controller + * + * Copyright (c) 2016 Hervé Poussineau + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "hw/intc/intc.h" +#include "qemu/module.h" + +static const TypeInfo intctrl_info = { + .name = TYPE_INTERRUPT_STATS_PROVIDER, + .parent = TYPE_INTERFACE, + .class_size = sizeof(InterruptStatsProviderClass), +}; + +static void intc_register_types(void) +{ + type_register_static(&intctrl_info); +} + +type_init(intc_register_types) + diff --git a/include/hw/intc/intc.h b/include/hw/intc/intc.h new file mode 100644 index 00000000000..27d9828943a --- /dev/null +++ b/include/hw/intc/intc.h @@ -0,0 +1,33 @@ +#ifndef INTC_H +#define INTC_H + +#include "qom/object.h" + +#define TYPE_INTERRUPT_STATS_PROVIDER "intctrl" + +#define INTERRUPT_STATS_PROVIDER_CLASS(klass) \ + OBJECT_CLASS_CHECK(InterruptStatsProviderClass, (klass), \ + TYPE_INTERRUPT_STATS_PROVIDER) +#define INTERRUPT_STATS_PROVIDER_GET_CLASS(obj) \ + OBJECT_GET_CLASS(InterruptStatsProviderClass, (obj), \ + TYPE_INTERRUPT_STATS_PROVIDER) +#define INTERRUPT_STATS_PROVIDER(obj) \ + INTERFACE_CHECK(InterruptStatsProvider, (obj), \ + TYPE_INTERRUPT_STATS_PROVIDER) + +typedef struct InterruptStatsProvider { + Object parent; +} InterruptStatsProvider; + +typedef struct InterruptStatsProviderClass { + InterfaceClass parent; + + /* The returned pointer and statistics must remain valid until + * the BQL is next dropped. + */ + bool (*get_statistics)(InterruptStatsProvider *obj, uint64_t **irq_counts, + unsigned int *nb_irqs); + void (*print_info)(InterruptStatsProvider *obj, Monitor *mon); +} InterruptStatsProviderClass; + +#endif From 4f2e39e10360380862ae388424c129ce56ec8ae9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herv=C3=A9=20Poussineau?= Date: Mon, 26 Sep 2016 22:23:24 +0200 Subject: [PATCH 456/723] intc/i8259: implement InterruptStatsProvider interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Hervé Poussineau Message-Id: <1474921408-24710-3-git-send-email-hpoussin@reactos.org> Signed-off-by: Paolo Bonzini --- hw/intc/i8259.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/hw/intc/i8259.c b/hw/intc/i8259.c index c2607a58689..75c8d225183 100644 --- a/hw/intc/i8259.c +++ b/hw/intc/i8259.c @@ -29,6 +29,7 @@ #include "qemu/timer.h" #include "qemu/log.h" #include "hw/isa/i8259_internal.h" +#include "hw/intc/intc.h" /* debug PIC */ //#define DEBUG_PIC @@ -251,6 +252,35 @@ static void pic_reset(DeviceState *dev) pic_init_reset(s); } +static bool pic_get_statistics(InterruptStatsProvider *obj, + uint64_t **irq_counts, unsigned int *nb_irqs) +{ + PICCommonState *s = PIC_COMMON(obj); + + if (s->master) { +#ifdef DEBUG_IRQ_COUNT + *irq_counts = irq_count; + *nb_irqs = ARRAY_SIZE(irq_count); +#else + return false; +#endif + } else { + *irq_counts = NULL; + *nb_irqs = 0; + } + return true; +} + +static void pic_print_info(InterruptStatsProvider *obj, Monitor *mon) +{ + PICCommonState *s = PIC_COMMON(obj); + monitor_printf(mon, "pic%d: irr=%02x imr=%02x isr=%02x hprio=%d " + "irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n", + s->master ? 0 : 1, s->irr, s->imr, s->isr, s->priority_add, + s->irq_base, s->read_reg_select, s->elcr, + s->special_fully_nested_mode); +} + static void pic_ioport_write(void *opaque, hwaddr addr64, uint64_t val64, unsigned size) { @@ -503,10 +533,13 @@ static void i8259_class_init(ObjectClass *klass, void *data) { PICClass *k = PIC_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); + InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass); k->parent_realize = dc->realize; dc->realize = pic_realize; dc->reset = pic_reset; + ic->get_statistics = pic_get_statistics; + ic->print_info = pic_print_info; } static const TypeInfo i8259_info = { @@ -515,6 +548,10 @@ static const TypeInfo i8259_info = { .parent = TYPE_PIC_COMMON, .class_init = i8259_class_init, .class_size = sizeof(PICClass), + .interfaces = (InterfaceInfo[]) { + { TYPE_INTERRUPT_STATS_PROVIDER }, + { } + }, }; static void pic_register_types(void) From 148fbe950454a7faf9ffae1763a3a185fcc7233e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herv=C3=A9=20Poussineau?= Date: Mon, 26 Sep 2016 22:23:25 +0200 Subject: [PATCH 457/723] intc/slavio_intctl: implement InterruptStatsProvider interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Acked-by: Artyom Tarasenko Signed-off-by: Hervé Poussineau Message-Id: <1474921408-24710-4-git-send-email-hpoussin@reactos.org> Signed-off-by: Paolo Bonzini --- hw/intc/slavio_intctl.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/hw/intc/slavio_intctl.c b/hw/intc/slavio_intctl.c index e82e8936286..a9acb647cc6 100644 --- a/hw/intc/slavio_intctl.c +++ b/hw/intc/slavio_intctl.c @@ -26,6 +26,7 @@ #include "hw/sparc/sun4m.h" #include "monitor/monitor.h" #include "hw/sysbus.h" +#include "hw/intc/intc.h" #include "trace.h" //#define DEBUG_IRQ_COUNT @@ -418,6 +419,31 @@ static void slavio_intctl_reset(DeviceState *d) slavio_check_interrupts(s, 0); } +#ifdef DEBUG_IRQ_COUNT +static bool slavio_intctl_get_statistics(InterruptStatsProvider *obj, + uint64_t **irq_counts, + unsigned int *nb_irqs) +{ + SLAVIO_INTCTLState *s = SLAVIO_INTCTL(obj); + *irq_counts = s->irq_count; + *nb_irqs = ARRAY_SIZE(s->irq_count); + return true; +} +#endif + +static void slavio_intctl_print_info(InterruptStatsProvider *obj, Monitor *mon) +{ + SLAVIO_INTCTLState *s = SLAVIO_INTCTL(obj); + int i; + + for (i = 0; i < MAX_CPUS; i++) { + monitor_printf(mon, "per-cpu %d: pending 0x%08x\n", i, + s->slaves[i].intreg_pending); + } + monitor_printf(mon, "master: pending 0x%08x, disabled 0x%08x\n", + s->intregm_pending, s->intregm_disabled); +} + static void slavio_intctl_init(Object *obj) { DeviceState *dev = DEVICE(obj); @@ -449,9 +475,14 @@ static void slavio_intctl_init(Object *obj) static void slavio_intctl_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass); dc->reset = slavio_intctl_reset; dc->vmsd = &vmstate_intctl; +#ifdef DEBUG_IRQ_COUNT + ic->get_statistics = slavio_intctl_get_statistics; +#endif + ic->print_info = slavio_intctl_print_info; } static const TypeInfo slavio_intctl_info = { @@ -460,6 +491,10 @@ static const TypeInfo slavio_intctl_info = { .instance_size = sizeof(SLAVIO_INTCTLState), .instance_init = slavio_intctl_init, .class_init = slavio_intctl_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_INTERRUPT_STATS_PROVIDER }, + { } + }, }; static void slavio_intctl_register_types(void) From 7c468ec54cf1b077022f870e211c41966bf58a2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herv=C3=A9=20Poussineau?= Date: Mon, 26 Sep 2016 22:23:26 +0200 Subject: [PATCH 458/723] intc/lm32_pic: implement InterruptStatsProvider interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have to change the vmstate version due to changes in statistics counters. Signed-off-by: Hervé Poussineau Message-Id: <1474921408-24710-5-git-send-email-hpoussin@reactos.org> Signed-off-by: Paolo Bonzini --- hw/intc/lm32_pic.c | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/hw/intc/lm32_pic.c b/hw/intc/lm32_pic.c index 3dad01c5ba1..c045b99e328 100644 --- a/hw/intc/lm32_pic.c +++ b/hw/intc/lm32_pic.c @@ -25,6 +25,7 @@ #include "hw/sysbus.h" #include "trace.h" #include "hw/lm32/lm32_pic.h" +#include "hw/intc/intc.h" #define TYPE_LM32_PIC "lm32-pic" #define LM32_PIC(obj) OBJECT_CHECK(LM32PicState, (obj), TYPE_LM32_PIC) @@ -38,7 +39,7 @@ struct LM32PicState { uint32_t irq_state; /* statistics */ - uint32_t stats_irq_count[32]; + uint64_t stats_irq_count[32]; }; typedef struct LM32PicState LM32PicState; @@ -152,6 +153,22 @@ static void pic_reset(DeviceState *d) } } +static bool lm32_get_statistics(InterruptStatsProvider *obj, + uint64_t **irq_counts, unsigned int *nb_irqs) +{ + LM32PicState *s = LM32_PIC(obj); + *irq_counts = s->stats_irq_count; + *nb_irqs = ARRAY_SIZE(s->stats_irq_count); + return true; +} + +static void lm32_print_info(InterruptStatsProvider *obj, Monitor *mon) +{ + LM32PicState *s = LM32_PIC(obj); + monitor_printf(mon, "lm32-pic: im=%08x ip=%08x irq_state=%08x\n", + s->im, s->ip, s->irq_state); +} + static void lm32_pic_init(Object *obj) { DeviceState *dev = DEVICE(obj); @@ -166,13 +183,13 @@ static void lm32_pic_init(Object *obj) static const VMStateDescription vmstate_lm32_pic = { .name = "lm32-pic", - .version_id = 1, - .minimum_version_id = 1, + .version_id = 2, + .minimum_version_id = 2, .fields = (VMStateField[]) { VMSTATE_UINT32(im, LM32PicState), VMSTATE_UINT32(ip, LM32PicState), VMSTATE_UINT32(irq_state, LM32PicState), - VMSTATE_UINT32_ARRAY(stats_irq_count, LM32PicState, 32), + VMSTATE_UINT64_ARRAY(stats_irq_count, LM32PicState, 32), VMSTATE_END_OF_LIST() } }; @@ -180,9 +197,12 @@ static const VMStateDescription vmstate_lm32_pic = { static void lm32_pic_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass); dc->reset = pic_reset; dc->vmsd = &vmstate_lm32_pic; + ic->get_statistics = lm32_get_statistics; + ic->print_info = lm32_print_info; } static const TypeInfo lm32_pic_info = { @@ -191,6 +211,10 @@ static const TypeInfo lm32_pic_info = { .instance_size = sizeof(LM32PicState), .instance_init = lm32_pic_init, .class_init = lm32_pic_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_INTERRUPT_STATS_PROVIDER }, + { } + }, }; static void lm32_pic_register_types(void) From 61b97833b38122e22c7af08685277681c6b79653 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herv=C3=A9=20Poussineau?= Date: Mon, 26 Sep 2016 22:23:27 +0200 Subject: [PATCH 459/723] intc: make HMP 'info irq' and 'info pic' commands use InterruptStatsProvider interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Hervé Poussineau Message-Id: <1474921408-24710-6-git-send-email-hpoussin@reactos.org> Signed-off-by: Paolo Bonzini --- hmp-commands-info.hx | 12 ------- hmp.c | 65 ++++++++++++++++++++++++++++++++++++++ hmp.h | 2 ++ hw/intc/i8259.c | 36 --------------------- hw/intc/lm32_pic.c | 31 ------------------ hw/intc/slavio_intctl.c | 32 ------------------- hw/sparc/sun4m.c | 15 +-------- include/hw/i386/pc.h | 2 -- include/hw/lm32/lm32_pic.h | 3 -- include/hw/sparc/sun4m.h | 8 ----- monitor.c | 6 ---- 11 files changed, 68 insertions(+), 144 deletions(-) diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx index 19729e55aea..6a7c476065c 100644 --- a/hmp-commands-info.hx +++ b/hmp-commands-info.hx @@ -179,13 +179,7 @@ ETEXI .args_type = "", .params = "", .help = "show the interrupts statistics (if available)", -#ifdef TARGET_SPARC - .cmd = sun4m_hmp_info_irq, -#elif defined(TARGET_LM32) - .cmd = lm32_hmp_info_irq, -#else .cmd = hmp_info_irq, -#endif }, STEXI @@ -199,13 +193,7 @@ ETEXI .args_type = "", .params = "", .help = "show i8259 (PIC) state", -#ifdef TARGET_SPARC - .cmd = sun4m_hmp_info_pic, -#elif defined(TARGET_LM32) - .cmd = lm32_hmp_info_pic, -#else .cmd = hmp_info_pic, -#endif }, #endif diff --git a/hmp.c b/hmp.c index 336e7bf0769..a79e7f94b7c 100644 --- a/hmp.c +++ b/hmp.c @@ -36,6 +36,7 @@ #include "qemu-io.h" #include "qemu/cutils.h" #include "qemu/error-report.h" +#include "hw/intc/intc.h" #ifdef CONFIG_SPICE #include @@ -787,6 +788,70 @@ static void hmp_info_pci_device(Monitor *mon, const PciDeviceInfo *dev) } } +static int hmp_info_irq_foreach(Object *obj, void *opaque) +{ + InterruptStatsProvider *intc; + InterruptStatsProviderClass *k; + Monitor *mon = opaque; + + if (object_dynamic_cast(obj, TYPE_INTERRUPT_STATS_PROVIDER)) { + intc = INTERRUPT_STATS_PROVIDER(obj); + k = INTERRUPT_STATS_PROVIDER_GET_CLASS(obj); + uint64_t *irq_counts; + unsigned int nb_irqs, i; + if (k->get_statistics && + k->get_statistics(intc, &irq_counts, &nb_irqs)) { + if (nb_irqs > 0) { + monitor_printf(mon, "IRQ statistics for %s:\n", + object_get_typename(obj)); + for (i = 0; i < nb_irqs; i++) { + if (irq_counts[i] > 0) { + monitor_printf(mon, "%2d: %" PRId64 "\n", i, + irq_counts[i]); + } + } + } + } else { + monitor_printf(mon, "IRQ statistics not available for %s.\n", + object_get_typename(obj)); + } + } + + return 0; +} + +void hmp_info_irq(Monitor *mon, const QDict *qdict) +{ + object_child_foreach_recursive(object_get_root(), + hmp_info_irq_foreach, mon); +} + +static int hmp_info_pic_foreach(Object *obj, void *opaque) +{ + InterruptStatsProvider *intc; + InterruptStatsProviderClass *k; + Monitor *mon = opaque; + + if (object_dynamic_cast(obj, TYPE_INTERRUPT_STATS_PROVIDER)) { + intc = INTERRUPT_STATS_PROVIDER(obj); + k = INTERRUPT_STATS_PROVIDER_GET_CLASS(obj); + if (k->print_info) { + k->print_info(intc, mon); + } else { + monitor_printf(mon, "Interrupt controller information not available for %s.\n", + object_get_typename(obj)); + } + } + + return 0; +} + +void hmp_info_pic(Monitor *mon, const QDict *qdict) +{ + object_child_foreach_recursive(object_get_root(), + hmp_info_pic_foreach, mon); +} + void hmp_info_pci(Monitor *mon, const QDict *qdict) { PciInfoList *info_list, *info; diff --git a/hmp.h b/hmp.h index 0876ec03a18..184769c13f6 100644 --- a/hmp.h +++ b/hmp.h @@ -36,6 +36,8 @@ void hmp_info_blockstats(Monitor *mon, const QDict *qdict); void hmp_info_vnc(Monitor *mon, const QDict *qdict); void hmp_info_spice(Monitor *mon, const QDict *qdict); void hmp_info_balloon(Monitor *mon, const QDict *qdict); +void hmp_info_irq(Monitor *mon, const QDict *qdict); +void hmp_info_pic(Monitor *mon, const QDict *qdict); void hmp_info_pci(Monitor *mon, const QDict *qdict); void hmp_info_block_jobs(Monitor *mon, const QDict *qdict); void hmp_info_tpm(Monitor *mon, const QDict *qdict); diff --git a/hw/intc/i8259.c b/hw/intc/i8259.c index 75c8d225183..fe9ecd6bd48 100644 --- a/hw/intc/i8259.c +++ b/hw/intc/i8259.c @@ -461,42 +461,6 @@ static void pic_realize(DeviceState *dev, Error **errp) pc->parent_realize(dev, errp); } -void hmp_info_pic(Monitor *mon, const QDict *qdict) -{ - int i; - PICCommonState *s; - - if (!isa_pic) { - return; - } - for (i = 0; i < 2; i++) { - s = i == 0 ? PIC_COMMON(isa_pic) : slave_pic; - monitor_printf(mon, "pic%d: irr=%02x imr=%02x isr=%02x hprio=%d " - "irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n", - i, s->irr, s->imr, s->isr, s->priority_add, - s->irq_base, s->read_reg_select, s->elcr, - s->special_fully_nested_mode); - } -} - -void hmp_info_irq(Monitor *mon, const QDict *qdict) -{ -#ifndef DEBUG_IRQ_COUNT - monitor_printf(mon, "irq statistic code not compiled.\n"); -#else - int i; - int64_t count; - - monitor_printf(mon, "IRQ statistics:\n"); - for (i = 0; i < 16; i++) { - count = irq_count[i]; - if (count > 0) { - monitor_printf(mon, "%2d: %" PRId64 "\n", i, count); - } - } -#endif -} - qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq) { qemu_irq *irq_set; diff --git a/hw/intc/lm32_pic.c b/hw/intc/lm32_pic.c index c045b99e328..09e15115fb0 100644 --- a/hw/intc/lm32_pic.c +++ b/hw/intc/lm32_pic.c @@ -43,35 +43,6 @@ struct LM32PicState { }; typedef struct LM32PicState LM32PicState; -static LM32PicState *pic; -void lm32_hmp_info_pic(Monitor *mon, const QDict *qdict) -{ - if (pic == NULL) { - return; - } - - monitor_printf(mon, "lm32-pic: im=%08x ip=%08x irq_state=%08x\n", - pic->im, pic->ip, pic->irq_state); -} - -void lm32_hmp_info_irq(Monitor *mon, const QDict *qdict) -{ - int i; - uint32_t count; - - if (pic == NULL) { - return; - } - - monitor_printf(mon, "IRQ statistics:\n"); - for (i = 0; i < 32; i++) { - count = pic->stats_irq_count[i]; - if (count > 0) { - monitor_printf(mon, "%2d: %u\n", i, count); - } - } -} - static void update_irq(LM32PicState *s) { s->ip |= s->irq_state; @@ -177,8 +148,6 @@ static void lm32_pic_init(Object *obj) qdev_init_gpio_in(dev, irq_handler, 32); sysbus_init_irq(sbd, &s->parent_irq); - - pic = s; } static const VMStateDescription vmstate_lm32_pic = { diff --git a/hw/intc/slavio_intctl.c b/hw/intc/slavio_intctl.c index a9acb647cc6..84e0bee4a92 100644 --- a/hw/intc/slavio_intctl.c +++ b/hw/intc/slavio_intctl.c @@ -211,38 +211,6 @@ static const MemoryRegionOps slavio_intctlm_mem_ops = { }, }; -void slavio_pic_info(Monitor *mon, DeviceState *dev) -{ - SLAVIO_INTCTLState *s = SLAVIO_INTCTL(dev); - int i; - - for (i = 0; i < MAX_CPUS; i++) { - monitor_printf(mon, "per-cpu %d: pending 0x%08x\n", i, - s->slaves[i].intreg_pending); - } - monitor_printf(mon, "master: pending 0x%08x, disabled 0x%08x\n", - s->intregm_pending, s->intregm_disabled); -} - -void slavio_irq_info(Monitor *mon, DeviceState *dev) -{ -#ifndef DEBUG_IRQ_COUNT - monitor_printf(mon, "irq statistic code not compiled.\n"); -#else - SLAVIO_INTCTLState *s = SLAVIO_INTCTL(dev); - int i; - int64_t count; - - s = SLAVIO_INTCTL(dev); - monitor_printf(mon, "IRQ statistics:\n"); - for (i = 0; i < 32; i++) { - count = s->irq_count[i]; - if (count > 0) - monitor_printf(mon, "%2d: %" PRId64 "\n", i, count); - } -#endif -} - static const uint32_t intbit_to_level[] = { 2, 3, 5, 7, 9, 11, 13, 2, 3, 5, 7, 9, 11, 13, 12, 12, 6, 13, 4, 10, 8, 9, 11, 0, 0, 0, 0, 15, 15, 15, 15, 0, diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index 478fda82093..b3915e4fd6c 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -159,20 +159,6 @@ static void nvram_init(Nvram *nvram, uint8_t *macaddr, } } -static DeviceState *slavio_intctl; - -void sun4m_hmp_info_pic(Monitor *mon, const QDict *qdict) -{ - if (slavio_intctl) - slavio_pic_info(mon, slavio_intctl); -} - -void sun4m_hmp_info_irq(Monitor *mon, const QDict *qdict) -{ - if (slavio_intctl) - slavio_irq_info(mon, slavio_intctl); -} - void cpu_check_irqs(CPUSPARCState *env) { CPUState *cs; @@ -873,6 +859,7 @@ static void dummy_fdc_tc(void *opaque, int irq, int level) static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, MachineState *machine) { + DeviceState *slavio_intctl; const char *cpu_model = machine->cpu_model; unsigned int i; void *iommu, *espdma, *ledma, *nvram; diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 47bdf10cfd9..142b57f7536 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -181,8 +181,6 @@ qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq); qemu_irq *kvm_i8259_init(ISABus *bus); int pic_read_irq(DeviceState *d); int pic_get_output(DeviceState *d); -void hmp_info_pic(Monitor *mon, const QDict *qdict); -void hmp_info_irq(Monitor *mon, const QDict *qdict); /* ioapic.c */ diff --git a/include/hw/lm32/lm32_pic.h b/include/hw/lm32/lm32_pic.h index 189fa386f70..e6479b8f63f 100644 --- a/include/hw/lm32/lm32_pic.h +++ b/include/hw/lm32/lm32_pic.h @@ -8,7 +8,4 @@ uint32_t lm32_pic_get_im(DeviceState *d); void lm32_pic_set_ip(DeviceState *d, uint32_t ip); void lm32_pic_set_im(DeviceState *d, uint32_t im); -void lm32_hmp_info_pic(Monitor *mon, const QDict *qdict); -void lm32_hmp_info_irq(Monitor *mon, const QDict *qdict); - #endif /* QEMU_HW_LM32_PIC_H */ diff --git a/include/hw/sparc/sun4m.h b/include/hw/sparc/sun4m.h index 9c17425a436..580d87b252f 100644 --- a/include/hw/sparc/sun4m.h +++ b/include/hw/sparc/sun4m.h @@ -24,14 +24,6 @@ static inline void sparc_iommu_memory_write(void *opaque, sparc_iommu_memory_rw(opaque, addr, buf, len, 1); } -/* slavio_intctl.c */ -void slavio_pic_info(Monitor *mon, DeviceState *dev); -void slavio_irq_info(Monitor *mon, DeviceState *dev); - -/* sun4m.c */ -void sun4m_hmp_info_pic(Monitor *mon, const QDict *qdict); -void sun4m_hmp_info_irq(Monitor *mon, const QDict *qdict); - /* sparc32_dma.c */ #include "hw/sparc/sparc32_dma.h" diff --git a/monitor.c b/monitor.c index 83c4edfce08..d26c3bcfcf4 100644 --- a/monitor.c +++ b/monitor.c @@ -81,12 +81,6 @@ #include "qemu/cutils.h" #include "qapi/qmp/dispatch.h" -/* for hmp_info_irq/pic */ -#if defined(TARGET_SPARC) -#include "hw/sparc/sun4m.h" -#endif -#include "hw/lm32/lm32_pic.h" - #if defined(TARGET_S390X) #include "hw/s390x/storage-keys.h" #endif From 254316fa1f3f9c9ee9bf530278359146f97e309e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herv=C3=A9=20Poussineau?= Date: Mon, 26 Sep 2016 22:23:28 +0200 Subject: [PATCH 460/723] intc: make HMP 'info irq' and 'info pic' commands available on all targets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Hervé Poussineau Message-Id: <1474921408-24710-7-git-send-email-hpoussin@reactos.org> Signed-off-by: Paolo Bonzini --- hmp-commands-info.hx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx index 6a7c476065c..55d50c42c68 100644 --- a/hmp-commands-info.hx +++ b/hmp-commands-info.hx @@ -172,8 +172,6 @@ STEXI Show the command line history. ETEXI -#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_MIPS) || \ - defined(TARGET_LM32) || (defined(TARGET_SPARC) && !defined(TARGET_SPARC64)) { .name = "irq", .args_type = "", @@ -192,10 +190,9 @@ ETEXI .name = "pic", .args_type = "", .params = "", - .help = "show i8259 (PIC) state", + .help = "show PIC state", .cmd = hmp_info_pic, }, -#endif STEXI @item info pic From 23ea7f57949f2f5934f4d5bbc29fe321b3a7067b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 30 Sep 2016 22:30:52 +0100 Subject: [PATCH 461/723] atomic.h: fix __SANITIZE_THREAD__ build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only very modern GCC's actually set this define when building with the ThreadSanitizer so this little typo slipped though. Signed-off-by: Alex Bennée Message-Id: <20160930213106.20186-2-alex.bennee@linaro.org> Signed-off-by: Paolo Bonzini --- include/qemu/atomic.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/qemu/atomic.h b/include/qemu/atomic.h index 0cce246ea92..c493f89059c 100644 --- a/include/qemu/atomic.h +++ b/include/qemu/atomic.h @@ -82,7 +82,7 @@ */ #if defined(__SANITIZE_THREAD__) #define smp_read_barrier_depends() ({ barrier(); __atomic_thread_fence(__ATOMIC_CONSUME); }) -#elsif defined(__alpha__) +#elif defined(__alpha__) #define smp_read_barrier_depends() asm volatile("mb":::"memory") #else #define smp_read_barrier_depends() barrier() From e653bc6b0ff645c25b8a2eb607c18a5c98b59db6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 30 Sep 2016 22:30:53 +0100 Subject: [PATCH 462/723] atomic.h: comment on use of atomic_read/set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add some notes on the use of the relaxed atomic access helpers and their importance for defined behaviour in C11's multi-threaded memory model. Signed-off-by: Alex Bennée Message-Id: <20160930213106.20186-3-alex.bennee@linaro.org> Signed-off-by: Paolo Bonzini --- include/qemu/atomic.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/qemu/atomic.h b/include/qemu/atomic.h index c493f89059c..c4f6950fcb7 100644 --- a/include/qemu/atomic.h +++ b/include/qemu/atomic.h @@ -92,6 +92,12 @@ /* Weak atomic operations prevent the compiler moving other * loads/stores past the atomic operation load/store. However there is * no explicit memory barrier for the processor. + * + * The C11 memory model says that variables that are accessed from + * different threads should at least be done with __ATOMIC_RELAXED + * primitives or the result is undefined. Generally this has little to + * no effect on the generated code but not using the atomic primitives + * will get flagged by sanitizers as a violation. */ #define atomic_read(ptr) \ ({ \ From 550276ae0a88851edda2cb7fcdd64256dbb8e314 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 30 Sep 2016 22:30:55 +0100 Subject: [PATCH 463/723] tcg/optimize: move default return out of if statement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is to appease sanitizer builds which complain that: "error: control reaches end of non-void function" Signed-off-by: Alex Bennée Reviewed-by: Marc-André Lureau Message-Id: <20160930213106.20186-5-alex.bennee@linaro.org> Signed-off-by: Paolo Bonzini --- tcg/optimize.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tcg/optimize.c b/tcg/optimize.c index 9998ac74138..0f1349086b5 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -468,9 +468,8 @@ static TCGArg do_constant_folding_cond(TCGOpcode op, TCGArg x, default: return 2; } - } else { - return 2; } + return 2; } /* Return 2 if the condition can't be simplified, and the result From f96a8cc3c633b25d9269337408ae2417ebbbad8e Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 30 Sep 2016 22:30:56 +0100 Subject: [PATCH 464/723] seqlock: use atomic writes for the sequence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is a data race if the sequence is written concurrently to the read. In C11 this has undefined behavior. Use atomic_set; the read side is already using atomic_read. Reported-by: Alex Bennée Signed-off-by: Paolo Bonzini Signed-off-by: Alex Bennée Message-Id: <20160930213106.20186-6-alex.bennee@linaro.org> Signed-off-by: Paolo Bonzini --- include/qemu/seqlock.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/qemu/seqlock.h b/include/qemu/seqlock.h index 2e2be4c4f08..8dee11d1010 100644 --- a/include/qemu/seqlock.h +++ b/include/qemu/seqlock.h @@ -31,7 +31,7 @@ static inline void seqlock_init(QemuSeqLock *sl) /* Lock out other writers and update the count. */ static inline void seqlock_write_begin(QemuSeqLock *sl) { - ++sl->sequence; + atomic_set(&sl->sequence, sl->sequence + 1); /* Write sequence before updating other fields. */ smp_wmb(); @@ -42,7 +42,7 @@ static inline void seqlock_write_end(QemuSeqLock *sl) /* Write other fields before finalizing sequence. */ smp_wmb(); - ++sl->sequence; + atomic_set(&sl->sequence, sl->sequence + 1); } static inline unsigned seqlock_read_begin(QemuSeqLock *sl) From b6b3ccfda015dcd5ab50f70c189ee5cc6c622e91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 30 Sep 2016 22:30:57 +0100 Subject: [PATCH 465/723] qom/object: update class cache atomically MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The idiom CPU_GET_CLASS(cpu) is fairly extensively used in various threads and trips of ThreadSanitizer due to the fact it updates obj->class->object_cast_cache behind the scenes. As this is just a fast-path cache there is no need to lock updates. However to ensure defined C11 behaviour across threads we need to use the plain atomic_read/set primitives and keep the sanitizer happy. Signed-off-by: Alex Bennée Reviewed-by: Marc-André Lureau Message-Id: <20160930213106.20186-7-alex.bennee@linaro.org> Signed-off-by: Paolo Bonzini --- qom/object.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/qom/object.c b/qom/object.c index 8166b7dace6..7a05e35ed92 100644 --- a/qom/object.c +++ b/qom/object.c @@ -614,7 +614,7 @@ Object *object_dynamic_cast_assert(Object *obj, const char *typename, Object *inst; for (i = 0; obj && i < OBJECT_CLASS_CAST_CACHE; i++) { - if (obj->class->object_cast_cache[i] == typename) { + if (atomic_read(&obj->class->object_cast_cache[i]) == typename) { goto out; } } @@ -631,10 +631,10 @@ Object *object_dynamic_cast_assert(Object *obj, const char *typename, if (obj && obj == inst) { for (i = 1; i < OBJECT_CLASS_CAST_CACHE; i++) { - obj->class->object_cast_cache[i - 1] = - obj->class->object_cast_cache[i]; + atomic_set(&obj->class->object_cast_cache[i - 1], + atomic_read(&obj->class->object_cast_cache[i])); } - obj->class->object_cast_cache[i - 1] = typename; + atomic_set(&obj->class->object_cast_cache[i - 1], typename); } out: @@ -704,7 +704,7 @@ ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class, int i; for (i = 0; class && i < OBJECT_CLASS_CAST_CACHE; i++) { - if (class->class_cast_cache[i] == typename) { + if (atomic_read(&class->class_cast_cache[i]) == typename) { ret = class; goto out; } @@ -725,9 +725,10 @@ ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class, #ifdef CONFIG_QOM_CAST_DEBUG if (class && ret == class) { for (i = 1; i < OBJECT_CLASS_CAST_CACHE; i++) { - class->class_cast_cache[i - 1] = class->class_cast_cache[i]; + atomic_set(&class->class_cast_cache[i - 1], + atomic_read(&class->class_cast_cache[i])); } - class->class_cast_cache[i - 1] = typename; + atomic_set(&class->class_cast_cache[i - 1], typename); } out: #endif From ce7cf6a973f4b614162b9518954d441fa5e32fc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 30 Sep 2016 22:30:58 +0100 Subject: [PATCH 466/723] qom/cpu: atomically clear the tb_jmp_cache MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ThreadSanitizer rightly complains that something initialised with a normal access is later updated and read atomically. Signed-off-by: Alex Bennée Message-Id: <20160930213106.20186-8-alex.bennee@linaro.org> Signed-off-by: Paolo Bonzini --- qom/cpu.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/qom/cpu.c b/qom/cpu.c index 484c49388d6..ef905da9bec 100644 --- a/qom/cpu.c +++ b/qom/cpu.c @@ -253,6 +253,7 @@ void cpu_reset(CPUState *cpu) static void cpu_common_reset(CPUState *cpu) { CPUClass *cc = CPU_GET_CLASS(cpu); + int i; if (qemu_loglevel_mask(CPU_LOG_RESET)) { qemu_log("CPU Reset (CPU %d)\n", cpu->cpu_index); @@ -268,7 +269,10 @@ static void cpu_common_reset(CPUState *cpu) cpu->can_do_io = 1; cpu->exception_index = -1; cpu->crash_occurred = false; - memset(cpu->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof(void *)); + + for (i = 0; i < TB_JMP_CACHE_SIZE; ++i) { + atomic_set(&cpu->tb_jmp_cache[i], NULL); + } } static bool cpu_common_has_work(CPUState *cs) From 027d9a7d2911e993cdcbd21c7c35d1dd058f05bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 30 Sep 2016 22:30:59 +0100 Subject: [PATCH 467/723] cpu: atomically modify cpu->exit_request MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ThreadSanitizer picks up potential races although we already use barriers to ensure things are in the correct order when processing exit requests. For true C11 defined behaviour across threads we need to use relaxed atomic_set/atomic_read semantics to reassure tsan. Signed-off-by: Alex Bennée Message-Id: <20160930213106.20186-9-alex.bennee@linaro.org> Signed-off-by: Paolo Bonzini --- cpu-exec.c | 8 ++++---- qom/cpu.c | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 8823d23df7e..e114fcdf296 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -192,7 +192,7 @@ static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, TranslationBlock *itb) /* We were asked to stop executing TBs (probably a pending * interrupt. We've now stopped, so clear the flag. */ - cpu->tcg_exit_req = 0; + atomic_set(&cpu->tcg_exit_req, 0); } return ret; } @@ -490,8 +490,8 @@ static inline void cpu_handle_interrupt(CPUState *cpu, *last_tb = NULL; } } - if (unlikely(cpu->exit_request || replay_has_interrupt())) { - cpu->exit_request = 0; + if (unlikely(atomic_read(&cpu->exit_request) || replay_has_interrupt())) { + atomic_set(&cpu->exit_request, 0); cpu->exception_index = EXCP_INTERRUPT; cpu_loop_exit(cpu); } @@ -503,7 +503,7 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb, { uintptr_t ret; - if (unlikely(cpu->exit_request)) { + if (unlikely(atomic_read(&cpu->exit_request))) { return; } diff --git a/qom/cpu.c b/qom/cpu.c index ef905da9bec..e765bc0caf2 100644 --- a/qom/cpu.c +++ b/qom/cpu.c @@ -120,10 +120,10 @@ void cpu_reset_interrupt(CPUState *cpu, int mask) void cpu_exit(CPUState *cpu) { - cpu->exit_request = 1; + atomic_set(&cpu->exit_request, 1); /* Ensure cpu_exec will see the exit request after TCG has exited. */ smp_wmb(); - cpu->tcg_exit_req = 1; + atomic_set(&cpu->tcg_exit_req, 1); } int cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cpu, From a890643958f03aaa344290700093b280cb606c28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 30 Sep 2016 22:31:00 +0100 Subject: [PATCH 468/723] util/qht: atomically set b->hashes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ThreadSanitizer detects a possible race between reading/writing the hashes. The ordering semantics are already documented for QHT however for true C11 compliance we should use relaxed atomic primitives for accesses that are done across threads. On x86 this slightly changes to the code to not do a load/compare in a single instruction leading to a slight performance degradation. Running 'taskset -c 0 tests/qht-bench -n 1 -d 10' (i.e. all lookups) 10 times, we get: before the patch: $ ./mean.pl 34.04 34.24 34.38 34.25 34.18 34.51 34.46 34.44 34.29 34.08 34.287 +- 0.160072900059109 after: $ ./mean.pl 33.94 34.00 33.52 33.46 33.55 33.71 34.27 34.06 34.28 34.58 33.937 +- 0.374731014640279 Signed-off-by: Alex Bennée Reviewed-by: Emilio G. Cota Message-Id: <20160930213106.20186-10-alex.bennee@linaro.org> Signed-off-by: Paolo Bonzini --- util/qht.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/util/qht.c b/util/qht.c index 16a8d7950e8..571639d30a1 100644 --- a/util/qht.c +++ b/util/qht.c @@ -379,7 +379,7 @@ static void qht_bucket_reset__locked(struct qht_bucket *head) if (b->pointers[i] == NULL) { goto done; } - b->hashes[i] = 0; + atomic_set(&b->hashes[i], 0); atomic_set(&b->pointers[i], NULL); } b = b->next; @@ -444,7 +444,7 @@ void *qht_do_lookup(struct qht_bucket *head, qht_lookup_func_t func, do { for (i = 0; i < QHT_BUCKET_ENTRIES; i++) { - if (b->hashes[i] == hash) { + if (atomic_read(&b->hashes[i]) == hash) { /* The pointer is dereferenced before seqlock_read_retry, * so (unlike qht_insert__locked) we need to use * atomic_rcu_read here. @@ -538,8 +538,8 @@ static bool qht_insert__locked(struct qht *ht, struct qht_map *map, if (new) { atomic_rcu_set(&prev->next, b); } - b->hashes[i] = hash; /* smp_wmb() implicit in seqlock_write_begin. */ + atomic_set(&b->hashes[i], hash); atomic_set(&b->pointers[i], p); seqlock_write_end(&head->sequence); return true; @@ -607,10 +607,10 @@ qht_entry_move(struct qht_bucket *to, int i, struct qht_bucket *from, int j) qht_debug_assert(to->pointers[i]); qht_debug_assert(from->pointers[j]); - to->hashes[i] = from->hashes[j]; + atomic_set(&to->hashes[i], from->hashes[j]); atomic_set(&to->pointers[i], from->pointers[j]); - from->hashes[j] = 0; + atomic_set(&from->hashes[j], 0); atomic_set(&from->pointers[j], NULL); } From dd1f63493adbbb06fa16ed15f8fc16584f55ee81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 30 Sep 2016 22:31:01 +0100 Subject: [PATCH 469/723] linux-user/syscall: extend lock around cpu-list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is a potential race if several threads exit at once. To serialise the exits extend the lock above the initial checking of the CPU list. Signed-off-by: Alex Bennée Message-Id: <20160930213106.20186-11-alex.bennee@linaro.org> Signed-off-by: Paolo Bonzini --- linux-user/syscall.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 0815f309654..fa559be47f3 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -7476,13 +7476,16 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; } + cpu_list_lock(); + if (CPU_NEXT(first_cpu)) { TaskState *ts; - cpu_list_lock(); /* Remove the CPU from the list. */ QTAILQ_REMOVE(&cpus, cpu, node); + cpu_list_unlock(); + ts = cpu->opaque; if (ts->child_tidptr) { put_user_u32(0, ts->child_tidptr); @@ -7495,6 +7498,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, rcu_unregister_thread(); pthread_exit(NULL); } + + cpu_list_unlock(); #ifdef TARGET_GPROF _mcleanup(); #endif From a31393e7a594e45f2ed0ae17e1b7987e94f30fcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 30 Sep 2016 22:31:02 +0100 Subject: [PATCH 470/723] qga/command: use QEMU atomic primitives MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The guest client's use of the glib's g_atomic primitives causes newer GCC's to barf when built on Travis. As QEMU has its own primitives with well understood semantics we might as well use them. The use of atomics was a little inconsistent so I've also ensure the values are correctly set with atomic primitives at the same time. I also made the usage of bool consistent while I was at it. Signed-off-by: Alex Bennée Message-Id: <20160930213106.20186-12-alex.bennee@linaro.org> Signed-off-by: Paolo Bonzini --- qga/commands.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/qga/commands.c b/qga/commands.c index 50fd26a817a..edd3e830e60 100644 --- a/qga/commands.c +++ b/qga/commands.c @@ -16,6 +16,7 @@ #include "qapi/qmp/qerror.h" #include "qemu/base64.h" #include "qemu/cutils.h" +#include "qemu/atomic.h" /* Maximum captured guest-exec out_data/err_data - 16MB */ #define GUEST_EXEC_MAX_OUTPUT (16*1024*1024) @@ -82,7 +83,7 @@ struct GuestExecIOData { guchar *data; gsize size; gsize length; - gint closed; + bool closed; bool truncated; const char *name; }; @@ -93,7 +94,7 @@ struct GuestExecInfo { int64_t pid_numeric; gint status; bool has_output; - gint finished; + bool finished; GuestExecIOData in; GuestExecIOData out; GuestExecIOData err; @@ -156,13 +157,13 @@ GuestExecStatus *qmp_guest_exec_status(int64_t pid, Error **err) ges = g_new0(GuestExecStatus, 1); - bool finished = g_atomic_int_get(&gei->finished); + bool finished = atomic_mb_read(&gei->finished); /* need to wait till output channels are closed * to be sure we captured all output at this point */ if (gei->has_output) { - finished = finished && g_atomic_int_get(&gei->out.closed); - finished = finished && g_atomic_int_get(&gei->err.closed); + finished = finished && atomic_mb_read(&gei->out.closed); + finished = finished && atomic_mb_read(&gei->err.closed); } ges->exited = finished; @@ -264,7 +265,7 @@ static void guest_exec_child_watch(GPid pid, gint status, gpointer data) (int32_t)gpid_to_int64(pid), (uint32_t)status); gei->status = status; - gei->finished = true; + atomic_mb_set(&gei->finished, true); g_spawn_close_pid(pid); } @@ -320,7 +321,7 @@ static gboolean guest_exec_input_watch(GIOChannel *ch, done: g_io_channel_shutdown(ch, true, NULL); g_io_channel_unref(ch); - g_atomic_int_set(&p->closed, 1); + atomic_mb_set(&p->closed, true); g_free(p->data); return false; @@ -374,7 +375,7 @@ static gboolean guest_exec_output_watch(GIOChannel *ch, close: g_io_channel_shutdown(ch, true, NULL); g_io_channel_unref(ch); - g_atomic_int_set(&p->closed, 1); + atomic_mb_set(&p->closed, true); return false; } From 32265288a9b207dcd3f8da516643f81e1d2c5a1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Fri, 30 Sep 2016 22:31:03 +0100 Subject: [PATCH 471/723] .travis.yml: add gcc sanitizer build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As it seems easy to break the ThreadSanitizer build we should defend it to ensure that fixes get applied when it breaks. We use the Ubuntu GCC PPA to get the latest GCC goodness. As we need to use the -fuse-ld=gold work around we have to disable the linux-user targets as these trip up the linker. The make check run is also disabled for Travis but this can be re-enabled once the check targets have been fixed. Signed-off-by: Alex Bennée Message-Id: <20160930213106.20186-13-alex.bennee@linaro.org> --- .travis.yml | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/.travis.yml b/.travis.yml index f30b10e4f71..9916178bf3c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,7 @@ cache: ccache addons: apt: packages: + # Build dependencies - libaio-dev - libattr1-dev - libbrlapi-dev @@ -89,6 +90,7 @@ matrix: - env: CONFIG="" os: osx compiler: clang + # Plain Trusty Build - env: CONFIG="" sudo: required addons: @@ -99,3 +101,46 @@ matrix: - sudo apt-get build-dep -qq qemu - wget -O - http://people.linaro.org/~alex.bennee/qemu-submodule-git-seed.tar.xz | tar -xvJ - git submodule update --init --recursive + # Using newer GCC with sanitizers + - addons: + apt: + sources: + # PPAs for newer toolchains + - ubuntu-toolchain-r-test + packages: + # Extra toolchains + - gcc-5 + - g++-5 + # Build dependencies + - libaio-dev + - libattr1-dev + - libbrlapi-dev + - libcap-ng-dev + - libgnutls-dev + - libgtk-3-dev + - libiscsi-dev + - liblttng-ust-dev + - libnfs-dev + - libncurses5-dev + - libnss3-dev + - libpixman-1-dev + - libpng12-dev + - librados-dev + - libsdl1.2-dev + - libseccomp-dev + - libspice-protocol-dev + - libspice-server-dev + - libssh2-1-dev + - liburcu-dev + - libusb-1.0-0-dev + - libvte-2.90-dev + - sparse + - uuid-dev + language: generic + compiler: none + env: + - COMPILER_NAME=gcc CXX=g++-5 CC=gcc-5 + - CONFIG="--cc=gcc-5 --cxx=g++-5 --disable-pie --disable-linux-user --with-coroutine=gthread" + - TEST_CMD="" + before_script: + - ./configure ${CONFIG} --extra-cflags="-g3 -O0 -fsanitize=thread -fuse-ld=gold" || cat config.log From 25a8535943b456954eeb82eb7d1f53d2b4f168e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herv=C3=A9=20Poussineau?= Date: Sun, 2 Oct 2016 21:44:27 +0200 Subject: [PATCH 472/723] i8259: give ISA device when registering ISA ioports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Hervé Poussineau Message-Id: <1475437467-22781-1-git-send-email-hpoussin@reactos.org> Signed-off-by: Paolo Bonzini --- hw/intc/i8259_common.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/intc/i8259_common.c b/hw/intc/i8259_common.c index 3a850b0c662..d9a5e8b2177 100644 --- a/hw/intc/i8259_common.c +++ b/hw/intc/i8259_common.c @@ -70,10 +70,11 @@ static int pic_dispatch_post_load(void *opaque, int version_id) static void pic_common_realize(DeviceState *dev, Error **errp) { PICCommonState *s = PIC_COMMON(dev); + ISADevice *isa = ISA_DEVICE(dev); - isa_register_ioport(NULL, &s->base_io, s->iobase); + isa_register_ioport(isa, &s->base_io, s->iobase); if (s->elcr_addr != -1) { - isa_register_ioport(NULL, &s->elcr_io, s->elcr_addr); + isa_register_ioport(isa, &s->elcr_io, s->elcr_addr); } qdev_set_legacy_instance_id(dev, s->iobase, 1); From 949055a2549afc4cde06b7972072c7288bb43722 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 3 Oct 2016 13:47:04 +0400 Subject: [PATCH 473/723] char: use a fixed idx for child muxed chr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mux_chr_update_read_handler() is adding a new mux_cnt each time mux_chr_update_read_handler() is called, it's not possible to actually update the "child" chr callbacks that were set previously. This may lead to crashes if the "child" chr is destroyed: valgrind x86_64-softmmu/qemu-system-x86_64 -chardev stdio,mux=on,id=char0 -mon chardev=char0,mode=control,default when quitting: ==4306== Invalid read of size 8 ==4306== at 0x8061D3: json_lexer_destroy (json-lexer.c:385) ==4306== by 0x7E39F8: json_message_parser_destroy (json-streamer.c:134) ==4306== by 0x3447F6: monitor_qmp_event (monitor.c:3908) ==4306== by 0x480153: mux_chr_send_event (qemu-char.c:630) ==4306== by 0x480694: mux_chr_event (qemu-char.c:734) ==4306== by 0x47F1E9: qemu_chr_be_event (qemu-char.c:205) ==4306== by 0x481207: fd_chr_close (qemu-char.c:1114) ==4306== by 0x481659: qemu_chr_close_stdio (qemu-char.c:1221) ==4306== by 0x486F07: qemu_chr_free (qemu-char.c:4146) ==4306== by 0x486F97: qemu_chr_delete (qemu-char.c:4154) ==4306== by 0x487E66: qemu_chr_cleanup (qemu-char.c:4678) ==4306== by 0x495A98: main (vl.c:4675) ==4306== Address 0x28439e90 is 112 bytes inside a block of size 240 free'd ==4306== at 0x4C2CD5A: free (vg_replace_malloc.c:530) ==4306== by 0x1E4CBF2D: g_free (in /usr/lib64/libglib-2.0.so.0.4800.2) ==4306== by 0x344DE9: monitor_cleanup (monitor.c:4058) ==4306== by 0x495A93: main (vl.c:4674) ==4306== Block was alloc'd at ==4306== at 0x4C2BBAD: malloc (vg_replace_malloc.c:299) ==4306== by 0x1E4CBE18: g_malloc (in /usr/lib64/libglib-2.0.so.0.4800.2) ==4306== by 0x344BF8: monitor_init (monitor.c:4021) ==4306== by 0x49063C: mon_init_func (vl.c:2417) ==4306== by 0x7FC6DE: qemu_opts_foreach (qemu-option.c:1116) ==4306== by 0x4954E0: main (vl.c:4473) Instead, keep the "child" chr associated with a particular idx so its handlers can be updated and removed to avoid the crash. Signed-off-by: Marc-André Lureau Message-Id: <20161003094704.18087-3-marcandre.lureau@redhat.com> Signed-off-by: Paolo Bonzini --- include/sysemu/char.h | 1 + qemu-char.c | 22 +++++++++++++++------- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/include/sysemu/char.h b/include/sysemu/char.h index 0d0465ae0e0..4593576cf7b 100644 --- a/include/sysemu/char.h +++ b/include/sysemu/char.h @@ -92,6 +92,7 @@ struct CharDriverState { int explicit_be_open; int avail_connections; int is_mux; + int mux_idx; guint fd_in_tag; QemuOpts *opts; bool replay; diff --git a/qemu-char.c b/qemu-char.c index fb456cec345..7a85b1f0b37 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -165,6 +165,7 @@ CharDriverState *qemu_chr_alloc(ChardevCommon *backend, Error **errp) CharDriverState *chr = g_malloc0(sizeof(CharDriverState)); qemu_mutex_init(&chr->chr_write_lock); + chr->mux_idx = -1; if (backend->has_logfile) { int flags = O_WRONLY | O_CREAT; if (backend->has_logappend && @@ -738,17 +739,25 @@ static void mux_chr_update_read_handler(CharDriverState *chr, GMainContext *context) { MuxDriver *d = chr->opaque; + int idx; if (d->mux_cnt >= MAX_MUX) { fprintf(stderr, "Cannot add I/O handlers, MUX array is full\n"); return; } - d->ext_opaque[d->mux_cnt] = chr->handler_opaque; - d->chr_can_read[d->mux_cnt] = chr->chr_can_read; - d->chr_read[d->mux_cnt] = chr->chr_read; - d->chr_event[d->mux_cnt] = chr->chr_event; + + if (chr->mux_idx == -1) { + chr->mux_idx = d->mux_cnt++; + } + + idx = chr->mux_idx; + d->ext_opaque[idx] = chr->handler_opaque; + d->chr_can_read[idx] = chr->chr_can_read; + d->chr_read[idx] = chr->chr_read; + d->chr_event[idx] = chr->chr_event; + /* Fix up the real driver with mux routines */ - if (d->mux_cnt == 0) { + if (d->mux_cnt == 1) { qemu_chr_add_handlers_full(d->drv, mux_chr_can_read, mux_chr_read, mux_chr_event, @@ -757,8 +766,7 @@ static void mux_chr_update_read_handler(CharDriverState *chr, if (d->focus != -1) { mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_OUT); } - d->focus = d->mux_cnt; - d->mux_cnt++; + d->focus = idx; mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_IN); } From 6a7b2b21008f271e7a91e937e521e22f94579bb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 3 Oct 2016 13:47:03 +0400 Subject: [PATCH 474/723] char: update read handler in all cases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In commit ac1b84dd1 (rhbz#1027181), a check was added to only update the "read handler" when the front-end is opened, because the read callbacks were not restored when a device is plugged. However, this seems not correct, the handler is correctly set back on hotplug (in virtconsole_realize) and the bug can no longer be reproduced. Calling chr_update_read_handler() allows to fix the mux driver to stop calling the child handlers (which may be going to be destroyed). Signed-off-by: Marc-André Lureau Message-Id: <20161003094704.18087-2-marcandre.lureau@redhat.com> Signed-off-by: Paolo Bonzini --- qemu-char.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qemu-char.c b/qemu-char.c index 7a85b1f0b37..4b330ea90fa 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -469,7 +469,7 @@ void qemu_chr_add_handlers_full(CharDriverState *s, s->chr_read = fd_read; s->chr_event = fd_event; s->handler_opaque = opaque; - if (fe_open && s->chr_update_read_handler) { + if (s->chr_update_read_handler) { s->chr_update_read_handler(s, context); } From 7dc9ae4339faa97e89daadb2e1098147ab4aadc8 Mon Sep 17 00:00:00 2001 From: Michal Privoznik Date: Tue, 27 Sep 2016 17:24:56 +0200 Subject: [PATCH 475/723] util: Introduce qemu_get_pid_name This is a small helper that tries to fetch binary name for given PID. Signed-off-by: Michal Privoznik Message-Id: <4d75d475c1884f8e94ee8b1e57273ddf3ed68bf7.1474987617.git.mprivozn@redhat.com> Signed-off-by: Paolo Bonzini --- include/qemu/osdep.h | 10 ++++++++++ util/oslib-posix.c | 27 +++++++++++++++++++++++++++ util/oslib-win32.c | 7 +++++++ 3 files changed, 44 insertions(+) diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index 9e9fa615464..384bfe245f2 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -387,6 +387,16 @@ void os_mem_prealloc(int fd, char *area, size_t sz, Error **errp); int qemu_read_password(char *buf, int buf_size); +/** + * qemu_get_pid_name: + * @pid: pid of a process + * + * For given @pid fetch its name. Caller is responsible for + * freeing the string when no longer needed. + * Returns allocated string on success, NULL on failure. + */ +char *qemu_get_pid_name(pid_t pid); + /** * qemu_fork: * diff --git a/util/oslib-posix.c b/util/oslib-posix.c index f2d4e9e592e..8c1e8d6841a 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -46,6 +46,7 @@ #ifdef __FreeBSD__ #include +#include #endif #include "qemu/mmap-alloc.h" @@ -430,6 +431,32 @@ int qemu_read_password(char *buf, int buf_size) } +char *qemu_get_pid_name(pid_t pid) +{ + char *name = NULL; + +#if defined(__FreeBSD__) + /* BSDs don't have /proc, but they provide a nice substitute */ + struct kinfo_proc *proc = kinfo_getproc(pid); + + if (proc) { + name = g_strdup(proc->ki_comm); + free(proc); + } +#else + /* Assume a system with reasonable procfs */ + char *pid_path; + size_t len; + + pid_path = g_strdup_printf("/proc/%d/cmdline", pid); + g_file_get_contents(pid_path, &name, &len, NULL); + g_free(pid_path); +#endif + + return name; +} + + pid_t qemu_fork(Error **errp) { sigset_t oldmask, newmask; diff --git a/util/oslib-win32.c b/util/oslib-win32.c index 4c1dcf1e664..d09863cc9d2 100644 --- a/util/oslib-win32.c +++ b/util/oslib-win32.c @@ -575,6 +575,13 @@ int qemu_read_password(char *buf, int buf_size) } +char *qemu_get_pid_name(pid_t pid) +{ + /* XXX Implement me */ + abort(); +} + + pid_t qemu_fork(Error **errp) { errno = ENOSYS; From fbe7e3327a8cfa1b08664c2cda7a0a341cf0530a Mon Sep 17 00:00:00 2001 From: Michal Privoznik Date: Tue, 27 Sep 2016 17:24:57 +0200 Subject: [PATCH 476/723] qemu_kill_report: Report PID name too When qemu is being killed, its last words are: 2016-08-31T11:48:15.293587Z qemu-system-x86_64: terminating on signal 15 from pid 11180 That's nice, but what process is 11180? What if I told you we can do better: 2016-08-31T11:48:15.293587Z qemu-system-x86_64: terminating on signal 15 from pid 11180 (/usr/sbin/libvirtd) And that's exactly what this patch does. Signed-off-by: Michal Privoznik Message-Id: Signed-off-by: Paolo Bonzini --- vl.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/vl.c b/vl.c index f3abd99eb2f..6c5a51c49c9 100644 --- a/vl.c +++ b/vl.c @@ -1675,8 +1675,12 @@ static void qemu_kill_report(void) */ error_report("terminating on signal %d", shutdown_signal); } else { - error_report("terminating on signal %d from pid " FMT_pid, - shutdown_signal, shutdown_pid); + char *shutdown_cmd = qemu_get_pid_name(shutdown_pid); + + error_report("terminating on signal %d from pid " FMT_pid " (%s)", + shutdown_signal, shutdown_pid, + shutdown_cmd ? shutdown_cmd : ""); + g_free(shutdown_cmd); } shutdown_signal = -1; } From 81fed1d017d9460ac39e9ba775fcbe8bd90b1847 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Tue, 4 Oct 2016 13:28:06 +0100 Subject: [PATCH 477/723] STM32F205: Remove the individual device variables Cleanup the individual DeviceState and SysBusDevice variables to re-use the same variable for each device. Signed-off-by: Alistair Francis Reviewed-by: Peter Crosthwaite Message-id: fc5d75a57d320b69704df2c1146ff0fd482e4a88.1474742262.git.alistair@alistair23.me Signed-off-by: Peter Maydell --- hw/arm/stm32f205_soc.c | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/hw/arm/stm32f205_soc.c b/hw/arm/stm32f205_soc.c index de26b8caff9..5b6fa3bc352 100644 --- a/hw/arm/stm32f205_soc.c +++ b/hw/arm/stm32f205_soc.c @@ -62,8 +62,8 @@ static void stm32f205_soc_initfn(Object *obj) static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp) { STM32F205State *s = STM32F205_SOC(dev_soc); - DeviceState *syscfgdev, *usartdev, *timerdev, *nvic; - SysBusDevice *syscfgbusdev, *usartbusdev, *timerbusdev; + DeviceState *dev, *nvic; + SysBusDevice *busdev; Error *err = NULL; int i; @@ -94,44 +94,43 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp) s->kernel_filename, s->cpu_model); /* System configuration controller */ - syscfgdev = DEVICE(&s->syscfg); + dev = DEVICE(&s->syscfg); object_property_set_bool(OBJECT(&s->syscfg), true, "realized", &err); if (err != NULL) { error_propagate(errp, err); return; } - syscfgbusdev = SYS_BUS_DEVICE(syscfgdev); - sysbus_mmio_map(syscfgbusdev, 0, 0x40013800); - sysbus_connect_irq(syscfgbusdev, 0, qdev_get_gpio_in(nvic, 71)); + busdev = SYS_BUS_DEVICE(dev); + sysbus_mmio_map(busdev, 0, 0x40013800); + sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(nvic, 71)); /* Attach UART (uses USART registers) and USART controllers */ for (i = 0; i < STM_NUM_USARTS; i++) { - usartdev = DEVICE(&(s->usart[i])); - qdev_prop_set_chr(usartdev, "chardev", i < MAX_SERIAL_PORTS ? serial_hds[i] : NULL); + dev = DEVICE(&(s->usart[i])); + qdev_prop_set_chr(dev, "chardev", + i < MAX_SERIAL_PORTS ? serial_hds[i] : NULL); object_property_set_bool(OBJECT(&s->usart[i]), true, "realized", &err); if (err != NULL) { error_propagate(errp, err); return; } - usartbusdev = SYS_BUS_DEVICE(usartdev); - sysbus_mmio_map(usartbusdev, 0, usart_addr[i]); - sysbus_connect_irq(usartbusdev, 0, - qdev_get_gpio_in(nvic, usart_irq[i])); + busdev = SYS_BUS_DEVICE(dev); + sysbus_mmio_map(busdev, 0, usart_addr[i]); + sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(nvic, usart_irq[i])); } /* Timer 2 to 5 */ for (i = 0; i < STM_NUM_TIMERS; i++) { - timerdev = DEVICE(&(s->timer[i])); - qdev_prop_set_uint64(timerdev, "clock-frequency", 1000000000); + dev = DEVICE(&(s->timer[i])); + qdev_prop_set_uint64(dev, "clock-frequency", 1000000000); object_property_set_bool(OBJECT(&s->timer[i]), true, "realized", &err); if (err != NULL) { error_propagate(errp, err); return; } - timerbusdev = SYS_BUS_DEVICE(timerdev); - sysbus_mmio_map(timerbusdev, 0, timer_addr[i]); - sysbus_connect_irq(timerbusdev, 0, - qdev_get_gpio_in(nvic, timer_irq[i])); + busdev = SYS_BUS_DEVICE(dev); + sysbus_mmio_map(busdev, 0, timer_addr[i]); + sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(nvic, timer_irq[i])); } } From cbcb93e802076ecea9b3defe609ce4a45719e809 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Tue, 4 Oct 2016 13:28:07 +0100 Subject: [PATCH 478/723] STM32F2xx: Display PWM duty cycle from timer If correctly configured allow the STM32F2xx timer to print out the PWM duty cycle information. Signed-off-by: Alistair Francis Reviewed-by: Peter Crosthwaite Message-id: cdb59039a25e061615713a94b40797baa12ea9f9.1474742262.git.alistair@alistair23.me Signed-off-by: Peter Maydell --- hw/timer/stm32f2xx_timer.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/hw/timer/stm32f2xx_timer.c b/hw/timer/stm32f2xx_timer.c index bf0fb288c43..8c4c1f9f055 100644 --- a/hw/timer/stm32f2xx_timer.c +++ b/hw/timer/stm32f2xx_timer.c @@ -51,6 +51,15 @@ static void stm32f2xx_timer_interrupt(void *opaque) qemu_irq_pulse(s->irq); stm32f2xx_timer_set_alarm(s, s->hit_time); } + + if (s->tim_ccmr1 & (TIM_CCMR1_OC2M2 | TIM_CCMR1_OC2M1) && + !(s->tim_ccmr1 & TIM_CCMR1_OC2M0) && + s->tim_ccmr1 & TIM_CCMR1_OC2PE && + s->tim_ccer & TIM_CCER_CC2E) { + /* PWM 2 - Mode 1 */ + DB_PRINT("PWM2 Duty Cycle: %d%%\n", + s->tim_ccr2 / (100 * (s->tim_psc + 1))); + } } static inline int64_t stm32f2xx_ns_to_ticks(STM32F2XXTimerState *s, int64_t t) From d1f711d4070155ec6b81d331169c52f1bd6a4f21 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Tue, 4 Oct 2016 13:28:07 +0100 Subject: [PATCH 479/723] STM32F2xx: Add the ADC device Add the STM32F2xx ADC device. This device randomly generates values on each read. This also includes creating a hw/adc directory. Signed-off-by: Alistair Francis Reviewed-by: Peter Maydell Message-id: 3240e660adaf537f55a63ce06096e844aece8cda.1474742262.git.alistair@alistair23.me Signed-off-by: Peter Maydell --- default-configs/arm-softmmu.mak | 1 + hw/Makefile.objs | 1 + hw/adc/Makefile.objs | 1 + hw/adc/stm32f2xx_adc.c | 306 ++++++++++++++++++++++++++++++++ include/hw/adc/stm32f2xx_adc.h | 87 +++++++++ 5 files changed, 396 insertions(+) create mode 100644 hw/adc/Makefile.objs create mode 100644 hw/adc/stm32f2xx_adc.c create mode 100644 include/hw/adc/stm32f2xx_adc.h diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak index e1243602e99..3379b55f561 100644 --- a/default-configs/arm-softmmu.mak +++ b/default-configs/arm-softmmu.mak @@ -86,6 +86,7 @@ CONFIG_ZYNQ=y CONFIG_STM32F2XX_TIMER=y CONFIG_STM32F2XX_USART=y CONFIG_STM32F2XX_SYSCFG=y +CONFIG_STM32F2XX_ADC=y CONFIG_STM32F205_SOC=y CONFIG_VERSATILE_PCI=y diff --git a/hw/Makefile.objs b/hw/Makefile.objs index 4a07ed43442..0ffd2811456 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -1,5 +1,6 @@ devices-dirs-$(call land, $(CONFIG_VIRTIO),$(call land,$(CONFIG_VIRTFS),$(CONFIG_PCI))) += 9pfs/ devices-dirs-$(CONFIG_ACPI) += acpi/ +devices-dirs-$(CONFIG_SOFTMMU) += adc/ devices-dirs-$(CONFIG_SOFTMMU) += audio/ devices-dirs-$(CONFIG_SOFTMMU) += block/ devices-dirs-$(CONFIG_SOFTMMU) += bt/ diff --git a/hw/adc/Makefile.objs b/hw/adc/Makefile.objs new file mode 100644 index 00000000000..3f6dfdedaec --- /dev/null +++ b/hw/adc/Makefile.objs @@ -0,0 +1 @@ +obj-$(CONFIG_STM32F2XX_ADC) += stm32f2xx_adc.o diff --git a/hw/adc/stm32f2xx_adc.c b/hw/adc/stm32f2xx_adc.c new file mode 100644 index 00000000000..90fe9de2993 --- /dev/null +++ b/hw/adc/stm32f2xx_adc.c @@ -0,0 +1,306 @@ +/* + * STM32F2XX ADC + * + * Copyright (c) 2014 Alistair Francis + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "hw/hw.h" +#include "qapi/error.h" +#include "qemu/log.h" +#include "hw/adc/stm32f2xx_adc.h" + +#ifndef STM_ADC_ERR_DEBUG +#define STM_ADC_ERR_DEBUG 0 +#endif + +#define DB_PRINT_L(lvl, fmt, args...) do { \ + if (STM_ADC_ERR_DEBUG >= lvl) { \ + qemu_log("%s: " fmt, __func__, ## args); \ + } \ +} while (0); + +#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args) + +static void stm32f2xx_adc_reset(DeviceState *dev) +{ + STM32F2XXADCState *s = STM32F2XX_ADC(dev); + + s->adc_sr = 0x00000000; + s->adc_cr1 = 0x00000000; + s->adc_cr2 = 0x00000000; + s->adc_smpr1 = 0x00000000; + s->adc_smpr2 = 0x00000000; + s->adc_jofr[0] = 0x00000000; + s->adc_jofr[1] = 0x00000000; + s->adc_jofr[2] = 0x00000000; + s->adc_jofr[3] = 0x00000000; + s->adc_htr = 0x00000FFF; + s->adc_ltr = 0x00000000; + s->adc_sqr1 = 0x00000000; + s->adc_sqr2 = 0x00000000; + s->adc_sqr3 = 0x00000000; + s->adc_jsqr = 0x00000000; + s->adc_jdr[0] = 0x00000000; + s->adc_jdr[1] = 0x00000000; + s->adc_jdr[2] = 0x00000000; + s->adc_jdr[3] = 0x00000000; + s->adc_dr = 0x00000000; +} + +static uint32_t stm32f2xx_adc_generate_value(STM32F2XXADCState *s) +{ + /* Attempts to fake some ADC values */ + s->adc_dr = s->adc_dr + 7; + + switch ((s->adc_cr1 & ADC_CR1_RES) >> 24) { + case 0: + /* 12-bit */ + s->adc_dr &= 0xFFF; + break; + case 1: + /* 10-bit */ + s->adc_dr &= 0x3FF; + break; + case 2: + /* 8-bit */ + s->adc_dr &= 0xFF; + break; + default: + /* 6-bit */ + s->adc_dr &= 0x3F; + } + + if (s->adc_cr2 & ADC_CR2_ALIGN) { + return (s->adc_dr << 1) & 0xFFF0; + } else { + return s->adc_dr; + } +} + +static uint64_t stm32f2xx_adc_read(void *opaque, hwaddr addr, + unsigned int size) +{ + STM32F2XXADCState *s = opaque; + + DB_PRINT("Address: 0x%" HWADDR_PRIx "\n", addr); + + if (addr >= ADC_COMMON_ADDRESS) { + qemu_log_mask(LOG_UNIMP, + "%s: ADC Common Register Unsupported\n", __func__); + } + + switch (addr) { + case ADC_SR: + return s->adc_sr; + case ADC_CR1: + return s->adc_cr1; + case ADC_CR2: + return s->adc_cr2 & 0xFFFFFFF; + case ADC_SMPR1: + return s->adc_smpr1; + case ADC_SMPR2: + return s->adc_smpr2; + case ADC_JOFR1: + case ADC_JOFR2: + case ADC_JOFR3: + case ADC_JOFR4: + qemu_log_mask(LOG_UNIMP, "%s: " \ + "Injection ADC is not implemented, the registers are " \ + "included for compatibility\n", __func__); + return s->adc_jofr[(addr - ADC_JOFR1) / 4]; + case ADC_HTR: + return s->adc_htr; + case ADC_LTR: + return s->adc_ltr; + case ADC_SQR1: + return s->adc_sqr1; + case ADC_SQR2: + return s->adc_sqr2; + case ADC_SQR3: + return s->adc_sqr3; + case ADC_JSQR: + qemu_log_mask(LOG_UNIMP, "%s: " \ + "Injection ADC is not implemented, the registers are " \ + "included for compatibility\n", __func__); + return s->adc_jsqr; + case ADC_JDR1: + case ADC_JDR2: + case ADC_JDR3: + case ADC_JDR4: + qemu_log_mask(LOG_UNIMP, "%s: " \ + "Injection ADC is not implemented, the registers are " \ + "included for compatibility\n", __func__); + return s->adc_jdr[(addr - ADC_JDR1) / 4] - + s->adc_jofr[(addr - ADC_JDR1) / 4]; + case ADC_DR: + if ((s->adc_cr2 & ADC_CR2_ADON) && (s->adc_cr2 & ADC_CR2_SWSTART)) { + s->adc_cr2 ^= ADC_CR2_SWSTART; + return stm32f2xx_adc_generate_value(s); + } else { + return 0; + } + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, addr); + } + + return 0; +} + +static void stm32f2xx_adc_write(void *opaque, hwaddr addr, + uint64_t val64, unsigned int size) +{ + STM32F2XXADCState *s = opaque; + uint32_t value = (uint32_t) val64; + + DB_PRINT("Address: 0x%" HWADDR_PRIx ", Value: 0x%x\n", + addr, value); + + if (addr >= 0x100) { + qemu_log_mask(LOG_UNIMP, + "%s: ADC Common Register Unsupported\n", __func__); + } + + switch (addr) { + case ADC_SR: + s->adc_sr &= (value & 0x3F); + break; + case ADC_CR1: + s->adc_cr1 = value; + break; + case ADC_CR2: + s->adc_cr2 = value; + break; + case ADC_SMPR1: + s->adc_smpr1 = value; + break; + case ADC_SMPR2: + s->adc_smpr2 = value; + break; + case ADC_JOFR1: + case ADC_JOFR2: + case ADC_JOFR3: + case ADC_JOFR4: + s->adc_jofr[(addr - ADC_JOFR1) / 4] = (value & 0xFFF); + qemu_log_mask(LOG_UNIMP, "%s: " \ + "Injection ADC is not implemented, the registers are " \ + "included for compatibility\n", __func__); + break; + case ADC_HTR: + s->adc_htr = value; + break; + case ADC_LTR: + s->adc_ltr = value; + break; + case ADC_SQR1: + s->adc_sqr1 = value; + break; + case ADC_SQR2: + s->adc_sqr2 = value; + break; + case ADC_SQR3: + s->adc_sqr3 = value; + break; + case ADC_JSQR: + s->adc_jsqr = value; + qemu_log_mask(LOG_UNIMP, "%s: " \ + "Injection ADC is not implemented, the registers are " \ + "included for compatibility\n", __func__); + break; + case ADC_JDR1: + case ADC_JDR2: + case ADC_JDR3: + case ADC_JDR4: + s->adc_jdr[(addr - ADC_JDR1) / 4] = value; + qemu_log_mask(LOG_UNIMP, "%s: " \ + "Injection ADC is not implemented, the registers are " \ + "included for compatibility\n", __func__); + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, addr); + } +} + +static const MemoryRegionOps stm32f2xx_adc_ops = { + .read = stm32f2xx_adc_read, + .write = stm32f2xx_adc_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static const VMStateDescription vmstate_stm32f2xx_adc = { + .name = TYPE_STM32F2XX_ADC, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(adc_sr, STM32F2XXADCState), + VMSTATE_UINT32(adc_cr1, STM32F2XXADCState), + VMSTATE_UINT32(adc_cr2, STM32F2XXADCState), + VMSTATE_UINT32(adc_smpr1, STM32F2XXADCState), + VMSTATE_UINT32(adc_smpr2, STM32F2XXADCState), + VMSTATE_UINT32_ARRAY(adc_jofr, STM32F2XXADCState, 4), + VMSTATE_UINT32(adc_htr, STM32F2XXADCState), + VMSTATE_UINT32(adc_ltr, STM32F2XXADCState), + VMSTATE_UINT32(adc_sqr1, STM32F2XXADCState), + VMSTATE_UINT32(adc_sqr2, STM32F2XXADCState), + VMSTATE_UINT32(adc_sqr3, STM32F2XXADCState), + VMSTATE_UINT32(adc_jsqr, STM32F2XXADCState), + VMSTATE_UINT32_ARRAY(adc_jdr, STM32F2XXADCState, 4), + VMSTATE_UINT32(adc_dr, STM32F2XXADCState), + VMSTATE_END_OF_LIST() + } +}; + +static void stm32f2xx_adc_init(Object *obj) +{ + STM32F2XXADCState *s = STM32F2XX_ADC(obj); + + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq); + + memory_region_init_io(&s->mmio, obj, &stm32f2xx_adc_ops, s, + TYPE_STM32F2XX_ADC, 0xFF); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); +} + +static void stm32f2xx_adc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = stm32f2xx_adc_reset; + dc->vmsd = &vmstate_stm32f2xx_adc; +} + +static const TypeInfo stm32f2xx_adc_info = { + .name = TYPE_STM32F2XX_ADC, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(STM32F2XXADCState), + .instance_init = stm32f2xx_adc_init, + .class_init = stm32f2xx_adc_class_init, +}; + +static void stm32f2xx_adc_register_types(void) +{ + type_register_static(&stm32f2xx_adc_info); +} + +type_init(stm32f2xx_adc_register_types) diff --git a/include/hw/adc/stm32f2xx_adc.h b/include/hw/adc/stm32f2xx_adc.h new file mode 100644 index 00000000000..a72f734eb1e --- /dev/null +++ b/include/hw/adc/stm32f2xx_adc.h @@ -0,0 +1,87 @@ +/* + * STM32F2XX ADC + * + * Copyright (c) 2014 Alistair Francis + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef HW_STM32F2XX_ADC_H +#define HW_STM32F2XX_ADC_H + +#define ADC_SR 0x00 +#define ADC_CR1 0x04 +#define ADC_CR2 0x08 +#define ADC_SMPR1 0x0C +#define ADC_SMPR2 0x10 +#define ADC_JOFR1 0x14 +#define ADC_JOFR2 0x18 +#define ADC_JOFR3 0x1C +#define ADC_JOFR4 0x20 +#define ADC_HTR 0x24 +#define ADC_LTR 0x28 +#define ADC_SQR1 0x2C +#define ADC_SQR2 0x30 +#define ADC_SQR3 0x34 +#define ADC_JSQR 0x38 +#define ADC_JDR1 0x3C +#define ADC_JDR2 0x40 +#define ADC_JDR3 0x44 +#define ADC_JDR4 0x48 +#define ADC_DR 0x4C + +#define ADC_CR2_ADON 0x01 +#define ADC_CR2_CONT 0x02 +#define ADC_CR2_ALIGN 0x800 +#define ADC_CR2_SWSTART 0x40000000 + +#define ADC_CR1_RES 0x3000000 + +#define ADC_COMMON_ADDRESS 0x100 + +#define TYPE_STM32F2XX_ADC "stm32f2xx-adc" +#define STM32F2XX_ADC(obj) \ + OBJECT_CHECK(STM32F2XXADCState, (obj), TYPE_STM32F2XX_ADC) + +typedef struct { + /* */ + SysBusDevice parent_obj; + + /* */ + MemoryRegion mmio; + + uint32_t adc_sr; + uint32_t adc_cr1; + uint32_t adc_cr2; + uint32_t adc_smpr1; + uint32_t adc_smpr2; + uint32_t adc_jofr[4]; + uint32_t adc_htr; + uint32_t adc_ltr; + uint32_t adc_sqr1; + uint32_t adc_sqr2; + uint32_t adc_sqr3; + uint32_t adc_jsqr; + uint32_t adc_jdr[4]; + uint32_t adc_dr; + + qemu_irq irq; +} STM32F2XXADCState; + +#endif /* HW_STM32F2XX_ADC_H */ From 5ae74402d1f3221ed26936c4b9febc7e69ecdc5b Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Tue, 4 Oct 2016 13:28:07 +0100 Subject: [PATCH 480/723] STM32F2xx: Add the SPI device Add the STM32F2xx SPI device. Signed-off-by: Alistair Francis Reviewed-by: Peter Maydell Message-id: 8197811d5c94f814fa67c6a33ca2f7fd0aa97432.1474742262.git.alistair@alistair23.me Signed-off-by: Peter Maydell --- default-configs/arm-softmmu.mak | 1 + hw/ssi/Makefile.objs | 1 + hw/ssi/stm32f2xx_spi.c | 225 ++++++++++++++++++++++++++++++++ include/hw/ssi/stm32f2xx_spi.h | 72 ++++++++++ 4 files changed, 299 insertions(+) create mode 100644 hw/ssi/stm32f2xx_spi.c create mode 100644 include/hw/ssi/stm32f2xx_spi.h diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak index 3379b55f561..6de3e16a3e1 100644 --- a/default-configs/arm-softmmu.mak +++ b/default-configs/arm-softmmu.mak @@ -87,6 +87,7 @@ CONFIG_STM32F2XX_TIMER=y CONFIG_STM32F2XX_USART=y CONFIG_STM32F2XX_SYSCFG=y CONFIG_STM32F2XX_ADC=y +CONFIG_STM32F2XX_SPI=y CONFIG_STM32F205_SOC=y CONFIG_VERSATILE_PCI=y diff --git a/hw/ssi/Makefile.objs b/hw/ssi/Makefile.objs index c79a8dcd86a..487add28793 100644 --- a/hw/ssi/Makefile.objs +++ b/hw/ssi/Makefile.objs @@ -3,6 +3,7 @@ common-obj-$(CONFIG_SSI) += ssi.o common-obj-$(CONFIG_XILINX_SPI) += xilinx_spi.o common-obj-$(CONFIG_XILINX_SPIPS) += xilinx_spips.o common-obj-$(CONFIG_ASPEED_SOC) += aspeed_smc.o +common-obj-$(CONFIG_STM32F2XX_SPI) += stm32f2xx_spi.o obj-$(CONFIG_OMAP) += omap_spi.o obj-$(CONFIG_IMX) += imx_spi.o diff --git a/hw/ssi/stm32f2xx_spi.c b/hw/ssi/stm32f2xx_spi.c new file mode 100644 index 00000000000..26a1b4ddf55 --- /dev/null +++ b/hw/ssi/stm32f2xx_spi.c @@ -0,0 +1,225 @@ +/* + * STM32F405 SPI + * + * Copyright (c) 2014 Alistair Francis + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/log.h" +#include "hw/ssi/stm32f2xx_spi.h" + +#ifndef STM_SPI_ERR_DEBUG +#define STM_SPI_ERR_DEBUG 0 +#endif + +#define DB_PRINT_L(lvl, fmt, args...) do { \ + if (STM_SPI_ERR_DEBUG >= lvl) { \ + qemu_log("%s: " fmt, __func__, ## args); \ + } \ +} while (0); + +#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args) + +static void stm32f2xx_spi_reset(DeviceState *dev) +{ + STM32F2XXSPIState *s = STM32F2XX_SPI(dev); + + s->spi_cr1 = 0x00000000; + s->spi_cr2 = 0x00000000; + s->spi_sr = 0x0000000A; + s->spi_dr = 0x0000000C; + s->spi_crcpr = 0x00000007; + s->spi_rxcrcr = 0x00000000; + s->spi_txcrcr = 0x00000000; + s->spi_i2scfgr = 0x00000000; + s->spi_i2spr = 0x00000002; +} + +static void stm32f2xx_spi_transfer(STM32F2XXSPIState *s) +{ + DB_PRINT("Data to send: 0x%x\n", s->spi_dr); + + s->spi_dr = ssi_transfer(s->ssi, s->spi_dr); + s->spi_sr |= STM_SPI_SR_RXNE; + + DB_PRINT("Data received: 0x%x\n", s->spi_dr); +} + +static uint64_t stm32f2xx_spi_read(void *opaque, hwaddr addr, + unsigned int size) +{ + STM32F2XXSPIState *s = opaque; + + DB_PRINT("Address: 0x%" HWADDR_PRIx "\n", addr); + + switch (addr) { + case STM_SPI_CR1: + return s->spi_cr1; + case STM_SPI_CR2: + qemu_log_mask(LOG_UNIMP, "%s: Interrupts and DMA are not implemented\n", + __func__); + return s->spi_cr2; + case STM_SPI_SR: + return s->spi_sr; + case STM_SPI_DR: + stm32f2xx_spi_transfer(s); + s->spi_sr &= ~STM_SPI_SR_RXNE; + return s->spi_dr; + case STM_SPI_CRCPR: + qemu_log_mask(LOG_UNIMP, "%s: CRC is not implemented, the registers " \ + "are included for compatibility\n", __func__); + return s->spi_crcpr; + case STM_SPI_RXCRCR: + qemu_log_mask(LOG_UNIMP, "%s: CRC is not implemented, the registers " \ + "are included for compatibility\n", __func__); + return s->spi_rxcrcr; + case STM_SPI_TXCRCR: + qemu_log_mask(LOG_UNIMP, "%s: CRC is not implemented, the registers " \ + "are included for compatibility\n", __func__); + return s->spi_txcrcr; + case STM_SPI_I2SCFGR: + qemu_log_mask(LOG_UNIMP, "%s: I2S is not implemented, the registers " \ + "are included for compatibility\n", __func__); + return s->spi_i2scfgr; + case STM_SPI_I2SPR: + qemu_log_mask(LOG_UNIMP, "%s: I2S is not implemented, the registers " \ + "are included for compatibility\n", __func__); + return s->spi_i2spr; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", + __func__, addr); + } + + return 0; +} + +static void stm32f2xx_spi_write(void *opaque, hwaddr addr, + uint64_t val64, unsigned int size) +{ + STM32F2XXSPIState *s = opaque; + uint32_t value = val64; + + DB_PRINT("Address: 0x%" HWADDR_PRIx ", Value: 0x%x\n", addr, value); + + switch (addr) { + case STM_SPI_CR1: + s->spi_cr1 = value; + return; + case STM_SPI_CR2: + qemu_log_mask(LOG_UNIMP, "%s: " \ + "Interrupts and DMA are not implemented\n", __func__); + s->spi_cr2 = value; + return; + case STM_SPI_SR: + /* Read only register, except for clearing the CRCERR bit, which + * is not supported + */ + return; + case STM_SPI_DR: + s->spi_dr = value; + stm32f2xx_spi_transfer(s); + return; + case STM_SPI_CRCPR: + qemu_log_mask(LOG_UNIMP, "%s: CRC is not implemented\n", __func__); + return; + case STM_SPI_RXCRCR: + qemu_log_mask(LOG_GUEST_ERROR, "%s: Read only register: " \ + "0x%" HWADDR_PRIx "\n", __func__, addr); + return; + case STM_SPI_TXCRCR: + qemu_log_mask(LOG_GUEST_ERROR, "%s: Read only register: " \ + "0x%" HWADDR_PRIx "\n", __func__, addr); + return; + case STM_SPI_I2SCFGR: + qemu_log_mask(LOG_UNIMP, "%s: " \ + "I2S is not implemented\n", __func__); + return; + case STM_SPI_I2SPR: + qemu_log_mask(LOG_UNIMP, "%s: " \ + "I2S is not implemented\n", __func__); + return; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, addr); + } +} + +static const MemoryRegionOps stm32f2xx_spi_ops = { + .read = stm32f2xx_spi_read, + .write = stm32f2xx_spi_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static const VMStateDescription vmstate_stm32f2xx_spi = { + .name = TYPE_STM32F2XX_SPI, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(spi_cr1, STM32F2XXSPIState), + VMSTATE_UINT32(spi_cr2, STM32F2XXSPIState), + VMSTATE_UINT32(spi_sr, STM32F2XXSPIState), + VMSTATE_UINT32(spi_dr, STM32F2XXSPIState), + VMSTATE_UINT32(spi_crcpr, STM32F2XXSPIState), + VMSTATE_UINT32(spi_rxcrcr, STM32F2XXSPIState), + VMSTATE_UINT32(spi_txcrcr, STM32F2XXSPIState), + VMSTATE_UINT32(spi_i2scfgr, STM32F2XXSPIState), + VMSTATE_UINT32(spi_i2spr, STM32F2XXSPIState), + VMSTATE_END_OF_LIST() + } +}; + +static void stm32f2xx_spi_init(Object *obj) +{ + STM32F2XXSPIState *s = STM32F2XX_SPI(obj); + DeviceState *dev = DEVICE(obj); + + memory_region_init_io(&s->mmio, obj, &stm32f2xx_spi_ops, s, + TYPE_STM32F2XX_SPI, 0x400); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); + + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq); + + s->ssi = ssi_create_bus(dev, "ssi"); +} + +static void stm32f2xx_spi_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = stm32f2xx_spi_reset; + dc->vmsd = &vmstate_stm32f2xx_spi; +} + +static const TypeInfo stm32f2xx_spi_info = { + .name = TYPE_STM32F2XX_SPI, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(STM32F2XXSPIState), + .instance_init = stm32f2xx_spi_init, + .class_init = stm32f2xx_spi_class_init, +}; + +static void stm32f2xx_spi_register_types(void) +{ + type_register_static(&stm32f2xx_spi_info); +} + +type_init(stm32f2xx_spi_register_types) diff --git a/include/hw/ssi/stm32f2xx_spi.h b/include/hw/ssi/stm32f2xx_spi.h new file mode 100644 index 00000000000..1cd73e4cd41 --- /dev/null +++ b/include/hw/ssi/stm32f2xx_spi.h @@ -0,0 +1,72 @@ +/* + * STM32F2XX SPI + * + * Copyright (c) 2014 Alistair Francis + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef HW_STM32F2XX_SPI_H +#define HW_STM32F2XX_SPI_H + +#include "hw/sysbus.h" +#include "hw/hw.h" +#include "hw/ssi/ssi.h" + +#define STM_SPI_CR1 0x00 +#define STM_SPI_CR2 0x04 +#define STM_SPI_SR 0x08 +#define STM_SPI_DR 0x0C +#define STM_SPI_CRCPR 0x10 +#define STM_SPI_RXCRCR 0x14 +#define STM_SPI_TXCRCR 0x18 +#define STM_SPI_I2SCFGR 0x1C +#define STM_SPI_I2SPR 0x20 + +#define STM_SPI_CR1_SPE (1 << 6) +#define STM_SPI_CR1_MSTR (1 << 2) + +#define STM_SPI_SR_RXNE 1 + +#define TYPE_STM32F2XX_SPI "stm32f2xx-spi" +#define STM32F2XX_SPI(obj) \ + OBJECT_CHECK(STM32F2XXSPIState, (obj), TYPE_STM32F2XX_SPI) + +typedef struct { + /* */ + SysBusDevice parent_obj; + + /* */ + MemoryRegion mmio; + + uint32_t spi_cr1; + uint32_t spi_cr2; + uint32_t spi_sr; + uint32_t spi_dr; + uint32_t spi_crcpr; + uint32_t spi_rxcrcr; + uint32_t spi_txcrcr; + uint32_t spi_i2scfgr; + uint32_t spi_i2spr; + + qemu_irq irq; + SSIBus *ssi; +} STM32F2XXSPIState; + +#endif /* HW_STM32F2XX_SPI_H */ From 1b2556776531ba3f492f5ce9f6ae769f3b4e7a82 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Tue, 4 Oct 2016 13:28:07 +0100 Subject: [PATCH 481/723] irq: Add a new irq device that allows the ORing of lines Signed-off-by: Alistair Francis Message-id: 52e5d361e3b5a0ea8554aca73ee65ae2b586112e.1474742262.git.alistair@alistair23.me Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/core/Makefile.objs | 1 + hw/core/or-irq.c | 107 ++++++++++++++++++++++++++++++++++++++++++ include/hw/or-irq.h | 44 +++++++++++++++++ 3 files changed, 152 insertions(+) create mode 100644 hw/core/or-irq.c create mode 100644 include/hw/or-irq.h diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs index cfd48403974..b47241bb2f8 100644 --- a/hw/core/Makefile.objs +++ b/hw/core/Makefile.objs @@ -16,4 +16,5 @@ common-obj-$(CONFIG_SOFTMMU) += null-machine.o common-obj-$(CONFIG_SOFTMMU) += loader.o common-obj-$(CONFIG_SOFTMMU) += qdev-properties-system.o common-obj-$(CONFIG_SOFTMMU) += register.o +common-obj-$(CONFIG_SOFTMMU) += or-irq.o common-obj-$(CONFIG_PLATFORM_BUS) += platform-bus.o diff --git a/hw/core/or-irq.c b/hw/core/or-irq.c new file mode 100644 index 00000000000..1ac090d1a4a --- /dev/null +++ b/hw/core/or-irq.c @@ -0,0 +1,107 @@ +/* + * QEMU IRQ/GPIO common code. + * + * Copyright (c) 2016 Alistair Francis . + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "hw/or-irq.h" + +static void or_irq_handler(void *opaque, int n, int level) +{ + qemu_or_irq *s = OR_IRQ(opaque); + int or_level = 0; + int i; + + s->levels[n] = level; + + for (i = 0; i < s->num_lines; i++) { + or_level |= s->levels[i]; + } + + qemu_set_irq(s->out_irq, or_level); +} + +static void or_irq_reset(DeviceState *dev) +{ + qemu_or_irq *s = OR_IRQ(dev); + int i; + + for (i = 0; i < MAX_OR_LINES; i++) { + s->levels[i] = false; + } +} + +static void or_irq_realize(DeviceState *dev, Error **errp) +{ + qemu_or_irq *s = OR_IRQ(dev); + + assert(s->num_lines < MAX_OR_LINES); + + qdev_init_gpio_in(dev, or_irq_handler, s->num_lines); +} + +static void or_irq_init(Object *obj) +{ + qemu_or_irq *s = OR_IRQ(obj); + + qdev_init_gpio_out(DEVICE(obj), &s->out_irq, 1); +} + +static const VMStateDescription vmstate_or_irq = { + .name = TYPE_OR_IRQ, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_BOOL_ARRAY(levels, qemu_or_irq, MAX_OR_LINES), + VMSTATE_END_OF_LIST(), + } +}; + +static Property or_irq_properties[] = { + DEFINE_PROP_UINT16("num-lines", qemu_or_irq, num_lines, 1), + DEFINE_PROP_END_OF_LIST(), +}; + +static void or_irq_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = or_irq_reset; + dc->props = or_irq_properties; + dc->realize = or_irq_realize; + dc->vmsd = &vmstate_or_irq; +} + +static const TypeInfo or_irq_type_info = { + .name = TYPE_OR_IRQ, + .parent = TYPE_DEVICE, + .instance_size = sizeof(qemu_or_irq), + .instance_init = or_irq_init, + .class_init = or_irq_class_init, +}; + +static void or_irq_register_types(void) +{ + type_register_static(&or_irq_type_info); +} + +type_init(or_irq_register_types) diff --git a/include/hw/or-irq.h b/include/hw/or-irq.h new file mode 100644 index 00000000000..d400a8120b7 --- /dev/null +++ b/include/hw/or-irq.h @@ -0,0 +1,44 @@ +/* + * QEMU IRQ/GPIO common code. + * + * Copyright (c) 2016 Alistair Francis . + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "hw/irq.h" +#include "hw/sysbus.h" +#include "qom/object.h" + +#define TYPE_OR_IRQ "or-irq" + +#define MAX_OR_LINES 16 + +typedef struct OrIRQState qemu_or_irq; + +#define OR_IRQ(obj) OBJECT_CHECK(qemu_or_irq, (obj), TYPE_OR_IRQ) + +struct OrIRQState { + DeviceState parent_obj; + + qemu_irq out_irq; + qemu_irq *in_irqs; + bool levels[MAX_OR_LINES]; + uint16_t num_lines; +}; From b63041c8f6b1ad2332c6c8f458f26b34325613bf Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Tue, 4 Oct 2016 13:28:07 +0100 Subject: [PATCH 482/723] STM32F205: Connect the ADC devices Connect the ADC devices to the STM32F205 SoC. Signed-off-by: Alistair Francis Message-id: 6214eda399da7b47014f6f895be25323d52dbc9e.1474742262.git.alistair@alistair23.me Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/stm32f205_soc.c | 35 ++++++++++++++++++++++++++++++++++ include/hw/arm/stm32f205_soc.h | 6 ++++++ 2 files changed, 41 insertions(+) diff --git a/hw/arm/stm32f205_soc.c b/hw/arm/stm32f205_soc.c index 5b6fa3bc352..2feddc3d078 100644 --- a/hw/arm/stm32f205_soc.c +++ b/hw/arm/stm32f205_soc.c @@ -34,9 +34,12 @@ static const uint32_t timer_addr[STM_NUM_TIMERS] = { 0x40000000, 0x40000400, 0x40000800, 0x40000C00 }; static const uint32_t usart_addr[STM_NUM_USARTS] = { 0x40011000, 0x40004400, 0x40004800, 0x40004C00, 0x40005000, 0x40011400 }; +static const uint32_t adc_addr[STM_NUM_ADCS] = { 0x40012000, 0x40012100, + 0x40012200 }; static const int timer_irq[STM_NUM_TIMERS] = {28, 29, 30, 50}; static const int usart_irq[STM_NUM_USARTS] = {37, 38, 39, 52, 53, 71}; +#define ADC_IRQ 18 static void stm32f205_soc_initfn(Object *obj) { @@ -57,6 +60,14 @@ static void stm32f205_soc_initfn(Object *obj) TYPE_STM32F2XX_TIMER); qdev_set_parent_bus(DEVICE(&s->timer[i]), sysbus_get_default()); } + + s->adc_irqs = OR_IRQ(object_new(TYPE_OR_IRQ)); + + for (i = 0; i < STM_NUM_ADCS; i++) { + object_initialize(&s->adc[i], sizeof(s->adc[i]), + TYPE_STM32F2XX_ADC); + qdev_set_parent_bus(DEVICE(&s->adc[i]), sysbus_get_default()); + } } static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp) @@ -132,6 +143,30 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp) sysbus_mmio_map(busdev, 0, timer_addr[i]); sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(nvic, timer_irq[i])); } + + /* ADC 1 to 3 */ + object_property_set_int(OBJECT(s->adc_irqs), STM_NUM_ADCS, + "num-lines", &err); + object_property_set_bool(OBJECT(s->adc_irqs), true, "realized", &err); + if (err != NULL) { + error_propagate(errp, err); + return; + } + qdev_connect_gpio_out(DEVICE(s->adc_irqs), 0, + qdev_get_gpio_in(nvic, ADC_IRQ)); + + for (i = 0; i < STM_NUM_ADCS; i++) { + dev = DEVICE(&(s->adc[i])); + object_property_set_bool(OBJECT(&s->adc[i]), true, "realized", &err); + if (err != NULL) { + error_propagate(errp, err); + return; + } + busdev = SYS_BUS_DEVICE(dev); + sysbus_mmio_map(busdev, 0, adc_addr[i]); + sysbus_connect_irq(busdev, 0, + qdev_get_gpio_in(DEVICE(s->adc_irqs), i)); + } } static Property stm32f205_soc_properties[] = { diff --git a/include/hw/arm/stm32f205_soc.h b/include/hw/arm/stm32f205_soc.h index 779b5da2dce..1adf8246cde 100644 --- a/include/hw/arm/stm32f205_soc.h +++ b/include/hw/arm/stm32f205_soc.h @@ -28,6 +28,8 @@ #include "hw/misc/stm32f2xx_syscfg.h" #include "hw/timer/stm32f2xx_timer.h" #include "hw/char/stm32f2xx_usart.h" +#include "hw/adc/stm32f2xx_adc.h" +#include "hw/or-irq.h" #define TYPE_STM32F205_SOC "stm32f205-soc" #define STM32F205_SOC(obj) \ @@ -35,6 +37,7 @@ #define STM_NUM_USARTS 6 #define STM_NUM_TIMERS 4 +#define STM_NUM_ADCS 3 #define FLASH_BASE_ADDRESS 0x08000000 #define FLASH_SIZE (1024 * 1024) @@ -52,6 +55,9 @@ typedef struct STM32F205State { STM32F2XXSyscfgState syscfg; STM32F2XXUsartState usart[STM_NUM_USARTS]; STM32F2XXTimerState timer[STM_NUM_TIMERS]; + STM32F2XXADCState adc[STM_NUM_ADCS]; + + qemu_or_irq *adc_irqs; } STM32F205State; #endif From 540a8f34b4f018570a0bbd86975d41dee0d9510c Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Tue, 4 Oct 2016 13:28:07 +0100 Subject: [PATCH 483/723] STM32F205: Connect the SPI devices Connect the SPI devices to the STM32F205 SoC. Signed-off-by: Alistair Francis Reviewed-by: Peter Crosthwaite Message-id: d05849120420f8db0d9aa053bd23134c33cd9180.1474742262.git.alistair@alistair23.me Signed-off-by: Peter Maydell --- hw/arm/stm32f205_soc.c | 22 ++++++++++++++++++++++ include/hw/arm/stm32f205_soc.h | 3 +++ 2 files changed, 25 insertions(+) diff --git a/hw/arm/stm32f205_soc.c b/hw/arm/stm32f205_soc.c index 2feddc3d078..38425bda6c7 100644 --- a/hw/arm/stm32f205_soc.c +++ b/hw/arm/stm32f205_soc.c @@ -36,10 +36,13 @@ static const uint32_t usart_addr[STM_NUM_USARTS] = { 0x40011000, 0x40004400, 0x40004800, 0x40004C00, 0x40005000, 0x40011400 }; static const uint32_t adc_addr[STM_NUM_ADCS] = { 0x40012000, 0x40012100, 0x40012200 }; +static const uint32_t spi_addr[STM_NUM_SPIS] = { 0x40013000, 0x40003800, + 0x40003C00 }; static const int timer_irq[STM_NUM_TIMERS] = {28, 29, 30, 50}; static const int usart_irq[STM_NUM_USARTS] = {37, 38, 39, 52, 53, 71}; #define ADC_IRQ 18 +static const int spi_irq[STM_NUM_SPIS] = {35, 36, 51}; static void stm32f205_soc_initfn(Object *obj) { @@ -68,6 +71,12 @@ static void stm32f205_soc_initfn(Object *obj) TYPE_STM32F2XX_ADC); qdev_set_parent_bus(DEVICE(&s->adc[i]), sysbus_get_default()); } + + for (i = 0; i < STM_NUM_SPIS; i++) { + object_initialize(&s->spi[i], sizeof(s->spi[i]), + TYPE_STM32F2XX_SPI); + qdev_set_parent_bus(DEVICE(&s->spi[i]), sysbus_get_default()); + } } static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp) @@ -167,6 +176,19 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp) sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(DEVICE(s->adc_irqs), i)); } + + /* SPI 1 and 2 */ + for (i = 0; i < STM_NUM_SPIS; i++) { + dev = DEVICE(&(s->spi[i])); + object_property_set_bool(OBJECT(&s->spi[i]), true, "realized", &err); + if (err != NULL) { + error_propagate(errp, err); + return; + } + busdev = SYS_BUS_DEVICE(dev); + sysbus_mmio_map(busdev, 0, spi_addr[i]); + sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(nvic, spi_irq[i])); + } } static Property stm32f205_soc_properties[] = { diff --git a/include/hw/arm/stm32f205_soc.h b/include/hw/arm/stm32f205_soc.h index 1adf8246cde..133214195b9 100644 --- a/include/hw/arm/stm32f205_soc.h +++ b/include/hw/arm/stm32f205_soc.h @@ -30,6 +30,7 @@ #include "hw/char/stm32f2xx_usart.h" #include "hw/adc/stm32f2xx_adc.h" #include "hw/or-irq.h" +#include "hw/ssi/stm32f2xx_spi.h" #define TYPE_STM32F205_SOC "stm32f205-soc" #define STM32F205_SOC(obj) \ @@ -38,6 +39,7 @@ #define STM_NUM_USARTS 6 #define STM_NUM_TIMERS 4 #define STM_NUM_ADCS 3 +#define STM_NUM_SPIS 3 #define FLASH_BASE_ADDRESS 0x08000000 #define FLASH_SIZE (1024 * 1024) @@ -56,6 +58,7 @@ typedef struct STM32F205State { STM32F2XXUsartState usart[STM_NUM_USARTS]; STM32F2XXTimerState timer[STM_NUM_TIMERS]; STM32F2XXADCState adc[STM_NUM_ADCS]; + STM32F2XXSPIState spi[STM_NUM_SPIS]; qemu_or_irq *adc_irqs; } STM32F205State; From a1f8193bb41283923710f23faf436b6b0a7bb3f2 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Tue, 4 Oct 2016 13:28:07 +0100 Subject: [PATCH 484/723] MAINTAINERS: Add Alistair to the maintainers list Add Alistair Francis as the maintainer for the Netduino 2 and SMM32F205 SoC. Signed-off-by: Alistair Francis Reviewed-by: Peter Crosthwaite Message-id: 5a46ccf398b050a41cc3b3d0e94bcff4ce2d85e0.1474742262.git.alistair@alistair23.me Signed-off-by: Peter Maydell --- MAINTAINERS | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 63cf21fdb11..88fd6745fc1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -479,6 +479,21 @@ S: Maintained F: hw/arm/virt-acpi-build.c F: include/hw/arm/virt-acpi-build.h +STM32F205 +M: Alistair Francis +S: Maintained +F: hw/arm/stm32f205_soc.c +F: hw/misc/stm32f2xx_syscfg.c +F: hw/char/stm32f2xx_usart.c +F: hw/timer/stm32f2xx_timer.c +F: hw/adc/* +F: hw/ssi/stm32f2xx_spi.c + +Netduino 2 +M: Alistair Francis +S: Maintained +F: hw/arm/netduino2.c + CRIS Machines ------------- Axis Dev88 From 8cb2d2db50eed3e708b9504891735e78f00e6e3d Mon Sep 17 00:00:00 2001 From: Vijay Kumar B Date: Tue, 4 Oct 2016 13:28:07 +0100 Subject: [PATCH 485/723] mainstone: Fix incorrect key mapping for Enter key. According to the manual the (5, 5) corresponds to backspace key, and not Enter key. Linux kernel maps (5, 4) to the enter key. Fixing it up to match the mapping in the Linux kernel. Signed-off-by: Vijay Kumar B. Reviewed-by: Deepak S. Message-id: 1475063033-8176-2-git-send-email-vijaykumar@zilogic.com Signed-off-by: Peter Maydell --- hw/arm/mainstone.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/arm/mainstone.c b/hw/arm/mainstone.c index 454acc5d2be..e81b8783f9c 100644 --- a/hw/arm/mainstone.c +++ b/hw/arm/mainstone.c @@ -88,7 +88,7 @@ static const struct keymap map[0xE0] = { * Matrix position {5,4} and other keys are missing here. * TODO: Compare with Linux code and test real hardware. */ - [0x1c] = {5,5}, /* enter (TODO: might be wrong) */ + [0x1c] = {5,4}, /* enter */ [0xc8] = {6,0}, /* up */ [0xd0] = {6,1}, /* down */ [0xcb] = {6,2}, /* left */ From 0c74e95bf87f9fb2187e7b1baa427a7b74d69ccd Mon Sep 17 00:00:00 2001 From: Vijay Kumar B Date: Tue, 4 Oct 2016 13:28:08 +0100 Subject: [PATCH 486/723] mainstone: Add mapping for dot, slash and backspace. Add missed out mappings. These mappings are from the "Intel PXA27x Processor Developer's Kit User Guide". Signed-off-by: Vijay Kumar B. Reviewed-by: Deepak S. Message-id: 1475063033-8176-3-git-send-email-vijaykumar@zilogic.com Signed-off-by: Peter Maydell --- hw/arm/mainstone.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/arm/mainstone.c b/hw/arm/mainstone.c index e81b8783f9c..f962236cf4c 100644 --- a/hw/arm/mainstone.c +++ b/hw/arm/mainstone.c @@ -73,8 +73,10 @@ static const struct keymap map[0xE0] = { [0x2f] = {3,3}, /* v */ [0x11] = {3,4}, /* w */ [0x2d] = {3,5}, /* x */ + [0x34] = {4,0}, /* . */ [0x15] = {4,2}, /* y */ [0x2c] = {4,3}, /* z */ + [0x35] = {4,4}, /* / */ [0xc7] = {5,0}, /* Home */ [0x2a] = {5,1}, /* shift */ /* @@ -89,6 +91,7 @@ static const struct keymap map[0xE0] = { * TODO: Compare with Linux code and test real hardware. */ [0x1c] = {5,4}, /* enter */ + [0x0e] = {5,5}, /* backspace */ [0xc8] = {6,0}, /* up */ [0xd0] = {6,1}, /* down */ [0xcb] = {6,2}, /* left */ From e9d9ee234f852026d58b275d89a0350cb9ddbc01 Mon Sep 17 00:00:00 2001 From: Jakub Jermar Date: Tue, 4 Oct 2016 13:28:08 +0100 Subject: [PATCH 487/723] hw/arm: Fix Integrator/CM initialization Initialization of a class instance cannot depend on its own properties as these are not yet set. Move parts of integratorcm_init() that depend on the "memsz" property to the newly added integratorcm_realize(). This fixes: https://bugs.launchpad.net/qemu/+bug/1624726 Signed-off-by: Jakub Jermar Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/integratorcp.c | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c index 96dc1500256..039812a3fd8 100644 --- a/hw/arm/integratorcp.c +++ b/hw/arm/integratorcp.c @@ -252,6 +252,26 @@ static void integratorcm_init(Object *obj) /* ??? What should the high bits of this value be? */ s->cm_auxosc = 0x0007feff; s->cm_sdram = 0x00011122; + memcpy(integrator_spd + 73, "QEMU-MEMORY", 11); + s->cm_init = 0x00000112; + s->cm_refcnt_offset = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24, + 1000); + memory_region_init_ram(&s->flash, obj, "integrator.flash", 0x100000, + &error_fatal); + vmstate_register_ram_global(&s->flash); + + memory_region_init_io(&s->iomem, obj, &integratorcm_ops, s, + "integratorcm", 0x00800000); + sysbus_init_mmio(dev, &s->iomem); + + integratorcm_do_remap(s); + /* ??? Save/restore. */ +} + +static void integratorcm_realize(DeviceState *d, Error **errp) +{ + IntegratorCMState *s = INTEGRATOR_CM(d); + if (s->memsz >= 256) { integrator_spd[31] = 64; s->cm_sdram |= 0x10; @@ -267,20 +287,6 @@ static void integratorcm_init(Object *obj) } else { integrator_spd[31] = 2; } - memcpy(integrator_spd + 73, "QEMU-MEMORY", 11); - s->cm_init = 0x00000112; - s->cm_refcnt_offset = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24, - 1000); - memory_region_init_ram(&s->flash, obj, "integrator.flash", 0x100000, - &error_fatal); - vmstate_register_ram_global(&s->flash); - - memory_region_init_io(&s->iomem, obj, &integratorcm_ops, s, - "integratorcm", 0x00800000); - sysbus_init_mmio(dev, &s->iomem); - - integratorcm_do_remap(s); - /* ??? Save/restore. */ } /* Integrator/CP hardware emulation. */ @@ -633,6 +639,7 @@ static void core_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); dc->props = core_properties; + dc->realize = integratorcm_realize; } static const TypeInfo core_info = { From a321bb51fa208a0a3b421ff9944558b936cc1e5a Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Tue, 4 Oct 2016 13:28:08 +0100 Subject: [PATCH 488/723] vmstateify tsc2005 I've converted the fields in it's main data structure to fixed size types in ways that look sane. Signed-off-by: Dr. David Alan Gilbert Message-id: 1474977735-10156-2-git-send-email-dgilbert@redhat.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/input/tsc2005.c | 190 ++++++++++++++++++--------------------------- 1 file changed, 75 insertions(+), 115 deletions(-) diff --git a/hw/input/tsc2005.c b/hw/input/tsc2005.c index 9b359aaec0a..eb5320af409 100644 --- a/hw/input/tsc2005.c +++ b/hw/input/tsc2005.c @@ -31,30 +31,31 @@ typedef struct { QEMUTimer *timer; uint16_t model; - int x, y; - int pressure; + int32_t x, y; + bool pressure; - int state, reg, irq, command; + uint8_t reg, state; + bool irq, command; uint16_t data, dav; - int busy; - int enabled; - int host_mode; - int function; - int nextfunction; - int precision; - int nextprecision; - int filter; - int pin_func; - int timing[2]; - int noise; - int reset; - int pdst; - int pnd0; + bool busy; + bool enabled; + bool host_mode; + int8_t function; + int8_t nextfunction; + bool precision; + bool nextprecision; + uint16_t filter; + uint8_t pin_func; + uint16_t timing[2]; + uint8_t noise; + bool reset; + bool pdst; + bool pnd0; uint16_t temp_thr[2]; uint16_t aux_thr[2]; - int tr[8]; + int32_t tr[8]; } TSC2005State; enum { @@ -149,7 +150,7 @@ static uint16_t tsc2005_read(TSC2005State *s, int reg) ret = s->dav | (s->reset << 7) | (s->pdst << 2) | 0x0; s->dav &= ~(mode_regs[TSC_MODE_X_TEST] | mode_regs[TSC_MODE_Y_TEST] | mode_regs[TSC_MODE_TS_TEST]); - s->reset = 1; + s->reset = true; return ret; case 0x8: /* AUX high treshold */ @@ -196,14 +197,14 @@ static void tsc2005_write(TSC2005State *s, int reg, uint16_t data) break; case 0xc: /* CFR0 */ - s->host_mode = data >> 15; + s->host_mode = (data >> 15) != 0; if (s->enabled != !(data & 0x4000)) { s->enabled = !(data & 0x4000); fprintf(stderr, "%s: touchscreen sense %sabled\n", __FUNCTION__, s->enabled ? "en" : "dis"); if (s->busy && !s->enabled) timer_del(s->timer); - s->busy &= s->enabled; + s->busy = s->busy && s->enabled; } s->nextprecision = (data >> 13) & 1; s->timing[0] = data & 0x1fff; @@ -229,7 +230,7 @@ static void tsc2005_write(TSC2005State *s, int reg, uint16_t data) static void tsc2005_pin_update(TSC2005State *s) { int64_t expires; - int pin_state; + bool pin_state; switch (s->pin_func) { case 0: @@ -253,7 +254,7 @@ static void tsc2005_pin_update(TSC2005State *s) case TSC_MODE_XYZ_SCAN: case TSC_MODE_XY_SCAN: if (!s->host_mode && s->dav) - s->enabled = 0; + s->enabled = false; if (!s->pressure) return; /* Fall through */ @@ -273,7 +274,7 @@ static void tsc2005_pin_update(TSC2005State *s) case TSC_MODE_Y_TEST: case TSC_MODE_TS_TEST: if (s->dav) - s->enabled = 0; + s->enabled = false; break; case TSC_MODE_RESERVED: @@ -287,7 +288,7 @@ static void tsc2005_pin_update(TSC2005State *s) if (!s->enabled || s->busy) return; - s->busy = 1; + s->busy = true; s->precision = s->nextprecision; s->function = s->nextfunction; s->pdst = !s->pnd0; /* Synchronised on internal clock */ @@ -300,17 +301,17 @@ static void tsc2005_reset(TSC2005State *s) { s->state = 0; s->pin_func = 0; - s->enabled = 0; - s->busy = 0; - s->nextprecision = 0; + s->enabled = false; + s->busy = false; + s->nextprecision = false; s->nextfunction = 0; s->timing[0] = 0; s->timing[1] = 0; - s->irq = 0; + s->irq = false; s->dav = 0; - s->reset = 0; - s->pdst = 1; - s->pnd0 = 0; + s->reset = false; + s->pdst = true; + s->pnd0 = false; s->function = -1; s->temp_thr[0] = 0x000; s->temp_thr[1] = 0xfff; @@ -340,7 +341,7 @@ static uint8_t tsc2005_txrx_word(void *opaque, uint8_t value) __FUNCTION__, s->enabled ? "en" : "dis"); if (s->busy && !s->enabled) timer_del(s->timer); - s->busy &= s->enabled; + s->busy = s->busy && s->enabled; } tsc2005_pin_update(s); } @@ -407,7 +408,7 @@ static void tsc2005_timer_tick(void *opaque) if (!s->busy) return; - s->busy = 0; + s->busy = false; s->dav |= mode_regs[s->function]; s->function = -1; tsc2005_pin_update(s); @@ -434,86 +435,9 @@ static void tsc2005_touchscreen_event(void *opaque, tsc2005_pin_update(s); } -static void tsc2005_save(QEMUFile *f, void *opaque) +static int tsc2005_post_load(void *opaque, int version_id) { TSC2005State *s = (TSC2005State *) opaque; - int i; - - qemu_put_be16(f, s->x); - qemu_put_be16(f, s->y); - qemu_put_byte(f, s->pressure); - - qemu_put_byte(f, s->state); - qemu_put_byte(f, s->reg); - qemu_put_byte(f, s->command); - - qemu_put_byte(f, s->irq); - qemu_put_be16s(f, &s->dav); - qemu_put_be16s(f, &s->data); - - timer_put(f, s->timer); - qemu_put_byte(f, s->enabled); - qemu_put_byte(f, s->host_mode); - qemu_put_byte(f, s->function); - qemu_put_byte(f, s->nextfunction); - qemu_put_byte(f, s->precision); - qemu_put_byte(f, s->nextprecision); - qemu_put_be16(f, s->filter); - qemu_put_byte(f, s->pin_func); - qemu_put_be16(f, s->timing[0]); - qemu_put_be16(f, s->timing[1]); - qemu_put_be16s(f, &s->temp_thr[0]); - qemu_put_be16s(f, &s->temp_thr[1]); - qemu_put_be16s(f, &s->aux_thr[0]); - qemu_put_be16s(f, &s->aux_thr[1]); - qemu_put_be32(f, s->noise); - qemu_put_byte(f, s->reset); - qemu_put_byte(f, s->pdst); - qemu_put_byte(f, s->pnd0); - - for (i = 0; i < 8; i ++) - qemu_put_be32(f, s->tr[i]); -} - -static int tsc2005_load(QEMUFile *f, void *opaque, int version_id) -{ - TSC2005State *s = (TSC2005State *) opaque; - int i; - - s->x = qemu_get_be16(f); - s->y = qemu_get_be16(f); - s->pressure = qemu_get_byte(f); - - s->state = qemu_get_byte(f); - s->reg = qemu_get_byte(f); - s->command = qemu_get_byte(f); - - s->irq = qemu_get_byte(f); - qemu_get_be16s(f, &s->dav); - qemu_get_be16s(f, &s->data); - - timer_get(f, s->timer); - s->enabled = qemu_get_byte(f); - s->host_mode = qemu_get_byte(f); - s->function = qemu_get_byte(f); - s->nextfunction = qemu_get_byte(f); - s->precision = qemu_get_byte(f); - s->nextprecision = qemu_get_byte(f); - s->filter = qemu_get_be16(f); - s->pin_func = qemu_get_byte(f); - s->timing[0] = qemu_get_be16(f); - s->timing[1] = qemu_get_be16(f); - qemu_get_be16s(f, &s->temp_thr[0]); - qemu_get_be16s(f, &s->temp_thr[1]); - qemu_get_be16s(f, &s->aux_thr[0]); - qemu_get_be16s(f, &s->aux_thr[1]); - s->noise = qemu_get_be32(f); - s->reset = qemu_get_byte(f); - s->pdst = qemu_get_byte(f); - s->pnd0 = qemu_get_byte(f); - - for (i = 0; i < 8; i ++) - s->tr[i] = qemu_get_be32(f); s->busy = timer_pending(s->timer); tsc2005_pin_update(s); @@ -521,6 +445,42 @@ static int tsc2005_load(QEMUFile *f, void *opaque, int version_id) return 0; } +static const VMStateDescription vmstate_tsc2005 = { + .name = "tsc2005", + .version_id = 2, + .minimum_version_id = 2, + .post_load = tsc2005_post_load, + .fields = (VMStateField []) { + VMSTATE_BOOL(pressure, TSC2005State), + VMSTATE_BOOL(irq, TSC2005State), + VMSTATE_BOOL(command, TSC2005State), + VMSTATE_BOOL(enabled, TSC2005State), + VMSTATE_BOOL(host_mode, TSC2005State), + VMSTATE_BOOL(reset, TSC2005State), + VMSTATE_BOOL(pdst, TSC2005State), + VMSTATE_BOOL(pnd0, TSC2005State), + VMSTATE_BOOL(precision, TSC2005State), + VMSTATE_BOOL(nextprecision, TSC2005State), + VMSTATE_UINT8(reg, TSC2005State), + VMSTATE_UINT8(state, TSC2005State), + VMSTATE_UINT16(data, TSC2005State), + VMSTATE_UINT16(dav, TSC2005State), + VMSTATE_UINT16(filter, TSC2005State), + VMSTATE_INT8(nextfunction, TSC2005State), + VMSTATE_INT8(function, TSC2005State), + VMSTATE_INT32(x, TSC2005State), + VMSTATE_INT32(y, TSC2005State), + VMSTATE_TIMER_PTR(timer, TSC2005State), + VMSTATE_UINT8(pin_func, TSC2005State), + VMSTATE_UINT16_ARRAY(timing, TSC2005State, 2), + VMSTATE_UINT8(noise, TSC2005State), + VMSTATE_UINT16_ARRAY(temp_thr, TSC2005State, 2), + VMSTATE_UINT16_ARRAY(aux_thr, TSC2005State, 2), + VMSTATE_INT32_ARRAY(tr, TSC2005State, 8), + VMSTATE_END_OF_LIST() + } +}; + void *tsc2005_init(qemu_irq pintdav) { TSC2005State *s; @@ -529,8 +489,8 @@ void *tsc2005_init(qemu_irq pintdav) g_malloc0(sizeof(TSC2005State)); s->x = 400; s->y = 240; - s->pressure = 0; - s->precision = s->nextprecision = 0; + s->pressure = false; + s->precision = s->nextprecision = false; s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, tsc2005_timer_tick, s); s->pint = pintdav; s->model = 0x2005; @@ -550,7 +510,7 @@ void *tsc2005_init(qemu_irq pintdav) "QEMU TSC2005-driven Touchscreen"); qemu_register_reset((void *) tsc2005_reset, s); - register_savevm(NULL, "tsc2005", -1, 0, tsc2005_save, tsc2005_load, s); + vmstate_register(NULL, 0, &vmstate_tsc2005, s); return s; } From fa53b7f047d2c39311d4160f29a20801c1f7af3c Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Tue, 4 Oct 2016 13:28:08 +0100 Subject: [PATCH 489/723] vmstateify tsc210x I'm now saving all 3 of the pll entries; only 2 were saved before. There are a couple of times that were previously stored as offsets from 'now' calculated before saving; with vmstate it's easier to store the 'now' and fix it up on reload. Signed-off-by: Dr. David Alan Gilbert Message-id: 1474977735-10156-3-git-send-email-dgilbert@redhat.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/input/tsc210x.c | 227 +++++++++++++++++++++------------------------ 1 file changed, 104 insertions(+), 123 deletions(-) diff --git a/hw/input/tsc210x.c b/hw/input/tsc210x.c index 93ca374fcd1..b0683437716 100644 --- a/hw/input/tsc210x.c +++ b/hw/input/tsc210x.c @@ -47,24 +47,25 @@ typedef struct { uint8_t out_fifo[16384]; uint16_t model; - int x, y; - int pressure; - - int state, page, offset, irq; - uint16_t command, dav; - - int busy; - int enabled; - int host_mode; - int function; - int nextfunction; - int precision; - int nextprecision; - int filter; - int pin_func; - int ref; - int timing; - int noise; + int32_t x, y; + bool pressure; + + uint8_t page, offset; + uint16_t dav; + + bool state; + bool irq; + bool command; + bool busy; + bool enabled; + bool host_mode; + uint8_t function, nextfunction; + uint8_t precision, nextprecision; + uint8_t filter; + uint8_t pin_func; + uint8_t ref; + uint8_t timing; + uint8_t noise; uint16_t audio_ctrl1; uint16_t audio_ctrl2; @@ -72,7 +73,7 @@ typedef struct { uint16_t pll[3]; uint16_t volume; int64_t volume_change; - int softstep; + bool softstep; uint16_t dac_power; int64_t powerdown; uint16_t filter_data[0x14]; @@ -93,6 +94,7 @@ typedef struct { int mode; int intr; } kb; + int64_t now; /* Time at migration */ } TSC210xState; static const int resolution[4] = { 12, 8, 10, 12 }; @@ -154,14 +156,14 @@ static const uint16_t mode_regs[16] = { static void tsc210x_reset(TSC210xState *s) { - s->state = 0; + s->state = false; s->pin_func = 2; - s->enabled = 0; - s->busy = 0; + s->enabled = false; + s->busy = false; s->nextfunction = 0; s->ref = 0; s->timing = 0; - s->irq = 0; + s->irq = false; s->dav = 0; s->audio_ctrl1 = 0x0000; @@ -172,7 +174,7 @@ static void tsc210x_reset(TSC210xState *s) s->pll[2] = 0x1fff; s->volume = 0xffff; s->dac_power = 0x8540; - s->softstep = 1; + s->softstep = true; s->volume_change = 0; s->powerdown = 0; s->filter_data[0x00] = 0x6be3; @@ -566,7 +568,7 @@ static void tsc2102_control_register_write( s->enabled = !(value & 0x4000); if (s->busy && !s->enabled) timer_del(s->timer); - s->busy &= s->enabled; + s->busy = s->busy && s->enabled; s->nextfunction = (value >> 10) & 0xf; s->nextprecision = (value >> 8) & 3; s->filter = value & 0xff; @@ -773,7 +775,7 @@ static void tsc2102_audio_register_write( static void tsc210x_pin_update(TSC210xState *s) { int64_t expires; - int pin_state; + bool pin_state; switch (s->pin_func) { case 0: @@ -788,7 +790,7 @@ static void tsc210x_pin_update(TSC210xState *s) } if (!s->enabled) - pin_state = 0; + pin_state = false; if (pin_state != s->irq) { s->irq = pin_state; @@ -814,7 +816,7 @@ static void tsc210x_pin_update(TSC210xState *s) case TSC_MODE_TEMP1: case TSC_MODE_TEMP2: if (s->dav) - s->enabled = 0; + s->enabled = false; break; case TSC_MODE_AUX_SCAN: @@ -832,7 +834,7 @@ static void tsc210x_pin_update(TSC210xState *s) if (!s->enabled || s->busy || s->dav) return; - s->busy = 1; + s->busy = true; s->precision = s->nextprecision; s->function = s->nextfunction; expires = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + @@ -867,7 +869,7 @@ static uint16_t tsc210x_read(TSC210xState *s) /* Allow sequential reads. */ s->offset ++; - s->state = 0; + s->state = false; return ret; } @@ -878,10 +880,10 @@ static void tsc210x_write(TSC210xState *s, uint16_t value) * command and data every second time. */ if (!s->state) { - s->command = value >> 15; + s->command = (value >> 15) != 0; s->page = (value >> 11) & 0x0f; s->offset = (value >> 5) & 0x3f; - s->state = 1; + s->state = true; } else { if (s->command) fprintf(stderr, "tsc210x_write: SPI overrun!\n"); @@ -901,7 +903,7 @@ static void tsc210x_write(TSC210xState *s, uint16_t value) } tsc210x_pin_update(s); - s->state = 0; + s->state = false; } } @@ -933,7 +935,7 @@ static void tsc210x_timer_tick(void *opaque) if (!s->busy) return; - s->busy = 0; + s->busy = false; s->dav |= mode_regs[s->function]; tsc210x_pin_update(s); qemu_irq_lower(s->davint); @@ -974,108 +976,34 @@ static void tsc210x_i2s_set_rate(TSC210xState *s, int in, int out) s->i2s_rx_rate = in; } -static void tsc210x_save(QEMUFile *f, void *opaque) +static void tsc210x_pre_save(void *opaque) { TSC210xState *s = (TSC210xState *) opaque; - int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - int i; - - qemu_put_be16(f, s->x); - qemu_put_be16(f, s->y); - qemu_put_byte(f, s->pressure); - - qemu_put_byte(f, s->state); - qemu_put_byte(f, s->page); - qemu_put_byte(f, s->offset); - qemu_put_byte(f, s->command); - - qemu_put_byte(f, s->irq); - qemu_put_be16s(f, &s->dav); - - timer_put(f, s->timer); - qemu_put_byte(f, s->enabled); - qemu_put_byte(f, s->host_mode); - qemu_put_byte(f, s->function); - qemu_put_byte(f, s->nextfunction); - qemu_put_byte(f, s->precision); - qemu_put_byte(f, s->nextprecision); - qemu_put_byte(f, s->filter); - qemu_put_byte(f, s->pin_func); - qemu_put_byte(f, s->ref); - qemu_put_byte(f, s->timing); - qemu_put_be32(f, s->noise); - - qemu_put_be16s(f, &s->audio_ctrl1); - qemu_put_be16s(f, &s->audio_ctrl2); - qemu_put_be16s(f, &s->audio_ctrl3); - qemu_put_be16s(f, &s->pll[0]); - qemu_put_be16s(f, &s->pll[1]); - qemu_put_be16s(f, &s->volume); - qemu_put_sbe64(f, (s->volume_change - now)); - qemu_put_sbe64(f, (s->powerdown - now)); - qemu_put_byte(f, s->softstep); - qemu_put_be16s(f, &s->dac_power); - - for (i = 0; i < 0x14; i ++) - qemu_put_be16s(f, &s->filter_data[i]); + s->now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); } -static int tsc210x_load(QEMUFile *f, void *opaque, int version_id) +static int tsc210x_post_load(void *opaque, int version_id) { TSC210xState *s = (TSC210xState *) opaque; int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - int i; - - s->x = qemu_get_be16(f); - s->y = qemu_get_be16(f); - s->pressure = qemu_get_byte(f); - - s->state = qemu_get_byte(f); - s->page = qemu_get_byte(f); - s->offset = qemu_get_byte(f); - s->command = qemu_get_byte(f); - s->irq = qemu_get_byte(f); - qemu_get_be16s(f, &s->dav); - - timer_get(f, s->timer); - s->enabled = qemu_get_byte(f); - s->host_mode = qemu_get_byte(f); - s->function = qemu_get_byte(f); - if (s->function < 0 || s->function >= ARRAY_SIZE(mode_regs)) { + if (s->function >= ARRAY_SIZE(mode_regs)) { return -EINVAL; } - s->nextfunction = qemu_get_byte(f); - if (s->nextfunction < 0 || s->nextfunction >= ARRAY_SIZE(mode_regs)) { + if (s->nextfunction >= ARRAY_SIZE(mode_regs)) { return -EINVAL; } - s->precision = qemu_get_byte(f); - if (s->precision < 0 || s->precision >= ARRAY_SIZE(resolution)) { + if (s->precision >= ARRAY_SIZE(resolution)) { return -EINVAL; } - s->nextprecision = qemu_get_byte(f); - if (s->nextprecision < 0 || s->nextprecision >= ARRAY_SIZE(resolution)) { + if (s->nextprecision >= ARRAY_SIZE(resolution)) { return -EINVAL; } - s->filter = qemu_get_byte(f); - s->pin_func = qemu_get_byte(f); - s->ref = qemu_get_byte(f); - s->timing = qemu_get_byte(f); - s->noise = qemu_get_be32(f); - - qemu_get_be16s(f, &s->audio_ctrl1); - qemu_get_be16s(f, &s->audio_ctrl2); - qemu_get_be16s(f, &s->audio_ctrl3); - qemu_get_be16s(f, &s->pll[0]); - qemu_get_be16s(f, &s->pll[1]); - qemu_get_be16s(f, &s->volume); - s->volume_change = qemu_get_sbe64(f) + now; - s->powerdown = qemu_get_sbe64(f) + now; - s->softstep = qemu_get_byte(f); - qemu_get_be16s(f, &s->dac_power); - - for (i = 0; i < 0x14; i ++) - qemu_get_be16s(f, &s->filter_data[i]); + + s->volume_change -= s->now; + s->volume_change += now; + s->powerdown -= s->now; + s->powerdown += now; s->busy = timer_pending(s->timer); qemu_set_irq(s->pint, !s->irq); @@ -1084,6 +1012,60 @@ static int tsc210x_load(QEMUFile *f, void *opaque, int version_id) return 0; } +static VMStateField vmstatefields_tsc210x[] = { + VMSTATE_BOOL(enabled, TSC210xState), + VMSTATE_BOOL(host_mode, TSC210xState), + VMSTATE_BOOL(irq, TSC210xState), + VMSTATE_BOOL(command, TSC210xState), + VMSTATE_BOOL(pressure, TSC210xState), + VMSTATE_BOOL(softstep, TSC210xState), + VMSTATE_BOOL(state, TSC210xState), + VMSTATE_UINT16(dav, TSC210xState), + VMSTATE_INT32(x, TSC210xState), + VMSTATE_INT32(y, TSC210xState), + VMSTATE_UINT8(offset, TSC210xState), + VMSTATE_UINT8(page, TSC210xState), + VMSTATE_UINT8(filter, TSC210xState), + VMSTATE_UINT8(pin_func, TSC210xState), + VMSTATE_UINT8(ref, TSC210xState), + VMSTATE_UINT8(timing, TSC210xState), + VMSTATE_UINT8(noise, TSC210xState), + VMSTATE_UINT8(function, TSC210xState), + VMSTATE_UINT8(nextfunction, TSC210xState), + VMSTATE_UINT8(precision, TSC210xState), + VMSTATE_UINT8(nextprecision, TSC210xState), + VMSTATE_UINT16(audio_ctrl1, TSC210xState), + VMSTATE_UINT16(audio_ctrl2, TSC210xState), + VMSTATE_UINT16(audio_ctrl3, TSC210xState), + VMSTATE_UINT16_ARRAY(pll, TSC210xState, 3), + VMSTATE_UINT16(volume, TSC210xState), + VMSTATE_UINT16(dac_power, TSC210xState), + VMSTATE_INT64(volume_change, TSC210xState), + VMSTATE_INT64(powerdown, TSC210xState), + VMSTATE_INT64(now, TSC210xState), + VMSTATE_UINT16_ARRAY(filter_data, TSC210xState, 0x14), + VMSTATE_TIMER_PTR(timer, TSC210xState), + VMSTATE_END_OF_LIST() +}; + +static const VMStateDescription vmstate_tsc2102 = { + .name = "tsc2102", + .version_id = 1, + .minimum_version_id = 1, + .pre_save = tsc210x_pre_save, + .post_load = tsc210x_post_load, + .fields = vmstatefields_tsc210x, +}; + +static const VMStateDescription vmstate_tsc2301 = { + .name = "tsc2301", + .version_id = 1, + .minimum_version_id = 1, + .pre_save = tsc210x_pre_save, + .post_load = tsc210x_post_load, + .fields = vmstatefields_tsc210x, +}; + uWireSlave *tsc2102_init(qemu_irq pint) { TSC210xState *s; @@ -1125,8 +1107,7 @@ uWireSlave *tsc2102_init(qemu_irq pint) AUD_register_card(s->name, &s->card); qemu_register_reset((void *) tsc210x_reset, s); - register_savevm(NULL, s->name, -1, 0, - tsc210x_save, tsc210x_load, s); + vmstate_register(NULL, 0, &vmstate_tsc2102, s); return &s->chip; } @@ -1174,7 +1155,7 @@ uWireSlave *tsc2301_init(qemu_irq penirq, qemu_irq kbirq, qemu_irq dav) AUD_register_card(s->name, &s->card); qemu_register_reset((void *) tsc210x_reset, s); - register_savevm(NULL, s->name, -1, 0, tsc210x_save, tsc210x_load, s); + vmstate_register(NULL, 0, &vmstate_tsc2301, s); return &s->chip; } From 96b0439bbe2083c10308ce91860e2129f52bc1ae Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 4 Oct 2016 13:28:08 +0100 Subject: [PATCH 490/723] hw/arm/virt: add 2.8 machine type Signed-off-by: Andrew Jones Message-id: 1474641676-25017-1-git-send-email-drjones@redhat.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/virt.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index a193b5a95b3..2ead58db8ff 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -1479,7 +1479,7 @@ static void machvirt_machine_init(void) } type_init(machvirt_machine_init); -static void virt_2_7_instance_init(Object *obj) +static void virt_2_8_instance_init(Object *obj) { VirtMachineState *vms = VIRT_MACHINE(obj); @@ -1512,10 +1512,25 @@ static void virt_2_7_instance_init(Object *obj) "Valid values are 2, 3 and host", NULL); } +static void virt_machine_2_8_options(MachineClass *mc) +{ +} +DEFINE_VIRT_MACHINE_AS_LATEST(2, 8) + +#define VIRT_COMPAT_2_7 \ + HW_COMPAT_2_7 + +static void virt_2_7_instance_init(Object *obj) +{ + virt_2_8_instance_init(obj); +} + static void virt_machine_2_7_options(MachineClass *mc) { + virt_machine_2_8_options(mc); + SET_MACHINE_COMPAT(mc, VIRT_COMPAT_2_7); } -DEFINE_VIRT_MACHINE_AS_LATEST(2, 7) +DEFINE_VIRT_MACHINE(2, 7) #define VIRT_COMPAT_2_6 \ HW_COMPAT_2_6 From d19a4d4ef448e736d341df47bd1adc78c8e40814 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Tue, 4 Oct 2016 13:28:08 +0100 Subject: [PATCH 491/723] hw/intc/arm_gic(v3)_kvm: Initialize gsi routing Advertise gsi routing and set up irqchip routing entries for GIC SPIs. This is not mandated as long as MSI routing is not used (because the kernel sets a default irqchip routing table). However once MSI routing gets used (for VIRTIO-PCI vhost for example), the first call to KVM_SET_GSI_ROUTING overrides the kernel default irqchip table. If no routing entry exists for the GSI, any IRQFD signaling for this GSI will fail. Signed-off-by: Eric Auger Reviewed-by: Peter Maydell Message-id: 1474616617-366-2-git-send-email-eric.auger@redhat.com Signed-off-by: Peter Maydell --- hw/intc/arm_gic_kvm.c | 12 ++++++++++++ hw/intc/arm_gicv3_kvm.c | 13 +++++++++++++ 2 files changed, 25 insertions(+) diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c index 5593cdb3e43..ae7ac58ffd4 100644 --- a/hw/intc/arm_gic_kvm.c +++ b/hw/intc/arm_gic_kvm.c @@ -577,6 +577,18 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp) "not support vGICv2 migration"); migrate_add_blocker(s->migration_blocker); } + + if (kvm_has_gsi_routing()) { + /* set up irq routing */ + kvm_init_irq_routing(kvm_state); + for (i = 0; i < s->num_irq - GIC_INTERNAL; ++i) { + kvm_irqchip_add_irq_route(kvm_state, i, 0, i); + } + + kvm_gsi_routing_allowed = true; + + kvm_irqchip_commit_routes(kvm_state); + } } static void kvm_arm_gic_class_init(ObjectClass *klass, void *data) diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c index 711fde38f3f..199a439ccf2 100644 --- a/hw/intc/arm_gicv3_kvm.c +++ b/hw/intc/arm_gicv3_kvm.c @@ -85,6 +85,7 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) GICv3State *s = KVM_ARM_GICV3(dev); KVMARMGICv3Class *kgc = KVM_ARM_GICV3_GET_CLASS(s); Error *local_err = NULL; + int i; DPRINTF("kvm_arm_gicv3_realize\n"); @@ -127,6 +128,18 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) */ error_setg(&s->migration_blocker, "vGICv3 migration is not implemented"); migrate_add_blocker(s->migration_blocker); + + if (kvm_has_gsi_routing()) { + /* set up irq routing */ + kvm_init_irq_routing(kvm_state); + for (i = 0; i < s->num_irq - GIC_INTERNAL; ++i) { + kvm_irqchip_add_irq_route(kvm_state, i, 0, i); + } + + kvm_gsi_routing_allowed = true; + + kvm_irqchip_commit_routes(kvm_state); + } } static void kvm_arm_gicv3_class_init(ObjectClass *klass, void *data) From 386ce3c7fc6bf384eaf78cfbb766c015c26bf9ca Mon Sep 17 00:00:00 2001 From: Pavel Fedin Date: Tue, 4 Oct 2016 13:28:08 +0100 Subject: [PATCH 492/723] hw/intc/arm_gicv3_its: Implement ITS base class This is the basic skeleton for both KVM and software-emulated ITS. Since we already prepare status structure, we also introduce complete VMState description. But, because we currently have no migratable implementations, we also set unmigratable flag. Signed-off-by: Pavel Fedin Signed-off-by: Eric Auger Reviewed-by: Peter Maydell Message-id: 1474616617-366-3-git-send-email-eric.auger@redhat.com Signed-off-by: Peter Maydell --- hw/intc/Makefile.objs | 1 + hw/intc/arm_gicv3_its_common.c | 148 +++++++++++++++++++++++++ include/hw/intc/arm_gicv3_its_common.h | 78 +++++++++++++ target-arm/kvm_arm.h | 19 ++++ 4 files changed, 246 insertions(+) create mode 100644 hw/intc/arm_gicv3_its_common.c create mode 100644 include/hw/intc/arm_gicv3_its_common.h diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs index 05ec21b21e0..23a39f72344 100644 --- a/hw/intc/Makefile.objs +++ b/hw/intc/Makefile.objs @@ -16,6 +16,7 @@ common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_common.o common-obj-$(CONFIG_ARM_GIC) += arm_gicv3.o common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_dist.o common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_redist.o +common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_its_common.o common-obj-$(CONFIG_OPENPIC) += openpic.o obj-$(CONFIG_APIC) += apic.o apic_common.o diff --git a/hw/intc/arm_gicv3_its_common.c b/hw/intc/arm_gicv3_its_common.c new file mode 100644 index 00000000000..9d67c5c1ee5 --- /dev/null +++ b/hw/intc/arm_gicv3_its_common.c @@ -0,0 +1,148 @@ +/* + * ITS base class for a GICv3-based system + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * Written by Pavel Fedin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#include "qemu/osdep.h" +#include "hw/pci/msi.h" +#include "hw/intc/arm_gicv3_its_common.h" +#include "qemu/log.h" + +static void gicv3_its_pre_save(void *opaque) +{ + GICv3ITSState *s = (GICv3ITSState *)opaque; + GICv3ITSCommonClass *c = ARM_GICV3_ITS_COMMON_GET_CLASS(s); + + if (c->pre_save) { + c->pre_save(s); + } +} + +static int gicv3_its_post_load(void *opaque, int version_id) +{ + GICv3ITSState *s = (GICv3ITSState *)opaque; + GICv3ITSCommonClass *c = ARM_GICV3_ITS_COMMON_GET_CLASS(s); + + if (c->post_load) { + c->post_load(s); + } + return 0; +} + +static const VMStateDescription vmstate_its = { + .name = "arm_gicv3_its", + .pre_save = gicv3_its_pre_save, + .post_load = gicv3_its_post_load, + .unmigratable = true, +}; + +static MemTxResult gicv3_its_trans_read(void *opaque, hwaddr offset, + uint64_t *data, unsigned size, + MemTxAttrs attrs) +{ + qemu_log_mask(LOG_GUEST_ERROR, "ITS read at offset 0x%"PRIx64"\n", offset); + return MEMTX_ERROR; +} + +static MemTxResult gicv3_its_trans_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size, + MemTxAttrs attrs) +{ + if (offset == 0x0040 && ((size == 2) || (size == 4))) { + GICv3ITSState *s = ARM_GICV3_ITS_COMMON(opaque); + GICv3ITSCommonClass *c = ARM_GICV3_ITS_COMMON_GET_CLASS(s); + int ret = c->send_msi(s, le64_to_cpu(value), attrs.requester_id); + + if (ret <= 0) { + qemu_log_mask(LOG_GUEST_ERROR, + "ITS: Error sending MSI: %s\n", strerror(-ret)); + return MEMTX_DECODE_ERROR; + } + + return MEMTX_OK; + } else { + qemu_log_mask(LOG_GUEST_ERROR, + "ITS write at bad offset 0x%"PRIx64"\n", offset); + return MEMTX_DECODE_ERROR; + } +} + +static const MemoryRegionOps gicv3_its_trans_ops = { + .read_with_attrs = gicv3_its_trans_read, + .write_with_attrs = gicv3_its_trans_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +void gicv3_its_init_mmio(GICv3ITSState *s, const MemoryRegionOps *ops) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(s); + + memory_region_init_io(&s->iomem_its_cntrl, OBJECT(s), ops, s, + "control", ITS_CONTROL_SIZE); + memory_region_init_io(&s->iomem_its_translation, OBJECT(s), + &gicv3_its_trans_ops, s, + "translation", ITS_TRANS_SIZE); + + /* Our two regions are always adjacent, therefore we now combine them + * into a single one in order to make our users' life easier. + */ + memory_region_init(&s->iomem_main, OBJECT(s), "gicv3_its", ITS_SIZE); + memory_region_add_subregion(&s->iomem_main, 0, &s->iomem_its_cntrl); + memory_region_add_subregion(&s->iomem_main, ITS_CONTROL_SIZE, + &s->iomem_its_translation); + sysbus_init_mmio(sbd, &s->iomem_main); + + msi_nonbroken = true; +} + +static void gicv3_its_common_reset(DeviceState *dev) +{ + GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev); + + s->ctlr = 0; + s->cbaser = 0; + s->cwriter = 0; + s->creadr = 0; + memset(&s->baser, 0, sizeof(s->baser)); + + gicv3_its_post_load(s, 0); +} + +static void gicv3_its_common_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = gicv3_its_common_reset; + dc->vmsd = &vmstate_its; +} + +static const TypeInfo gicv3_its_common_info = { + .name = TYPE_ARM_GICV3_ITS_COMMON, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(GICv3ITSState), + .class_size = sizeof(GICv3ITSCommonClass), + .class_init = gicv3_its_common_class_init, + .abstract = true, +}; + +static void gicv3_its_common_register_types(void) +{ + type_register_static(&gicv3_its_common_info); +} + +type_init(gicv3_its_common_register_types) diff --git a/include/hw/intc/arm_gicv3_its_common.h b/include/hw/intc/arm_gicv3_its_common.h new file mode 100644 index 00000000000..1ba18944cf7 --- /dev/null +++ b/include/hw/intc/arm_gicv3_its_common.h @@ -0,0 +1,78 @@ +/* + * ITS support for ARM GICv3 + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * Written by Pavel Fedin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#ifndef QEMU_ARM_GICV3_ITS_COMMON_H +#define QEMU_ARM_GICV3_ITS_COMMON_H + +#include "hw/sysbus.h" +#include "hw/intc/arm_gicv3_common.h" + +#define ITS_CONTROL_SIZE 0x10000 +#define ITS_TRANS_SIZE 0x10000 +#define ITS_SIZE (ITS_CONTROL_SIZE + ITS_TRANS_SIZE) + +struct GICv3ITSState { + SysBusDevice parent_obj; + + MemoryRegion iomem_main; + MemoryRegion iomem_its_cntrl; + MemoryRegion iomem_its_translation; + + GICv3State *gicv3; + + int dev_fd; /* kvm device fd if backed by kvm vgic support */ + uint64_t gits_translater_gpa; + bool translater_gpa_known; + + /* Registers */ + uint32_t ctlr; + uint64_t cbaser; + uint64_t cwriter; + uint64_t creadr; + uint64_t baser[8]; + + Error *migration_blocker; +}; + +typedef struct GICv3ITSState GICv3ITSState; + +void gicv3_its_init_mmio(GICv3ITSState *s, const MemoryRegionOps *ops); + +#define TYPE_ARM_GICV3_ITS_COMMON "arm-gicv3-its-common" +#define ARM_GICV3_ITS_COMMON(obj) \ + OBJECT_CHECK(GICv3ITSState, (obj), TYPE_ARM_GICV3_ITS_COMMON) +#define ARM_GICV3_ITS_COMMON_CLASS(klass) \ + OBJECT_CLASS_CHECK(GICv3ITSCommonClass, (klass), TYPE_ARM_GICV3_ITS_COMMON) +#define ARM_GICV3_ITS_COMMON_GET_CLASS(obj) \ + OBJECT_GET_CLASS(GICv3ITSCommonClass, (obj), TYPE_ARM_GICV3_ITS_COMMON) + +struct GICv3ITSCommonClass { + /*< private >*/ + SysBusDeviceClass parent_class; + /*< public >*/ + + int (*send_msi)(GICv3ITSState *s, uint32_t data, uint16_t devid); + void (*pre_save)(GICv3ITSState *s); + void (*post_load)(GICv3ITSState *s); +}; + +typedef struct GICv3ITSCommonClass GICv3ITSCommonClass; + +#endif diff --git a/target-arm/kvm_arm.h b/target-arm/kvm_arm.h index a4193684a8f..544e404aa5f 100644 --- a/target-arm/kvm_arm.h +++ b/target-arm/kvm_arm.h @@ -255,4 +255,23 @@ struct kvm_guest_debug_arch; void kvm_arm_copy_hw_debug_data(struct kvm_guest_debug_arch *ptr); +/** + * its_class_name + * + * Return the ITS class name to use depending on whether KVM acceleration + * and KVM CAP_SIGNAL_MSI are supported + * + * Returns: class name to use or NULL + */ +static inline const char *its_class_name(void) +{ + if (kvm_irqchip_in_kernel()) { + /* KVM implementation requires this capability */ + return kvm_direct_msi_enabled() ? "arm-its-kvm" : NULL; + } else { + /* Software emulation is not implemented yet */ + return NULL; + } +} + #endif From 1b20616f261f28ef971c2b40066b968206104501 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Tue, 4 Oct 2016 13:28:08 +0100 Subject: [PATCH 493/723] target-arm: move gicv3_class_name from machine to kvm_arm.h Machine.c contains code related to migration. Let's move gicv3_class_name to kvm_arm.h instead. Signed-off-by: Eric Auger Reviewed-by: Peter Maydell Message-id: 1474616617-366-4-git-send-email-eric.auger@redhat.com Suggested-by: Peter Maydell Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target-arm/kvm_arm.h | 16 +++++++++++++++- target-arm/machine.c | 15 --------------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/target-arm/kvm_arm.h b/target-arm/kvm_arm.h index 544e404aa5f..633d08828a5 100644 --- a/target-arm/kvm_arm.h +++ b/target-arm/kvm_arm.h @@ -13,6 +13,7 @@ #include "sysemu/kvm.h" #include "exec/memory.h" +#include "qemu/error-report.h" /** * kvm_arm_vcpu_init: @@ -223,7 +224,20 @@ static inline const char *gic_class_name(void) * * Returns: class name to use */ -const char *gicv3_class_name(void); +static inline const char *gicv3_class_name(void) +{ + if (kvm_irqchip_in_kernel()) { +#ifdef TARGET_AARCH64 + return "kvm-arm-gicv3"; +#else + error_report("KVM GICv3 acceleration is not supported on this " + "platform"); + exit(1); +#endif + } else { + return "arm-gicv3"; + } +} /** * kvm_arm_handle_debug: diff --git a/target-arm/machine.c b/target-arm/machine.c index 7a6ca31a8ef..d90943b6dbe 100644 --- a/target-arm/machine.c +++ b/target-arm/machine.c @@ -331,18 +331,3 @@ const VMStateDescription vmstate_arm_cpu = { NULL } }; - -const char *gicv3_class_name(void) -{ - if (kvm_irqchip_in_kernel()) { -#ifdef TARGET_AARCH64 - return "kvm-arm-gicv3"; -#else - error_report("KVM GICv3 acceleration is not supported on this " - "platform"); - exit(1); -#endif - } else { - return "arm-gicv3"; - } -} From 767a554a0c752cff1e1d17550aefd4e9dca881d6 Mon Sep 17 00:00:00 2001 From: Pavel Fedin Date: Tue, 4 Oct 2016 13:28:09 +0100 Subject: [PATCH 494/723] kvm-all: Pass requester ID to MSI routing functions Introduce global kvm_msi_use_devid flag plus associated kvm_msi_devid_required() macro. Passes the device ID, if needed, while building the MSI route entry. Device IDs are required by the ARM GICv3 ITS (IRQ remapping function is based on this information). Signed-off-by: Pavel Fedin Signed-off-by: Eric Auger Message-id: 1474616617-366-5-git-send-email-eric.auger@redhat.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- include/sysemu/kvm.h | 9 +++++++++ kvm-all.c | 9 +++++++++ kvm-stub.c | 1 + 3 files changed, 19 insertions(+) diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index 3e17ba76ce0..df67cc06720 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -53,6 +53,7 @@ extern bool kvm_gsi_direct_mapping; extern bool kvm_readonly_mem_allowed; extern bool kvm_direct_msi_allowed; extern bool kvm_ioeventfd_any_length_allowed; +extern bool kvm_msi_use_devid; #if defined CONFIG_KVM || !defined NEED_CPU_H #define kvm_enabled() (kvm_allowed) @@ -169,6 +170,13 @@ extern bool kvm_ioeventfd_any_length_allowed; */ #define kvm_ioeventfd_any_length_enabled() (kvm_ioeventfd_any_length_allowed) +/** + * kvm_msi_devid_required: + * Returns: true if KVM requires a device id to be provided while + * defining an MSI routing entry. + */ +#define kvm_msi_devid_required() (kvm_msi_use_devid) + #else #define kvm_enabled() (0) #define kvm_irqchip_in_kernel() (false) @@ -184,6 +192,7 @@ extern bool kvm_ioeventfd_any_length_allowed; #define kvm_readonly_mem_enabled() (false) #define kvm_direct_msi_enabled() (false) #define kvm_ioeventfd_any_length_enabled() (false) +#define kvm_msi_devid_required() (false) #endif struct kvm_run; diff --git a/kvm-all.c b/kvm-all.c index fc2898a9517..efb5fe37e2b 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -119,6 +119,7 @@ bool kvm_readonly_mem_allowed; bool kvm_vm_attributes_allowed; bool kvm_direct_msi_allowed; bool kvm_ioeventfd_any_length_allowed; +bool kvm_msi_use_devid; static const KVMCapabilityInfo kvm_required_capabilites[] = { KVM_CAP_INFO(USER_MEMORY), @@ -1275,6 +1276,10 @@ int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev) kroute.u.msi.address_lo = (uint32_t)msg.address; kroute.u.msi.address_hi = msg.address >> 32; kroute.u.msi.data = le32_to_cpu(msg.data); + if (kvm_msi_devid_required()) { + kroute.flags = KVM_MSI_VALID_DEVID; + kroute.u.msi.devid = pci_requester_id(dev); + } if (kvm_arch_fixup_msi_route(&kroute, msg.address, msg.data, dev)) { kvm_irqchip_release_virq(s, virq); return -EINVAL; @@ -1308,6 +1313,10 @@ int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg, kroute.u.msi.address_lo = (uint32_t)msg.address; kroute.u.msi.address_hi = msg.address >> 32; kroute.u.msi.data = le32_to_cpu(msg.data); + if (kvm_msi_devid_required()) { + kroute.flags = KVM_MSI_VALID_DEVID; + kroute.u.msi.devid = pci_requester_id(dev); + } if (kvm_arch_fixup_msi_route(&kroute, msg.address, msg.data, dev)) { return -EINVAL; } diff --git a/kvm-stub.c b/kvm-stub.c index 322712764f9..b1b6b96c960 100644 --- a/kvm-stub.c +++ b/kvm-stub.c @@ -31,6 +31,7 @@ bool kvm_gsi_direct_mapping; bool kvm_allowed; bool kvm_readonly_mem_allowed; bool kvm_ioeventfd_any_length_allowed; +bool kvm_msi_use_devid; int kvm_destroy_vcpu(CPUState *cpu) { From 0c9f302ea2906eb763cd175134e34d23ed4fea6a Mon Sep 17 00:00:00 2001 From: Pavel Fedin Date: Tue, 4 Oct 2016 13:28:09 +0100 Subject: [PATCH 495/723] hw/intc/arm_gicv3_its: Implement support for in-kernel ITS emulation The ITS control frame is in-kernel emulated while accesses to the GITS_TRANSLATER are mediated through the KVM_SIGNAL_MSI ioctl (MSI direct MSI injection advertised by the CAP_SIGNAL_MSI capability) the kvm_gsi_direct_mapping is explicitly set to false to emphasize the difference with GICv2M. Direct mapping cannot work with ITS since the content of the MSI data is not the target interrupt ID but an eventd id. GSI routing is advertised (kvm_gsi_routing_allowed) as well as msi/irqfd signaling (kvm_msi_via_irqfd_allowed). The MSI frame (GITS_TRANSLATER) absolute GPA is computed on first kvm_its_send_msi() call. It is then passed through KVM_SIGNAL_MSI ioctl. Signed-off-by: Pavel Fedin Signed-off-by: Eric Auger Message-id: 1474616617-366-6-git-send-email-eric.auger@redhat.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/intc/Makefile.objs | 1 + hw/intc/arm_gicv3_its_kvm.c | 121 ++++++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 hw/intc/arm_gicv3_its_kvm.c diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs index 23a39f72344..9cca2800d32 100644 --- a/hw/intc/Makefile.objs +++ b/hw/intc/Makefile.objs @@ -22,6 +22,7 @@ common-obj-$(CONFIG_OPENPIC) += openpic.o obj-$(CONFIG_APIC) += apic.o apic_common.o obj-$(CONFIG_ARM_GIC_KVM) += arm_gic_kvm.o obj-$(call land,$(CONFIG_ARM_GIC_KVM),$(TARGET_AARCH64)) += arm_gicv3_kvm.o +obj-$(call land,$(CONFIG_ARM_GIC_KVM),$(TARGET_AARCH64)) += arm_gicv3_its_kvm.o obj-$(CONFIG_STELLARIS) += armv7m_nvic.o obj-$(CONFIG_EXYNOS4) += exynos4210_gic.o exynos4210_combiner.o obj-$(CONFIG_GRLIB) += grlib_irqmp.o diff --git a/hw/intc/arm_gicv3_its_kvm.c b/hw/intc/arm_gicv3_its_kvm.c new file mode 100644 index 00000000000..fc246e0cb50 --- /dev/null +++ b/hw/intc/arm_gicv3_its_kvm.c @@ -0,0 +1,121 @@ +/* + * KVM-based ITS implementation for a GICv3-based system + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * Written by Pavel Fedin + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/intc/arm_gicv3_its_common.h" +#include "sysemu/sysemu.h" +#include "sysemu/kvm.h" +#include "kvm_arm.h" +#include "migration/migration.h" + +#define TYPE_KVM_ARM_ITS "arm-its-kvm" +#define KVM_ARM_ITS(obj) OBJECT_CHECK(GICv3ITSState, (obj), TYPE_KVM_ARM_ITS) + +static int kvm_its_send_msi(GICv3ITSState *s, uint32_t value, uint16_t devid) +{ + struct kvm_msi msi; + + if (unlikely(!s->translater_gpa_known)) { + MemoryRegion *mr = &s->iomem_its_translation; + MemoryRegionSection mrs; + + mrs = memory_region_find(mr, 0, 1); + memory_region_unref(mrs.mr); + s->gits_translater_gpa = mrs.offset_within_address_space + 0x40; + s->translater_gpa_known = true; + } + + msi.address_lo = extract64(s->gits_translater_gpa, 0, 32); + msi.address_hi = extract64(s->gits_translater_gpa, 32, 32); + msi.data = le32_to_cpu(value); + msi.flags = KVM_MSI_VALID_DEVID; + msi.devid = devid; + memset(msi.pad, 0, sizeof(msi.pad)); + + return kvm_vm_ioctl(kvm_state, KVM_SIGNAL_MSI, &msi); +} + +static void kvm_arm_its_realize(DeviceState *dev, Error **errp) +{ + GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev); + + s->dev_fd = kvm_create_device(kvm_state, KVM_DEV_TYPE_ARM_VGIC_ITS, false); + if (s->dev_fd < 0) { + error_setg_errno(errp, -s->dev_fd, "error creating in-kernel ITS"); + return; + } + + /* explicit init of the ITS */ + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, + KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true); + + /* register the base address */ + kvm_arm_register_device(&s->iomem_its_cntrl, -1, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_ITS_ADDR_TYPE, s->dev_fd); + + gicv3_its_init_mmio(s, NULL); + + /* + * Block migration of a KVM GICv3 ITS device: the API for saving and + * restoring the state in the kernel is not yet available + */ + error_setg(&s->migration_blocker, "vITS migration is not implemented"); + migrate_add_blocker(s->migration_blocker); + + kvm_msi_use_devid = true; + kvm_gsi_direct_mapping = false; + kvm_msi_via_irqfd_allowed = kvm_irqfds_enabled(); +} + +static void kvm_arm_its_init(Object *obj) +{ + GICv3ITSState *s = KVM_ARM_ITS(obj); + + object_property_add_link(obj, "parent-gicv3", + "kvm-arm-gicv3", (Object **)&s->gicv3, + object_property_allow_set_link, + OBJ_PROP_LINK_UNREF_ON_RELEASE, + &error_abort); +} + +static void kvm_arm_its_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + GICv3ITSCommonClass *icc = ARM_GICV3_ITS_COMMON_CLASS(klass); + + dc->realize = kvm_arm_its_realize; + icc->send_msi = kvm_its_send_msi; +} + +static const TypeInfo kvm_arm_its_info = { + .name = TYPE_KVM_ARM_ITS, + .parent = TYPE_ARM_GICV3_ITS_COMMON, + .instance_size = sizeof(GICv3ITSState), + .instance_init = kvm_arm_its_init, + .class_init = kvm_arm_its_class_init, +}; + +static void kvm_arm_its_register_types(void) +{ + type_register_static(&kvm_arm_its_info); +} + +type_init(kvm_arm_its_register_types) From 02f9873180c0893dfe79854ae80cc4b02f862237 Mon Sep 17 00:00:00 2001 From: Pavel Fedin Date: Tue, 4 Oct 2016 13:28:09 +0100 Subject: [PATCH 496/723] arm/virt: Add ITS to the virt board If supported by the configuration, ITS will be added automatically. This patch also renames v2m_phandle to msi_phandle because it's now used by both MSI implementations. Signed-off-by: Pavel Fedin Signed-off-by: Eric Auger Reviewed-by: Peter Maydell Message-id: 1474616617-366-7-git-send-email-eric.auger@redhat.com Signed-off-by: Peter Maydell --- hw/arm/virt.c | 47 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 2ead58db8ff..0f6305d3c7f 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -76,7 +76,7 @@ typedef struct VirtBoardInfo { int fdt_size; uint32_t clock_phandle; uint32_t gic_phandle; - uint32_t v2m_phandle; + uint32_t msi_phandle; bool using_psci; } VirtBoardInfo; @@ -423,9 +423,22 @@ static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi) } } +static void fdt_add_its_gic_node(VirtBoardInfo *vbi) +{ + vbi->msi_phandle = qemu_fdt_alloc_phandle(vbi->fdt); + qemu_fdt_add_subnode(vbi->fdt, "/intc/its"); + qemu_fdt_setprop_string(vbi->fdt, "/intc/its", "compatible", + "arm,gic-v3-its"); + qemu_fdt_setprop(vbi->fdt, "/intc/its", "msi-controller", NULL, 0); + qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc/its", "reg", + 2, vbi->memmap[VIRT_GIC_ITS].base, + 2, vbi->memmap[VIRT_GIC_ITS].size); + qemu_fdt_setprop_cell(vbi->fdt, "/intc/its", "phandle", vbi->msi_phandle); +} + static void fdt_add_v2m_gic_node(VirtBoardInfo *vbi) { - vbi->v2m_phandle = qemu_fdt_alloc_phandle(vbi->fdt); + vbi->msi_phandle = qemu_fdt_alloc_phandle(vbi->fdt); qemu_fdt_add_subnode(vbi->fdt, "/intc/v2m"); qemu_fdt_setprop_string(vbi->fdt, "/intc/v2m", "compatible", "arm,gic-v2m-frame"); @@ -433,7 +446,7 @@ static void fdt_add_v2m_gic_node(VirtBoardInfo *vbi) qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc/v2m", "reg", 2, vbi->memmap[VIRT_GIC_V2M].base, 2, vbi->memmap[VIRT_GIC_V2M].size); - qemu_fdt_setprop_cell(vbi->fdt, "/intc/v2m", "phandle", vbi->v2m_phandle); + qemu_fdt_setprop_cell(vbi->fdt, "/intc/v2m", "phandle", vbi->msi_phandle); } static void fdt_add_gic_node(VirtBoardInfo *vbi, int type) @@ -500,6 +513,26 @@ static void fdt_add_pmu_nodes(const VirtBoardInfo *vbi, int gictype) } } +static void create_its(VirtBoardInfo *vbi, DeviceState *gicdev) +{ + const char *itsclass = its_class_name(); + DeviceState *dev; + + if (!itsclass) { + /* Do nothing if not supported */ + return; + } + + dev = qdev_create(NULL, itsclass); + + object_property_set_link(OBJECT(dev), OBJECT(gicdev), "parent-gicv3", + &error_abort); + qdev_init_nofail(dev); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vbi->memmap[VIRT_GIC_ITS].base); + + fdt_add_its_gic_node(vbi); +} + static void create_v2m(VirtBoardInfo *vbi, qemu_irq *pic) { int i; @@ -583,7 +616,9 @@ static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic, int type, bool secure) fdt_add_gic_node(vbi, type); - if (type == 2) { + if (type == 3) { + create_its(vbi, gicdev); + } else { create_v2m(vbi, pic); } } @@ -1025,9 +1060,9 @@ static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic, nr_pcie_buses - 1); qemu_fdt_setprop(vbi->fdt, nodename, "dma-coherent", NULL, 0); - if (vbi->v2m_phandle) { + if (vbi->msi_phandle) { qemu_fdt_setprop_cells(vbi->fdt, nodename, "msi-parent", - vbi->v2m_phandle); + vbi->msi_phandle); } qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", From 1c2e4ea7b645a127ee6d13a7072f6669d4d826c7 Mon Sep 17 00:00:00 2001 From: Shannon Zhao Date: Tue, 4 Oct 2016 13:28:09 +0100 Subject: [PATCH 497/723] ACPI: Add GIC Interrupt Translation Service Structure definition ACPI Spec 6.0 introduces GIC Interrupt Translation Service Structure. Here we add the definition of the Structure. Signed-off-by: Shannon Zhao Signed-off-by: Eric Auger Message-id: 1474616617-366-8-git-send-email-eric.auger@redhat.com Signed-off-by: Peter Maydell --- include/hw/acpi/acpi-defs.h | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h index 41c1d95c4cb..9c1b7cb5d64 100644 --- a/include/hw/acpi/acpi-defs.h +++ b/include/hw/acpi/acpi-defs.h @@ -294,7 +294,8 @@ typedef struct AcpiMultipleApicTable AcpiMultipleApicTable; #define ACPI_APIC_GENERIC_DISTRIBUTOR 12 #define ACPI_APIC_GENERIC_MSI_FRAME 13 #define ACPI_APIC_GENERIC_REDISTRIBUTOR 14 -#define ACPI_APIC_RESERVED 15 /* 15 and greater are reserved */ +#define ACPI_APIC_GENERIC_TRANSLATOR 15 +#define ACPI_APIC_RESERVED 16 /* 16 and greater are reserved */ /* * MADT sub-structures (Follow MULTIPLE_APIC_DESCRIPTION_TABLE) @@ -395,6 +396,16 @@ struct AcpiMadtGenericRedistributor { typedef struct AcpiMadtGenericRedistributor AcpiMadtGenericRedistributor; +struct AcpiMadtGenericTranslator { + ACPI_SUB_HEADER_DEF + uint16_t reserved; + uint32_t translation_id; + uint64_t base_address; + uint32_t reserved2; +} QEMU_PACKED; + +typedef struct AcpiMadtGenericTranslator AcpiMadtGenericTranslator; + /* * Generic Timer Description Table (GTDT) */ From 13e5c54d30312aef7ac7a265209e39f4655be211 Mon Sep 17 00:00:00 2001 From: Shannon Zhao Date: Tue, 4 Oct 2016 13:28:09 +0100 Subject: [PATCH 498/723] ARM: Virt: ACPI: Add GIC ITS description in ACPI MADT table If GIC ITS is supported, add description in ACPI MADT table, then guest could use ITS when booting with ACPI. Signed-off-by: Shannon Zhao Signed-off-by: Eric Auger Message-id: 1474616617-366-9-git-send-email-eric.auger@redhat.com Signed-off-by: Peter Maydell --- hw/arm/virt-acpi-build.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index 295ec868281..7b39b1d2d67 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -44,6 +44,7 @@ #include "hw/pci/pcie_host.h" #include "hw/pci/pci.h" #include "sysemu/numa.h" +#include "kvm_arm.h" #define ARM_SPI_BASE 32 #define ACPI_POWER_BUTTON_DEVICE "PWRB" @@ -546,6 +547,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) } if (guest_info->gic_version == 3) { + AcpiMadtGenericTranslator *gic_its; AcpiMadtGenericRedistributor *gicr = acpi_data_push(table_data, sizeof *gicr); @@ -553,6 +555,16 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) gicr->length = sizeof(*gicr); gicr->base_address = cpu_to_le64(memmap[VIRT_GIC_REDIST].base); gicr->range_length = cpu_to_le32(memmap[VIRT_GIC_REDIST].size); + + if (!its_class_name()) { + return; + } + + gic_its = acpi_data_push(table_data, sizeof *gic_its); + gic_its->type = ACPI_APIC_GENERIC_TRANSLATOR; + gic_its->length = sizeof(*gic_its); + gic_its->translation_id = 0; + gic_its->base_address = cpu_to_le64(memmap[VIRT_GIC_ITS].base); } else { gic_msi = acpi_data_push(table_data, sizeof *gic_msi); gic_msi->type = ACPI_APIC_GENERIC_MSI_FRAME; From e481a1f63c93344974f799a5e38df980ef5f7f9c Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Tue, 4 Oct 2016 13:28:09 +0100 Subject: [PATCH 499/723] generic-loader: Add a generic loader Add a generic loader to QEMU which can be used to load images or set memory values. Internally inside QEMU this is a device. It is a strange device that provides no hardware interface but allows QEMU to monkey patch memory specified when it is created. To be able to do this it has a reset callback that does the memory operations. This device allows the user to monkey patch memory. To be able to do this it needs a backend to manage the datas, the same as other memory-related devices. In this case as the backend is so trivial we have merged it with the frontend instead of creating and maintaining a seperate backend. Signed-off-by: Alistair Francis Reviewed-by: Peter Maydell Acked-by: Markus Armbruster Message-id: 10f2a9dce5e5e11b6c6d959415b0ad6ee22bcba5.1475195078.git.alistair.francis@xilinx.com Signed-off-by: Peter Maydell --- MAINTAINERS | 6 + hw/core/Makefile.objs | 2 + hw/core/generic-loader.c | 211 +++++++++++++++++++++++++++++++ include/hw/core/generic-loader.h | 46 +++++++ 4 files changed, 265 insertions(+) create mode 100644 hw/core/generic-loader.c create mode 100644 include/hw/core/generic-loader.h diff --git a/MAINTAINERS b/MAINTAINERS index 88fd6745fc1..76a0fdb2c41 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1029,6 +1029,12 @@ M: Dmitry Fleytman S: Maintained F: hw/net/e1000e* +Generic Loader +M: Alistair Francis +S: Maintained +F: hw/core/generic-loader.c +F: include/hw/core/generic-loader.h + Subsystems ---------- Audio diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs index b47241bb2f8..a4c94e522dc 100644 --- a/hw/core/Makefile.objs +++ b/hw/core/Makefile.objs @@ -18,3 +18,5 @@ common-obj-$(CONFIG_SOFTMMU) += qdev-properties-system.o common-obj-$(CONFIG_SOFTMMU) += register.o common-obj-$(CONFIG_SOFTMMU) += or-irq.o common-obj-$(CONFIG_PLATFORM_BUS) += platform-bus.o + +obj-$(CONFIG_SOFTMMU) += generic-loader.o diff --git a/hw/core/generic-loader.c b/hw/core/generic-loader.c new file mode 100644 index 00000000000..79ab6df3575 --- /dev/null +++ b/hw/core/generic-loader.c @@ -0,0 +1,211 @@ +/* + * Generic Loader + * + * Copyright (C) 2014 Li Guang + * Copyright (C) 2016 Xilinx Inc. + * Written by Li Guang + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + */ + +/* + * Internally inside QEMU this is a device. It is a strange device that + * provides no hardware interface but allows QEMU to monkey patch memory + * specified when it is created. To be able to do this it has a reset + * callback that does the memory operations. + + * This device allows the user to monkey patch memory. To be able to do + * this it needs a backend to manage the datas, the same as other + * memory-related devices. In this case as the backend is so trivial we + * have merged it with the frontend instead of creating and maintaining a + * seperate backend. + */ + +#include "qemu/osdep.h" +#include "qom/cpu.h" +#include "hw/sysbus.h" +#include "sysemu/dma.h" +#include "hw/loader.h" +#include "qapi/error.h" +#include "hw/core/generic-loader.h" + +#define CPU_NONE 0xFFFFFFFF + +static void generic_loader_reset(void *opaque) +{ + GenericLoaderState *s = GENERIC_LOADER(opaque); + + if (s->set_pc) { + CPUClass *cc = CPU_GET_CLASS(s->cpu); + cpu_reset(s->cpu); + if (cc) { + cc->set_pc(s->cpu, s->addr); + } + } + + if (s->data_len) { + assert(s->data_len < sizeof(s->data)); + dma_memory_write(s->cpu->as, s->addr, &s->data, s->data_len); + } +} + +static void generic_loader_realize(DeviceState *dev, Error **errp) +{ + GenericLoaderState *s = GENERIC_LOADER(dev); + hwaddr entry; + int big_endian; + int size = 0; + + s->set_pc = false; + + /* Perform some error checking on the user's options */ + if (s->data || s->data_len || s->data_be) { + /* User is loading memory values */ + if (s->file) { + error_setg(errp, "Specifying a file is not supported when loading " + "memory values"); + return; + } else if (s->force_raw) { + error_setg(errp, "Specifying force-raw is not supported when " + "loading memory values"); + return; + } else if (!s->data_len) { + /* We cant' check for !data here as a value of 0 is still valid. */ + error_setg(errp, "Both data and data-len must be specified"); + return; + } else if (s->data_len > 8) { + error_setg(errp, "data-len cannot be greater then 8 bytes"); + return; + } + } else if (s->file || s->force_raw) { + /* User is loading an image */ + if (s->data || s->data_len || s->data_be) { + error_setg(errp, "data can not be specified when loading an " + "image"); + return; + } + s->set_pc = true; + } else if (s->addr) { + /* User is setting the PC */ + if (s->data || s->data_len || s->data_be) { + error_setg(errp, "data can not be specified when setting a " + "program counter"); + return; + } else if (!s->cpu_num) { + error_setg(errp, "cpu_num must be specified when setting a " + "program counter"); + return; + } + s->set_pc = true; + } else { + /* Did the user specify anything? */ + error_setg(errp, "please include valid arguments"); + return; + } + + qemu_register_reset(generic_loader_reset, dev); + + if (s->cpu_num != CPU_NONE) { + s->cpu = qemu_get_cpu(s->cpu_num); + if (!s->cpu) { + error_setg(errp, "Specified boot CPU#%d is nonexistent", + s->cpu_num); + return; + } + } else { + s->cpu = first_cpu; + } + +#ifdef TARGET_WORDS_BIGENDIAN + big_endian = 1; +#else + big_endian = 0; +#endif + + if (s->file) { + if (!s->force_raw) { + size = load_elf_as(s->file, NULL, NULL, &entry, NULL, NULL, + big_endian, 0, 0, 0, s->cpu->as); + + if (size < 0) { + size = load_uimage_as(s->file, &entry, NULL, NULL, NULL, NULL, + s->cpu->as); + } + } + + if (size < 0 || s->force_raw) { + /* Default to the maximum size being the machine's ram size */ + size = load_image_targphys_as(s->file, s->addr, ram_size, + s->cpu->as); + } else { + s->addr = entry; + } + + if (size < 0) { + error_setg(errp, "Cannot load specified image %s", s->file); + return; + } + } + + /* Convert the data endiannes */ + if (s->data_be) { + s->data = cpu_to_be64(s->data); + } else { + s->data = cpu_to_le64(s->data); + } +} + +static void generic_loader_unrealize(DeviceState *dev, Error **errp) +{ + qemu_unregister_reset(generic_loader_reset, dev); +} + +static Property generic_loader_props[] = { + DEFINE_PROP_UINT64("addr", GenericLoaderState, addr, 0), + DEFINE_PROP_UINT64("data", GenericLoaderState, data, 0), + DEFINE_PROP_UINT8("data-len", GenericLoaderState, data_len, 0), + DEFINE_PROP_BOOL("data-be", GenericLoaderState, data_be, false), + DEFINE_PROP_UINT32("cpu-num", GenericLoaderState, cpu_num, CPU_NONE), + DEFINE_PROP_BOOL("force-raw", GenericLoaderState, force_raw, false), + DEFINE_PROP_STRING("file", GenericLoaderState, file), + DEFINE_PROP_END_OF_LIST(), +}; + +static void generic_loader_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + /* The reset function is not registered here and is instead registered in + * the realize function to allow this device to be added via the device_add + * command in the QEMU monitor. + * TODO: Improve the device_add functionality to allow resets to be + * connected + */ + dc->realize = generic_loader_realize; + dc->unrealize = generic_loader_unrealize; + dc->props = generic_loader_props; + dc->desc = "Generic Loader"; +} + +static TypeInfo generic_loader_info = { + .name = TYPE_GENERIC_LOADER, + .parent = TYPE_DEVICE, + .instance_size = sizeof(GenericLoaderState), + .class_init = generic_loader_class_init, +}; + +static void generic_loader_register_type(void) +{ + type_register_static(&generic_loader_info); +} + +type_init(generic_loader_register_type) diff --git a/include/hw/core/generic-loader.h b/include/hw/core/generic-loader.h new file mode 100644 index 00000000000..dd27c42ab03 --- /dev/null +++ b/include/hw/core/generic-loader.h @@ -0,0 +1,46 @@ +/* + * Generic Loader + * + * Copyright (C) 2014 Li Guang + * Written by Li Guang + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#ifndef GENERIC_LOADER_H +#define GENERIC_LOADER_H + +#include "elf.h" + +typedef struct GenericLoaderState { + /* */ + DeviceState parent_obj; + + /* */ + CPUState *cpu; + + uint64_t addr; + uint64_t data; + uint8_t data_len; + uint32_t cpu_num; + + char *file; + + bool force_raw; + bool data_be; + bool set_pc; +} GenericLoaderState; + +#define TYPE_GENERIC_LOADER "loader" +#define GENERIC_LOADER(obj) OBJECT_CHECK(GenericLoaderState, (obj), \ + TYPE_GENERIC_LOADER) + +#endif From 03bf19535c2581937397e608335c111c03895ba8 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Tue, 4 Oct 2016 13:28:09 +0100 Subject: [PATCH 500/723] docs: Add a generic loader explanation document Signed-off-by: Alistair Francis Reviewed-by: Peter Maydell Message-id: 9d991a2df990cf55e2630410a5a03ea48930af5d.1475195078.git.alistair.francis@xilinx.com Signed-off-by: Peter Maydell --- docs/generic-loader.txt | 84 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 docs/generic-loader.txt diff --git a/docs/generic-loader.txt b/docs/generic-loader.txt new file mode 100644 index 00000000000..8fcb5504143 --- /dev/null +++ b/docs/generic-loader.txt @@ -0,0 +1,84 @@ +Copyright (c) 2016 Xilinx Inc. + +This work is licensed under the terms of the GNU GPL, version 2 or later. See +the COPYING file in the top-level directory. + + +The 'loader' device allows the user to load multiple images or values into +QEMU at startup. + +Loading Data into Memory Values +--------------------- +The loader device allows memory values to be set from the command line. This +can be done by following the syntax below: + + -device loader,addr=,data=,data-len= + [,data-be=][,cpu-num=] + + - The address to store the data in. + - The value to be written to the address. The maximum size of + the data is 8 bytes. + - The length of the data in bytes. This argument must be + included if the data argument is. + - Set to true if the data to be stored on the guest should be + written as big endian data. The default is to write little + endian data. + - The number of the CPU's address space where the data should + be loaded. If not specified the address space of the first + CPU is used. + +All values are parsed using the standard QemuOps parsing. This allows the user +to specify any values in any format supported. By default the values +will be parsed as decimal. To use hex values the user should prefix the number +with a '0x'. + +An example of loading value 0x8000000e to address 0xfd1a0104 is: + -device loader,addr=0xfd1a0104,data=0x8000000e,data-len=4 + +Setting a CPU's Program Counter +--------------------- +The loader device allows the CPU's PC to be set from the command line. This +can be done by following the syntax below: + + -device loader,addr=,cpu-num= + + - The value to use as the CPU's PC. + - The number of the CPU whose PC should be set to the + specified value. + +All values are parsed using the standard QemuOps parsing. This allows the user +to specify any values in any format supported. By default the values +will be parsed as decimal. To use hex values the user should prefix the number +with a '0x'. + +An example of setting CPU 0's PC to 0x8000 is: + -device loader,addr=0x8000,cpu-num=0 + +Loading Files +--------------------- +The loader device also allows files to be loaded into memory. This can be done +similarly to setting memory values. The syntax is shown below: + + -device loader,file=[,addr=][,cpu-num=][,force-raw=] + + - A file to be loaded into memory + - The addr in memory that the file should be loaded. This is + ignored if you are using an ELF (unless force-raw is true). + This is required if you aren't loading an ELF. + - This specifies the CPU that should be used. This is an + optional argument and will cause the CPU's PC to be set to + where the image is stored or in the case of an ELF file to + the value in the header. This option should only be used + for the boot image. + This will also cause the image to be written to the specified + CPU's address space. If not specified, the default is CPU 0. + - Forces the file to be treated as a raw image. This can be + used to specify the load address of ELF files. + +All values are parsed using the standard QemuOps parsing. This allows the user +to specify any values in any format supported. By default the values +will be parsed as decimal. To use hex values the user should prefix the number +with a '0x'. + +An example of loading an ELF file which CPU0 will boot is shown below: + -device loader,file=./images/boot.elf,cpu-num=0 From 79b2ac8f28748b09816d09bd62a2b49ddc01ebeb Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Tue, 4 Oct 2016 13:28:09 +0100 Subject: [PATCH 501/723] cadence_gem: Fix priority queue out of bounds access There was an error with some of the register implementation assuming there are 16 priority queues supported when the IP only supports 8. This patch corrects the registers to only support 8 queues. Signed-off-by: Alistair Francis Reported-by: Paolo Bonzini Message-id: 33bf2d28326d22875602234b8b15cf56fb678333.1474911607.git.alistair.francis@xilinx.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/net/cadence_gem.c | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index 8618e7acac7..7915732f74c 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -147,25 +147,19 @@ #define GEM_INT_Q1_MASK (0x00000640 / 4) #define GEM_TRANSMIT_Q1_PTR (0x00000440 / 4) -#define GEM_TRANSMIT_Q15_PTR (GEM_TRANSMIT_Q1_PTR + 14) +#define GEM_TRANSMIT_Q7_PTR (GEM_TRANSMIT_Q1_PTR + 6) #define GEM_RECEIVE_Q1_PTR (0x00000480 / 4) -#define GEM_RECEIVE_Q15_PTR (GEM_RECEIVE_Q1_PTR + 14) +#define GEM_RECEIVE_Q7_PTR (GEM_RECEIVE_Q1_PTR + 6) #define GEM_INT_Q1_ENABLE (0x00000600 / 4) #define GEM_INT_Q7_ENABLE (GEM_INT_Q1_ENABLE + 6) -#define GEM_INT_Q8_ENABLE (0x00000660 / 4) -#define GEM_INT_Q15_ENABLE (GEM_INT_Q8_ENABLE + 7) #define GEM_INT_Q1_DISABLE (0x00000620 / 4) #define GEM_INT_Q7_DISABLE (GEM_INT_Q1_DISABLE + 6) -#define GEM_INT_Q8_DISABLE (0x00000680 / 4) -#define GEM_INT_Q15_DISABLE (GEM_INT_Q8_DISABLE + 7) #define GEM_INT_Q1_MASK (0x00000640 / 4) #define GEM_INT_Q7_MASK (GEM_INT_Q1_MASK + 6) -#define GEM_INT_Q8_MASK (0x000006A0 / 4) -#define GEM_INT_Q15_MASK (GEM_INT_Q8_MASK + 7) #define GEM_SCREENING_TYPE1_REGISTER_0 (0x00000500 / 4) @@ -1372,13 +1366,13 @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val, case GEM_RXQBASE: s->rx_desc_addr[0] = val; break; - case GEM_RECEIVE_Q1_PTR ... GEM_RECEIVE_Q15_PTR: + case GEM_RECEIVE_Q1_PTR ... GEM_RECEIVE_Q7_PTR: s->rx_desc_addr[offset - GEM_RECEIVE_Q1_PTR + 1] = val; break; case GEM_TXQBASE: s->tx_desc_addr[0] = val; break; - case GEM_TRANSMIT_Q1_PTR ... GEM_TRANSMIT_Q15_PTR: + case GEM_TRANSMIT_Q1_PTR ... GEM_TRANSMIT_Q7_PTR: s->tx_desc_addr[offset - GEM_TRANSMIT_Q1_PTR + 1] = val; break; case GEM_RXSTATUS: @@ -1392,10 +1386,6 @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val, s->regs[GEM_INT_Q1_MASK + offset - GEM_INT_Q1_ENABLE] &= ~val; gem_update_int_status(s); break; - case GEM_INT_Q8_ENABLE ... GEM_INT_Q15_ENABLE: - s->regs[GEM_INT_Q8_MASK + offset - GEM_INT_Q8_ENABLE] &= ~val; - gem_update_int_status(s); - break; case GEM_IDR: s->regs[GEM_IMR] |= val; gem_update_int_status(s); @@ -1404,10 +1394,6 @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val, s->regs[GEM_INT_Q1_MASK + offset - GEM_INT_Q1_DISABLE] |= val; gem_update_int_status(s); break; - case GEM_INT_Q8_DISABLE ... GEM_INT_Q15_DISABLE: - s->regs[GEM_INT_Q8_MASK + offset - GEM_INT_Q8_DISABLE] |= val; - gem_update_int_status(s); - break; case GEM_SPADDR1LO: case GEM_SPADDR2LO: case GEM_SPADDR3LO: From 173ff58580b383a7841b18fddb293038c9d40d1c Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Tue, 4 Oct 2016 13:28:10 +0100 Subject: [PATCH 502/723] target-arm: A64: Fix decoding of iss_sf in disas_ld_lit Fix the decoding of iss_sf in disas_ld_lit. The SF (Sixty-Four) field in the ISS (Instruction Specific Syndrome) is a bit that specifies the width of the register that the instruction loads to. If cleared it specifies 32 bits. If set it specifies 64 bits. Signed-off-by: Edgar E. Iglesias Message-id: 1475230780-8669-1-git-send-email-edgar.iglesias@gmail.com [PMM: tweaked phrasing per on-list discussion] Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target-arm/translate-a64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c index ddf52f5e796..307e2815576 100644 --- a/target-arm/translate-a64.c +++ b/target-arm/translate-a64.c @@ -2025,7 +2025,7 @@ static void disas_ld_lit(DisasContext *s, uint32_t insn) do_fp_ld(s, rt, tcg_addr, size); } else { /* Only unsigned 32bit loads target 32bit registers. */ - bool iss_sf = opc == 0 ? 32 : 64; + bool iss_sf = opc != 0; do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed, false, true, rt, iss_sf, false); From 9b6a3ea7a699594162ed3d11e4e04b98568dc5c0 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 4 Oct 2016 13:28:10 +0100 Subject: [PATCH 503/723] target-arm: Correctly handle 'sub pc, pc, 1' for ARMv6 In the ARM v6 architecture, 'sub pc, pc, 1' is not an interworking branch, so the computed new value is written to r15 as a normal value. The architecture says that in this case, bits [1:0] of the value written must be ignored if we are in ARM mode (or bit [0] ignored if in Thumb mode); this is a change from the ARMv4/v5 specification that behaviour is UNPREDICTABLE. Use the correct mask on the PC value when doing a non-interworking store to PC. A popular library used on RaspberryPi uses this instruction as part of a trick to determine whether it is running on ARMv6 or ARMv7, and we were mishandling the sequence. Fixes bug: https://bugs.launchpad.net/bugs/1625295 Reported-by: Signed-off-by: Peter Maydell Message-id: 1474380941-4730-1-git-send-email-peter.maydell@linaro.org --- target-arm/translate.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 693d4bc6a24..8df24bf35a8 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -180,7 +180,12 @@ static inline TCGv_i32 load_reg(DisasContext *s, int reg) static void store_reg(DisasContext *s, int reg, TCGv_i32 var) { if (reg == 15) { - tcg_gen_andi_i32(var, var, ~1); + /* In Thumb mode, we must ignore bit 0. + * In ARM mode, for ARMv4 and ARMv5, it is UNPREDICTABLE if bits [1:0] + * are not 0b00, but for ARMv6 and above, we must ignore bits [1:0]. + * We choose to ignore [1:0] in ARM mode for all architecture versions. + */ + tcg_gen_andi_i32(var, var, s->thumb ? ~1 : ~3); s->is_jmp = DISAS_JUMP; } tcg_gen_mov_i32(cpu_R[reg], var); From 456d97d364e34adc4e68cbd51c2ad6ecd548492d Mon Sep 17 00:00:00 2001 From: Wanpeng Li Date: Fri, 23 Sep 2016 11:47:36 +0800 Subject: [PATCH 504/723] hmp: fix qemu crash due to ioapic state dump w/ split irqchip The qemu will crash when info ioapic through hmp if irqchip is split. Below message is splat: KVM_GET_IRQCHIP failed: Unknown error -6 This patch fix it by dumping the ioapic state from the qemu emulated ioapic if irqchip is split. Cc: Paolo Bonzini Cc: Richard Henderson Cc: Eduardo Habkost Signed-off-by: Wanpeng Li Message-Id: <1474602456-3232-1-git-send-email-wanpeng.li@hotmail.com> Reviewed-by: Peter Xu Message-ID: <20160923090824.GF15411@pxdev.xzpeter.org> Signed-off-by: Dr. David Alan Gilbert --- target-i386/monitor.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target-i386/monitor.c b/target-i386/monitor.c index fccfe40ab7b..9a3b4d746e8 100644 --- a/target-i386/monitor.c +++ b/target-i386/monitor.c @@ -504,7 +504,8 @@ void hmp_info_local_apic(Monitor *mon, const QDict *qdict) void hmp_info_io_apic(Monitor *mon, const QDict *qdict) { - if (kvm_irqchip_in_kernel()) { + if (kvm_irqchip_in_kernel() && + !kvm_irqchip_is_split()) { kvm_ioapic_dump_state(mon, qdict); } else { ioapic_dump_state(mon, qdict); From 196fe23734ca8888ca0275ad203ccb0d20907e6d Mon Sep 17 00:00:00 2001 From: Felipe Franciosi Date: Mon, 26 Sep 2016 15:17:44 +0100 Subject: [PATCH 505/723] spapr_vscsi: fix build error introduced by f19661c8 A typo introduced in f19661c8 prevents qemu from building when configured with --enable-trace-backend=dtrace. Signed-off-by: Felipe Franciosi Reviewed-by: Laurent Vivier Signed-off-by: David Gibson --- hw/scsi/spapr_vscsi.c | 2 +- hw/scsi/trace-events | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c index d8a2296b7ba..6090a204a03 100644 --- a/hw/scsi/spapr_vscsi.c +++ b/hw/scsi/spapr_vscsi.c @@ -658,7 +658,7 @@ static void vscsi_process_login(VSCSIState *s, vscsi_req *req) struct srp_login_rsp *rsp = &iu->srp.login_rsp; uint64_t tag = iu->srp.rsp.tag; - trace_spapr_vscsi__process_login(); + trace_spapr_vscsi_process_login(); /* TODO handle case that requested size is wrong and * buffer format is wrong diff --git a/hw/scsi/trace-events b/hw/scsi/trace-events index d1995b84f87..4a2e5d66df5 100644 --- a/hw/scsi/trace-events +++ b/hw/scsi/trace-events @@ -225,7 +225,7 @@ spapr_vscsi_command_complete_sense_data2(unsigned s8, unsigned s9, unsigned s10, spapr_vscsi_command_complete_status(uint32_t status) "Command complete err=%"PRIu32 spapr_vscsi_save_request(uint32_t qtag, unsigned desc, unsigned offset) "saving tag=%"PRIu32", current desc#%u, offset=0x%x" spapr_vscsi_load_request(uint32_t qtag, unsigned desc, unsigned offset) "restoring tag=%"PRIu32", current desc#%u, offset=0x%x" -spapr_vscsi__process_login(void) "Got login, sending response !" +spapr_vscsi_process_login(void) "Got login, sending response !" spapr_vscsi_queue_cmd_no_drive(uint64_t lun) "Command for lun %08" PRIx64 " with no drive" spapr_vscsi_queue_cmd(uint32_t qtag, unsigned cdb, const char *cmd, int lun, int ret) "Queued command tag 0x%"PRIx32" CMD 0x%x=%s LUN %d ret: %d" spapr_vscsi_do_crq(unsigned c0, unsigned c1) "crq: %02x %02x ..." From 1485ef1c45eb349c841c22b1d31a51a5ece68a89 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 26 Sep 2016 22:17:46 +0200 Subject: [PATCH 506/723] tests: Test IPv6 and ppc64 in the PXE tester The firmware of the pseries machine, SLOF, is able to load files via IPv6 networking, too. So to test both, network bootloading on ppc64 and IPv6 (via Slirp) , let's add some PXE tests for this environment, too. Since we can not use the normal x86 boot sector for network boot loading, we use a simple Forth script on ppc64 instead. Signed-off-by: Thomas Huth Signed-off-by: David Gibson --- tests/Makefile.include | 1 + tests/boot-sector.c | 9 +++++++++ tests/pxe-test.c | 22 +++++++++++++++------- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/tests/Makefile.include b/tests/Makefile.include index 8162f6f7357..77d42d78ac3 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -271,6 +271,7 @@ check-qtest-ppc64-y += tests/drive_del-test$(EXESUF) check-qtest-ppc64-y += tests/postcopy-test$(EXESUF) check-qtest-ppc64-y += tests/boot-serial-test$(EXESUF) check-qtest-ppc64-y += tests/rtas-test$(EXESUF) +check-qtest-ppc64-y += tests/pxe-test$(EXESUF) check-qtest-sh4-y = tests/endianness-test$(EXESUF) diff --git a/tests/boot-sector.c b/tests/boot-sector.c index 3ffe2987ff0..e3193c0a128 100644 --- a/tests/boot-sector.c +++ b/tests/boot-sector.c @@ -77,6 +77,15 @@ int boot_sector_init(const char *fname) fprintf(stderr, "Couldn't open \"%s\": %s", fname, strerror(errno)); return 1; } + + /* For Open Firmware based system, we can use a Forth script instead */ + if (strcmp(qtest_get_arch(), "ppc64") == 0) { + memset(boot_sector, ' ', sizeof boot_sector); + sprintf((char *)boot_sector, "\\ Bootscript\n%x %x c! %x %x c!\n", + LOW(SIGNATURE), BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET, + HIGH(SIGNATURE), BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET + 1); + } + fwrite(boot_sector, 1, sizeof boot_sector, f); fclose(f); return 0; diff --git a/tests/pxe-test.c b/tests/pxe-test.c index b2cc355a950..0bdb7a170a7 100644 --- a/tests/pxe-test.c +++ b/tests/pxe-test.c @@ -21,14 +21,14 @@ static const char *disk = "tests/pxe-test-disk.raw"; -static void test_pxe_one(const char *params) +static void test_pxe_one(const char *params, bool ipv6) { char *args; - args = g_strdup_printf("-machine accel=tcg " - "-netdev user,id=" NETNAME ",tftp=./,bootfile=%s " - "%s ", - disk, params); + args = g_strdup_printf("-machine accel=tcg -boot order=n " + "-netdev user,id=" NETNAME ",tftp=./,bootfile=%s," + "ipv4=%s,ipv6=%s %s", disk, ipv6 ? "off" : "on", + ipv6 ? "on" : "off", params); qtest_start(args); boot_sector_test(); @@ -38,12 +38,17 @@ static void test_pxe_one(const char *params) static void test_pxe_e1000(void) { - test_pxe_one("-device e1000,netdev=" NETNAME); + test_pxe_one("-device e1000,netdev=" NETNAME, false); } static void test_pxe_virtio_pci(void) { - test_pxe_one("-device virtio-net-pci,netdev=" NETNAME); + test_pxe_one("-device virtio-net-pci,netdev=" NETNAME, false); +} + +static void test_pxe_spapr_vlan(void) +{ + test_pxe_one("-vga none -device spapr-vlan,netdev=" NETNAME, true); } int main(int argc, char *argv[]) @@ -60,6 +65,9 @@ int main(int argc, char *argv[]) if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { qtest_add_func("pxe/e1000", test_pxe_e1000); qtest_add_func("pxe/virtio", test_pxe_virtio_pci); + } else if (strcmp(arch, "ppc64") == 0) { + qtest_add_func("pxe/virtio", test_pxe_virtio_pci); + qtest_add_func("pxe/spapr-vlan", test_pxe_spapr_vlan); } ret = g_test_run(); boot_sector_cleanup(disk); From db800b21d82a63eb88b06da9d1fb3d8a8e046aca Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 28 Sep 2016 14:31:55 +1000 Subject: [PATCH 507/723] pseries: Add 2.8 machine type, set up compatibility macros Now that 2.7 is released, create the pseries-2.8 machine type and add the boilerplate compatiblity macro stuff. There's nothing new to put into the 2.7 compatiliby properties yet, but we'll need something eventually, so we might as well get it ready now. Signed-off-by: David Gibson --- hw/ppc/spapr.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 14b6821a944..420ad1b741b 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -2436,19 +2436,37 @@ static const TypeInfo spapr_machine_info = { } \ type_init(spapr_machine_register_##suffix) +/* + * pseries-2.8 + */ +static void spapr_machine_2_8_instance_options(MachineState *machine) +{ +} + +static void spapr_machine_2_8_class_options(MachineClass *mc) +{ + /* Defaults for the latest behaviour inherited from the base class */ +} + +DEFINE_SPAPR_MACHINE(2_8, "2.8", true); + /* * pseries-2.7 */ +#define SPAPR_COMPAT_2_7 \ + HW_COMPAT_2_7 \ + static void spapr_machine_2_7_instance_options(MachineState *machine) { } static void spapr_machine_2_7_class_options(MachineClass *mc) { - /* Defaults for the latest behaviour inherited from the base class */ + spapr_machine_2_8_class_options(mc); + SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_7); } -DEFINE_SPAPR_MACHINE(2_7, "2.7", true); +DEFINE_SPAPR_MACHINE(2_7, "2.7", false); /* * pseries-2.6 From 230bf719d3a3b144a4ffa441e5d6170ef0ad8999 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 28 Sep 2016 13:16:28 +0200 Subject: [PATCH 508/723] hw/ppc/spapr: Move code related to "ibm,pa-features" to a separate function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function spapr_populate_cpu_dt() has become quite big already, and since we likely have to extend the pa-features property for every new processor generation, it is nicer if we put the related code into a separate function. Signed-off-by: Thomas Huth Reviewed-by: Cédric Le Goater Signed-off-by: David Gibson --- hw/ppc/spapr.c | 66 +++++++++++++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 420ad1b741b..8048f92eac7 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -546,6 +546,41 @@ static int spapr_populate_memory(sPAPRMachineState *spapr, void *fdt) return 0; } +/* Populate the "ibm,pa-features" property */ +static void spapr_populate_pa_features(CPUPPCState *env, void *fdt, int offset) +{ + uint8_t pa_features_206[] = { 6, 0, + 0xf6, 0x1f, 0xc7, 0x00, 0x80, 0xc0 }; + uint8_t pa_features_207[] = { 24, 0, + 0xf6, 0x1f, 0xc7, 0xc0, 0x80, 0xf0, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00 }; + uint8_t *pa_features; + size_t pa_size; + + if (env->mmu_model == POWERPC_MMU_2_06) { + pa_features = pa_features_206; + pa_size = sizeof(pa_features_206); + } else { /* env->mmu_model == POWERPC_MMU_2_07 */ + pa_features = pa_features_207; + pa_size = sizeof(pa_features_207); + } + + if (env->ci_large_pages) { + /* + * Note: we keep CI large pages off by default because a 64K capable + * guest provisioned with large pages might otherwise try to map a qemu + * framebuffer (or other kind of memory mapped PCI BAR) using 64K pages + * even if that qemu runs on a 4k host. + * We dd this bit back here if we are confident this is not an issue + */ + pa_features[3] |= 0x20; + } + + _FDT((fdt_setprop(fdt, offset, "ibm,pa-features", pa_features, pa_size))); +} + static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset, sPAPRMachineState *spapr) { @@ -573,24 +608,6 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset, _FDT((fdt_setprop_cell(fdt, offset, "ibm,my-drc-index", drc_index))); } - /* Note: we keep CI large pages off for now because a 64K capable guest - * provisioned with large pages might otherwise try to map a qemu - * framebuffer (or other kind of memory mapped PCI BAR) using 64K pages - * even if that qemu runs on a 4k host. - * - * We can later add this bit back when we are confident this is not - * an issue (!HV KVM or 64K host) - */ - uint8_t pa_features_206[] = { 6, 0, - 0xf6, 0x1f, 0xc7, 0x00, 0x80, 0xc0 }; - uint8_t pa_features_207[] = { 24, 0, - 0xf6, 0x1f, 0xc7, 0xc0, 0x80, 0xf0, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, - 0x80, 0x00, 0x80, 0x00, 0x80, 0x00 }; - uint8_t *pa_features; - size_t pa_size; - _FDT((fdt_setprop_cell(fdt, offset, "reg", index))); _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu"))); @@ -657,18 +674,7 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset, page_sizes_prop, page_sizes_prop_size))); } - /* Do the ibm,pa-features property, adjust it for ci-large-pages */ - if (env->mmu_model == POWERPC_MMU_2_06) { - pa_features = pa_features_206; - pa_size = sizeof(pa_features_206); - } else /* env->mmu_model == POWERPC_MMU_2_07 */ { - pa_features = pa_features_207; - pa_size = sizeof(pa_features_207); - } - if (env->ci_large_pages) { - pa_features[3] |= 0x20; - } - _FDT((fdt_setprop(fdt, offset, "ibm,pa-features", pa_features, pa_size))); + spapr_populate_pa_features(env, fdt, offset); _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id", cs->cpu_index / vcpus_per_socket))); From 4cbec30d769a73853b60dc7f275e6e7da9ab5162 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 28 Sep 2016 13:16:29 +0200 Subject: [PATCH 509/723] hw/ppc/spapr: Fix the selection of the processor features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current code uses pa_features_206 for POWERPC_MMU_2_06, and for everything else, it uses pa_features_207. This is bad in some cases because there is also a "degraded" MMU version of ISA 2.06, called POWERPC_MMU_2_06a, which should of course use the flags for 2.06 instead. And there is also the possibility that the user runs the pseries machine with a POWER5+ or even 970 processor. In that case we certainly do not want to set the flags for 2.07, and rather simply skip the setting of the pa-features property instead. Signed-off-by: Thomas Huth Reviewed-by: Cédric Le Goater Signed-off-by: David Gibson --- hw/ppc/spapr.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 8048f92eac7..8654108061d 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -559,12 +559,19 @@ static void spapr_populate_pa_features(CPUPPCState *env, void *fdt, int offset) uint8_t *pa_features; size_t pa_size; - if (env->mmu_model == POWERPC_MMU_2_06) { + switch (env->mmu_model) { + case POWERPC_MMU_2_06: + case POWERPC_MMU_2_06a: pa_features = pa_features_206; pa_size = sizeof(pa_features_206); - } else { /* env->mmu_model == POWERPC_MMU_2_07 */ + break; + case POWERPC_MMU_2_07: + case POWERPC_MMU_2_07a: pa_features = pa_features_207; pa_size = sizeof(pa_features_207); + break; + default: + return; } if (env->ci_large_pages) { From bac3bf287ab60e264b636f5f00c116a19b655762 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 28 Sep 2016 13:16:30 +0200 Subject: [PATCH 510/723] ppc: Check the availability of transactional memory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit KVM-PR currently does not support transactional memory, and the implementation in TCG is just a fake. We should not announce TM support in the ibm,pa-features property when running on such a system, so disable it by default and only enable it if the KVM implementation supports it (i.e. recent versions of KVM-HV). These changes are based on some earlier work from Anton Blanchard (thanks!). Signed-off-by: Thomas Huth Reviewed-by: Cédric Le Goater Signed-off-by: David Gibson --- hw/ppc/spapr.c | 5 ++++- target-ppc/kvm.c | 7 +++++++ target-ppc/kvm_ppc.h | 6 ++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 8654108061d..63b6a0dd46a 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -555,7 +555,7 @@ static void spapr_populate_pa_features(CPUPPCState *env, void *fdt, int offset) 0xf6, 0x1f, 0xc7, 0xc0, 0x80, 0xf0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, - 0x80, 0x00, 0x80, 0x00, 0x80, 0x00 }; + 0x80, 0x00, 0x80, 0x00, 0x00, 0x00 }; uint8_t *pa_features; size_t pa_size; @@ -584,6 +584,9 @@ static void spapr_populate_pa_features(CPUPPCState *env, void *fdt, int offset) */ pa_features[3] |= 0x20; } + if (kvmppc_has_cap_htm() && pa_size > 24) { + pa_features[24] |= 0x80; /* Transactional memory support */ + } _FDT((fdt_setprop(fdt, offset, "ibm,pa-features", pa_features, pa_size))); } diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index a18d4d5654b..e9a9fafb884 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -80,6 +80,7 @@ static int cap_ppc_watchdog; static int cap_papr; static int cap_htab_fd; static int cap_fixup_hcalls; +static int cap_htm; /* Hardware transactional memory support */ static uint32_t debug_inst_opcode; @@ -122,6 +123,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s) * only activated after this by kvmppc_set_papr() */ cap_htab_fd = kvm_check_extension(s, KVM_CAP_PPC_HTAB_FD); cap_fixup_hcalls = kvm_check_extension(s, KVM_CAP_PPC_FIXUP_HCALL); + cap_htm = kvm_vm_check_extension(s, KVM_CAP_PPC_HTM); if (!cap_interrupt_level) { fprintf(stderr, "KVM: Couldn't find level irq capability. Expect the " @@ -2353,6 +2355,11 @@ bool kvmppc_has_cap_fixup_hcalls(void) return cap_fixup_hcalls; } +bool kvmppc_has_cap_htm(void) +{ + return cap_htm; +} + static PowerPCCPUClass *ppc_cpu_get_family_class(PowerPCCPUClass *pcc) { ObjectClass *oc = OBJECT_CLASS(pcc); diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index a778184567d..bd1d78bfbe3 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -55,6 +55,7 @@ void kvmppc_hash64_free_pteg(uint64_t token); void kvmppc_hash64_write_pte(CPUPPCState *env, target_ulong pte_index, target_ulong pte0, target_ulong pte1); bool kvmppc_has_cap_fixup_hcalls(void); +bool kvmppc_has_cap_htm(void); int kvmppc_enable_hwrng(void); int kvmppc_put_books_sregs(PowerPCCPU *cpu); PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void); @@ -249,6 +250,11 @@ static inline bool kvmppc_has_cap_fixup_hcalls(void) abort(); } +static inline bool kvmppc_has_cap_htm(void) +{ + return false; +} + static inline int kvmppc_enable_hwrng(void) { return -1; From 6358320228010e0425955ca6ed32ac878b24f12a Mon Sep 17 00:00:00 2001 From: Ravi Bangoria Date: Thu, 29 Sep 2016 00:11:52 +0530 Subject: [PATCH 511/723] target-ppc: Implement mfvsrld instruction mfvsrld: Move From VSR Lower Doubleword Signed-off-by: Ravi Bangoria Signed-off-by: Nikunj A Dadhania Reviewed-by: Richard Henderson Signed-off-by: David Gibson --- target-ppc/translate/vsx-impl.inc.c | 17 +++++++++++++++++ target-ppc/translate/vsx-ops.inc.c | 1 + 2 files changed, 18 insertions(+) diff --git a/target-ppc/translate/vsx-impl.inc.c b/target-ppc/translate/vsx-impl.inc.c index eee6052d038..b669e8c818d 100644 --- a/target-ppc/translate/vsx-impl.inc.c +++ b/target-ppc/translate/vsx-impl.inc.c @@ -217,6 +217,23 @@ static void gen_##name(DisasContext *ctx) \ MV_VSRD(mfvsrd, cpu_gpr[rA(ctx->opcode)], cpu_vsrh(xS(ctx->opcode))) MV_VSRD(mtvsrd, cpu_vsrh(xT(ctx->opcode)), cpu_gpr[rA(ctx->opcode)]) +static void gen_mfvsrld(DisasContext *ctx) +{ + if (xS(ctx->opcode) < 32) { + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + } else { + if (unlikely(!ctx->altivec_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VPU); + return; + } + } + + tcg_gen_mov_i64(cpu_gpr[rA(ctx->opcode)], cpu_vsrl(xS(ctx->opcode))); +} + #endif static void gen_xxpermdi(DisasContext *ctx) diff --git a/target-ppc/translate/vsx-ops.inc.c b/target-ppc/translate/vsx-ops.inc.c index 414b73bd104..3b296f8efdc 100644 --- a/target-ppc/translate/vsx-ops.inc.c +++ b/target-ppc/translate/vsx-ops.inc.c @@ -22,6 +22,7 @@ GEN_HANDLER_E(mtvsrwz, 0x1F, 0x13, 0x07, 0x0000F800, PPC_NONE, PPC2_VSX207), #if defined(TARGET_PPC64) GEN_HANDLER_E(mfvsrd, 0x1F, 0x13, 0x01, 0x0000F800, PPC_NONE, PPC2_VSX207), GEN_HANDLER_E(mtvsrd, 0x1F, 0x13, 0x05, 0x0000F800, PPC_NONE, PPC2_VSX207), +GEN_HANDLER_E(mfvsrld, 0X1F, 0x13, 0x09, 0x0000F800, PPC_NONE, PPC2_ISA300), #endif #define GEN_XX1FORM(name, opc2, opc3, fl2) \ From b9731075b3c6417eca2bc14612688046c4b7f9e6 Mon Sep 17 00:00:00 2001 From: Ravi Bangoria Date: Thu, 29 Sep 2016 00:11:53 +0530 Subject: [PATCH 512/723] target-ppc: Implement mtvsrdd instruction mtvsrdd: Move To VSR Double Doubleword Signed-off-by: Ravi Bangoria Signed-off-by: Nikunj A Dadhania Reviewed-by: Richard Henderson Signed-off-by: David Gibson --- target-ppc/translate/vsx-impl.inc.c | 23 +++++++++++++++++++++++ target-ppc/translate/vsx-ops.inc.c | 1 + 2 files changed, 24 insertions(+) diff --git a/target-ppc/translate/vsx-impl.inc.c b/target-ppc/translate/vsx-impl.inc.c index b669e8c818d..c4c50ddb62c 100644 --- a/target-ppc/translate/vsx-impl.inc.c +++ b/target-ppc/translate/vsx-impl.inc.c @@ -234,6 +234,29 @@ static void gen_mfvsrld(DisasContext *ctx) tcg_gen_mov_i64(cpu_gpr[rA(ctx->opcode)], cpu_vsrl(xS(ctx->opcode))); } +static void gen_mtvsrdd(DisasContext *ctx) +{ + if (xT(ctx->opcode) < 32) { + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + } else { + if (unlikely(!ctx->altivec_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VPU); + return; + } + } + + if (!rA(ctx->opcode)) { + tcg_gen_movi_i64(cpu_vsrh(xT(ctx->opcode)), 0); + } else { + tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), cpu_gpr[rA(ctx->opcode)]); + } + + tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), cpu_gpr[rB(ctx->opcode)]); +} + #endif static void gen_xxpermdi(DisasContext *ctx) diff --git a/target-ppc/translate/vsx-ops.inc.c b/target-ppc/translate/vsx-ops.inc.c index 3b296f8efdc..1287973636c 100644 --- a/target-ppc/translate/vsx-ops.inc.c +++ b/target-ppc/translate/vsx-ops.inc.c @@ -23,6 +23,7 @@ GEN_HANDLER_E(mtvsrwz, 0x1F, 0x13, 0x07, 0x0000F800, PPC_NONE, PPC2_VSX207), GEN_HANDLER_E(mfvsrd, 0x1F, 0x13, 0x01, 0x0000F800, PPC_NONE, PPC2_VSX207), GEN_HANDLER_E(mtvsrd, 0x1F, 0x13, 0x05, 0x0000F800, PPC_NONE, PPC2_VSX207), GEN_HANDLER_E(mfvsrld, 0X1F, 0x13, 0x09, 0x0000F800, PPC_NONE, PPC2_ISA300), +GEN_HANDLER_E(mtvsrdd, 0X1F, 0x13, 0x0D, 0x0, PPC_NONE, PPC2_ISA300), #endif #define GEN_XX1FORM(name, opc2, opc3, fl2) \ From f34001ec96ebc126aad49db4e3e01391b28ed264 Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Thu, 29 Sep 2016 00:11:55 +0530 Subject: [PATCH 513/723] target-ppc: improve lxvw4x implementation Load 8byte at a time and manipulate. Big-Endian Storage +-------------+-------------+-------------+-------------+ | 00 11 22 33 | 44 55 66 77 | 88 99 AA BB | CC DD EE FF | +-------------+-------------+-------------+-------------+ Little-Endian Storage +-------------+-------------+-------------+-------------+ | 33 22 11 00 | 77 66 55 44 | BB AA 99 88 | FF EE DD CC | +-------------+-------------+-------------+-------------+ Vector load results in (32-bit elements): +----------+----------+----------+----------+ | 00112233 | 44556677 | 8899AABB | CCDDEEFF | +----------+----------+----------+----------+ Signed-off-by: Nikunj A Dadhania Reviewed-by: Richard Henderson [dwg: Slight tweak to commit description] Signed-off-by: David Gibson --- target-ppc/translate/vsx-impl.inc.c | 32 ++++++++++++++++------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/target-ppc/translate/vsx-impl.inc.c b/target-ppc/translate/vsx-impl.inc.c index c4c50ddb62c..ec871b24307 100644 --- a/target-ppc/translate/vsx-impl.inc.c +++ b/target-ppc/translate/vsx-impl.inc.c @@ -75,7 +75,6 @@ static void gen_lxvdsx(DisasContext *ctx) static void gen_lxvw4x(DisasContext *ctx) { TCGv EA; - TCGv_i64 tmp; TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode)); TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode)); if (unlikely(!ctx->vsx_enabled)) { @@ -84,22 +83,27 @@ static void gen_lxvw4x(DisasContext *ctx) } gen_set_access_type(ctx, ACCESS_INT); EA = tcg_temp_new(); - tmp = tcg_temp_new_i64(); gen_addr_reg_index(ctx, EA); - gen_qemu_ld32u_i64(ctx, tmp, EA); - tcg_gen_addi_tl(EA, EA, 4); - gen_qemu_ld32u_i64(ctx, xth, EA); - tcg_gen_deposit_i64(xth, xth, tmp, 32, 32); - - tcg_gen_addi_tl(EA, EA, 4); - gen_qemu_ld32u_i64(ctx, tmp, EA); - tcg_gen_addi_tl(EA, EA, 4); - gen_qemu_ld32u_i64(ctx, xtl, EA); - tcg_gen_deposit_i64(xtl, xtl, tmp, 32, 32); - + if (ctx->le_mode) { + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + + tcg_gen_qemu_ld_i64(t0, EA, ctx->mem_idx, MO_LEQ); + tcg_gen_shri_i64(t1, t0, 32); + tcg_gen_deposit_i64(xth, t1, t0, 32, 32); + tcg_gen_addi_tl(EA, EA, 8); + tcg_gen_qemu_ld_i64(t0, EA, ctx->mem_idx, MO_LEQ); + tcg_gen_shri_i64(t1, t0, 32); + tcg_gen_deposit_i64(xtl, t1, t0, 32, 32); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); + } else { + tcg_gen_qemu_ld_i64(xth, EA, ctx->mem_idx, MO_BEQ); + tcg_gen_addi_tl(EA, EA, 8); + tcg_gen_qemu_ld_i64(xtl, EA, ctx->mem_idx, MO_BEQ); + } tcg_temp_free(EA); - tcg_temp_free_i64(tmp); } #define VSX_STORE_SCALAR(name, operation) \ From 0aec21d8fa1be9a2b57b0e018b36ba566508d21c Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Thu, 29 Sep 2016 00:11:56 +0530 Subject: [PATCH 514/723] target-ppc: improve stxvw4x implementation Manipulate data and store 8bytes instead of 4bytes. Vector (32-bit elements): +----------+----------+----------+----------+ | 00112233 | 44556677 | 8899AABB | CCDDEEFF | +----------+----------+----------+----------+ Store results in following: Big-Endian Storage +-------------+-------------+-------------+-------------+ | 00 11 22 33 | 44 55 66 77 | 88 99 AA BB | CC DD EE FF | +-------------+-------------+-------------+-------------+ Little-Endian Storage +-------------+-------------+-------------+-------------+ | 33 22 11 00 | 77 66 55 44 | BB AA 99 88 | FF EE DD CC | +-------------+-------------+-------------+-------------+ Signed-off-by: Nikunj A Dadhania Reviewed-by: Richard Henderson Signed-off-by: David Gibson --- target-ppc/translate/vsx-impl.inc.c | 33 +++++++++++++++++------------ 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/target-ppc/translate/vsx-impl.inc.c b/target-ppc/translate/vsx-impl.inc.c index ec871b24307..a7e35d06e93 100644 --- a/target-ppc/translate/vsx-impl.inc.c +++ b/target-ppc/translate/vsx-impl.inc.c @@ -146,7 +146,8 @@ static void gen_stxvd2x(DisasContext *ctx) static void gen_stxvw4x(DisasContext *ctx) { - TCGv_i64 tmp; + TCGv_i64 xsh = cpu_vsrh(xS(ctx->opcode)); + TCGv_i64 xsl = cpu_vsrl(xS(ctx->opcode)); TCGv EA; if (unlikely(!ctx->vsx_enabled)) { gen_exception(ctx, POWERPC_EXCP_VSXU); @@ -155,21 +156,25 @@ static void gen_stxvw4x(DisasContext *ctx) gen_set_access_type(ctx, ACCESS_INT); EA = tcg_temp_new(); gen_addr_reg_index(ctx, EA); - tmp = tcg_temp_new_i64(); - - tcg_gen_shri_i64(tmp, cpu_vsrh(xS(ctx->opcode)), 32); - gen_qemu_st32_i64(ctx, tmp, EA); - tcg_gen_addi_tl(EA, EA, 4); - gen_qemu_st32_i64(ctx, cpu_vsrh(xS(ctx->opcode)), EA); - - tcg_gen_shri_i64(tmp, cpu_vsrl(xS(ctx->opcode)), 32); - tcg_gen_addi_tl(EA, EA, 4); - gen_qemu_st32_i64(ctx, tmp, EA); - tcg_gen_addi_tl(EA, EA, 4); - gen_qemu_st32_i64(ctx, cpu_vsrl(xS(ctx->opcode)), EA); + if (ctx->le_mode) { + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + tcg_gen_shri_i64(t0, xsh, 32); + tcg_gen_deposit_i64(t1, t0, xsh, 32, 32); + tcg_gen_qemu_st_i64(t1, EA, ctx->mem_idx, MO_LEQ); + tcg_gen_addi_tl(EA, EA, 8); + tcg_gen_shri_i64(t0, xsl, 32); + tcg_gen_deposit_i64(t1, t0, xsl, 32, 32); + tcg_gen_qemu_st_i64(t1, EA, ctx->mem_idx, MO_LEQ); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); + } else { + tcg_gen_qemu_st_i64(xsh, EA, ctx->mem_idx, MO_BEQ); + tcg_gen_addi_tl(EA, EA, 8); + tcg_gen_qemu_st_i64(xsl, EA, ctx->mem_idx, MO_BEQ); + } tcg_temp_free(EA); - tcg_temp_free_i64(tmp); } #define MV_VSRW(name, tcgop1, tcgop2, target, source) \ From 1c0744190ca69732da13d49f6cb48e648dff9a40 Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Thu, 29 Sep 2016 00:11:57 +0530 Subject: [PATCH 515/723] target-ppc: add lxvh8x instruction lxvh8x: Load VSX Vector Halfword*8 Big-Endian Storage +-------+-------+-------+-------+-------+-------+-------+-------+ | 00 01 | 10 11 | 20 21 | 30 31 | 40 41 | 50 51 | 60 61 | 70 71 | +-------+-------+-------+-------+-------+-------+-------+-------+ Little-Endian Storage +-------+-------+-------+-------+-------+-------+-------+-------+ | 01 00 | 11 10 | 21 20 | 31 30 | 41 40 | 51 50 | 61 60 | 71 70 | +-------+-------+-------+-------+-------+-------+-------+-------+ Vector load results in (16-bit elements): +------+------+------+------+------+------+------+------+ | 0001 | 1011 | 2021 | 3031 | 4041 | 5051 | 6061 | 7071 | +------+------+------+------+------+------+------+------+ Signed-off-by: Nikunj A Dadhania Reviewed-by: Richard Henderson [dwg: Tweak to commit description] Signed-off-by: David Gibson --- target-ppc/translate/vsx-impl.inc.c | 49 +++++++++++++++++++++++++++++ target-ppc/translate/vsx-ops.inc.c | 1 + 2 files changed, 50 insertions(+) diff --git a/target-ppc/translate/vsx-impl.inc.c b/target-ppc/translate/vsx-impl.inc.c index a7e35d06e93..1376be8ddfd 100644 --- a/target-ppc/translate/vsx-impl.inc.c +++ b/target-ppc/translate/vsx-impl.inc.c @@ -106,6 +106,55 @@ static void gen_lxvw4x(DisasContext *ctx) tcg_temp_free(EA); } +static void gen_bswap16x8(TCGv_i64 outh, TCGv_i64 outl, + TCGv_i64 inh, TCGv_i64 inl) +{ + TCGv_i64 mask = tcg_const_i64(0x00FF00FF00FF00FF); + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + + /* outh = ((inh & mask) << 8) | ((inh >> 8) & mask) */ + tcg_gen_and_i64(t0, inh, mask); + tcg_gen_shli_i64(t0, t0, 8); + tcg_gen_shri_i64(t1, inh, 8); + tcg_gen_and_i64(t1, t1, mask); + tcg_gen_or_i64(outh, t0, t1); + + /* outl = ((inl & mask) << 8) | ((inl >> 8) & mask) */ + tcg_gen_and_i64(t0, inl, mask); + tcg_gen_shli_i64(t0, t0, 8); + tcg_gen_shri_i64(t1, inl, 8); + tcg_gen_and_i64(t1, t1, mask); + tcg_gen_or_i64(outl, t0, t1); + + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); + tcg_temp_free_i64(mask); +} + +static void gen_lxvh8x(DisasContext *ctx) +{ + TCGv EA; + TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode)); + TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode)); + + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + gen_set_access_type(ctx, ACCESS_INT); + + EA = tcg_temp_new(); + gen_addr_reg_index(ctx, EA); + tcg_gen_qemu_ld_i64(xth, EA, ctx->mem_idx, MO_BEQ); + tcg_gen_addi_tl(EA, EA, 8); + tcg_gen_qemu_ld_i64(xtl, EA, ctx->mem_idx, MO_BEQ); + if (ctx->le_mode) { + gen_bswap16x8(xth, xtl, xth, xtl); + } + tcg_temp_free(EA); +} + #define VSX_STORE_SCALAR(name, operation) \ static void gen_##name(DisasContext *ctx) \ { \ diff --git a/target-ppc/translate/vsx-ops.inc.c b/target-ppc/translate/vsx-ops.inc.c index 1287973636c..322fd5bb2f5 100644 --- a/target-ppc/translate/vsx-ops.inc.c +++ b/target-ppc/translate/vsx-ops.inc.c @@ -7,6 +7,7 @@ GEN_HANDLER_E(lxsspx, 0x1F, 0x0C, 0x10, 0, PPC_NONE, PPC2_VSX207), GEN_HANDLER_E(lxvd2x, 0x1F, 0x0C, 0x1A, 0, PPC_NONE, PPC2_VSX), GEN_HANDLER_E(lxvdsx, 0x1F, 0x0C, 0x0A, 0, PPC_NONE, PPC2_VSX), GEN_HANDLER_E(lxvw4x, 0x1F, 0x0C, 0x18, 0, PPC_NONE, PPC2_VSX), +GEN_HANDLER_E(lxvh8x, 0x1F, 0x0C, 0x19, 0, PPC_NONE, PPC2_ISA300), GEN_HANDLER_E(stxsdx, 0x1F, 0xC, 0x16, 0, PPC_NONE, PPC2_VSX), GEN_HANDLER_E(stxsibx, 0x1F, 0xD, 0x1C, 0, PPC_NONE, PPC2_ISA300), From 0b8ac648ecb02c4d157101c032518390b949e770 Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Thu, 29 Sep 2016 00:11:58 +0530 Subject: [PATCH 516/723] target-ppc: add stxvh8x instruction stxvh8x: Store VSX Vector Halfword*8 Vector (16-bit elements): +------+------+------+------+------+------+------+------+ | 0001 | 1011 | 2021 | 3031 | 4041 | 5051 | 6061 | 7071 | +------+------+------+------+------+------+------+------+ Store results in following: Big-Endian Storage +-------+-------+-------+-------+-------+-------+-------+-------+ | 00 01 | 10 11 | 20 21 | 30 31 | 40 41 | 50 51 | 60 61 | 70 71 | +-------+-------+-------+-------+-------+-------+-------+-------+ Little-Endian Storage +-------+-------+-------+-------+-------+-------+-------+-------+ | 01 00 | 11 10 | 21 20 | 31 30 | 41 40 | 51 50 | 61 60 | 71 70 | +-------+-------+-------+-------+-------+-------+-------+-------+ Signed-off-by: Nikunj A Dadhania Reviewed-by: Richard Henderson [dwg: Tweak commit description] Signed-off-by: David Gibson --- target-ppc/translate/vsx-impl.inc.c | 31 +++++++++++++++++++++++++++++ target-ppc/translate/vsx-ops.inc.c | 1 + 2 files changed, 32 insertions(+) diff --git a/target-ppc/translate/vsx-impl.inc.c b/target-ppc/translate/vsx-impl.inc.c index 1376be8ddfd..ed55e97cc4c 100644 --- a/target-ppc/translate/vsx-impl.inc.c +++ b/target-ppc/translate/vsx-impl.inc.c @@ -226,6 +226,37 @@ static void gen_stxvw4x(DisasContext *ctx) tcg_temp_free(EA); } +static void gen_stxvh8x(DisasContext *ctx) +{ + TCGv_i64 xsh = cpu_vsrh(xS(ctx->opcode)); + TCGv_i64 xsl = cpu_vsrl(xS(ctx->opcode)); + TCGv EA; + + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + gen_set_access_type(ctx, ACCESS_INT); + EA = tcg_temp_new(); + gen_addr_reg_index(ctx, EA); + if (ctx->le_mode) { + TCGv_i64 outh = tcg_temp_new_i64(); + TCGv_i64 outl = tcg_temp_new_i64(); + + gen_bswap16x8(outh, outl, xsh, xsl); + tcg_gen_qemu_st_i64(outh, EA, ctx->mem_idx, MO_BEQ); + tcg_gen_addi_tl(EA, EA, 8); + tcg_gen_qemu_st_i64(outl, EA, ctx->mem_idx, MO_BEQ); + tcg_temp_free_i64(outh); + tcg_temp_free_i64(outl); + } else { + tcg_gen_qemu_st_i64(xsh, EA, ctx->mem_idx, MO_BEQ); + tcg_gen_addi_tl(EA, EA, 8); + tcg_gen_qemu_st_i64(xsl, EA, ctx->mem_idx, MO_BEQ); + } + tcg_temp_free(EA); +} + #define MV_VSRW(name, tcgop1, tcgop2, target, source) \ static void gen_##name(DisasContext *ctx) \ { \ diff --git a/target-ppc/translate/vsx-ops.inc.c b/target-ppc/translate/vsx-ops.inc.c index 322fd5bb2f5..9abea1a1b13 100644 --- a/target-ppc/translate/vsx-ops.inc.c +++ b/target-ppc/translate/vsx-ops.inc.c @@ -16,6 +16,7 @@ GEN_HANDLER_E(stxsiwx, 0x1F, 0xC, 0x04, 0, PPC_NONE, PPC2_VSX207), GEN_HANDLER_E(stxsspx, 0x1F, 0xC, 0x14, 0, PPC_NONE, PPC2_VSX207), GEN_HANDLER_E(stxvd2x, 0x1F, 0xC, 0x1E, 0, PPC_NONE, PPC2_VSX), GEN_HANDLER_E(stxvw4x, 0x1F, 0xC, 0x1C, 0, PPC_NONE, PPC2_VSX), +GEN_HANDLER_E(stxvh8x, 0x1F, 0x0C, 0x1D, 0, PPC_NONE, PPC2_ISA300), GEN_HANDLER_E(mfvsrwz, 0x1F, 0x13, 0x03, 0x0000F800, PPC_NONE, PPC2_VSX207), GEN_HANDLER_E(mtvsrwa, 0x1F, 0x13, 0x06, 0x0000F800, PPC_NONE, PPC2_VSX207), From 8ee38face981c0da805a35e681cfe141191a3569 Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Thu, 29 Sep 2016 00:11:59 +0530 Subject: [PATCH 517/723] target-ppc: add lxvb16x instruction lxvb16x: Load VSX Vector Byte*16 Little/Big-endian Storage +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ |F0|F1|F2|F3|F4|F5|F6|F7|E0|E1|E2|E3|E4|E5|E6|E7| +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ Vector load results in (8-bit elements): +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ |F0|F1|F2|F3|F4|F5|F6|F7|E0|E1|E2|E3|E4|E5|E6|E7| +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ Signed-off-by: Nikunj A Dadhania Reviewed-by: Richard Henderson Signed-off-by: David Gibson --- target-ppc/translate/vsx-impl.inc.c | 19 +++++++++++++++++++ target-ppc/translate/vsx-ops.inc.c | 1 + 2 files changed, 20 insertions(+) diff --git a/target-ppc/translate/vsx-impl.inc.c b/target-ppc/translate/vsx-impl.inc.c index ed55e97cc4c..cddb90bb5c7 100644 --- a/target-ppc/translate/vsx-impl.inc.c +++ b/target-ppc/translate/vsx-impl.inc.c @@ -155,6 +155,25 @@ static void gen_lxvh8x(DisasContext *ctx) tcg_temp_free(EA); } +static void gen_lxvb16x(DisasContext *ctx) +{ + TCGv EA; + TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode)); + TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode)); + + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + gen_set_access_type(ctx, ACCESS_INT); + EA = tcg_temp_new(); + gen_addr_reg_index(ctx, EA); + tcg_gen_qemu_ld_i64(xth, EA, ctx->mem_idx, MO_BEQ); + tcg_gen_addi_tl(EA, EA, 8); + tcg_gen_qemu_ld_i64(xtl, EA, ctx->mem_idx, MO_BEQ); + tcg_temp_free(EA); +} + #define VSX_STORE_SCALAR(name, operation) \ static void gen_##name(DisasContext *ctx) \ { \ diff --git a/target-ppc/translate/vsx-ops.inc.c b/target-ppc/translate/vsx-ops.inc.c index 9abea1a1b13..e7683116b26 100644 --- a/target-ppc/translate/vsx-ops.inc.c +++ b/target-ppc/translate/vsx-ops.inc.c @@ -8,6 +8,7 @@ GEN_HANDLER_E(lxvd2x, 0x1F, 0x0C, 0x1A, 0, PPC_NONE, PPC2_VSX), GEN_HANDLER_E(lxvdsx, 0x1F, 0x0C, 0x0A, 0, PPC_NONE, PPC2_VSX), GEN_HANDLER_E(lxvw4x, 0x1F, 0x0C, 0x18, 0, PPC_NONE, PPC2_VSX), GEN_HANDLER_E(lxvh8x, 0x1F, 0x0C, 0x19, 0, PPC_NONE, PPC2_ISA300), +GEN_HANDLER_E(lxvb16x, 0x1F, 0x0C, 0x1B, 0, PPC_NONE, PPC2_ISA300), GEN_HANDLER_E(stxsdx, 0x1F, 0xC, 0x16, 0, PPC_NONE, PPC2_VSX), GEN_HANDLER_E(stxsibx, 0x1F, 0xD, 0x1C, 0, PPC_NONE, PPC2_ISA300), From f3333ce0b50924cf1b3abe2802789125d91e6474 Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Thu, 29 Sep 2016 00:12:00 +0530 Subject: [PATCH 518/723] target-ppc: add stxvb16x instruction stxvb16x: Store VSX Vector Byte*16 Vector (8-bit elements): +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ |F0|F1|F2|F3|F4|F5|F6|F7|E0|E1|E2|E3|E4|E5|E6|E7| +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ Store results in following: Little/Big-endian Storage +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ |F0|F1|F2|F3|F4|F5|F6|F7|E0|E1|E2|E3|E4|E5|E6|E7| +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ Signed-off-by: Nikunj A Dadhania Reviewed-by: Richard Henderson Signed-off-by: David Gibson --- target-ppc/translate/vsx-impl.inc.c | 19 +++++++++++++++++++ target-ppc/translate/vsx-ops.inc.c | 1 + 2 files changed, 20 insertions(+) diff --git a/target-ppc/translate/vsx-impl.inc.c b/target-ppc/translate/vsx-impl.inc.c index cddb90bb5c7..4120c0145c6 100644 --- a/target-ppc/translate/vsx-impl.inc.c +++ b/target-ppc/translate/vsx-impl.inc.c @@ -276,6 +276,25 @@ static void gen_stxvh8x(DisasContext *ctx) tcg_temp_free(EA); } +static void gen_stxvb16x(DisasContext *ctx) +{ + TCGv_i64 xsh = cpu_vsrh(xS(ctx->opcode)); + TCGv_i64 xsl = cpu_vsrl(xS(ctx->opcode)); + TCGv EA; + + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + gen_set_access_type(ctx, ACCESS_INT); + EA = tcg_temp_new(); + gen_addr_reg_index(ctx, EA); + tcg_gen_qemu_st_i64(xsh, EA, ctx->mem_idx, MO_BEQ); + tcg_gen_addi_tl(EA, EA, 8); + tcg_gen_qemu_st_i64(xsl, EA, ctx->mem_idx, MO_BEQ); + tcg_temp_free(EA); +} + #define MV_VSRW(name, tcgop1, tcgop2, target, source) \ static void gen_##name(DisasContext *ctx) \ { \ diff --git a/target-ppc/translate/vsx-ops.inc.c b/target-ppc/translate/vsx-ops.inc.c index e7683116b26..c49ba6dab9a 100644 --- a/target-ppc/translate/vsx-ops.inc.c +++ b/target-ppc/translate/vsx-ops.inc.c @@ -18,6 +18,7 @@ GEN_HANDLER_E(stxsspx, 0x1F, 0xC, 0x14, 0, PPC_NONE, PPC2_VSX207), GEN_HANDLER_E(stxvd2x, 0x1F, 0xC, 0x1E, 0, PPC_NONE, PPC2_VSX), GEN_HANDLER_E(stxvw4x, 0x1F, 0xC, 0x1C, 0, PPC_NONE, PPC2_VSX), GEN_HANDLER_E(stxvh8x, 0x1F, 0x0C, 0x1D, 0, PPC_NONE, PPC2_ISA300), +GEN_HANDLER_E(stxvb16x, 0x1F, 0x0C, 0x1F, 0, PPC_NONE, PPC2_ISA300), GEN_HANDLER_E(mfvsrwz, 0x1F, 0x13, 0x03, 0x0000F800, PPC_NONE, PPC2_VSX207), GEN_HANDLER_E(mtvsrwa, 0x1F, 0x13, 0x06, 0x0000F800, PPC_NONE, PPC2_VSX207), From 4aaefd93b9a7f5fdef83a757702b228d2144112a Mon Sep 17 00:00:00 2001 From: Avinesh Kumar Date: Wed, 28 Sep 2016 11:15:16 +0530 Subject: [PATCH 519/723] target-ppc: fix invalid mask - cmpl, bctar cmpl: invalid bit mask should be 0x00400001 bctar: invalid bit mask should be 0x0000E000 Signed-off-by: Avinesh Kumar Signed-off-by: Rajalakshmi Srinivasaraghavan Signed-off-by: David Gibson --- target-ppc/translate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 8eefd8231dd..dab8f19a916 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -6203,7 +6203,7 @@ static opcode_t opcodes[] = { GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, PPC_NONE), GEN_HANDLER(cmp, 0x1F, 0x00, 0x00, 0x00400000, PPC_INTEGER), GEN_HANDLER(cmpi, 0x0B, 0xFF, 0xFF, 0x00400000, PPC_INTEGER), -GEN_HANDLER(cmpl, 0x1F, 0x00, 0x01, 0x00400000, PPC_INTEGER), +GEN_HANDLER(cmpl, 0x1F, 0x00, 0x01, 0x00400001, PPC_INTEGER), GEN_HANDLER(cmpli, 0x0A, 0xFF, 0xFF, 0x00400000, PPC_INTEGER), #if defined(TARGET_PPC64) GEN_HANDLER_E(cmpeqb, 0x1F, 0x00, 0x07, 0x00600000, PPC_NONE, PPC2_ISA300), @@ -6297,7 +6297,7 @@ GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW), GEN_HANDLER(bc, 0x10, 0xFF, 0xFF, 0x00000000, PPC_FLOW), GEN_HANDLER(bcctr, 0x13, 0x10, 0x10, 0x00000000, PPC_FLOW), GEN_HANDLER(bclr, 0x13, 0x10, 0x00, 0x00000000, PPC_FLOW), -GEN_HANDLER_E(bctar, 0x13, 0x10, 0x11, 0, PPC_NONE, PPC2_BCTAR_ISA207), +GEN_HANDLER_E(bctar, 0x13, 0x10, 0x11, 0x0000E000, PPC_NONE, PPC2_BCTAR_ISA207), GEN_HANDLER(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PPC_INTEGER), GEN_HANDLER(rfi, 0x13, 0x12, 0x01, 0x03FF8001, PPC_FLOW), #if defined(TARGET_PPC64) From 0fa59364348e9cb52c48b0d83a1ceaed840854aa Mon Sep 17 00:00:00 2001 From: Rajalakshmi Srinivasaraghavan Date: Wed, 28 Sep 2016 11:15:17 +0530 Subject: [PATCH 520/723] target-ppc: add vector compare not equal instructions The following vector compare not equal instructions are added from ISA 3.0. vcmpneb - Vector Compare Not Equal Byte vcmpneh - Vector Compare Not Equal Halfword vcmpnew - Vector Compare Not Equal Word Signed-off-by: Rajalakshmi Srinivasaraghavan Reviewed-by: Richard Henderson Signed-off-by: David Gibson --- target-ppc/helper.h | 6 ++++++ target-ppc/int_helper.c | 31 ++++++++++++++++++----------- target-ppc/translate/vmx-impl.inc.c | 11 +++++++++- target-ppc/translate/vmx-ops.inc.c | 6 +++--- 4 files changed, 38 insertions(+), 16 deletions(-) diff --git a/target-ppc/helper.h b/target-ppc/helper.h index a1c29628bd7..91c208226fb 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -147,6 +147,9 @@ DEF_HELPER_4(vcmpequb, void, env, avr, avr, avr) DEF_HELPER_4(vcmpequh, void, env, avr, avr, avr) DEF_HELPER_4(vcmpequw, void, env, avr, avr, avr) DEF_HELPER_4(vcmpequd, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpneb, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpneh, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpnew, void, env, avr, avr, avr) DEF_HELPER_4(vcmpnezb, void, env, avr, avr, avr) DEF_HELPER_4(vcmpnezh, void, env, avr, avr, avr) DEF_HELPER_4(vcmpnezw, void, env, avr, avr, avr) @@ -166,6 +169,9 @@ DEF_HELPER_4(vcmpequb_dot, void, env, avr, avr, avr) DEF_HELPER_4(vcmpequh_dot, void, env, avr, avr, avr) DEF_HELPER_4(vcmpequw_dot, void, env, avr, avr, avr) DEF_HELPER_4(vcmpequd_dot, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpneb_dot, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpneh_dot, void, env, avr, avr, avr) +DEF_HELPER_4(vcmpnew_dot, void, env, avr, avr, avr) DEF_HELPER_4(vcmpnezb_dot, void, env, avr, avr, avr) DEF_HELPER_4(vcmpnezh_dot, void, env, avr, avr, avr) DEF_HELPER_4(vcmpnezw_dot, void, env, avr, avr, avr) diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c index 51a9ac51827..77d6bced892 100644 --- a/target-ppc/int_helper.c +++ b/target-ppc/int_helper.c @@ -735,20 +735,24 @@ VCMP(gtsd, >, s64) #undef VCMP_DO #undef VCMP -#define VCMPNEZ_DO(suffix, element, etype, record) \ -void helper_vcmpnez##suffix(CPUPPCState *env, ppc_avr_t *r, \ +#define VCMPNE_DO(suffix, element, etype, cmpzero, record) \ +void helper_vcmpne##suffix(CPUPPCState *env, ppc_avr_t *r, \ ppc_avr_t *a, ppc_avr_t *b) \ { \ etype ones = (etype)-1; \ etype all = ones; \ - etype none = 0; \ + etype result, none = 0; \ int i; \ \ for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ - etype result = ((a->element[i] == 0) \ + if (cmpzero) { \ + result = ((a->element[i] == 0) \ || (b->element[i] == 0) \ || (a->element[i] != b->element[i]) ? \ ones : 0x0); \ + } else { \ + result = (a->element[i] != b->element[i]) ? ones : 0x0; \ + } \ r->element[i] = result; \ all &= result; \ none |= result; \ @@ -762,14 +766,17 @@ void helper_vcmpnez##suffix(CPUPPCState *env, ppc_avr_t *r, \ * suffix - instruction mnemonic suffix (b: byte, h: halfword, w: word) * element - element type to access from vector */ -#define VCMPNEZ(suffix, element, etype) \ - VCMPNEZ_DO(suffix, element, etype, 0) \ - VCMPNEZ_DO(suffix##_dot, element, etype, 1) -VCMPNEZ(b, u8, uint8_t) -VCMPNEZ(h, u16, uint16_t) -VCMPNEZ(w, u32, uint32_t) -#undef VCMPNEZ_DO -#undef VCMPNEZ +#define VCMPNE(suffix, element, etype, cmpzero) \ + VCMPNE_DO(suffix, element, etype, cmpzero, 0) \ + VCMPNE_DO(suffix##_dot, element, etype, cmpzero, 1) +VCMPNE(zb, u8, uint8_t, 1) +VCMPNE(zh, u16, uint16_t, 1) +VCMPNE(zw, u32, uint32_t, 1) +VCMPNE(b, u8, uint8_t, 0) +VCMPNE(h, u16, uint16_t, 0) +VCMPNE(w, u32, uint32_t, 0) +#undef VCMPNE_DO +#undef VCMPNE #define VCMPFP_DO(suffix, compare, order, record) \ void helper_vcmp##suffix(CPUPPCState *env, ppc_avr_t *r, \ diff --git a/target-ppc/translate/vmx-impl.inc.c b/target-ppc/translate/vmx-impl.inc.c index 3ce374d8911..fd06abcc492 100644 --- a/target-ppc/translate/vmx-impl.inc.c +++ b/target-ppc/translate/vmx-impl.inc.c @@ -510,7 +510,16 @@ GEN_VXRFORM(vcmpeqfp, 3, 3) GEN_VXRFORM(vcmpgefp, 3, 7) GEN_VXRFORM(vcmpgtfp, 3, 11) GEN_VXRFORM(vcmpbfp, 3, 15) - +GEN_VXRFORM(vcmpneb, 3, 0) +GEN_VXRFORM(vcmpneh, 3, 1) +GEN_VXRFORM(vcmpnew, 3, 2) + +GEN_VXRFORM_DUAL(vcmpequb, PPC_NONE, PPC2_ALTIVEC_207, \ + vcmpneb, PPC_NONE, PPC2_ISA300) +GEN_VXRFORM_DUAL(vcmpequh, PPC_NONE, PPC2_ALTIVEC_207, \ + vcmpneh, PPC_NONE, PPC2_ISA300) +GEN_VXRFORM_DUAL(vcmpequw, PPC_NONE, PPC2_ALTIVEC_207, \ + vcmpnew, PPC_NONE, PPC2_ISA300) GEN_VXRFORM_DUAL(vcmpeqfp, PPC_ALTIVEC, PPC_NONE, \ vcmpequd, PPC_NONE, PPC2_ALTIVEC_207) GEN_VXRFORM_DUAL(vcmpbfp, PPC_ALTIVEC, PPC_NONE, \ diff --git a/target-ppc/translate/vmx-ops.inc.c b/target-ppc/translate/vmx-ops.inc.c index a7022a0de54..1edb353a6ba 100644 --- a/target-ppc/translate/vmx-ops.inc.c +++ b/target-ppc/translate/vmx-ops.inc.c @@ -181,9 +181,6 @@ GEN_HANDLER2_E(name, str, 0x4, opc2, opc3, 0x00000000, PPC_NONE, PPC2_ISA300), GEN_VXRFORM1_300(name, name, #name, opc2, opc3) \ GEN_VXRFORM1_300(name##_dot, name##_, #name ".", opc2, (opc3 | (0x1 << 4))) -GEN_VXRFORM(vcmpequb, 3, 0) -GEN_VXRFORM(vcmpequh, 3, 1) -GEN_VXRFORM(vcmpequw, 3, 2) GEN_VXRFORM_300(vcmpnezb, 3, 4) GEN_VXRFORM_300(vcmpnezh, 3, 5) GEN_VXRFORM_300(vcmpnezw, 3, 6) @@ -197,6 +194,9 @@ GEN_VXRFORM_DUAL(vcmpeqfp, vcmpequd, 3, 3, PPC_ALTIVEC, PPC_NONE) GEN_VXRFORM(vcmpgefp, 3, 7) GEN_VXRFORM_DUAL(vcmpgtfp, vcmpgtud, 3, 11, PPC_ALTIVEC, PPC_NONE) GEN_VXRFORM_DUAL(vcmpbfp, vcmpgtsd, 3, 15, PPC_ALTIVEC, PPC_NONE) +GEN_VXRFORM_DUAL(vcmpequb, vcmpneb, 3, 0, PPC_NONE, PPC2_ALTIVEC_207) +GEN_VXRFORM_DUAL(vcmpequh, vcmpneh, 3, 1, PPC_NONE, PPC2_ALTIVEC_207) +GEN_VXRFORM_DUAL(vcmpequw, vcmpnew, 3, 2, PPC_NONE, PPC2_ALTIVEC_207) #define GEN_VXFORM_DUAL_INV(name0, name1, opc2, opc3, inval0, inval1, type) \ GEN_OPCODE_DUAL(name0##_##name1, 0x04, opc2, opc3, inval0, inval1, type, \ From 4879538c99117e249ceb092a2ec0828d23aff01e Mon Sep 17 00:00:00 2001 From: Rajalakshmi Srinivasaraghavan Date: Wed, 28 Sep 2016 11:15:18 +0530 Subject: [PATCH 521/723] target-ppc: add vclzlsbb/vctzlsbb instructions The following vector instructions are added from ISA 3.0. vclzlsbb - Vector Count Leading Zero Least-Significant Bits Byte vctzlsbb - Vector Count Trailing Zero Least-Significant Bits Byte Signed-off-by: Rajalakshmi Srinivasaraghavan Reviewed-by: Richard Henderson Signed-off-by: David Gibson --- target-ppc/helper.h | 2 ++ target-ppc/int_helper.c | 30 +++++++++++++++++++++++++++++ target-ppc/translate/vmx-impl.inc.c | 14 ++++++++++++++ target-ppc/translate/vmx-ops.inc.c | 2 ++ 4 files changed, 48 insertions(+) diff --git a/target-ppc/helper.h b/target-ppc/helper.h index 91c208226fb..796ad455f8b 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -343,6 +343,8 @@ DEF_HELPER_2(vpopcntb, void, avr, avr) DEF_HELPER_2(vpopcnth, void, avr, avr) DEF_HELPER_2(vpopcntw, void, avr, avr) DEF_HELPER_2(vpopcntd, void, avr, avr) +DEF_HELPER_1(vclzlsbb, tl, avr) +DEF_HELPER_1(vctzlsbb, tl, avr) DEF_HELPER_3(vbpermd, void, avr, avr, avr) DEF_HELPER_3(vbpermq, void, avr, avr, avr) DEF_HELPER_2(vgbbd, void, avr, avr) diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c index 77d6bced892..202854fabdb 100644 --- a/target-ppc/int_helper.c +++ b/target-ppc/int_helper.c @@ -881,6 +881,36 @@ VCT(uxs, cvtsduw, u32) VCT(sxs, cvtsdsw, s32) #undef VCT +target_ulong helper_vclzlsbb(ppc_avr_t *r) +{ + target_ulong count = 0; + int i; + VECTOR_FOR_INORDER_I(i, u8) { + if (r->u8[i] & 0x01) { + break; + } + count++; + } + return count; +} + +target_ulong helper_vctzlsbb(ppc_avr_t *r) +{ + target_ulong count = 0; + int i; +#if defined(HOST_WORDS_BIGENDIAN) + for (i = ARRAY_SIZE(r->u8) - 1; i >= 0; i--) { +#else + for (i = 0; i < ARRAY_SIZE(r->u8); i++) { +#endif + if (r->u8[i] & 0x01) { + break; + } + count++; + } + return count; +} + void helper_vmhaddshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { diff --git a/target-ppc/translate/vmx-impl.inc.c b/target-ppc/translate/vmx-impl.inc.c index fd06abcc492..f646e8542ed 100644 --- a/target-ppc/translate/vmx-impl.inc.c +++ b/target-ppc/translate/vmx-impl.inc.c @@ -593,6 +593,18 @@ static void glue(gen_, name)(DisasContext *ctx) \ tcg_temp_free_ptr(rd); \ } +#define GEN_VXFORM_NOA_3(name, opc2, opc3, opc4) \ +static void glue(gen_, name)(DisasContext *ctx) \ + { \ + TCGv_ptr rb; \ + if (unlikely(!ctx->altivec_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VPU); \ + return; \ + } \ + rb = gen_avr_ptr(rB(ctx->opcode)); \ + gen_helper_##name(cpu_gpr[rD(ctx->opcode)], rb); \ + tcg_temp_free_ptr(rb); \ + } GEN_VXFORM_NOA(vupkhsb, 7, 8); GEN_VXFORM_NOA(vupkhsh, 7, 9); GEN_VXFORM_NOA(vupkhsw, 7, 25); @@ -807,6 +819,8 @@ GEN_VXFORM_NOA_2(vctzb, 1, 24, 28) GEN_VXFORM_NOA_2(vctzh, 1, 24, 29) GEN_VXFORM_NOA_2(vctzw, 1, 24, 30) GEN_VXFORM_NOA_2(vctzd, 1, 24, 31) +GEN_VXFORM_NOA_3(vclzlsbb, 1, 24, 0) +GEN_VXFORM_NOA_3(vctzlsbb, 1, 24, 1) GEN_VXFORM_NOA(vpopcntb, 1, 28) GEN_VXFORM_NOA(vpopcnth, 1, 29) GEN_VXFORM_NOA(vpopcntw, 1, 30) diff --git a/target-ppc/translate/vmx-ops.inc.c b/target-ppc/translate/vmx-ops.inc.c index 1edb353a6ba..b63e33dabbd 100644 --- a/target-ppc/translate/vmx-ops.inc.c +++ b/target-ppc/translate/vmx-ops.inc.c @@ -219,6 +219,8 @@ GEN_VXFORM_300_EO(vctzb, 0x01, 0x18, 0x1C), GEN_VXFORM_300_EO(vctzh, 0x01, 0x18, 0x1D), GEN_VXFORM_300_EO(vctzw, 0x01, 0x18, 0x1E), GEN_VXFORM_300_EO(vctzd, 0x01, 0x18, 0x1F), +GEN_VXFORM_300_EO(vclzlsbb, 0x01, 0x18, 0x0), +GEN_VXFORM_300_EO(vctzlsbb, 0x01, 0x18, 0x1), GEN_VXFORM_300(vpermr, 0x1D, 0xFF), #define GEN_VXFORM_NOA(name, opc2, opc3) \ From 1a136cdce078c32f5e8a556d43cc0af8614c2d8d Mon Sep 17 00:00:00 2001 From: Ravi Bangoria Date: Thu, 29 Sep 2016 09:22:17 +0530 Subject: [PATCH 522/723] target-ppc: Implement mtvsrws instruction mtvsrws: Move To VSR Word & Splat Signed-off-by: Ravi Bangoria Signed-off-by: Nikunj A Dadhania Reviewed-by: Richard Henderson Signed-off-by: David Gibson --- target-ppc/translate/vsx-impl.inc.c | 19 +++++++++++++++++++ target-ppc/translate/vsx-ops.inc.c | 1 + 2 files changed, 20 insertions(+) diff --git a/target-ppc/translate/vsx-impl.inc.c b/target-ppc/translate/vsx-impl.inc.c index 4120c0145c6..23ec1e115c9 100644 --- a/target-ppc/translate/vsx-impl.inc.c +++ b/target-ppc/translate/vsx-impl.inc.c @@ -384,6 +384,25 @@ static void gen_mtvsrdd(DisasContext *ctx) tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), cpu_gpr[rB(ctx->opcode)]); } +static void gen_mtvsrws(DisasContext *ctx) +{ + if (xT(ctx->opcode) < 32) { + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + } else { + if (unlikely(!ctx->altivec_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VPU); + return; + } + } + + tcg_gen_deposit_i64(cpu_vsrl(xT(ctx->opcode)), cpu_gpr[rA(ctx->opcode)], + cpu_gpr[rA(ctx->opcode)], 32, 32); + tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), cpu_vsrl(xT(ctx->opcode))); +} + #endif static void gen_xxpermdi(DisasContext *ctx) diff --git a/target-ppc/translate/vsx-ops.inc.c b/target-ppc/translate/vsx-ops.inc.c index c49ba6dab9a..10eb4b94705 100644 --- a/target-ppc/translate/vsx-ops.inc.c +++ b/target-ppc/translate/vsx-ops.inc.c @@ -28,6 +28,7 @@ GEN_HANDLER_E(mfvsrd, 0x1F, 0x13, 0x01, 0x0000F800, PPC_NONE, PPC2_VSX207), GEN_HANDLER_E(mtvsrd, 0x1F, 0x13, 0x05, 0x0000F800, PPC_NONE, PPC2_VSX207), GEN_HANDLER_E(mfvsrld, 0X1F, 0x13, 0x09, 0x0000F800, PPC_NONE, PPC2_ISA300), GEN_HANDLER_E(mtvsrdd, 0X1F, 0x13, 0x0D, 0x0, PPC_NONE, PPC2_ISA300), +GEN_HANDLER_E(mtvsrws, 0x1F, 0x13, 0x0C, 0x0000F800, PPC_NONE, PPC2_ISA300), #endif #define GEN_XX1FORM(name, opc2, opc3, fl2) \ From 835c42d34e0547180babaee7036c532a0e6977d7 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 29 Sep 2016 09:40:33 +0200 Subject: [PATCH 523/723] MAINTAINERS: Add two more ppc related files The file hw/intc/heathrow_pic.c belongs to the Old World Mac machine, and pc-bios/ppc_rom.bin belongs to the PReP machine. Signed-off-by: Thomas Huth Signed-off-by: David Gibson --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 76a0fdb2c41..9bca506365e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -620,6 +620,7 @@ S: Maintained F: hw/ppc/mac_oldworld.c F: hw/pci-host/grackle.c F: hw/misc/macio/ +F: hw/intc/heathrow_pic.c PReP L: qemu-devel@nongnu.org @@ -628,6 +629,7 @@ S: Odd Fixes F: hw/ppc/prep.c F: hw/pci-host/prep.[hc] F: hw/isa/pc87312.[hc] +F: pc-bios/ppc_rom.bin sPAPR M: David Gibson From 96c9cff0ab986f3a0606e1a96c5b00e6a7c675c6 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 29 Sep 2016 12:48:06 +0200 Subject: [PATCH 524/723] target-ppc/kvm: Add a wrapper function to check for KVM-PR It makes more sense if we have a proper function to check for KVM-PR than to check for the GET_PVINFO extension all over the place. Signed-off-by: Thomas Huth [dwg: Expanded a comment to discourage overuse of this function] Signed-off-by: David Gibson --- target-ppc/kvm.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index e9a9fafb884..83482b46aee 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -102,6 +102,16 @@ static void kvm_kick_cpu(void *opaque) qemu_cpu_kick(CPU(cpu)); } +/* Check whether we are running with KVM-PR (instead of KVM-HV). This + * should only be used for fallback tests - generally we should use + * explicit capabilities for the features we want, rather than + * assuming what is/isn't available depending on the KVM variant. */ +static bool kvmppc_is_pr(KVMState *ks) +{ + /* Assume KVM-PR if the GET_PVINFO capability is available */ + return kvm_check_extension(ks, KVM_CAP_PPC_GET_PVINFO) != 0; +} + static int kvm_ppc_register_host_cpu_type(void); int kvm_arch_init(MachineState *ms, KVMState *s) @@ -223,10 +233,9 @@ static void kvm_get_fallback_smmu_info(PowerPCCPU *cpu, * * For that to work we make a few assumptions: * - * - If KVM_CAP_PPC_GET_PVINFO is supported we are running "PR" - * KVM which only supports 4K and 16M pages, but supports them - * regardless of the backing store characteritics. We also don't - * support 1T segments. + * - Check whether we are running "PR" KVM which only supports 4K + * and 16M pages, but supports them regardless of the backing + * store characteritics. We also don't support 1T segments. * * This is safe as if HV KVM ever supports that capability or PR * KVM grows supports for more page/segment sizes, those versions @@ -241,7 +250,7 @@ static void kvm_get_fallback_smmu_info(PowerPCCPU *cpu, * implements KVM_CAP_PPC_GET_SMMU_INFO and thus doesn't hit * this fallback. */ - if (kvm_check_extension(cs->kvm_state, KVM_CAP_PPC_GET_PVINFO)) { + if (kvmppc_is_pr(cs->kvm_state)) { /* No flags */ info->flags = 0; info->slb_size = 64; @@ -2270,11 +2279,8 @@ int kvmppc_reset_htab(int shift_hint) /* We have a kernel that predates the htab reset calls. For PR * KVM, we need to allocate the htab ourselves, for an HV KVM of - * this era, it has allocated a 16MB fixed size hash table - * already. Kernels of this era have the GET_PVINFO capability - * only on PR, so we use this hack to determine the right - * answer */ - if (kvm_check_extension(kvm_state, KVM_CAP_PPC_GET_PVINFO)) { + * this era, it has allocated a 16MB fixed size hash table already. */ + if (kvmppc_is_pr(kvm_state)) { /* PR - tell caller to allocate htab */ return 0; } else { From 7f516c9675285298826d4ef20ce1a093b13caf89 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 29 Sep 2016 12:48:07 +0200 Subject: [PATCH 525/723] target-ppc/kvm: Enable transactional memory on POWER8 with KVM-HV, too Transactional memory is also supported on POWER8 KVM-HV if the KVM_CAP_PPC_HTM is not available in the kernel yet, so add a hack to allow TM here, too. Signed-off-by: Thomas Huth Signed-off-by: David Gibson --- target-ppc/kvm.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 83482b46aee..9c4834c4fc1 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -570,11 +570,18 @@ int kvm_arch_init_vcpu(CPUState *cs) idle_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, kvm_kick_cpu, cpu); - /* Some targets support access to KVM's guest TLB. */ switch (cenv->mmu_model) { case POWERPC_MMU_BOOKE206: + /* This target supports access to KVM's guest TLB */ ret = kvm_booke206_tlb_init(cpu); break; + case POWERPC_MMU_2_07: + if (!cap_htm && !kvmppc_is_pr(cs->kvm_state)) { + /* KVM-HV has transactional memory on POWER8 also without the + * KVM_CAP_PPC_HTM extension, so enable it here instead. */ + cap_htm = true; + } + break; default: break; } From 2020b67d851affd9dd8b3732a5290d90be6187d1 Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Thu, 29 Sep 2016 15:52:37 +0530 Subject: [PATCH 526/723] target-ppc: fix vmx instruction type/type2 A few of the new instructions added inadvertently changed the type of old instruction(PPC_ALTIVEC) to PPC2_ALTIVEC_207 in the dual form declaration. commit: b5d569a1 (target-ppc: add vector extract instructions) commit: e7b1e06f (target-ppc: add vector insert instructions) commit: 3aa56a19 (target-ppc: add vector compare not equal instructions) New ISA 3.0 instructions added: vextractub PPC_NONE PPC2_ISA300 vextractuh PPC_NONE PPC2_ISA300 vextractuw PPC_NONE PPC2_ISA300 vinsertb PPC_NONE PPC2_ISA300 vinserth PPC_NONE PPC2_ISA300 vinsertw PPC_NONE PPC2_ISA300 vcmpneb PPC_NONE PPC2_ISA300 vcmpneh PPC_NONE PPC2_ISA300 vcmpnew PPC_NONE PPC2_ISA300 Affected older instructions: vspltb PPC_ALTIVEC PPC_NONE vsplth PPC_ALTIVEC PPC_NONE vspltw PPC_ALTIVEC PPC_NONE vspltisb PPC_ALTIVEC PPC_NONE vspltish PPC_ALTIVEC PPC_NONE vspltisw PPC_ALTIVEC PPC_NONE vcmpequb PPC_ALTIVEC PPC_NONE vcmpequh PPC_ALTIVEC PPC_NONE vcmpequw PPC_ALTIVEC PPC_NONE Change the instruction type/type2 for the older instructions back to what it was(PPC_ALTIVEC). CC: Rajalakshmi Srinivasaraghavan Reported-by: Bharata B Rao Signed-off-by: Nikunj A Dadhania Signed-off-by: David Gibson --- target-ppc/translate/vmx-impl.inc.c | 30 ++++++++++++++--------------- target-ppc/translate/vmx-ops.inc.c | 18 ++++++++--------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/target-ppc/translate/vmx-impl.inc.c b/target-ppc/translate/vmx-impl.inc.c index f646e8542ed..25cd0735acc 100644 --- a/target-ppc/translate/vmx-impl.inc.c +++ b/target-ppc/translate/vmx-impl.inc.c @@ -514,11 +514,11 @@ GEN_VXRFORM(vcmpneb, 3, 0) GEN_VXRFORM(vcmpneh, 3, 1) GEN_VXRFORM(vcmpnew, 3, 2) -GEN_VXRFORM_DUAL(vcmpequb, PPC_NONE, PPC2_ALTIVEC_207, \ +GEN_VXRFORM_DUAL(vcmpequb, PPC_ALTIVEC, PPC_NONE, \ vcmpneb, PPC_NONE, PPC2_ISA300) -GEN_VXRFORM_DUAL(vcmpequh, PPC_NONE, PPC2_ALTIVEC_207, \ +GEN_VXRFORM_DUAL(vcmpequh, PPC_ALTIVEC, PPC_NONE, \ vcmpneh, PPC_NONE, PPC2_ISA300) -GEN_VXRFORM_DUAL(vcmpequw, PPC_NONE, PPC2_ALTIVEC_207, \ +GEN_VXRFORM_DUAL(vcmpequw, PPC_ALTIVEC, PPC_NONE, \ vcmpnew, PPC_NONE, PPC2_ISA300) GEN_VXRFORM_DUAL(vcmpeqfp, PPC_ALTIVEC, PPC_NONE, \ vcmpequd, PPC_NONE, PPC2_ALTIVEC_207) @@ -712,18 +712,18 @@ GEN_VXFORM_UIMM_ENV(vcfux, 5, 12); GEN_VXFORM_UIMM_ENV(vcfsx, 5, 13); GEN_VXFORM_UIMM_ENV(vctuxs, 5, 14); GEN_VXFORM_UIMM_ENV(vctsxs, 5, 15); -GEN_VXFORM_DUAL(vspltb, PPC_NONE, PPC2_ALTIVEC_207, - vextractub, PPC_NONE, PPC2_ISA300); -GEN_VXFORM_DUAL(vsplth, PPC_NONE, PPC2_ALTIVEC_207, - vextractuh, PPC_NONE, PPC2_ISA300); -GEN_VXFORM_DUAL(vspltw, PPC_NONE, PPC2_ALTIVEC_207, - vextractuw, PPC_NONE, PPC2_ISA300); -GEN_VXFORM_DUAL(vspltisb, PPC_NONE, PPC2_ALTIVEC_207, - vinsertb, PPC_NONE, PPC2_ISA300); -GEN_VXFORM_DUAL(vspltish, PPC_NONE, PPC2_ALTIVEC_207, - vinserth, PPC_NONE, PPC2_ISA300); -GEN_VXFORM_DUAL(vspltisw, PPC_NONE, PPC2_ALTIVEC_207, - vinsertw, PPC_NONE, PPC2_ISA300); +GEN_VXFORM_DUAL(vspltb, PPC_ALTIVEC, PPC_NONE, + vextractub, PPC_NONE, PPC2_ISA300); +GEN_VXFORM_DUAL(vsplth, PPC_ALTIVEC, PPC_NONE, + vextractuh, PPC_NONE, PPC2_ISA300); +GEN_VXFORM_DUAL(vspltw, PPC_ALTIVEC, PPC_NONE, + vextractuw, PPC_NONE, PPC2_ISA300); +GEN_VXFORM_DUAL(vspltisb, PPC_ALTIVEC, PPC_NONE, + vinsertb, PPC_NONE, PPC2_ISA300); +GEN_VXFORM_DUAL(vspltish, PPC_ALTIVEC, PPC_NONE, + vinserth, PPC_NONE, PPC2_ISA300); +GEN_VXFORM_DUAL(vspltisw, PPC_ALTIVEC, PPC_NONE, + vinsertw, PPC_NONE, PPC2_ISA300); static void gen_vsldoi(DisasContext *ctx) { diff --git a/target-ppc/translate/vmx-ops.inc.c b/target-ppc/translate/vmx-ops.inc.c index b63e33dabbd..ac1dc9b2b22 100644 --- a/target-ppc/translate/vmx-ops.inc.c +++ b/target-ppc/translate/vmx-ops.inc.c @@ -194,26 +194,26 @@ GEN_VXRFORM_DUAL(vcmpeqfp, vcmpequd, 3, 3, PPC_ALTIVEC, PPC_NONE) GEN_VXRFORM(vcmpgefp, 3, 7) GEN_VXRFORM_DUAL(vcmpgtfp, vcmpgtud, 3, 11, PPC_ALTIVEC, PPC_NONE) GEN_VXRFORM_DUAL(vcmpbfp, vcmpgtsd, 3, 15, PPC_ALTIVEC, PPC_NONE) -GEN_VXRFORM_DUAL(vcmpequb, vcmpneb, 3, 0, PPC_NONE, PPC2_ALTIVEC_207) -GEN_VXRFORM_DUAL(vcmpequh, vcmpneh, 3, 1, PPC_NONE, PPC2_ALTIVEC_207) -GEN_VXRFORM_DUAL(vcmpequw, vcmpnew, 3, 2, PPC_NONE, PPC2_ALTIVEC_207) +GEN_VXRFORM_DUAL(vcmpequb, vcmpneb, 3, 0, PPC_ALTIVEC, PPC_NONE) +GEN_VXRFORM_DUAL(vcmpequh, vcmpneh, 3, 1, PPC_ALTIVEC, PPC_NONE) +GEN_VXRFORM_DUAL(vcmpequw, vcmpnew, 3, 2, PPC_ALTIVEC, PPC_NONE) #define GEN_VXFORM_DUAL_INV(name0, name1, opc2, opc3, inval0, inval1, type) \ GEN_OPCODE_DUAL(name0##_##name1, 0x04, opc2, opc3, inval0, inval1, type, \ PPC_NONE) GEN_VXFORM_DUAL_INV(vspltb, vextractub, 6, 8, 0x00000000, 0x100000, - PPC2_ALTIVEC_207), + PPC_ALTIVEC), GEN_VXFORM_DUAL_INV(vsplth, vextractuh, 6, 9, 0x00000000, 0x100000, - PPC2_ALTIVEC_207), + PPC_ALTIVEC), GEN_VXFORM_DUAL_INV(vspltw, vextractuw, 6, 10, 0x00000000, 0x100000, - PPC2_ALTIVEC_207), + PPC_ALTIVEC), GEN_VXFORM_300_EXT(vextractd, 6, 11, 0x100000), GEN_VXFORM_DUAL_INV(vspltisb, vinsertb, 6, 12, 0x00000000, 0x100000, - PPC2_ALTIVEC_207), + PPC_ALTIVEC), GEN_VXFORM_DUAL_INV(vspltish, vinserth, 6, 13, 0x00000000, 0x100000, - PPC2_ALTIVEC_207), + PPC_ALTIVEC), GEN_VXFORM_DUAL_INV(vspltisw, vinsertw, 6, 14, 0x00000000, 0x100000, - PPC2_ALTIVEC_207), + PPC_ALTIVEC), GEN_VXFORM_300_EXT(vinsertd, 6, 15, 0x100000), GEN_VXFORM_300_EO(vctzb, 0x01, 0x18, 0x1C), GEN_VXFORM_300_EO(vctzh, 0x01, 0x18, 0x1D), From cf716b31cba278a6dbff585d58fa29d1ae2fe334 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 29 Sep 2016 12:32:44 +0200 Subject: [PATCH 527/723] libqos: add PPC64 PCI support Signed-off-by: Laurent Vivier [dwg: Fixed build problem on 32-bit hosts] Signed-off-by: David Gibson --- tests/Makefile.include | 1 + tests/libqos/pci-pc.c | 22 --- tests/libqos/pci-spapr.c | 288 +++++++++++++++++++++++++++++++++++++++ tests/libqos/pci-spapr.h | 17 +++ tests/libqos/pci.c | 22 ++- tests/libqos/rtas.c | 45 ++++++ tests/libqos/rtas.h | 4 + 7 files changed, 376 insertions(+), 23 deletions(-) create mode 100644 tests/libqos/pci-spapr.c create mode 100644 tests/libqos/pci-spapr.h diff --git a/tests/Makefile.include b/tests/Makefile.include index 77d42d78ac3..8b1c1717de1 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -591,6 +591,7 @@ libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o libqos-spapr-obj-y = $(libqos-obj-y) tests/libqos/malloc-spapr.o libqos-spapr-obj-y += tests/libqos/libqos-spapr.o libqos-spapr-obj-y += tests/libqos/rtas.o +libqos-spapr-obj-y += tests/libqos/pci-spapr.o libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o libqos-pc-obj-y += tests/libqos/ahci.o diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c index 1ae2d3780f3..82066b8531f 100644 --- a/tests/libqos/pci-pc.c +++ b/tests/libqos/pci-pc.c @@ -255,28 +255,6 @@ void qpci_free_pc(QPCIBus *bus) g_free(s); } -void qpci_plug_device_test(const char *driver, const char *id, - uint8_t slot, const char *opts) -{ - QDict *response; - char *cmd; - - cmd = g_strdup_printf("{'execute': 'device_add'," - " 'arguments': {" - " 'driver': '%s'," - " 'addr': '%d'," - " %s%s" - " 'id': '%s'" - "}}", driver, slot, - opts ? opts : "", opts ? "," : "", - id); - response = qmp(cmd); - g_free(cmd); - g_assert(response); - g_assert(!qdict_haskey(response, "error")); - QDECREF(response); -} - void qpci_unplug_acpi_device_test(const char *id, uint8_t slot) { QDict *response; diff --git a/tests/libqos/pci-spapr.c b/tests/libqos/pci-spapr.c new file mode 100644 index 00000000000..2f73badfd94 --- /dev/null +++ b/tests/libqos/pci-spapr.c @@ -0,0 +1,288 @@ +/* + * libqos PCI bindings for SPAPR + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "libqtest.h" +#include "libqos/pci-spapr.h" +#include "libqos/rtas.h" + +#include "hw/pci/pci_regs.h" + +#include "qemu-common.h" +#include "qemu/host-utils.h" + + +/* From include/hw/pci-host/spapr.h */ + +#define SPAPR_PCI_BASE_BUID 0x800000020000000ULL + +#define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL + +#define SPAPR_PCI_WINDOW_BASE 0x10000000000ULL +#define SPAPR_PCI_WINDOW_SPACING 0x1000000000ULL +#define SPAPR_PCI_MMIO_WIN_OFF 0xA0000000 +#define SPAPR_PCI_MMIO_WIN_SIZE (SPAPR_PCI_WINDOW_SPACING - \ + SPAPR_PCI_MEM_WIN_BUS_OFFSET) +#define SPAPR_PCI_IO_WIN_OFF 0x80000000 +#define SPAPR_PCI_IO_WIN_SIZE 0x10000 + +/* index is the phb index */ + +#define BUIDBASE(index) (SPAPR_PCI_BASE_BUID + (index)) +#define PCIBASE(index) (SPAPR_PCI_WINDOW_BASE + \ + (index) * SPAPR_PCI_WINDOW_SPACING) +#define IOBASE(index) (PCIBASE(index) + SPAPR_PCI_IO_WIN_OFF) +#define MMIOBASE(index) (PCIBASE(index) + SPAPR_PCI_MMIO_WIN_OFF) + +typedef struct QPCIBusSPAPR { + QPCIBus bus; + QGuestAllocator *alloc; + + uint64_t pci_hole_start; + uint64_t pci_hole_size; + uint64_t pci_hole_alloc; + + uint32_t pci_iohole_start; + uint32_t pci_iohole_size; + uint32_t pci_iohole_alloc; +} QPCIBusSPAPR; + +/* + * PCI devices are always little-endian + * SPAPR by default is big-endian + * so PCI accessors need to swap data endianness + */ + +static uint8_t qpci_spapr_io_readb(QPCIBus *bus, void *addr) +{ + uint64_t port = (uintptr_t)addr; + uint8_t v; + if (port < SPAPR_PCI_IO_WIN_SIZE) { + v = readb(IOBASE(0) + port); + } else { + v = readb(MMIOBASE(0) + port); + } + return v; +} + +static uint16_t qpci_spapr_io_readw(QPCIBus *bus, void *addr) +{ + uint64_t port = (uintptr_t)addr; + uint16_t v; + if (port < SPAPR_PCI_IO_WIN_SIZE) { + v = readw(IOBASE(0) + port); + } else { + v = readw(MMIOBASE(0) + port); + } + return bswap16(v); +} + +static uint32_t qpci_spapr_io_readl(QPCIBus *bus, void *addr) +{ + uint64_t port = (uintptr_t)addr; + uint32_t v; + if (port < SPAPR_PCI_IO_WIN_SIZE) { + v = readl(IOBASE(0) + port); + } else { + v = readl(MMIOBASE(0) + port); + } + return bswap32(v); +} + +static void qpci_spapr_io_writeb(QPCIBus *bus, void *addr, uint8_t value) +{ + uint64_t port = (uintptr_t)addr; + if (port < SPAPR_PCI_IO_WIN_SIZE) { + writeb(IOBASE(0) + port, value); + } else { + writeb(MMIOBASE(0) + port, value); + } +} + +static void qpci_spapr_io_writew(QPCIBus *bus, void *addr, uint16_t value) +{ + uint64_t port = (uintptr_t)addr; + value = bswap16(value); + if (port < SPAPR_PCI_IO_WIN_SIZE) { + writew(IOBASE(0) + port, value); + } else { + writew(MMIOBASE(0) + port, value); + } +} + +static void qpci_spapr_io_writel(QPCIBus *bus, void *addr, uint32_t value) +{ + uint64_t port = (uintptr_t)addr; + value = bswap32(value); + if (port < SPAPR_PCI_IO_WIN_SIZE) { + writel(IOBASE(0) + port, value); + } else { + writel(MMIOBASE(0) + port, value); + } +} + +static uint8_t qpci_spapr_config_readb(QPCIBus *bus, int devfn, uint8_t offset) +{ + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); + uint32_t config_addr = (devfn << 8) | offset; + return qrtas_ibm_read_pci_config(s->alloc, BUIDBASE(0), + config_addr, 1); +} + +static uint16_t qpci_spapr_config_readw(QPCIBus *bus, int devfn, uint8_t offset) +{ + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); + uint32_t config_addr = (devfn << 8) | offset; + return qrtas_ibm_read_pci_config(s->alloc, BUIDBASE(0), + config_addr, 2); +} + +static uint32_t qpci_spapr_config_readl(QPCIBus *bus, int devfn, uint8_t offset) +{ + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); + uint32_t config_addr = (devfn << 8) | offset; + return qrtas_ibm_read_pci_config(s->alloc, BUIDBASE(0), + config_addr, 4); +} + +static void qpci_spapr_config_writeb(QPCIBus *bus, int devfn, uint8_t offset, + uint8_t value) +{ + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); + uint32_t config_addr = (devfn << 8) | offset; + qrtas_ibm_write_pci_config(s->alloc, BUIDBASE(0), + config_addr, 1, value); +} + +static void qpci_spapr_config_writew(QPCIBus *bus, int devfn, uint8_t offset, + uint16_t value) +{ + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); + uint32_t config_addr = (devfn << 8) | offset; + qrtas_ibm_write_pci_config(s->alloc, BUIDBASE(0), + config_addr, 2, value); +} + +static void qpci_spapr_config_writel(QPCIBus *bus, int devfn, uint8_t offset, + uint32_t value) +{ + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); + uint32_t config_addr = (devfn << 8) | offset; + qrtas_ibm_write_pci_config(s->alloc, BUIDBASE(0), + config_addr, 4, value); +} + +static void *qpci_spapr_iomap(QPCIBus *bus, QPCIDevice *dev, int barno, + uint64_t *sizeptr) +{ + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); + static const int bar_reg_map[] = { + PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, PCI_BASE_ADDRESS_2, + PCI_BASE_ADDRESS_3, PCI_BASE_ADDRESS_4, PCI_BASE_ADDRESS_5, + }; + int bar_reg; + uint32_t addr; + uint64_t size; + uint32_t io_type; + + g_assert(barno >= 0 && barno <= 5); + bar_reg = bar_reg_map[barno]; + + qpci_config_writel(dev, bar_reg, 0xFFFFFFFF); + addr = qpci_config_readl(dev, bar_reg); + + io_type = addr & PCI_BASE_ADDRESS_SPACE; + if (io_type == PCI_BASE_ADDRESS_SPACE_IO) { + addr &= PCI_BASE_ADDRESS_IO_MASK; + } else { + addr &= PCI_BASE_ADDRESS_MEM_MASK; + } + + size = (1ULL << ctzl(addr)); + if (size == 0) { + return NULL; + } + if (sizeptr) { + *sizeptr = size; + } + + if (io_type == PCI_BASE_ADDRESS_SPACE_IO) { + uint16_t loc; + + g_assert(QEMU_ALIGN_UP(s->pci_iohole_alloc, size) + size + <= s->pci_iohole_size); + s->pci_iohole_alloc = QEMU_ALIGN_UP(s->pci_iohole_alloc, size); + loc = s->pci_iohole_start + s->pci_iohole_alloc; + s->pci_iohole_alloc += size; + + qpci_config_writel(dev, bar_reg, loc | PCI_BASE_ADDRESS_SPACE_IO); + + return (void *)(unsigned long)loc; + } else { + uint64_t loc; + + g_assert(QEMU_ALIGN_UP(s->pci_hole_alloc, size) + size + <= s->pci_hole_size); + s->pci_hole_alloc = QEMU_ALIGN_UP(s->pci_hole_alloc, size); + loc = s->pci_hole_start + s->pci_hole_alloc; + s->pci_hole_alloc += size; + + qpci_config_writel(dev, bar_reg, loc); + + return (void *)(unsigned long)loc; + } +} + +static void qpci_spapr_iounmap(QPCIBus *bus, void *data) +{ + /* FIXME */ +} + +QPCIBus *qpci_init_spapr(QGuestAllocator *alloc) +{ + QPCIBusSPAPR *ret; + + ret = g_malloc(sizeof(*ret)); + + ret->alloc = alloc; + + ret->bus.io_readb = qpci_spapr_io_readb; + ret->bus.io_readw = qpci_spapr_io_readw; + ret->bus.io_readl = qpci_spapr_io_readl; + + ret->bus.io_writeb = qpci_spapr_io_writeb; + ret->bus.io_writew = qpci_spapr_io_writew; + ret->bus.io_writel = qpci_spapr_io_writel; + + ret->bus.config_readb = qpci_spapr_config_readb; + ret->bus.config_readw = qpci_spapr_config_readw; + ret->bus.config_readl = qpci_spapr_config_readl; + + ret->bus.config_writeb = qpci_spapr_config_writeb; + ret->bus.config_writew = qpci_spapr_config_writew; + ret->bus.config_writel = qpci_spapr_config_writel; + + ret->bus.iomap = qpci_spapr_iomap; + ret->bus.iounmap = qpci_spapr_iounmap; + + ret->pci_hole_start = 0xC0000000; + ret->pci_hole_size = SPAPR_PCI_MMIO_WIN_SIZE; + ret->pci_hole_alloc = 0; + + ret->pci_iohole_start = 0xc000; + ret->pci_iohole_size = SPAPR_PCI_IO_WIN_SIZE; + ret->pci_iohole_alloc = 0; + + return &ret->bus; +} + +void qpci_free_spapr(QPCIBus *bus) +{ + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); + + g_free(s); +} diff --git a/tests/libqos/pci-spapr.h b/tests/libqos/pci-spapr.h new file mode 100644 index 00000000000..4192126d862 --- /dev/null +++ b/tests/libqos/pci-spapr.h @@ -0,0 +1,17 @@ +/* + * libqos PCI bindings for SPAPR + * + * 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 LIBQOS_PCI_SPAPR_H +#define LIBQOS_PCI_SPAPR_H + +#include "libqos/malloc.h" +#include "libqos/pci.h" + +QPCIBus *qpci_init_spapr(QGuestAllocator *alloc); +void qpci_free_spapr(QPCIBus *bus); + +#endif diff --git a/tests/libqos/pci.c b/tests/libqos/pci.c index ed78d91cea8..c3f3382b7c3 100644 --- a/tests/libqos/pci.c +++ b/tests/libqos/pci.c @@ -263,4 +263,24 @@ void qpci_iounmap(QPCIDevice *dev, void *data) dev->bus->iounmap(dev->bus, data); } - +void qpci_plug_device_test(const char *driver, const char *id, + uint8_t slot, const char *opts) +{ + QDict *response; + char *cmd; + + cmd = g_strdup_printf("{'execute': 'device_add'," + " 'arguments': {" + " 'driver': '%s'," + " 'addr': '%d'," + " %s%s" + " 'id': '%s'" + "}}", driver, slot, + opts ? opts : "", opts ? "," : "", + id); + response = qmp(cmd); + g_free(cmd); + g_assert(response); + g_assert(!qdict_haskey(response, "error")); + QDECREF(response); +} diff --git a/tests/libqos/rtas.c b/tests/libqos/rtas.c index 820321a3a7c..0269803ce09 100644 --- a/tests/libqos/rtas.c +++ b/tests/libqos/rtas.c @@ -69,3 +69,48 @@ int qrtas_get_time_of_day(QGuestAllocator *alloc, struct tm *tm, uint32_t *ns) return res; } + +uint32_t qrtas_ibm_read_pci_config(QGuestAllocator *alloc, uint64_t buid, + uint32_t addr, uint32_t size) +{ + int res; + uint32_t args[4], ret[2]; + + args[0] = addr; + args[1] = buid >> 32; + args[2] = buid & 0xffffffff; + args[3] = size; + res = qrtas_call(alloc, "ibm,read-pci-config", 4, args, 2, ret); + if (res != 0) { + return -1; + } + + if (ret[0] != 0) { + return -1; + } + + return ret[1]; +} + +int qrtas_ibm_write_pci_config(QGuestAllocator *alloc, uint64_t buid, + uint32_t addr, uint32_t size, uint32_t val) +{ + int res; + uint32_t args[5], ret[1]; + + args[0] = addr; + args[1] = buid >> 32; + args[2] = buid & 0xffffffff; + args[3] = size; + args[4] = val; + res = qrtas_call(alloc, "ibm,write-pci-config", 5, args, 1, ret); + if (res != 0) { + return -1; + } + + if (ret[0] != 0) { + return -1; + } + + return 0; +} diff --git a/tests/libqos/rtas.h b/tests/libqos/rtas.h index a1b60a8eb4b..498eb192304 100644 --- a/tests/libqos/rtas.h +++ b/tests/libqos/rtas.h @@ -8,4 +8,8 @@ #include "libqos/malloc.h" int qrtas_get_time_of_day(QGuestAllocator *alloc, struct tm *tm, uint32_t *ns); +uint32_t qrtas_ibm_read_pci_config(QGuestAllocator *alloc, uint64_t buid, + uint32_t addr, uint32_t size); +int qrtas_ibm_write_pci_config(QGuestAllocator *alloc, uint64_t buid, + uint32_t addr, uint32_t size, uint32_t val); #endif /* LIBQOS_RTAS_H */ From 2ecd7e2f25a57e8966a15ee50a0afacd4ec067da Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 29 Sep 2016 12:32:45 +0200 Subject: [PATCH 528/723] libqos: add PCI management in qtest_vboot()/qtest_shutdown() Signed-off-by: Laurent Vivier Reviewed-by: Greg Kurz Reviewed-by: David Gibson Signed-off-by: David Gibson --- tests/e1000e-test.c | 2 +- tests/i440fx-test.c | 2 +- tests/ide-test.c | 2 +- tests/ivshmem-test.c | 2 +- tests/libqos/ahci.c | 2 +- tests/libqos/libqos-pc.c | 5 ++++- tests/libqos/libqos-spapr.c | 5 ++++- tests/libqos/libqos.c | 21 ++++++++++++++++----- tests/libqos/libqos.h | 3 +++ tests/libqos/pci-pc.c | 2 +- tests/libqos/pci-pc.h | 3 ++- tests/q35-test.c | 2 +- tests/rtl8139-test.c | 2 +- tests/tco-test.c | 2 +- tests/usb-hcd-ehci-test.c | 2 +- tests/usb-hcd-uhci-test.c | 2 +- tests/vhost-user-test.c | 4 ++-- tests/virtio-9p-test.c | 2 +- tests/virtio-blk-test.c | 2 +- tests/virtio-net-test.c | 2 +- tests/virtio-scsi-test.c | 2 +- 21 files changed, 46 insertions(+), 25 deletions(-) diff --git a/tests/e1000e-test.c b/tests/e1000e-test.c index d497b0857c7..3979b20bb0b 100644 --- a/tests/e1000e-test.c +++ b/tests/e1000e-test.c @@ -390,7 +390,7 @@ static void data_test_init(e1000e_device *d) qtest_start(cmdline); g_free(cmdline); - test_bus = qpci_init_pc(); + test_bus = qpci_init_pc(NULL); g_assert_nonnull(test_bus); test_alloc = pc_alloc_init(); diff --git a/tests/i440fx-test.c b/tests/i440fx-test.c index 3542ad114e0..da2d5a53f01 100644 --- a/tests/i440fx-test.c +++ b/tests/i440fx-test.c @@ -38,7 +38,7 @@ static QPCIBus *test_start_get_bus(const TestData *s) cmdline = g_strdup_printf("-smp %d", s->num_cpus); qtest_start(cmdline); g_free(cmdline); - return qpci_init_pc(); + return qpci_init_pc(NULL); } static void test_i440fx_defaults(gconstpointer opaque) diff --git a/tests/ide-test.c b/tests/ide-test.c index 1e51af2a944..a8a4081f780 100644 --- a/tests/ide-test.c +++ b/tests/ide-test.c @@ -143,7 +143,7 @@ static QPCIDevice *get_pci_device(uint16_t *bmdma_base) uint16_t vendor_id, device_id; if (!pcibus) { - pcibus = qpci_init_pc(); + pcibus = qpci_init_pc(NULL); } /* Find PCI device and verify it's the right one */ diff --git a/tests/ivshmem-test.c b/tests/ivshmem-test.c index 0957ee75556..f36bfe7d0a5 100644 --- a/tests/ivshmem-test.c +++ b/tests/ivshmem-test.c @@ -105,7 +105,7 @@ static void setup_vm_cmd(IVState *s, const char *cmd, bool msix) uint64_t barsize; s->qtest = qtest_start(cmd); - s->pcibus = qpci_init_pc(); + s->pcibus = qpci_init_pc(NULL); s->dev = get_device(s->pcibus); s->reg_base = qpci_iomap(s->dev, 0, &barsize); diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c index f3be5500e1c..716ab7939e1 100644 --- a/tests/libqos/ahci.c +++ b/tests/libqos/ahci.c @@ -128,7 +128,7 @@ QPCIDevice *get_ahci_device(uint32_t *fingerprint) uint32_t ahci_fingerprint; QPCIBus *pcibus; - pcibus = qpci_init_pc(); + pcibus = qpci_init_pc(NULL); /* Find the AHCI PCI device and verify it's the right one. */ ahci = qpci_device_find(pcibus, QPCI_DEVFN(0x1F, 0x02)); diff --git a/tests/libqos/libqos-pc.c b/tests/libqos/libqos-pc.c index df340928a65..aa17c980d84 100644 --- a/tests/libqos/libqos-pc.c +++ b/tests/libqos/libqos-pc.c @@ -1,10 +1,13 @@ #include "qemu/osdep.h" #include "libqos/libqos-pc.h" #include "libqos/malloc-pc.h" +#include "libqos/pci-pc.h" static QOSOps qos_ops = { .init_allocator = pc_alloc_init_flags, - .uninit_allocator = pc_alloc_uninit + .uninit_allocator = pc_alloc_uninit, + .qpci_init = qpci_init_pc, + .qpci_free = qpci_free_pc, }; QOSState *qtest_pc_vboot(const char *cmdline_fmt, va_list ap) diff --git a/tests/libqos/libqos-spapr.c b/tests/libqos/libqos-spapr.c index f19408be000..333e6fbb45e 100644 --- a/tests/libqos/libqos-spapr.c +++ b/tests/libqos/libqos-spapr.c @@ -1,10 +1,13 @@ #include "qemu/osdep.h" #include "libqos/libqos-spapr.h" #include "libqos/malloc-spapr.h" +#include "libqos/pci-spapr.h" static QOSOps qos_ops = { .init_allocator = spapr_alloc_init_flags, - .uninit_allocator = spapr_alloc_uninit + .uninit_allocator = spapr_alloc_uninit, + .qpci_init = qpci_init_spapr, + .qpci_free = qpci_free_spapr, }; QOSState *qtest_spapr_vboot(const char *cmdline_fmt, va_list ap) diff --git a/tests/libqos/libqos.c b/tests/libqos/libqos.c index a852dc5f8e4..d842bf5126e 100644 --- a/tests/libqos/libqos.c +++ b/tests/libqos/libqos.c @@ -20,8 +20,13 @@ QOSState *qtest_vboot(QOSOps *ops, const char *cmdline_fmt, va_list ap) cmdline = g_strdup_vprintf(cmdline_fmt, ap); qs->qts = qtest_start(cmdline); qs->ops = ops; - if (ops && ops->init_allocator) { - qs->alloc = ops->init_allocator(ALLOC_NO_FLAGS); + if (ops) { + if (ops->init_allocator) { + qs->alloc = ops->init_allocator(ALLOC_NO_FLAGS); + } + if (ops->qpci_init && qs->alloc) { + qs->pcibus = ops->qpci_init(qs->alloc); + } } g_free(cmdline); @@ -49,9 +54,15 @@ QOSState *qtest_boot(QOSOps *ops, const char *cmdline_fmt, ...) */ void qtest_shutdown(QOSState *qs) { - if (qs->alloc && qs->ops && qs->ops->uninit_allocator) { - qs->ops->uninit_allocator(qs->alloc); - qs->alloc = NULL; + if (qs->ops) { + if (qs->pcibus && qs->ops->qpci_free) { + qs->ops->qpci_free(qs->pcibus); + qs->pcibus = NULL; + } + if (qs->alloc && qs->ops->uninit_allocator) { + qs->ops->uninit_allocator(qs->alloc); + qs->alloc = NULL; + } } qtest_quit(qs->qts); g_free(qs); diff --git a/tests/libqos/libqos.h b/tests/libqos/libqos.h index 604980d1250..a9f699019ca 100644 --- a/tests/libqos/libqos.h +++ b/tests/libqos/libqos.h @@ -8,11 +8,14 @@ typedef struct QOSOps { QGuestAllocator *(*init_allocator)(QAllocOpts); void (*uninit_allocator)(QGuestAllocator *); + QPCIBus *(*qpci_init)(QGuestAllocator *alloc); + void (*qpci_free)(QPCIBus *bus); } QOSOps; typedef struct QOSState { QTestState *qts; QGuestAllocator *alloc; + QPCIBus *pcibus; QOSOps *ops; } QOSState; diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c index 82066b8531f..9600ed6e413 100644 --- a/tests/libqos/pci-pc.c +++ b/tests/libqos/pci-pc.c @@ -212,7 +212,7 @@ static void qpci_pc_iounmap(QPCIBus *bus, void *data) /* FIXME */ } -QPCIBus *qpci_init_pc(void) +QPCIBus *qpci_init_pc(QGuestAllocator *alloc) { QPCIBusPC *ret; diff --git a/tests/libqos/pci-pc.h b/tests/libqos/pci-pc.h index 26211790cd1..9479b51642f 100644 --- a/tests/libqos/pci-pc.h +++ b/tests/libqos/pci-pc.h @@ -14,8 +14,9 @@ #define LIBQOS_PCI_PC_H #include "libqos/pci.h" +#include "libqos/malloc.h" -QPCIBus *qpci_init_pc(void); +QPCIBus *qpci_init_pc(QGuestAllocator *alloc); void qpci_free_pc(QPCIBus *bus); #endif diff --git a/tests/q35-test.c b/tests/q35-test.c index 71538fc17c3..763fe3d6ae2 100644 --- a/tests/q35-test.c +++ b/tests/q35-test.c @@ -42,7 +42,7 @@ static void test_smram_lock(void) QPCIDevice *pcidev; QDict *response; - pcibus = qpci_init_pc(); + pcibus = qpci_init_pc(NULL); g_assert(pcibus != NULL); pcidev = qpci_device_find(pcibus, 0); diff --git a/tests/rtl8139-test.c b/tests/rtl8139-test.c index 13de7eeafd8..c2f601a3801 100644 --- a/tests/rtl8139-test.c +++ b/tests/rtl8139-test.c @@ -35,7 +35,7 @@ static QPCIDevice *get_device(void) { QPCIDevice *dev; - pcibus = qpci_init_pc(); + pcibus = qpci_init_pc(NULL); qpci_device_foreach(pcibus, 0x10ec, 0x8139, save_fn, &dev); g_assert(dev != NULL); diff --git a/tests/tco-test.c b/tests/tco-test.c index 0d13aa8d631..0d201b1fcbb 100644 --- a/tests/tco-test.c +++ b/tests/tco-test.c @@ -57,7 +57,7 @@ static void test_init(TestData *d) qtest_irq_intercept_in(qs, "ioapic"); g_free(s); - bus = qpci_init_pc(); + bus = qpci_init_pc(NULL); d->dev = qpci_device_find(bus, QPCI_DEVFN(0x1f, 0x00)); g_assert(d->dev != NULL); diff --git a/tests/usb-hcd-ehci-test.c b/tests/usb-hcd-ehci-test.c index eb247ad453e..a4ceeaaa438 100644 --- a/tests/usb-hcd-ehci-test.c +++ b/tests/usb-hcd-ehci-test.c @@ -56,7 +56,7 @@ static void pci_init(void) if (pcibus) { return; } - pcibus = qpci_init_pc(); + pcibus = qpci_init_pc(NULL); g_assert(pcibus != NULL); qusb_pci_init_one(pcibus, &uhci1, QPCI_DEVFN(0x1d, 0), 4); diff --git a/tests/usb-hcd-uhci-test.c b/tests/usb-hcd-uhci-test.c index 5cd59ad91f0..c24063e8f61 100644 --- a/tests/usb-hcd-uhci-test.c +++ b/tests/usb-hcd-uhci-test.c @@ -23,7 +23,7 @@ static void test_port(int port) struct qhc uhci; g_assert(port > 0); - pcibus = qpci_init_pc(); + pcibus = qpci_init_pc(NULL); g_assert(pcibus != NULL); qusb_pci_init_one(pcibus, &uhci, QPCI_DEVFN(0x1d, 0), 4); uhci_port_test(&uhci, port - 1, UHCI_PORT_CCS); diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c index a39846e6fd8..d7c48c589a5 100644 --- a/tests/vhost-user-test.c +++ b/tests/vhost-user-test.c @@ -163,7 +163,7 @@ static void init_virtio_dev(TestServer *s) QVirtioPCIDevice *dev; uint32_t features; - bus = qpci_init_pc(); + bus = qpci_init_pc(NULL); g_assert_nonnull(bus); dev = qvirtio_pci_device_find(bus, VIRTIO_ID_NET); @@ -884,7 +884,7 @@ static void test_multiqueue(void) qtest_start(cmd); g_free(cmd); - bus = qpci_init_pc(); + bus = qpci_init_pc(NULL); dev = virtio_net_pci_init(bus, PCI_SLOT); alloc = pc_alloc_init(); diff --git a/tests/virtio-9p-test.c b/tests/virtio-9p-test.c index b8fb6cd869a..e8b21967d8e 100644 --- a/tests/virtio-9p-test.c +++ b/tests/virtio-9p-test.c @@ -63,7 +63,7 @@ static QVirtIO9P *qvirtio_9p_pci_init(void) v9p = g_new0(QVirtIO9P, 1); v9p->alloc = pc_alloc_init(); - v9p->bus = qpci_init_pc(); + v9p->bus = qpci_init_pc(NULL); dev = qvirtio_pci_device_find(v9p->bus, VIRTIO_ID_9P); g_assert_nonnull(dev); diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c index 811cf756c8d..3c4fecc1f02 100644 --- a/tests/virtio-blk-test.c +++ b/tests/virtio-blk-test.c @@ -75,7 +75,7 @@ static QPCIBus *pci_test_start(void) g_free(tmp_path); g_free(cmdline); - return qpci_init_pc(); + return qpci_init_pc(NULL); } static void arm_test_start(void) diff --git a/tests/virtio-net-test.c b/tests/virtio-net-test.c index 361506faf5b..a343a6b0480 100644 --- a/tests/virtio-net-test.c +++ b/tests/virtio-net-test.c @@ -62,7 +62,7 @@ static QPCIBus *pci_test_start(int socket) qtest_start(cmdline); g_free(cmdline); - return qpci_init_pc(); + return qpci_init_pc(NULL); } static void driver_init(const QVirtioBus *bus, QVirtioDevice *dev) diff --git a/tests/virtio-scsi-test.c b/tests/virtio-scsi-test.c index f1489e68a0c..79088bb249e 100644 --- a/tests/virtio-scsi-test.c +++ b/tests/virtio-scsi-test.c @@ -146,7 +146,7 @@ static QVirtIOSCSI *qvirtio_scsi_pci_init(int slot) vs = g_new0(QVirtIOSCSI, 1); vs->alloc = pc_alloc_init(); - vs->bus = qpci_init_pc(); + vs->bus = qpci_init_pc(NULL); dev = qvirtio_pci_device_find(vs->bus, VIRTIO_ID_SCSI); vs->dev = (QVirtioDevice *)dev; From 61ae5cf3a2e1a7764a60fec69cd8731516d5fb83 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 29 Sep 2016 12:32:46 +0200 Subject: [PATCH 529/723] libqos: use generic qtest_shutdown() Machine specific shutdown function can be registered by the machine specific qtest_XXX_boot() if needed. So we will not have to test twice the architecture (on boot and on shutdown) if the test can be run on several architectures. Signed-off-by: Laurent Vivier Reviewed-by: Greg Kurz Reviewed-by: David Gibson Signed-off-by: David Gibson --- tests/libqos/libqos-pc.c | 3 ++- tests/libqos/libqos-spapr.c | 3 ++- tests/libqos/libqos.c | 11 ++++++++++- tests/libqos/libqos.h | 8 ++++++-- tests/rtas-test.c | 2 +- 5 files changed, 21 insertions(+), 6 deletions(-) diff --git a/tests/libqos/libqos-pc.c b/tests/libqos/libqos-pc.c index aa17c980d84..b5547588029 100644 --- a/tests/libqos/libqos-pc.c +++ b/tests/libqos/libqos-pc.c @@ -8,6 +8,7 @@ static QOSOps qos_ops = { .uninit_allocator = pc_alloc_uninit, .qpci_init = qpci_init_pc, .qpci_free = qpci_free_pc, + .shutdown = qtest_pc_shutdown, }; QOSState *qtest_pc_vboot(const char *cmdline_fmt, va_list ap) @@ -31,5 +32,5 @@ QOSState *qtest_pc_boot(const char *cmdline_fmt, ...) void qtest_pc_shutdown(QOSState *qs) { - return qtest_shutdown(qs); + return qtest_common_shutdown(qs); } diff --git a/tests/libqos/libqos-spapr.c b/tests/libqos/libqos-spapr.c index 333e6fbb45e..a37791e5d0d 100644 --- a/tests/libqos/libqos-spapr.c +++ b/tests/libqos/libqos-spapr.c @@ -8,6 +8,7 @@ static QOSOps qos_ops = { .uninit_allocator = spapr_alloc_uninit, .qpci_init = qpci_init_spapr, .qpci_free = qpci_free_spapr, + .shutdown = qtest_spapr_shutdown, }; QOSState *qtest_spapr_vboot(const char *cmdline_fmt, va_list ap) @@ -29,5 +30,5 @@ QOSState *qtest_spapr_boot(const char *cmdline_fmt, ...) void qtest_spapr_shutdown(QOSState *qs) { - return qtest_shutdown(qs); + return qtest_common_shutdown(qs); } diff --git a/tests/libqos/libqos.c b/tests/libqos/libqos.c index d842bf5126e..7abb48254e9 100644 --- a/tests/libqos/libqos.c +++ b/tests/libqos/libqos.c @@ -52,7 +52,7 @@ QOSState *qtest_boot(QOSOps *ops, const char *cmdline_fmt, ...) /** * Tear down the QEMU instance. */ -void qtest_shutdown(QOSState *qs) +void qtest_common_shutdown(QOSState *qs) { if (qs->ops) { if (qs->pcibus && qs->ops->qpci_free) { @@ -68,6 +68,15 @@ void qtest_shutdown(QOSState *qs) g_free(qs); } +void qtest_shutdown(QOSState *qs) +{ + if (qs->ops && qs->ops->shutdown) { + qs->ops->shutdown(qs); + } else { + qtest_common_shutdown(qs); + } +} + void set_context(QOSState *s) { global_qtest = s->qts; diff --git a/tests/libqos/libqos.h b/tests/libqos/libqos.h index a9f699019ca..231969766f1 100644 --- a/tests/libqos/libqos.h +++ b/tests/libqos/libqos.h @@ -5,22 +5,26 @@ #include "libqos/pci.h" #include "libqos/malloc-pc.h" +typedef struct QOSState QOSState; + typedef struct QOSOps { QGuestAllocator *(*init_allocator)(QAllocOpts); void (*uninit_allocator)(QGuestAllocator *); QPCIBus *(*qpci_init)(QGuestAllocator *alloc); void (*qpci_free)(QPCIBus *bus); + void (*shutdown)(QOSState *); } QOSOps; -typedef struct QOSState { +struct QOSState { QTestState *qts; QGuestAllocator *alloc; QPCIBus *pcibus; QOSOps *ops; -} QOSState; +}; QOSState *qtest_vboot(QOSOps *ops, const char *cmdline_fmt, va_list ap); QOSState *qtest_boot(QOSOps *ops, const char *cmdline_fmt, ...); +void qtest_common_shutdown(QOSState *qs); void qtest_shutdown(QOSState *qs); bool have_qemu_img(void); void mkimg(const char *file, const char *fmt, unsigned size_mb); diff --git a/tests/rtas-test.c b/tests/rtas-test.c index 73c780339b1..ba0867afbd2 100644 --- a/tests/rtas-test.c +++ b/tests/rtas-test.c @@ -22,7 +22,7 @@ static void test_rtas_get_time_of_day(void) t2 = mktimegm(&tm); g_assert(t2 - t1 < 5); /* 5 sec max to run the test */ - qtest_spapr_shutdown(qs); + qtest_shutdown(qs); } int main(int argc, char *argv[]) From aa9026fd5e3d58cdaf3b28b60a4639f69c7bfff6 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 29 Sep 2016 12:32:47 +0200 Subject: [PATCH 530/723] tests: enable ohci/uhci/xhci tests on PPC64 Signed-off-by: Laurent Vivier Signed-off-by: David Gibson --- tests/Makefile.include | 8 +++++++- tests/usb-hcd-uhci-test.c | 24 ++++++++++++++++-------- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/tests/Makefile.include b/tests/Makefile.include index 8b1c1717de1..c46a32d0f23 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -272,6 +272,12 @@ check-qtest-ppc64-y += tests/postcopy-test$(EXESUF) check-qtest-ppc64-y += tests/boot-serial-test$(EXESUF) check-qtest-ppc64-y += tests/rtas-test$(EXESUF) check-qtest-ppc64-y += tests/pxe-test$(EXESUF) +check-qtest-ppc64-y += tests/usb-hcd-ohci-test$(EXESUF) +gcov-files-ppc64-y += hw/usb/hcd-ohci.c +check-qtest-ppc64-y += tests/usb-hcd-uhci-test$(EXESUF) +gcov-files-ppc64-y += hw/usb/hcd-uhci.c +check-qtest-ppc64-y += tests/usb-hcd-xhci-test$(EXESUF) +gcov-files-ppc64-y += hw/usb/hcd-xhci.c check-qtest-sh4-y = tests/endianness-test$(EXESUF) @@ -597,7 +603,7 @@ libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o libqos-pc-obj-y += tests/libqos/ahci.o libqos-omap-obj-y = $(libqos-obj-y) tests/libqos/i2c-omap.o libqos-imx-obj-y = $(libqos-obj-y) tests/libqos/i2c-imx.o -libqos-usb-obj-y = $(libqos-pc-obj-y) tests/libqos/usb.o +libqos-usb-obj-y = $(libqos-spapr-obj-y) $(libqos-pc-obj-y) tests/libqos/usb.o libqos-virtio-obj-y = $(libqos-pc-obj-y) tests/libqos/virtio.o tests/libqos/virtio-pci.o tests/libqos/virtio-mmio.o tests/libqos/malloc-generic.o tests/device-introspect-test$(EXESUF): tests/device-introspect-test.o diff --git a/tests/usb-hcd-uhci-test.c b/tests/usb-hcd-uhci-test.c index c24063e8f61..4b951ce4922 100644 --- a/tests/usb-hcd-uhci-test.c +++ b/tests/usb-hcd-uhci-test.c @@ -9,9 +9,13 @@ #include "qemu/osdep.h" #include "libqtest.h" +#include "libqos/libqos.h" #include "libqos/usb.h" +#include "libqos/libqos-pc.h" +#include "libqos/libqos-spapr.h" #include "hw/usb/uhci-regs.h" +static QOSState *qs; static void test_uhci_init(void) { @@ -19,13 +23,10 @@ static void test_uhci_init(void) static void test_port(int port) { - QPCIBus *pcibus; struct qhc uhci; g_assert(port > 0); - pcibus = qpci_init_pc(NULL); - g_assert(pcibus != NULL); - qusb_pci_init_one(pcibus, &uhci, QPCI_DEVFN(0x1d, 0), 4); + qusb_pci_init_one(qs->pcibus, &uhci, QPCI_DEVFN(0x1d, 0), 4); uhci_port_test(&uhci, port - 1, UHCI_PORT_CCS); } @@ -75,6 +76,7 @@ static void test_usb_storage_hotplug(void) int main(int argc, char **argv) { + const char *arch = qtest_get_arch(); int ret; g_test_init(&argc, &argv, NULL); @@ -84,11 +86,17 @@ int main(int argc, char **argv) qtest_add_func("/uhci/pci/hotplug", test_uhci_hotplug); qtest_add_func("/uhci/pci/hotplug/usb-storage", test_usb_storage_hotplug); - qtest_start("-device piix3-usb-uhci,id=uhci,addr=1d.0" - " -drive id=drive0,if=none,file=/dev/null,format=raw" - " -device usb-tablet,bus=uhci.0,port=1"); + if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { + qs = qtest_pc_boot("-device piix3-usb-uhci,id=uhci,addr=1d.0" + " -drive id=drive0,if=none,file=/dev/null,format=raw" + " -device usb-tablet,bus=uhci.0,port=1"); + } else if (strcmp(arch, "ppc64") == 0) { + qs = qtest_spapr_boot("-device piix3-usb-uhci,id=uhci,addr=1d.0" + " -drive id=drive0,if=none,file=/dev/null,format=raw" + " -device usb-tablet,bus=uhci.0,port=1"); + } ret = g_test_run(); - qtest_end(); + qtest_shutdown(qs); return ret; } From e17a87792d4886d2a508672c1639df3c1d40f1d1 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Mon, 3 Oct 2016 14:13:20 +0200 Subject: [PATCH 531/723] spapr: fix check of cpu alias name in spapr_get_cpu_core_type() If the user passes an alias name and a property to -cpu, QEMU fails to find the CPU definition and exits. $ qemu-system-ppc64 -cpu POWER8E,compat=power7 qemu-system-ppc64: Unable to find sPAPR CPU Core definition This happens because spapr_get_cpu_core_type() passes the full string from the command line (i.e. "POWER8E,compat=power7") to ppc_cpu_lookup_alias(), instead of the alias name piece only (i.e. "POWER8E"). The fix is to pass model_pieces[0] to ppc_cpu_lookup_alias(). Signed-off-by: Greg Kurz Reviewed-by: Bharata B Rao Signed-off-by: David Gibson --- hw/ppc/spapr_cpu_core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index 6f0533c3425..35d1873b9ff 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -92,20 +92,20 @@ char *spapr_get_cpu_core_type(const char *model) gchar **model_pieces = g_strsplit(model, ",", 2); core_type = g_strdup_printf("%s-%s", model_pieces[0], TYPE_SPAPR_CPU_CORE); - g_strfreev(model_pieces); /* Check whether it exists or whether we have to look up an alias name */ if (!object_class_by_name(core_type)) { const char *realmodel; g_free(core_type); - realmodel = ppc_cpu_lookup_alias(model); + core_type = NULL; + realmodel = ppc_cpu_lookup_alias(model_pieces[0]); if (realmodel) { - return spapr_get_cpu_core_type(realmodel); + core_type = spapr_get_cpu_core_type(realmodel); } - return NULL; } + g_strfreev(model_pieces); return core_type; } From ef6c47f1d7c242cb0ce66fcaab4ebcd94ad2a134 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 5 Oct 2016 14:52:09 +0200 Subject: [PATCH 532/723] tests/pxe: Use -nodefaults to speed up ppc64/ipv6 pxe test SLOF is unfortunately quite slow when running with TCG, so the pxe test is also performing rather slow here. By using "-nodefaults" we can disable some devices (vscsi) that we are not interested in here, so that SLOF does not have to scan them during boot and thus starts up a little bit faster. The ppc64 pxe-test now only takes 27 seconds on my laptop instead of 33 seconds. The "-nodefaults" flag seems to work fine for the x86 tests, too, so it is added here unconditionally here (though there is no speed-up on x86 by using this flag). Suggested-by: Paolo Bonzini Signed-off-by: Thomas Huth Reviewed-by: Laurent Vivier Signed-off-by: David Gibson --- tests/pxe-test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/pxe-test.c b/tests/pxe-test.c index 0bdb7a170a7..5d3ddbe5e95 100644 --- a/tests/pxe-test.c +++ b/tests/pxe-test.c @@ -25,7 +25,7 @@ static void test_pxe_one(const char *params, bool ipv6) { char *args; - args = g_strdup_printf("-machine accel=tcg -boot order=n " + args = g_strdup_printf("-machine accel=tcg -nodefaults -boot order=n " "-netdev user,id=" NETNAME ",tftp=./,bootfile=%s," "ipv4=%s,ipv6=%s %s", disk, ipv6 ? "off" : "on", ipv6 ? "on" : "off", params); @@ -48,7 +48,7 @@ static void test_pxe_virtio_pci(void) static void test_pxe_spapr_vlan(void) { - test_pxe_one("-vga none -device spapr-vlan,netdev=" NETNAME, true); + test_pxe_one("-device spapr-vlan,netdev=" NETNAME, true); } int main(int argc, char *argv[]) From 3daa4a9f9580ffda47df93c7c53371af226bf970 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 5 Oct 2016 09:44:51 +0200 Subject: [PATCH 533/723] hw/ppc/spapr: Use POWER8 by default for the pseries-2.8 machine A couple of distributors are compiling their distributions with "-mcpu=power8" for ppc64le these days, so the user sooner or later runs into a crash there when not explicitely specifying the "-cpu POWER8" option to QEMU (which is currently using POWER7 for the "pseries" machine by default). Due to this reason, the linux-user target already switched to POWER8 a while ago (see commit de3f1b98410e0d5b406a0df3a48547b559d18602). Since the softmmu target of course has the same problem, we should switch there to POWER8 for the newer machine types, too. Signed-off-by: Thomas Huth Signed-off-by: David Gibson --- hw/ppc/spapr.c | 6 +++++- include/hw/ppc/spapr.h | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 63b6a0dd46a..03e38039e87 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1775,7 +1775,7 @@ static void ppc_spapr_init(MachineState *machine) /* init CPUs */ if (machine->cpu_model == NULL) { - machine->cpu_model = kvm_enabled() ? "host" : "POWER7"; + machine->cpu_model = kvm_enabled() ? "host" : smc->tcg_default_cpu; } ppc_cpu_parse_features(machine->cpu_model); @@ -2402,6 +2402,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) mc->cpu_index_to_socket_id = spapr_cpu_index_to_socket_id; smc->dr_lmb_enabled = true; + smc->tcg_default_cpu = "POWER8"; mc->query_hotpluggable_cpus = spapr_query_hotpluggable_cpus; fwc->get_dev_path = spapr_get_fw_dev_path; nc->nmi_monitor_handler = spapr_nmi; @@ -2478,7 +2479,10 @@ static void spapr_machine_2_7_instance_options(MachineState *machine) static void spapr_machine_2_7_class_options(MachineClass *mc) { + sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc); + spapr_machine_2_8_class_options(mc); + smc->tcg_default_cpu = "POWER7"; SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_7); } diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index 6289d50dbfb..39dadaa9ce6 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -39,6 +39,7 @@ struct sPAPRMachineClass { /*< public >*/ bool dr_lmb_enabled; /* enable dynamic-reconfig/hotplug of LMBs */ bool use_ohci_by_default; /* use USB-OHCI instead of XHCI */ + const char *tcg_default_cpu; /* which (TCG) CPU to simulate by default */ }; /** From 0bdb12c7c50e2e92f2e17fe29ca8a8ddee91b4a1 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 4 Oct 2016 17:27:21 +0100 Subject: [PATCH 534/723] rules.mak: quiet-command: Split command name and args to print The quiet-command make rule currently takes two arguments: the command and arguments to run, and a string to print if the V flag is not set (ie we are not being verbose). By convention, the string printed is of the form " NAME some args". Unfortunately to get nicely lined up output all the strings have to agree about what column the arguments should start in, which means that if we add a new quiet-command usage which wants a slightly longer CMD name then we either put up with misalignment or change every quiet-command string. Split the quiet-mode string into two, the "NAME" and the "same args" part, and use printf(1) to format the string automatically. This means we only need to change one place if we want to support a longer maximum name. In particular, we can now print 7-character names lined up properly (they are needed for the OSX "SETTOOL" invocation). Change all the uses of quiet-command to the new syntax. (Any which are missed or inadvertently reintroduced via later merges will result in slightly misformatted quiet output rather than disaster.) A few places in the pc-bios/ makefiles are updated to use "BUILD", "SIGN" and "STRIP" rather than "Building", "Signing" and "Stripping" for consistency and to keep them below 7 characters. Module .mo links now print "LD" rather than the nonstandard "LD -r". Signed-off-by: Peter Maydell Reviewed-by: Eric Blake Message-id: 1475598441-27908-1-git-send-email-peter.maydell@linaro.org --- Makefile | 66 +++++++++++++++++------------------ Makefile.target | 18 +++++----- pc-bios/optionrom/Makefile | 8 ++--- pc-bios/s390-ccw/Makefile | 4 +-- pc-bios/spapr-rtas/Makefile | 4 +-- po/Makefile | 6 ++-- qga/vss-win32/Makefile.objs | 6 ++-- rules.mak | 32 ++++++++++------- target-s390x/Makefile.objs | 4 +-- tests/Makefile.include | 26 +++++++------- tests/docker/Makefile.include | 8 ++--- trace/Makefile.objs | 24 ++++++------- 12 files changed, 106 insertions(+), 100 deletions(-) diff --git a/Makefile b/Makefile index f10361675da..b103a98c95b 100644 --- a/Makefile +++ b/Makefile @@ -107,20 +107,20 @@ SUBDIR_DEVICES_MAK_DEP=$(patsubst %, %-config-devices.mak.d, $(TARGET_DIRS)) ifeq ($(SUBDIR_DEVICES_MAK),) config-all-devices.mak: - $(call quiet-command,echo '# no devices' > $@," GEN $@") + $(call quiet-command,echo '# no devices' > $@,"GEN","$@") else config-all-devices.mak: $(SUBDIR_DEVICES_MAK) $(call quiet-command, sed -n \ 's|^\([^=]*\)=\(.*\)$$|\1:=$$(findstring y,$$(\1)\2)|p' \ $(SUBDIR_DEVICES_MAK) | sort -u > $@, \ - " GEN $@") + "GEN","$@") endif -include $(SUBDIR_DEVICES_MAK_DEP) %/config-devices.mak: default-configs/%.mak $(SRC_PATH)/scripts/make_device_config.sh $(call quiet-command, \ - $(SHELL) $(SRC_PATH)/scripts/make_device_config.sh $< $*-config-devices.mak.d $@ > $@.tmp, " GEN $@.tmp") + $(SHELL) $(SRC_PATH)/scripts/make_device_config.sh $< $*-config-devices.mak.d $@ > $@.tmp,"GEN","$@.tmp") $(call quiet-command, if test -f $@; then \ if cmp -s $@.old $@; then \ mv $@.tmp $@; \ @@ -137,7 +137,7 @@ endif else \ mv $@.tmp $@; \ cp -p $@ $@.old; \ - fi, " GEN $@"); + fi,"GEN","$@"); defconfig: rm -f config-all-devices.mak $(SUBDIR_DEVICES_MAK) @@ -191,7 +191,7 @@ qemu-version.h: FORCE config-host.h: config-host.h-timestamp config-host.h-timestamp: config-host.mak qemu-options.def: $(SRC_PATH)/qemu-options.hx $(SRC_PATH)/scripts/hxtool - $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@," GEN $@") + $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"GEN","$@") SUBDIR_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS)) SOFTMMU_SUBDIR_RULES=$(filter %-softmmu,$(SUBDIR_RULES)) @@ -235,9 +235,9 @@ ALL_SUBDIRS=$(TARGET_DIRS) $(patsubst %,pc-bios/%, $(ROMS)) recurse-all: $(SUBDIR_RULES) $(ROMSUBDIR_RULES) $(BUILD_DIR)/version.o: $(SRC_PATH)/version.rc config-host.h | $(BUILD_DIR)/version.lo - $(call quiet-command,$(WINDRES) -I$(BUILD_DIR) -o $@ $<," RC version.o") + $(call quiet-command,$(WINDRES) -I$(BUILD_DIR) -o $@ $<,"RC","version.o") $(BUILD_DIR)/version.lo: $(SRC_PATH)/version.rc config-host.h - $(call quiet-command,$(WINDRES) -I$(BUILD_DIR) -o $@ $<," RC version.lo") + $(call quiet-command,$(WINDRES) -I$(BUILD_DIR) -o $@ $<,"RC","version.lo") Makefile: $(version-obj-y) $(version-lobj-y) @@ -261,7 +261,7 @@ fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/9p-marshal fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/scripts/hxtool - $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@," GEN $@") + $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"GEN","$@") qemu-ga$(EXESUF): LIBS = $(LIBS_QGA) qemu-ga$(EXESUF): QEMU_CFLAGS += -I qga/qapi-generated @@ -274,17 +274,17 @@ qga/qapi-generated/qga-qapi-types.c qga/qapi-generated/qga-qapi-types.h :\ $(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py \ $(gen-out-type) -o qga/qapi-generated -p "qga-" $<, \ - " GEN $@") + "GEN","$@") qga/qapi-generated/qga-qapi-visit.c qga/qapi-generated/qga-qapi-visit.h :\ $(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py \ $(gen-out-type) -o qga/qapi-generated -p "qga-" $<, \ - " GEN $@") + "GEN","$@") qga/qapi-generated/qga-qmp-commands.h qga/qapi-generated/qga-qmp-marshal.c :\ $(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py \ $(gen-out-type) -o qga/qapi-generated -p "qga-" $<, \ - " GEN $@") + "GEN","$@") qapi-modules = $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/qapi/common.json \ $(SRC_PATH)/qapi/block.json $(SRC_PATH)/qapi/block-core.json \ @@ -296,27 +296,27 @@ qapi-types.c qapi-types.h :\ $(qapi-modules) $(SRC_PATH)/scripts/qapi-types.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py \ $(gen-out-type) -o "." -b $<, \ - " GEN $@") + "GEN","$@") qapi-visit.c qapi-visit.h :\ $(qapi-modules) $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py \ $(gen-out-type) -o "." -b $<, \ - " GEN $@") + "GEN","$@") qapi-event.c qapi-event.h :\ $(qapi-modules) $(SRC_PATH)/scripts/qapi-event.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-event.py \ $(gen-out-type) -o "." $<, \ - " GEN $@") + "GEN","$@") qmp-commands.h qmp-marshal.c :\ $(qapi-modules) $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py \ $(gen-out-type) -o "." $<, \ - " GEN $@") + "GEN","$@") qmp-introspect.h qmp-introspect.c :\ $(qapi-modules) $(SRC_PATH)/scripts/qapi-introspect.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-introspect.py \ $(gen-out-type) -o "." $<, \ - " GEN $@") + "GEN","$@") QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h) $(qga-obj-y) qemu-ga.o: $(QGALIB_GEN) @@ -335,7 +335,7 @@ $(QEMU_GA_MSI): config-host.mak $(QEMU_GA_MSI): $(SRC_PATH)/qga/installer/qemu-ga.wxs $(call quiet-command,QEMU_GA_VERSION="$(QEMU_GA_VERSION)" QEMU_GA_MANUFACTURER="$(QEMU_GA_MANUFACTURER)" QEMU_GA_DISTRO="$(QEMU_GA_DISTRO)" BUILD_DIR="$(BUILD_DIR)" \ - wixl -o $@ $(QEMU_GA_MSI_ARCH) $(QEMU_GA_MSI_WITH_VSS) $(QEMU_GA_MSI_MINGW_DLL_PATH) $<, " WIXL $@") + wixl -o $@ $(QEMU_GA_MSI_ARCH) $(QEMU_GA_MSI_WITH_VSS) $(QEMU_GA_MSI_MINGW_DLL_PATH) $<,"WIXL","$@") else msi: @echo "MSI build not configured or dependency resolution failed (reconfigure with --enable-guest-agent-msi option)" @@ -354,7 +354,7 @@ ivshmem-server$(EXESUF): $(ivshmem-server-obj-y) libqemuutil.a libqemustub.a module_block.h: $(SRC_PATH)/scripts/modules/module_block.py config-host.mak $(call quiet-command,$(PYTHON) $< $@ \ $(addprefix $(SRC_PATH)/,$(patsubst %.mo,%.c,$(block-obj-m))), \ - " GEN $@") + "GEN","$@") clean: # avoid old build problems by removing potentially incorrect old files @@ -521,13 +521,13 @@ ui/shader/%-vert.h: $(SRC_PATH)/ui/shader/%.vert $(SRC_PATH)/scripts/shaderinclu @mkdir -p $(dir $@) $(call quiet-command,\ perl $(SRC_PATH)/scripts/shaderinclude.pl $< > $@,\ - " VERT $@") + "VERT","$@") ui/shader/%-frag.h: $(SRC_PATH)/ui/shader/%.frag $(SRC_PATH)/scripts/shaderinclude.pl @mkdir -p $(dir $@) $(call quiet-command,\ perl $(SRC_PATH)/scripts/shaderinclude.pl $< > $@,\ - " FRAG $@") + "FRAG","$@") ui/console-gl.o: $(SRC_PATH)/ui/console-gl.c \ ui/shader/texture-blit-vert.h ui/shader/texture-blit-frag.h @@ -537,60 +537,60 @@ MAKEINFO=makeinfo MAKEINFOFLAGS=--no-headers --no-split --number-sections TEXIFLAG=$(if $(V),,--quiet) %.dvi: %.texi - $(call quiet-command,texi2dvi $(TEXIFLAG) -I . $<," GEN $@") + $(call quiet-command,texi2dvi $(TEXIFLAG) -I . $<,"GEN","$@") %.html: %.texi $(call quiet-command,LC_ALL=C $(MAKEINFO) $(MAKEINFOFLAGS) --html $< -o $@, \ - " GEN $@") + "GEN","$@") %.info: %.texi - $(call quiet-command,$(MAKEINFO) $< -o $@," GEN $@") + $(call quiet-command,$(MAKEINFO) $< -o $@,"GEN","$@") %.pdf: %.texi - $(call quiet-command,texi2pdf $(TEXIFLAG) -I . $<," GEN $@") + $(call quiet-command,texi2pdf $(TEXIFLAG) -I . $<,"GEN","$@") qemu-options.texi: $(SRC_PATH)/qemu-options.hx $(SRC_PATH)/scripts/hxtool - $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@," GEN $@") + $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"GEN","$@") qemu-monitor.texi: $(SRC_PATH)/hmp-commands.hx $(SRC_PATH)/scripts/hxtool - $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@," GEN $@") + $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"GEN","$@") qemu-monitor-info.texi: $(SRC_PATH)/hmp-commands-info.hx $(SRC_PATH)/scripts/hxtool - $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@," GEN $@") + $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"GEN","$@") qemu-img-cmds.texi: $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/scripts/hxtool - $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@," GEN $@") + $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"GEN","$@") qemu.1: qemu-doc.texi qemu-options.texi qemu-monitor.texi qemu-monitor-info.texi $(call quiet-command, \ perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu.pod && \ $(POD2MAN) --section=1 --center=" " --release=" " qemu.pod > $@, \ - " GEN $@") + "GEN","$@") qemu.1: qemu-option-trace.texi qemu-img.1: qemu-img.texi qemu-option-trace.texi qemu-img-cmds.texi $(call quiet-command, \ perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu-img.pod && \ $(POD2MAN) --section=1 --center=" " --release=" " qemu-img.pod > $@, \ - " GEN $@") + "GEN","$@") fsdev/virtfs-proxy-helper.1: fsdev/virtfs-proxy-helper.texi $(call quiet-command, \ perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< fsdev/virtfs-proxy-helper.pod && \ $(POD2MAN) --section=1 --center=" " --release=" " fsdev/virtfs-proxy-helper.pod > $@, \ - " GEN $@") + "GEN","$@") qemu-nbd.8: qemu-nbd.texi qemu-option-trace.texi $(call quiet-command, \ perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu-nbd.pod && \ $(POD2MAN) --section=8 --center=" " --release=" " qemu-nbd.pod > $@, \ - " GEN $@") + "GEN","$@") qemu-ga.8: qemu-ga.texi $(call quiet-command, \ perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu-ga.pod && \ $(POD2MAN) --section=8 --center=" " --release=" " qemu-ga.pod > $@, \ - " GEN $@") + "GEN","$@") dvi: qemu-doc.dvi qemu-tech.dvi html: qemu-doc.html qemu-tech.html diff --git a/Makefile.target b/Makefile.target index 19cc49c0d7c..9968871d6ee 100644 --- a/Makefile.target +++ b/Makefile.target @@ -26,7 +26,7 @@ ifneq (,$(findstring -mwindows,$(libs_softmmu))) # Terminate program name with a 'w' because the linker builds a windows executable. QEMU_PROGW=qemu-system-$(TARGET_NAME)w$(EXESUF) $(QEMU_PROG): $(QEMU_PROGW) - $(call quiet-command,$(OBJCOPY) --subsystem console $(QEMU_PROGW) $(QEMU_PROG)," GEN $(TARGET_DIR)$(QEMU_PROG)") + $(call quiet-command,$(OBJCOPY) --subsystem console $(QEMU_PROGW) $(QEMU_PROG),"GEN","$(TARGET_DIR)$(QEMU_PROG)") QEMU_PROG_BUILD = $(QEMU_PROGW) else QEMU_PROG_BUILD = $(QEMU_PROG) @@ -55,7 +55,7 @@ $(QEMU_PROG).stp-installed: $(BUILD_DIR)/trace-events-all --binary=$(bindir)/$(QEMU_PROG) \ --target-name=$(TARGET_NAME) \ --target-type=$(TARGET_TYPE) \ - < $< > $@," GEN $(TARGET_DIR)$(QEMU_PROG).stp-installed") + < $< > $@,"GEN","$(TARGET_DIR)$(QEMU_PROG).stp-installed") $(QEMU_PROG).stp: $(BUILD_DIR)/trace-events-all $(call quiet-command,$(TRACETOOL) \ @@ -64,14 +64,14 @@ $(QEMU_PROG).stp: $(BUILD_DIR)/trace-events-all --binary=$(realpath .)/$(QEMU_PROG) \ --target-name=$(TARGET_NAME) \ --target-type=$(TARGET_TYPE) \ - < $< > $@," GEN $(TARGET_DIR)$(QEMU_PROG).stp") + < $< > $@,"GEN","$(TARGET_DIR)$(QEMU_PROG).stp") $(QEMU_PROG)-simpletrace.stp: $(BUILD_DIR)/trace-events-all $(call quiet-command,$(TRACETOOL) \ --format=simpletrace-stap \ --backends=$(TRACE_BACKENDS) \ --probe-prefix=qemu.$(TARGET_TYPE).$(TARGET_NAME) \ - < $< > $@," GEN $(TARGET_DIR)$(QEMU_PROG)-simpletrace.stp") + < $< > $@,"GEN","$(TARGET_DIR)$(QEMU_PROG)-simpletrace.stp") else stap: @@ -196,18 +196,18 @@ $(QEMU_PROG_BUILD): config-devices.mak $(QEMU_PROG_BUILD): $(all-obj-y) ../libqemuutil.a ../libqemustub.a $(call LINK, $(filter-out %.mak, $^)) ifdef CONFIG_DARWIN - $(call quiet-command,Rez -append $(SRC_PATH)/pc-bios/qemu.rsrc -o $@," REZ $(TARGET_DIR)$@") - $(call quiet-command,SetFile -a C $@," SETFILE $(TARGET_DIR)$@") + $(call quiet-command,Rez -append $(SRC_PATH)/pc-bios/qemu.rsrc -o $@,"REZ","$(TARGET_DIR)$@") + $(call quiet-command,SetFile -a C $@,"SETFILE","$(TARGET_DIR)$@") endif gdbstub-xml.c: $(TARGET_XML_FILES) $(SRC_PATH)/scripts/feature_to_c.sh - $(call quiet-command,rm -f $@ && $(SHELL) $(SRC_PATH)/scripts/feature_to_c.sh $@ $(TARGET_XML_FILES)," GEN $(TARGET_DIR)$@") + $(call quiet-command,rm -f $@ && $(SHELL) $(SRC_PATH)/scripts/feature_to_c.sh $@ $(TARGET_XML_FILES),"GEN","$(TARGET_DIR)$@") hmp-commands.h: $(SRC_PATH)/hmp-commands.hx $(SRC_PATH)/scripts/hxtool - $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@," GEN $(TARGET_DIR)$@") + $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"GEN","$(TARGET_DIR)$@") hmp-commands-info.h: $(SRC_PATH)/hmp-commands-info.hx $(SRC_PATH)/scripts/hxtool - $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@," GEN $(TARGET_DIR)$@") + $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"GEN","$(TARGET_DIR)$@") clean: clean-target rm -f *.a *~ $(PROGS) diff --git a/pc-bios/optionrom/Makefile b/pc-bios/optionrom/Makefile index afa48f1cf1f..fa53d9e58e9 100644 --- a/pc-bios/optionrom/Makefile +++ b/pc-bios/optionrom/Makefile @@ -43,16 +43,16 @@ build-all: multiboot.bin linuxboot.bin linuxboot_dma.bin kvmvapic.bin %.o: %.S - $(call quiet-command,$(CPP) $(QEMU_INCLUDES) $(QEMU_DGFLAGS) -c -o - $< | $(AS) $(ASFLAGS) -o $@," AS $(TARGET_DIR)$@") + $(call quiet-command,$(CPP) $(QEMU_INCLUDES) $(QEMU_DGFLAGS) -c -o - $< | $(AS) $(ASFLAGS) -o $@,"AS","$(TARGET_DIR)$@") %.img: %.o - $(call quiet-command,$(LD) $(LDFLAGS_NOPIE) -m $(LD_I386_EMULATION) -T $(SRC_PATH)/pc-bios/optionrom/flat.lds -s -o $@ $<," Building $(TARGET_DIR)$@") + $(call quiet-command,$(LD) $(LDFLAGS_NOPIE) -m $(LD_I386_EMULATION) -T $(SRC_PATH)/pc-bios/optionrom/flat.lds -s -o $@ $<,"BUILD","$(TARGET_DIR)$@") %.raw: %.img - $(call quiet-command,$(OBJCOPY) -O binary -j .text $< $@," Building $(TARGET_DIR)$@") + $(call quiet-command,$(OBJCOPY) -O binary -j .text $< $@,"BUILD","$(TARGET_DIR)$@") %.bin: %.raw - $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/signrom.py $< $@," Signing $(TARGET_DIR)$@") + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/signrom.py $< $@,"SIGN","$(TARGET_DIR)$@") clean: rm -f *.o *.d *.raw *.img *.bin *~ diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile index 0ab25388a45..0339c247898 100644 --- a/pc-bios/s390-ccw/Makefile +++ b/pc-bios/s390-ccw/Makefile @@ -19,10 +19,10 @@ LDFLAGS += -Wl,-pie -nostdlib build-all: s390-ccw.img s390-ccw.elf: $(OBJECTS) - $(call quiet-command,$(CC) $(LDFLAGS) -o $@ $(OBJECTS)," Building $(TARGET_DIR)$@") + $(call quiet-command,$(CC) $(LDFLAGS) -o $@ $(OBJECTS),"BUILD","$(TARGET_DIR)$@") s390-ccw.img: s390-ccw.elf - $(call quiet-command,strip --strip-unneeded $< -o $@," Stripping $(TARGET_DIR)$@") + $(call quiet-command,strip --strip-unneeded $< -o $@,"STRIP","$(TARGET_DIR)$@") $(OBJECTS): Makefile diff --git a/pc-bios/spapr-rtas/Makefile b/pc-bios/spapr-rtas/Makefile index dc8b23e3ce8..f26dd428b79 100644 --- a/pc-bios/spapr-rtas/Makefile +++ b/pc-bios/spapr-rtas/Makefile @@ -15,10 +15,10 @@ $(call set-vpath, $(SRC_PATH)/pc-bios/spapr-rtas) build-all: spapr-rtas.bin %.img: %.o - $(call quiet-command,$(CC) -nostdlib -o $@ $<," Building $(TARGET_DIR)$@") + $(call quiet-command,$(CC) -nostdlib -o $@ $<,"Building","$(TARGET_DIR)$@") %.bin: %.img - $(call quiet-command,$(OBJCOPY) -O binary -j .text $< $@," Building $(TARGET_DIR)$@") + $(call quiet-command,$(OBJCOPY) -O binary -j .text $< $@,"Building","$(TARGET_DIR)$@") clean: rm -f *.o *.d *.img *.bin *~ diff --git a/po/Makefile b/po/Makefile index 7bab09dce2c..cc630363ded 100644 --- a/po/Makefile +++ b/po/Makefile @@ -10,7 +10,7 @@ all: .PHONY: all build clean install update %.mo: %.po - $(call quiet-command, msgfmt -o $@ $<, " GEN $@") + $(call quiet-command, msgfmt -o $@ $<,"GEN","$@") -include ../config-host.mak include $(SRC_PATH)/rules.mak @@ -46,7 +46,7 @@ $(PO_PATH)/messages.po: $(SRC_PATH)/ui/gtk.c xgettext -o - --from-code=UTF-8 --foreign-user \ --package-name=QEMU --package-version=$(VERSION) \ --msgid-bugs-address=qemu-devel@nongnu.org -k_ -C ui/gtk.c | \ - sed -e s/CHARSET/UTF-8/) >$@, " GEN $@") + sed -e s/CHARSET/UTF-8/) >$@,"GEN","$@") $(PO_PATH)/%.po: $(PO_PATH)/messages.po - $(call quiet-command, msgmerge -q $@ $< > $@.bak && mv $@.bak $@, " GEN $@") + $(call quiet-command, msgmerge -q $@ $< > $@.bak && mv $@.bak $@,"GEN","$@") diff --git a/qga/vss-win32/Makefile.objs b/qga/vss-win32/Makefile.objs index 7c96c6b2888..23d08da2259 100644 --- a/qga/vss-win32/Makefile.objs +++ b/qga/vss-win32/Makefile.objs @@ -7,7 +7,7 @@ $(obj-qga-vss-dll-obj-y): QEMU_CXXFLAGS = $(filter-out -Wstrict-prototypes -Wmis $(obj)/qga-vss.dll: LDFLAGS = -shared -Wl,--add-stdcall-alias,--enable-stdcall-fixup -lole32 -loleaut32 -lshlwapi -luuid -static $(obj)/qga-vss.dll: $(obj-qga-vss-dll-obj-y) $(SRC_PATH)/$(obj)/qga-vss.def - $(call quiet-command,$(CXX) -o $@ $(qga-vss-dll-obj-y) $(SRC_PATH)/qga/vss-win32/qga-vss.def $(CXXFLAGS) $(LDFLAGS)," LINK $(TARGET_DIR)$@") + $(call quiet-command,$(CXX) -o $@ $(qga-vss-dll-obj-y) $(SRC_PATH)/qga/vss-win32/qga-vss.def $(CXXFLAGS) $(LDFLAGS),"LINK","$(TARGET_DIR)$@") # rules to build qga-provider.tlb @@ -17,7 +17,7 @@ MIDL=$(WIN_SDK)/Bin/midl $(obj)/qga-vss.tlb: $(SRC_PATH)/$(obj)/qga-vss.idl ifeq ($(WIN_SDK),"") - $(call quiet-command,cp $(dir $<)qga-vss.tlb $@, " COPY $(TARGET_DIR)$@") + $(call quiet-command,cp $(dir $<)qga-vss.tlb $@,"COPY","$(TARGET_DIR)$@") else - $(call quiet-command,$(MIDL) -tlb $@ -I $(WIN_SDK)/Include $<," MIDL $(TARGET_DIR)$@") + $(call quiet-command,$(MIDL) -tlb $@ -I $(WIN_SDK)/Include $<,"MIDL","$(TARGET_DIR)$@") endif diff --git a/rules.mak b/rules.mak index 5c82c19f73f..3fdb261e32c 100644 --- a/rules.mak +++ b/rules.mak @@ -57,9 +57,9 @@ expand-objs = $(strip $(sort $(filter %.o,$1)) \ $(filter-out %.o %.mo,$1)) %.o: %.c - $(call quiet-command,$(CC) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) $($@-cflags) -c -o $@ $<," CC $(TARGET_DIR)$@") + $(call quiet-command,$(CC) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) $($@-cflags) -c -o $@ $<,"CC","$(TARGET_DIR)$@") %.o: %.rc - $(call quiet-command,$(WINDRES) -I. -o $@ $<," RC $(TARGET_DIR)$@") + $(call quiet-command,$(WINDRES) -I. -o $@ $<,"RC","$(TARGET_DIR)$@") # If we have a CXX we might have some C++ objects, in which case we # must link with the C++ compiler, not the plain C compiler. @@ -67,22 +67,22 @@ LINKPROG = $(or $(CXX),$(CC)) LINK = $(call quiet-command, $(LINKPROG) $(QEMU_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ \ $(call process-archive-undefs, $1) \ - $(version-obj-y) $(call extract-libs,$1) $(LIBS)," LINK $(TARGET_DIR)$@") + $(version-obj-y) $(call extract-libs,$1) $(LIBS),"LINK","$(TARGET_DIR)$@") %.o: %.S - $(call quiet-command,$(CCAS) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<," CCAS $(TARGET_DIR)$@") + $(call quiet-command,$(CCAS) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<,"CCAS","$(TARGET_DIR)$@") %.o: %.cc - $(call quiet-command,$(CXX) $(QEMU_INCLUDES) $(QEMU_CXXFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) $($@-cflags) -c -o $@ $<," CXX $(TARGET_DIR)$@") + $(call quiet-command,$(CXX) $(QEMU_INCLUDES) $(QEMU_CXXFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) $($@-cflags) -c -o $@ $<,"CXX","$(TARGET_DIR)$@") %.o: %.cpp - $(call quiet-command,$(CXX) $(QEMU_INCLUDES) $(QEMU_CXXFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) $($@-cflags) -c -o $@ $<," CXX $(TARGET_DIR)$@") + $(call quiet-command,$(CXX) $(QEMU_INCLUDES) $(QEMU_CXXFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) $($@-cflags) -c -o $@ $<,"CXX","$(TARGET_DIR)$@") %.o: %.m - $(call quiet-command,$(OBJCC) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) $($@-cflags) -c -o $@ $<," OBJC $(TARGET_DIR)$@") + $(call quiet-command,$(OBJCC) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) $($@-cflags) -c -o $@ $<,"OBJC","$(TARGET_DIR)$@") %.o: %.dtrace - $(call quiet-command,dtrace -o $@ -G -s $<, " GEN $(TARGET_DIR)$@") + $(call quiet-command,dtrace -o $@ -G -s $<,"GEN","$(TARGET_DIR)$@") DSO_OBJ_CFLAGS := -fPIC -DBUILD_DSO module-common.o: CFLAGS += $(DSO_OBJ_CFLAGS) @@ -90,13 +90,13 @@ module-common.o: CFLAGS += $(DSO_OBJ_CFLAGS) %$(DSOSUF): %.mo $(call LINK,$^) @# Copy to build root so modules can be loaded when program started without install - $(if $(findstring /,$@),$(call quiet-command,cp $@ $(subst /,-,$@), " CP $(subst /,-,$@)")) + $(if $(findstring /,$@),$(call quiet-command,cp $@ $(subst /,-,$@),"CP","$(subst /,-,$@)")) LD_REL := $(CC) -nostdlib -Wl,-r $(LD_REL_FLAGS) %.mo: - $(call quiet-command,$(LD_REL) -o $@ $^," LD -r $(TARGET_DIR)$@") + $(call quiet-command,$(LD_REL) -o $@ $^,"LD","$(TARGET_DIR)$@") .PHONY: modules modules: @@ -105,9 +105,15 @@ modules: $(call LINK,$(filter %.o %.a %.mo, $^)) %.a: - $(call quiet-command,rm -f $@ && $(AR) rcs $@ $^," AR $(TARGET_DIR)$@") + $(call quiet-command,rm -f $@ && $(AR) rcs $@ $^,"AR","$(TARGET_DIR)$@") -quiet-command = $(if $(V),$1,$(if $(2),@echo $2 && $1, @$1)) +# Usage: $(call quiet-command,command and args,"NAME","args to print") +# This will run "command and args", and either: +# if V=1 just print the whole command and args +# otherwise print the 'quiet' output in the format " NAME args to print" +# NAME should be a short name of the command, 7 letters or fewer. +# If called with only a single argument, will print nothing in quiet mode. +quiet-command = $(if $(V),$1,$(if $(2),@printf " %-7s %s\n" $2 $3 && $1, @$1)) # cc-option # Usage: CFLAGS+=$(call cc-option, -falign-functions=0, -malign-functions=0) @@ -173,7 +179,7 @@ config-%.h: config-%.h-timestamp @cmp $< $@ >/dev/null 2>&1 || cp $< $@ config-%.h-timestamp: config-%.mak $(SRC_PATH)/scripts/create_config - $(call quiet-command, sh $(SRC_PATH)/scripts/create_config < $< > $@, " GEN $(TARGET_DIR)config-$*.h") + $(call quiet-command, sh $(SRC_PATH)/scripts/create_config < $< > $@,"GEN","$(TARGET_DIR)config-$*.h") .PHONY: clean-timestamp clean-timestamp: diff --git a/target-s390x/Makefile.objs b/target-s390x/Makefile.objs index 4329d39c130..6b02b1794cf 100644 --- a/target-s390x/Makefile.objs +++ b/target-s390x/Makefile.objs @@ -14,10 +14,10 @@ endif $(feat-dst)gen-features.h: $(feat-dst)gen-features.h-timestamp @cmp $< $@ >/dev/null 2>&1 || cp $< $@ $(feat-dst)gen-features.h-timestamp: $(feat-dst)gen-features - $(call quiet-command,$< >$@," GEN $(TARGET_DIR)gen-features.h") + $(call quiet-command,$< >$@,"GEN","$(TARGET_DIR)gen-features.h") $(feat-dst)gen-features: $(feat-src)gen-features.c - $(call quiet-command,$(HOST_CC) $(QEMU_INCLUDES) -o $@ $<," CC $(TARGET_DIR)gen-features") + $(call quiet-command,$(HOST_CC) $(QEMU_INCLUDES) -o $@ $<,"CC","$(TARGET_DIR)gen-features") clean-target: rm -f gen-features.h-timestamp diff --git a/tests/Makefile.include b/tests/Makefile.include index 8162f6f7357..25aaae3c6e8 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -517,27 +517,27 @@ tests/test-qapi-types.c tests/test-qapi-types.h :\ $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py \ $(gen-out-type) -o tests -p "test-" $<, \ - " GEN $@") + "GEN","$@") tests/test-qapi-visit.c tests/test-qapi-visit.h :\ $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py \ $(gen-out-type) -o tests -p "test-" $<, \ - " GEN $@") + "GEN","$@") tests/test-qmp-commands.h tests/test-qmp-marshal.c :\ $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py \ $(gen-out-type) -o tests -p "test-" $<, \ - " GEN $@") + "GEN","$@") tests/test-qapi-event.c tests/test-qapi-event.h :\ $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-event.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-event.py \ $(gen-out-type) -o tests -p "test-" $<, \ - " GEN $@") + "GEN","$@") tests/test-qmp-introspect.c tests/test-qmp-introspect.h :\ $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-introspect.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-introspect.py \ $(gen-out-type) -o tests -p "test-" $<, \ - " GEN $@") + "GEN","$@") tests/test-string-output-visitor$(EXESUF): tests/test-string-output-visitor.o $(test-qapi-obj-y) tests/test-string-input-visitor$(EXESUF): tests/test-string-input-visitor.o $(test-qapi-obj-y) @@ -671,7 +671,7 @@ tests/ptimer-test$(EXESUF): tests/ptimer-test.o tests/ptimer-test-stubs.o hw/cor tests/test-uuid$(EXESUF): tests/test-uuid.o $(test-util-obj-y) tests/migration/stress$(EXESUF): tests/migration/stress.o - $(call quiet-command, $(LINKPROG) -static -O3 $(PTHREAD_LIB) -o $@ $< ," LINK $(TARGET_DIR)$@") + $(call quiet-command, $(LINKPROG) -static -O3 $(PTHREAD_LIB) -o $@ $< ,"LINK","$(TARGET_DIR)$@") INITRD_WORK_DIR=tests/migration/initrd @@ -734,7 +734,7 @@ $(patsubst %, check-qtest-%, $(QTEST_TARGETS)): check-qtest-%: $(check-qtest-y) $(call quiet-command,QTEST_QEMU_BINARY=$*-softmmu/qemu-system-$* \ QTEST_QEMU_IMG=qemu-img$(EXESUF) \ MALLOC_PERTURB_=$${MALLOC_PERTURB_:-$$((RANDOM % 255 + 1))} \ - gtester $(GTESTER_OPTIONS) -m=$(SPEED) $(check-qtest-$*-y) $(check-qtest-generic-y),"GTESTER $@") + gtester $(GTESTER_OPTIONS) -m=$(SPEED) $(check-qtest-$*-y) $(check-qtest-generic-y),"GTESTER","$@") $(if $(CONFIG_GCOV),@for f in $(gcov-files-$*-y) $(gcov-files-generic-y); do \ echo Gcov report for $$f:;\ $(GCOV) $(GCOV_OPTIONS) $$f -o `dirname $$f`; \ @@ -745,7 +745,7 @@ $(patsubst %, check-%, $(check-unit-y)): check-%: % $(if $(CONFIG_GCOV),@rm -f *.gcda */*.gcda */*/*.gcda */*/*/*.gcda,) $(call quiet-command, \ MALLOC_PERTURB_=$${MALLOC_PERTURB_:-$$((RANDOM % 255 + 1))} \ - gtester $(GTESTER_OPTIONS) -m=$(SPEED) $*,"GTESTER $*") + gtester $(GTESTER_OPTIONS) -m=$(SPEED) $*,"GTESTER","$*") $(if $(CONFIG_GCOV),@for f in $(gcov-files-$(subst tests/,,$*)-y) $(gcov-files-generic-y); do \ echo Gcov report for $$f:;\ $(GCOV) $(GCOV_OPTIONS) $$f -o `dirname $$f`; \ @@ -756,18 +756,18 @@ $(patsubst %, check-%, $(check-unit-y)): check-%: % $(patsubst %, check-report-qtest-%.xml, $(QTEST_TARGETS)): check-report-qtest-%.xml: $(check-qtest-y) $(call quiet-command,QTEST_QEMU_BINARY=$*-softmmu/qemu-system-$* \ QTEST_QEMU_IMG=qemu-img$(EXESUF) \ - gtester -q $(GTESTER_OPTIONS) -o $@ -m=$(SPEED) $(check-qtest-$*-y) $(check-qtest-generic-y),"GTESTER $@") + gtester -q $(GTESTER_OPTIONS) -o $@ -m=$(SPEED) $(check-qtest-$*-y) $(check-qtest-generic-y),"GTESTER","$@") check-report-unit.xml: $(check-unit-y) - $(call quiet-command,gtester -q $(GTESTER_OPTIONS) -o $@ -m=$(SPEED) $^, "GTESTER $@") + $(call quiet-command,gtester -q $(GTESTER_OPTIONS) -o $@ -m=$(SPEED) $^,"GTESTER","$@") # Reports and overall runs check-report.xml: $(patsubst %,check-report-qtest-%.xml, $(QTEST_TARGETS)) check-report-unit.xml - $(call quiet-command,$(SRC_PATH)/scripts/gtester-cat $^ > $@, " GEN $@") + $(call quiet-command,$(SRC_PATH)/scripts/gtester-cat $^ > $@,"GEN","$@") check-report.html: check-report.xml - $(call quiet-command,gtester-report $< > $@, " GEN $@") + $(call quiet-command,gtester-report $< > $@,"GEN","$@") # Other tests @@ -787,7 +787,7 @@ $(patsubst %, check-%, $(check-qapi-schema-y)): check-%.json: $(SRC_PATH)/%.json $(PYTHON) $(SRC_PATH)/tests/qapi-schema/test-qapi.py \ $^ >$*.test.out 2>$*.test.err; \ echo $$? >$*.test.exit, \ - " TEST $*.out") + "TEST","$*.out") @diff -q $(SRC_PATH)/$*.out $*.test.out @# Sanitize error messages (make them independent of build directory) @perl -p -e 's|\Q$(SRC_PATH)\E/||g' $*.test.err | diff -q $(SRC_PATH)/$*.err - diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include index 2fcc3c64187..b44daabbce0 100644 --- a/tests/docker/Makefile.include +++ b/tests/docker/Makefile.include @@ -25,7 +25,7 @@ make-archive-maybe = $(if $(wildcard $1/*), \ else \ git archive -1 $$(git stash create) --format=tar.gz; \ fi) > $2, \ - " ARCHIVE $(notdir $2)")) + "ARCHIVE","$(notdir $2)")) CUR_TIME := $(shell date +%Y-%m-%d-%H.%M.%S.$$$$) DOCKER_SRC_COPY := docker-src.$(CUR_TIME) @@ -36,7 +36,7 @@ $(DOCKER_SRC_COPY): $(call make-archive-maybe, $(SRC_PATH)/dtc, $@/dtc.tgz) $(call make-archive-maybe, $(SRC_PATH)/pixman, $@/pixman.tgz) $(call quiet-command, cp $(SRC_PATH)/tests/docker/run $@/run, \ - " COPY RUNNER") + "COPY","RUNNER") docker-qemu-src: $(DOCKER_SRC_COPY) @@ -51,7 +51,7 @@ docker-image-%: $(DOCKER_FILES_DIR)/%.docker $(SRC_PATH)/tests/docker/docker.py build qemu:$* $< \ $(if $V,,--quiet) $(if $(NOCACHE),--no-cache) \ $(if $(EXECUTABLE),--include-executable=$(EXECUTABLE)),\ - " BUILD $*") + "BUILD","$*") # Expand all the pre-requistes for each docker image and test combination $(foreach i,$(DOCKER_IMAGES), \ @@ -125,7 +125,7 @@ docker-run-%: docker-qemu-src /var/tmp/qemu/run \ $(CMD); \ fi \ - , " RUN $(CMD) in $(IMAGE)"))) + ,"RUN","$(CMD) in $(IMAGE)"))) docker-clean: $(call quiet-command, $(SRC_PATH)/tests/docker/docker.py clean) diff --git a/trace/Makefile.objs b/trace/Makefile.objs index 4d91b3b833b..24d3b3758c4 100644 --- a/trace/Makefile.objs +++ b/trace/Makefile.objs @@ -22,7 +22,7 @@ $(obj)/generated-ust-provider.h-timestamp: $(BUILD_DIR)/trace-events-all $(trace $(call quiet-command,$(TRACETOOL) \ --format=ust-events-h \ --backends=$(TRACE_BACKENDS) \ - < $< > $@," GEN $(patsubst %-timestamp,%,$@)") + < $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") $(obj)/generated-ust.c: $(obj)/generated-ust.c-timestamp $(BUILD_DIR)/config-host.mak @cmp $< $@ >/dev/null 2>&1 || cp $< $@ @@ -30,7 +30,7 @@ $(obj)/generated-ust.c-timestamp: $(BUILD_DIR)/trace-events-all $(tracetool-y) $(call quiet-command,$(TRACETOOL) \ --format=ust-events-c \ --backends=$(TRACE_BACKENDS) \ - < $< > $@," GEN $(patsubst %-timestamp,%,$@)") + < $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") $(obj)/generated-events.h: $(obj)/generated-ust-provider.h $(obj)/generated-events.c: $(obj)/generated-ust.c @@ -46,7 +46,7 @@ $(obj)/generated-events.h-timestamp: $(BUILD_DIR)/trace-events-all $(tracetool-y $(call quiet-command,$(TRACETOOL) \ --format=events-h \ --backends=$(TRACE_BACKENDS) \ - < $< > $@," GEN $(patsubst %-timestamp,%,$@)") + < $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") $(obj)/generated-events.c: $(obj)/generated-events.c-timestamp $(BUILD_DIR)/config-host.mak @cmp $< $@ >/dev/null 2>&1 || cp $< $@ @@ -54,7 +54,7 @@ $(obj)/generated-events.c-timestamp: $(BUILD_DIR)/trace-events-all $(tracetool-y $(call quiet-command,$(TRACETOOL) \ --format=events-c \ --backends=$(TRACE_BACKENDS) \ - < $< > $@," GEN $(patsubst %-timestamp,%,$@)") + < $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") util-obj-y += generated-events.o @@ -71,7 +71,7 @@ $(obj)/generated-tracers.h-timestamp: $(BUILD_DIR)/trace-events-all $(BUILD_DIR) $(call quiet-command,$(TRACETOOL) \ --format=h \ --backends=$(TRACE_BACKENDS) \ - < $< > $@," GEN $(patsubst %-timestamp,%,$@)") + < $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") ############################## # non-DTrace @@ -82,7 +82,7 @@ $(obj)/generated-tracers.c-timestamp: $(BUILD_DIR)/trace-events-all $(BUILD_DIR) $(call quiet-command,$(TRACETOOL) \ --format=c \ --backends=$(TRACE_BACKENDS) \ - < $< > $@," GEN $(patsubst %-timestamp,%,$@)") + < $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") $(obj)/generated-tracers.o: $(obj)/generated-tracers.c $(obj)/generated-tracers.h @@ -100,10 +100,10 @@ $(obj)/generated-tracers-dtrace.dtrace-timestamp: $(BUILD_DIR)/trace-events-all $(call quiet-command,$(TRACETOOL) \ --format=d \ --backends=$(TRACE_BACKENDS) \ - < $< > $@," GEN $(patsubst %-timestamp,%,$@)") + < $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") $(obj)/generated-tracers-dtrace.h: $(obj)/generated-tracers-dtrace.dtrace - $(call quiet-command,dtrace -o $@ -h -s $<, " GEN $@") + $(call quiet-command,dtrace -o $@ -h -s $<,"GEN","$@") $(obj)/generated-tracers-dtrace.o: $(obj)/generated-tracers-dtrace.dtrace @@ -119,7 +119,7 @@ $(obj)/generated-helpers-wrappers.h-timestamp: $(BUILD_DIR)/trace-events-all $(B $(call quiet-command,$(TRACETOOL) \ --format=tcg-helper-wrapper-h \ --backend=$(TRACE_BACKENDS) \ - < $< > $@," GEN $(patsubst %-timestamp,%,$@)") + < $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") $(obj)/generated-helpers.h: $(obj)/generated-helpers.h-timestamp @cmp $< $@ >/dev/null 2>&1 || cp $< $@ @@ -127,7 +127,7 @@ $(obj)/generated-helpers.h-timestamp: $(BUILD_DIR)/trace-events-all $(BUILD_DIR) $(call quiet-command,$(TRACETOOL) \ --format=tcg-helper-h \ --backend=$(TRACE_BACKENDS) \ - < $< > $@," GEN $(patsubst %-timestamp,%,$@)") + < $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") $(obj)/generated-helpers.c: $(obj)/generated-helpers.c-timestamp @cmp $< $@ >/dev/null 2>&1 || cp $< $@ @@ -135,7 +135,7 @@ $(obj)/generated-helpers.c-timestamp: $(BUILD_DIR)/trace-events-all $(BUILD_DIR) $(call quiet-command,$(TRACETOOL) \ --format=tcg-helper-c \ --backend=$(TRACE_BACKENDS) \ - < $< > $@," GEN $(patsubst %-timestamp,%,$@)") + < $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") $(obj)/generated-helpers.o: $(obj)/generated-helpers.c @@ -148,7 +148,7 @@ $(obj)/generated-tcg-tracers.h-timestamp: $(BUILD_DIR)/trace-events-all $(BUILD_ $(call quiet-command,$(TRACETOOL) \ --format=tcg-h \ --backend=$(TRACE_BACKENDS) \ - < $< > $@," GEN $(patsubst %-timestamp,%,$@)") + < $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") ###################################################################### From e64c75a9752c5d0fd64eb2e684c656a5ea7d03c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Fri, 23 Sep 2016 00:39:25 +0400 Subject: [PATCH 535/723] qmp: fix object-add assert() without props MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit ad739706bbadee49, user_creatable_add_type() expects to be given a qdict. However, if object-add is called without props, you reach the assert: "qemu/qom/object_interfaces.c:115: user_creatable_add_type: Assertion `qdict' failed.", because the qdict isn't created in this case (it's optional). Furthermore, qmp_input_visitor_new() is not meant to be called without a dict, and a further commit will assert in this situation. If none given, create an empty qdict in qmp to avoid the user_creatable_add_type() assert(qdict). Signed-off-by: Marc-André Lureau Reviewed-by: Eric Blake Message-Id: <20160922203927.28241-2-marcandre.lureau@redhat.com> Tested-by: Xiao Long Jiang Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- qmp.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/qmp.c b/qmp.c index 621f6ae6d95..b3ba9ef9c4a 100644 --- a/qmp.c +++ b/qmp.c @@ -660,7 +660,7 @@ void qmp_add_client(const char *protocol, const char *fdname, void qmp_object_add(const char *type, const char *id, bool has_props, QObject *props, Error **errp) { - const QDict *pdict = NULL; + QDict *pdict; Visitor *v; Object *obj; @@ -670,14 +670,18 @@ void qmp_object_add(const char *type, const char *id, error_setg(errp, QERR_INVALID_PARAMETER_TYPE, "props", "dict"); return; } + QINCREF(pdict); + } else { + pdict = qdict_new(); } - v = qmp_input_visitor_new(props, true); + v = qmp_input_visitor_new(QOBJECT(pdict), true); obj = user_creatable_add_type(type, id, pdict, v, errp); visit_free(v); if (obj) { object_unref(obj); } + QDECREF(pdict); } void qmp_object_del(const char *id, Error **errp) From c489780203f9b22aca5539ec7589b7140bdc951f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Fri, 23 Sep 2016 00:39:26 +0400 Subject: [PATCH 536/723] qapi: Fix crash when 'any' or 'null' parameter is missing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unlike the other visit methods, visit_type_any() and visit_type_null() neglect to check whether qmp_input_get_object() succeeded. They crash when it fails. Reproducer: { "execute": "qom-set", "arguments": { "path": "/machine", "property": "rtc-time" } } Will crash with: qapi/qapi-visit-core.c:277: visit_type_any: Assertion `!err != !*obj' failed Broken in commit 5c678ee. Fix by adding the missing error checks. Signed-off-by: Marc-André Lureau Reviewed-by: Eric Blake Message-Id: <20160922203927.28241-3-marcandre.lureau@redhat.com> Reviewed-by: Markus Armbruster [Commit message rephrased] Signed-off-by: Markus Armbruster --- qapi/qmp-input-visitor.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c index 64dd392e6f7..fc91e748940 100644 --- a/qapi/qmp-input-visitor.c +++ b/qapi/qmp-input-visitor.c @@ -338,6 +338,12 @@ static void qmp_input_type_any(Visitor *v, const char *name, QObject **obj, QmpInputVisitor *qiv = to_qiv(v); QObject *qobj = qmp_input_get_object(qiv, name, true); + if (!qobj) { + error_setg(errp, QERR_MISSING_PARAMETER, name ? name : "null"); + *obj = NULL; + return; + } + qobject_incref(qobj); *obj = qobj; } @@ -347,6 +353,11 @@ static void qmp_input_type_null(Visitor *v, const char *name, Error **errp) QmpInputVisitor *qiv = to_qiv(v); QObject *qobj = qmp_input_get_object(qiv, name, true); + if (!qobj) { + error_setg(errp, QERR_MISSING_PARAMETER, name ? name : "null"); + return; + } + if (qobject_type(qobj) != QTYPE_QNULL) { error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "null"); From bce3035a44c40bd3ec29d3162025fd350f2d8dbf Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 4 Oct 2016 17:23:50 +0200 Subject: [PATCH 537/723] tests/test-qmp-input-strict: Cover missing struct members These tests would have caught the bug fixed by the previous commit. Signed-off-by: Markus Armbruster Message-Id: <1475594630-24758-1-git-send-email-armbru@redhat.com> --- tests/test-qmp-input-strict.c | 46 +++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/tests/test-qmp-input-strict.c b/tests/test-qmp-input-strict.c index 814550ac71b..d87f8b89a7c 100644 --- a/tests/test-qmp-input-strict.c +++ b/tests/test-qmp-input-strict.c @@ -193,6 +193,50 @@ static void test_validate_fail_struct_nested(TestInputVisitorData *data, g_assert(!udp); } +static void test_validate_fail_struct_missing(TestInputVisitorData *data, + const void *unused) +{ + Error *err = NULL; + Visitor *v; + QObject *any; + GenericAlternate *alt; + bool present; + int en; + int64_t i64; + uint32_t u32; + int8_t i8; + char *str; + double dbl; + + v = validate_test_init(data, "{}"); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_start_struct(v, "struct", NULL, 0, &err); + error_free_or_abort(&err); + visit_start_list(v, "list", NULL, 0, &err); + error_free_or_abort(&err); + visit_start_alternate(v, "alternate", &alt, sizeof(*alt), false, &err); + error_free_or_abort(&err); + visit_optional(v, "optional", &present); + g_assert(!present); + visit_type_enum(v, "enum", &en, EnumOne_lookup, &err); + error_free_or_abort(&err); + visit_type_int(v, "i64", &i64, &err); + error_free_or_abort(&err); + visit_type_uint32(v, "u32", &u32, &err); + error_free_or_abort(&err); + visit_type_int8(v, "i8", &i8, &err); + error_free_or_abort(&err); + visit_type_str(v, "i8", &str, &err); + error_free_or_abort(&err); + visit_type_number(v, "dbl", &dbl, &err); + error_free_or_abort(&err); + visit_type_any(v, "any", &any, &err); + error_free_or_abort(&err); + visit_type_null(v, "null", &err); + error_free_or_abort(&err); + visit_end_struct(v, NULL); +} + static void test_validate_fail_list(TestInputVisitorData *data, const void *unused) { @@ -316,6 +360,8 @@ int main(int argc, char **argv) &testdata, test_validate_fail_struct); validate_test_add("/visitor/input-strict/fail/struct-nested", &testdata, test_validate_fail_struct_nested); + validate_test_add("/visitor/input-strict/fail/struct-missing", + &testdata, test_validate_fail_struct_missing); validate_test_add("/visitor/input-strict/fail/list", &testdata, test_validate_fail_list); validate_test_add("/visitor/input-strict/fail/union-flat", From e424b6550f486b2a9ab32b13c3824021199bac54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Golembiovsk=C3=BD?= Date: Wed, 5 Oct 2016 23:40:20 +0200 Subject: [PATCH 538/723] qemu-nbd: Shrink image size by specified offset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When --offset is set the apparent device size has to be adjusted accordingly. Otherwise client may request read/write beyond the file end which would fail. Signed-off-by: Tomáš Golembiovský Message-Id: <8a31654cb182932db78b95aae1e904fc2bd1c465.1475698895.git.tgolembi@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Paolo Bonzini --- qemu-nbd.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/qemu-nbd.c b/qemu-nbd.c index 99297a556fc..705b95ec293 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -901,6 +901,14 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } + if (dev_offset >= fd_size) { + error_report("Offset (%lld) has to be smaller than the image size " + "(%lld)", + (long long int)dev_offset, (long long int)fd_size); + exit(EXIT_FAILURE); + } + fd_size -= dev_offset; + if (partition != -1) { ret = find_partition(blk, partition, &dev_offset, &fd_size); if (ret < 0) { From f555a9d0b3c785b698f32e6879e97d0a4b387314 Mon Sep 17 00:00:00 2001 From: "Emilio G. Cota" Date: Wed, 5 Oct 2016 18:34:38 -0400 Subject: [PATCH 539/723] qht: simplify qht_reset_size Sometimes gcc doesn't pick up the fact that 'new' is properly set if 'resize == true', which may generate an unnecessary build warning. Fix it by removing 'resize' and directly checking that 'new' is non-NULL. Signed-off-by: Emilio G. Cota Message-Id: <1475706880-10667-2-git-send-email-cota@braap.org> Signed-off-by: Paolo Bonzini --- util/qht.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/util/qht.c b/util/qht.c index 571639d30a1..4dd9be8822d 100644 --- a/util/qht.c +++ b/util/qht.c @@ -410,10 +410,9 @@ void qht_reset(struct qht *ht) bool qht_reset_size(struct qht *ht, size_t n_elems) { - struct qht_map *new; + struct qht_map *new = NULL; struct qht_map *map; size_t n_buckets; - bool resize = false; n_buckets = qht_elems_to_buckets(n_elems); @@ -421,18 +420,17 @@ bool qht_reset_size(struct qht *ht, size_t n_elems) map = ht->map; if (n_buckets != map->n_buckets) { new = qht_map_create(n_buckets); - resize = true; } qht_map_lock_buckets(map); qht_map_reset__all_locked(map); - if (resize) { + if (new) { qht_do_resize(ht, new); } qht_map_unlock_buckets(map); qemu_mutex_unlock(&ht->lock); - return resize; + return !!new; } static inline From 76b553b308dc8671eb672b889b38889b1231cf1e Mon Sep 17 00:00:00 2001 From: "Emilio G. Cota" Date: Wed, 5 Oct 2016 18:34:39 -0400 Subject: [PATCH 540/723] qht: fix unlock-after-free segfault upon resizing The old map's bucket locks are being unlocked *after* that same old map has been passed to RCU for destruction. This is a bug that can cause a segfault, since there's no guarantee that the deletion will be deferred (e.g. there may be no concurrent readers). The segfault is easily triggered in RHEL6/CentOS6 with qht-test, particularly on a single-core system or by pinning qht-test to a single core. Fix it by unlocking the map's bucket locks right after having published the new map, and (crucially) before marking the map for deletion via call_rcu(). While at it, expand qht_do_resize() to atomically do (1) a reset, (2) a resize, or (3) a reset+resize. This simplifies the calling code, since the new function (qht_do_resize_reset()) acquires and releases the buckets' locks. Note that no qht_do_reset inline is provided, since it would have no users--qht_reset() already performs a reset without taking ht->lock. Reported-by: Peter Maydell Reported-by: Daniel P. Berrange Signed-off-by: Emilio G. Cota Message-Id: <1475706880-10667-3-git-send-email-cota@braap.org> Signed-off-by: Paolo Bonzini --- util/qht.c | 49 ++++++++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/util/qht.c b/util/qht.c index 4dd9be8822d..ff4d2e69748 100644 --- a/util/qht.c +++ b/util/qht.c @@ -133,7 +133,8 @@ struct qht_map { /* trigger a resize when n_added_buckets > n_buckets / div */ #define QHT_NR_ADDED_BUCKETS_THRESHOLD_DIV 8 -static void qht_do_resize(struct qht *ht, struct qht_map *new); +static void qht_do_resize_reset(struct qht *ht, struct qht_map *new, + bool reset); static void qht_grow_maybe(struct qht *ht); #ifdef QHT_DEBUG @@ -408,6 +409,16 @@ void qht_reset(struct qht *ht) qht_map_unlock_buckets(map); } +static inline void qht_do_resize(struct qht *ht, struct qht_map *new) +{ + qht_do_resize_reset(ht, new, false); +} + +static inline void qht_do_resize_and_reset(struct qht *ht, struct qht_map *new) +{ + qht_do_resize_reset(ht, new, true); +} + bool qht_reset_size(struct qht *ht, size_t n_elems) { struct qht_map *new = NULL; @@ -421,13 +432,7 @@ bool qht_reset_size(struct qht *ht, size_t n_elems) if (n_buckets != map->n_buckets) { new = qht_map_create(n_buckets); } - - qht_map_lock_buckets(map); - qht_map_reset__all_locked(map); - if (new) { - qht_do_resize(ht, new); - } - qht_map_unlock_buckets(map); + qht_do_resize_and_reset(ht, new); qemu_mutex_unlock(&ht->lock); return !!new; @@ -559,9 +564,7 @@ static __attribute__((noinline)) void qht_grow_maybe(struct qht *ht) if (qht_map_needs_resize(map)) { struct qht_map *new = qht_map_create(map->n_buckets * 2); - qht_map_lock_buckets(map); qht_do_resize(ht, new); - qht_map_unlock_buckets(map); } qemu_mutex_unlock(&ht->lock); } @@ -737,24 +740,31 @@ static void qht_map_copy(struct qht *ht, void *p, uint32_t hash, void *userp) } /* - * Call with ht->lock and all bucket locks held. - * - * Creating the @new map here would add unnecessary delay while all the locks - * are held--holding up the bucket locks is particularly bad, since no writes - * can occur while these are held. Thus, we let callers create the new map, - * hopefully without the bucket locks held. + * Atomically perform a resize and/or reset. + * Call with ht->lock held. */ -static void qht_do_resize(struct qht *ht, struct qht_map *new) +static void qht_do_resize_reset(struct qht *ht, struct qht_map *new, bool reset) { struct qht_map *old; old = ht->map; - g_assert_cmpuint(new->n_buckets, !=, old->n_buckets); + qht_map_lock_buckets(old); + if (reset) { + qht_map_reset__all_locked(old); + } + + if (new == NULL) { + qht_map_unlock_buckets(old); + return; + } + + g_assert_cmpuint(new->n_buckets, !=, old->n_buckets); qht_map_iter__all_locked(ht, old, qht_map_copy, new); qht_map_debug__all_locked(new); atomic_rcu_set(&ht->map, new); + qht_map_unlock_buckets(old); call_rcu(old, qht_map_destroy, rcu); } @@ -766,12 +776,9 @@ bool qht_resize(struct qht *ht, size_t n_elems) qemu_mutex_lock(&ht->lock); if (n_buckets != ht->map->n_buckets) { struct qht_map *new; - struct qht_map *old = ht->map; new = qht_map_create(n_buckets); - qht_map_lock_buckets(old); qht_do_resize(ht, new); - qht_map_unlock_buckets(old); ret = true; } qemu_mutex_unlock(&ht->lock); From 9c7d64eb2a47033c9697fb4a5a540af1aa3915ab Mon Sep 17 00:00:00 2001 From: "Emilio G. Cota" Date: Wed, 5 Oct 2016 18:34:40 -0400 Subject: [PATCH 541/723] test-qht: perform lookups under rcu_read_lock qht_lookup is meant to be called from an RCU read-critical section. Make sure we're in such a section in test-qht when performing lookups, despite the fact that no races in qht can be triggered by test-qht since it is single-threaded. Note that rcu_register_thread is already called by the rcu_after_fork hook, and therefore duplicating it here would be a bug. Signed-off-by: Emilio G. Cota Message-Id: <1475706880-10667-4-git-send-email-cota@braap.org> Signed-off-by: Paolo Bonzini --- tests/test-qht.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/test-qht.c b/tests/test-qht.c index 46a64b6731d..9b7423abb62 100644 --- a/tests/test-qht.c +++ b/tests/test-qht.c @@ -6,6 +6,7 @@ */ #include "qemu/osdep.h" #include "qemu/qht.h" +#include "qemu/rcu.h" #define N 5000 @@ -51,6 +52,7 @@ static void check(int a, int b, bool expected) struct qht_stats stats; int i; + rcu_read_lock(); for (i = a; i < b; i++) { void *p; uint32_t hash; @@ -61,6 +63,8 @@ static void check(int a, int b, bool expected) p = qht_lookup(&ht, is_equal, &val, hash); g_assert_true(!!p == expected); } + rcu_read_unlock(); + qht_statistics_init(&ht, &stats); if (stats.used_head_buckets) { g_assert_cmpfloat(qdist_avg(&stats.chain), >=, 1.0); From f91c7e5235357d3bc0db02d6459238b901384bff Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 6 Oct 2016 16:29:25 +0200 Subject: [PATCH 542/723] qemu-tech: drop index Reviewed-by: Emilio G. Cota Signed-off-by: Paolo Bonzini --- qemu-tech.texi | 5 ----- 1 file changed, 5 deletions(-) diff --git a/qemu-tech.texi b/qemu-tech.texi index 1b048cb337b..be1c2106785 100644 --- a/qemu-tech.texi +++ b/qemu-tech.texi @@ -32,7 +32,6 @@ * Introduction:: * QEMU Internals:: * Regression Tests:: -* Index:: @end menu @end ifnottex @@ -691,8 +690,4 @@ This program tests various Linux system calls. It is used to verify that the system call parameters are correctly converted between target and host CPUs. -@node Index -@chapter Index -@printindex cp - @bye From 1f3e7e41bb0ca09e322e95aab98e2593e1f6ff55 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 6 Oct 2016 14:59:26 +0200 Subject: [PATCH 543/723] qemu-doc: replace introduction with the one from the internals manual The user manual has an obsolete introduction, and the one in the internals manual lists QEMU's features quite nicely. Drop the obsolete content and remove generic user-level documentation from qemu-tech. Reviewed-by: Emilio G. Cota Signed-off-by: Paolo Bonzini --- qemu-doc.texi | 84 ++++++++++++++++++++++++----------------------- qemu-tech.texi | 88 -------------------------------------------------- 2 files changed, 44 insertions(+), 128 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index f37fd3130e6..9f75c9d4d1f 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -57,65 +57,69 @@ QEMU is a FAST! processor emulator using dynamic translation to achieve good emulation speed. +@cindex operating modes QEMU has two operating modes: @itemize -@cindex operating modes - -@item @cindex system emulation -Full system emulation. In this mode, QEMU emulates a full system (for +@item Full system emulation. In this mode, QEMU emulates a full system (for example a PC), including one or several processors and various peripherals. It can be used to launch different Operating Systems without rebooting the PC or to debug system code. -@item @cindex user mode emulation -User mode emulation. In this mode, QEMU can launch +@item User mode emulation. In this mode, QEMU can launch processes compiled for one CPU on another CPU. It can be used to launch the Wine Windows API emulator (@url{http://www.winehq.org}) or to ease cross-compilation and cross-debugging. @end itemize -QEMU can run without a host kernel driver and yet gives acceptable -performance. +QEMU has the following features: + +@itemize +@item QEMU can run without a host kernel driver and yet gives acceptable +performance. It uses dynamic translation to native code for reasonable speed, +with support for self-modifying code and precise exceptions. + +@item It is portable to several operating systems (GNU/Linux, *BSD, Mac OS X, +Windows) and architectures. + +@item It performs accurate software emulation of the FPU. +@end itemize -For system emulation, the following hardware targets are supported: +QEMU user mode emulation has the following features: @itemize -@cindex emulated target systems -@cindex supported target systems -@item PC (x86 or x86_64 processor) -@item ISA PC (old style PC without PCI bus) -@item PREP (PowerPC processor) -@item G3 Beige PowerMac (PowerPC processor) -@item Mac99 PowerMac (PowerPC processor, in progress) -@item Sun4m/Sun4c/Sun4d (32-bit Sparc processor) -@item Sun4u/Sun4v (64-bit Sparc processor, in progress) -@item Malta board (32-bit and 64-bit MIPS processors) -@item MIPS Magnum (64-bit MIPS processor) -@item ARM Integrator/CP (ARM) -@item ARM Versatile baseboard (ARM) -@item ARM RealView Emulation/Platform baseboard (ARM) -@item Spitz, Akita, Borzoi, Terrier and Tosa PDAs (PXA270 processor) -@item Luminary Micro LM3S811EVB (ARM Cortex-M3) -@item Luminary Micro LM3S6965EVB (ARM Cortex-M3) -@item Freescale MCF5208EVB (ColdFire V2). -@item Arnewsh MCF5206 evaluation board (ColdFire V2). -@item Palm Tungsten|E PDA (OMAP310 processor) -@item N800 and N810 tablets (OMAP2420 processor) -@item MusicPal (MV88W8618 ARM processor) -@item Gumstix "Connex" and "Verdex" motherboards (PXA255/270). -@item Siemens SX1 smartphone (OMAP310 processor) -@item AXIS-Devboard88 (CRISv32 ETRAX-FS). -@item Petalogix Spartan 3aDSP1800 MMU ref design (MicroBlaze). -@item Avnet LX60/LX110/LX200 boards (Xtensa) +@item Generic Linux system call converter, including most ioctls. + +@item clone() emulation using native CPU clone() to use Linux scheduler for threads. + +@item Accurate signal handling by remapping host signals to target signals. +@end itemize + +QEMU full system emulation has the following features: +@itemize +@item +QEMU uses a full software MMU for maximum portability. + +@item +QEMU can optionally use an in-kernel accelerator, like kvm. The accelerators +execute most of the guest code natively, while +continuing to emulate the rest of the machine. + +@item +Various hardware devices can be emulated and in some cases, host +devices (e.g. serial and parallel ports, USB, drives) can be used +transparently by the guest Operating System. Host device passthrough +can be used for talking to external physical peripherals (e.g. a +webcam, modem or tape drive). + +@item +Symmetric multiprocessing (SMP) support. Currently, an in-kernel +accelerator is required to use more than one host CPU for emulation. + @end itemize -@cindex supported user mode targets -For user emulation, x86 (32 and 64 bit), PowerPC (32 and 64 bit), -ARM, MIPS (32 bit only), Sparc (32 and 64 bit), -Alpha, ColdFire(m68k), CRISv32 and MicroBlaze CPUs are supported. @node Installation @chapter Installation diff --git a/qemu-tech.texi b/qemu-tech.texi index be1c2106785..2ab7cd4cc30 100644 --- a/qemu-tech.texi +++ b/qemu-tech.texi @@ -41,7 +41,6 @@ @chapter Introduction @menu -* intro_features:: Features * intro_x86_emulation:: x86 and x86-64 emulation * intro_arm_emulation:: ARM emulation * intro_mips_emulation:: MIPS emulation @@ -51,93 +50,6 @@ * intro_other_emulation:: Other CPU emulation @end menu -@node intro_features -@section Features - -QEMU is a FAST! processor emulator using a portable dynamic -translator. - -QEMU has two operating modes: - -@itemize @minus - -@item -Full system emulation. In this mode (full platform virtualization), -QEMU emulates a full system (usually a PC), including a processor and -various peripherals. It can be used to launch several different -Operating Systems at once without rebooting the host machine or to -debug system code. - -@item -User mode emulation. In this mode (application level virtualization), -QEMU can launch processes compiled for one CPU on another CPU, however -the Operating Systems must match. This can be used for example to ease -cross-compilation and cross-debugging. -@end itemize - -As QEMU requires no host kernel driver to run, it is very safe and -easy to use. - -QEMU generic features: - -@itemize - -@item User space only or full system emulation. - -@item Using dynamic translation to native code for reasonable speed. - -@item -Working on x86, x86_64 and PowerPC32/64 hosts. Being tested on ARM, -S390x, Sparc32 and Sparc64. - -@item Self-modifying code support. - -@item Precise exceptions support. - -@item -Floating point library supporting both full software emulation and -native host FPU instructions. - -@end itemize - -QEMU user mode emulation features: -@itemize -@item Generic Linux system call converter, including most ioctls. - -@item clone() emulation using native CPU clone() to use Linux scheduler for threads. - -@item Accurate signal handling by remapping host signals to target signals. -@end itemize - -Linux user emulator (Linux host only) can be used to launch the Wine -Windows API emulator (@url{http://www.winehq.org}). A BSD user emulator for BSD -hosts is under development. It would also be possible to develop a -similar user emulator for Solaris. - -QEMU full system emulation features: -@itemize -@item -QEMU uses a full software MMU for maximum portability. - -@item -QEMU can optionally use an in-kernel accelerator, like kvm. The accelerators -execute some of the guest code natively, while -continuing to emulate the rest of the machine. - -@item -Various hardware devices can be emulated and in some cases, host -devices (e.g. serial and parallel ports, USB, drives) can be used -transparently by the guest Operating System. Host device passthrough -can be used for talking to external physical peripherals (e.g. a -webcam, modem or tape drive). - -@item -Symmetric multiprocessing (SMP) even on a host with a single CPU. On a -SMP host system, QEMU can use only one CPU fully due to difficulty in -implementing atomic memory accesses efficiently. - -@end itemize - @node intro_x86_emulation @section x86 and x86-64 emulation From 81f265a8a4f56e49aca3ecca83fce48821c01618 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 6 Oct 2016 16:52:20 +0200 Subject: [PATCH 544/723] qemu-doc: drop installation and compilation notes These are in README or obsolete, and the detailed version can be on a website instead. Reviewed-by: Emilio G. Cota Signed-off-by: Paolo Bonzini --- README | 2 - qemu-doc.texi | 249 -------------------------------------------------- 2 files changed, 251 deletions(-) diff --git a/README b/README index f38193fc67e..bd8060a3ee2 100644 --- a/README +++ b/README @@ -42,8 +42,6 @@ of other UNIX targets. The simple steps to build QEMU are: ../configure make -Complete details of the process for building and configuring QEMU for -all supported host platforms can be found in the qemu-tech.html file. Additional information can also be found online via the QEMU website: http://qemu-project.org/Hosts/Linux diff --git a/qemu-doc.texi b/qemu-doc.texi index 9f75c9d4d1f..e60c46b5c9d 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -32,11 +32,9 @@ @menu * Introduction:: -* Installation:: * QEMU PC System emulator:: * QEMU System emulator for non PC targets:: * QEMU User space emulator:: -* compilation:: Compilation from the sources * License:: * Index:: @end menu @@ -121,39 +119,6 @@ accelerator is required to use more than one host CPU for emulation. @end itemize -@node Installation -@chapter Installation - -If you want to compile QEMU yourself, see @ref{compilation}. - -@menu -* install_linux:: Linux -* install_windows:: Windows -* install_mac:: Macintosh -@end menu - -@node install_linux -@section Linux -@cindex installation (Linux) - -If a precompiled package is available for your distribution - you just -have to install it. Otherwise, see @ref{compilation}. - -@node install_windows -@section Windows -@cindex installation (Windows) - -Download the experimental binary installer at -@url{http://www.free.oszoo.org/@/download.html}. -TODO (no longer available) - -@node install_mac -@section Mac OS X - -Download the experimental binary installer at -@url{http://www.free.oszoo.org/@/download.html}. -TODO (no longer available) - @node QEMU PC System emulator @chapter QEMU PC System emulator @cindex system emulation (PC) @@ -2949,220 +2914,6 @@ Act as if the host page size was 'pagesize' bytes Run the emulation in single step mode. @end table -@node compilation -@chapter Compilation from the sources - -@menu -* Linux/Unix:: -* Windows:: -* Cross compilation for Windows with Linux:: -* Mac OS X:: -* Make targets:: -@end menu - -@node Linux/Unix -@section Linux/Unix - -@subsection Compilation - -First you must decompress the sources: -@example -cd /tmp -tar zxvf qemu-x.y.z.tar.gz -cd qemu-x.y.z -@end example - -Then you configure QEMU and build it (usually no options are needed): -@example -./configure -make -@end example - -Then type as root user: -@example -make install -@end example -to install QEMU in @file{/usr/local}. - -@node Windows -@section Windows - -@itemize -@item Install the current versions of MSYS and MinGW from -@url{http://www.mingw.org/}. You can find detailed installation -instructions in the download section and the FAQ. - -@item Download -the MinGW development library of SDL 1.2.x -(@file{SDL-devel-1.2.x-@/mingw32.tar.gz}) from -@url{http://www.libsdl.org}. Unpack it in a temporary place and -edit the @file{sdl-config} script so that it gives the -correct SDL directory when invoked. - -@item Install the MinGW version of zlib and make sure -@file{zlib.h} and @file{libz.dll.a} are in -MinGW's default header and linker search paths. - -@item Extract the current version of QEMU. - -@item Start the MSYS shell (file @file{msys.bat}). - -@item Change to the QEMU directory. Launch @file{./configure} and -@file{make}. If you have problems using SDL, verify that -@file{sdl-config} can be launched from the MSYS command line. - -@item You can install QEMU in @file{Program Files/QEMU} by typing -@file{make install}. Don't forget to copy @file{SDL.dll} in -@file{Program Files/QEMU}. - -@end itemize - -@node Cross compilation for Windows with Linux -@section Cross compilation for Windows with Linux - -@itemize -@item -Install the MinGW cross compilation tools available at -@url{http://www.mingw.org/}. - -@item Download -the MinGW development library of SDL 1.2.x -(@file{SDL-devel-1.2.x-@/mingw32.tar.gz}) from -@url{http://www.libsdl.org}. Unpack it in a temporary place and -edit the @file{sdl-config} script so that it gives the -correct SDL directory when invoked. Set up the @code{PATH} environment -variable so that @file{sdl-config} can be launched by -the QEMU configuration script. - -@item Install the MinGW version of zlib and make sure -@file{zlib.h} and @file{libz.dll.a} are in -MinGW's default header and linker search paths. - -@item -Configure QEMU for Windows cross compilation: -@example -PATH=/usr/i686-pc-mingw32/sys-root/mingw/bin:$PATH ./configure --cross-prefix='i686-pc-mingw32-' -@end example -The example assumes @file{sdl-config} is installed under @file{/usr/i686-pc-mingw32/sys-root/mingw/bin} and -MinGW cross compilation tools have names like @file{i686-pc-mingw32-gcc} and @file{i686-pc-mingw32-strip}. -We set the @code{PATH} environment variable to ensure the MinGW version of @file{sdl-config} is used and -use --cross-prefix to specify the name of the cross compiler. -You can also use --prefix to set the Win32 install path which defaults to @file{c:/Program Files/QEMU}. - -Under Fedora Linux, you can run: -@example -yum -y install mingw32-gcc mingw32-SDL mingw32-zlib -@end example -to get a suitable cross compilation environment. - -@item You can install QEMU in the installation directory by typing -@code{make install}. Don't forget to copy @file{SDL.dll} and @file{zlib1.dll} into the -installation directory. - -@end itemize - -Wine can be used to launch the resulting qemu-system-i386.exe -and all other qemu-system-@var{target}.exe compiled for Win32. - -@node Mac OS X -@section Mac OS X - -System Requirements: -@itemize -@item Mac OS 10.5 or higher -@item The clang compiler shipped with Xcode 4.2 or higher, -or GCC 4.3 or higher -@end itemize - -Additional Requirements (install in order): -@enumerate -@item libffi: @uref{https://sourceware.org/libffi/} -@item gettext: @uref{http://www.gnu.org/software/gettext/} -@item glib: @uref{http://ftp.gnome.org/pub/GNOME/sources/glib/} -@item pkg-config: @uref{http://www.freedesktop.org/wiki/Software/pkg-config/} -@item autoconf: @uref{http://www.gnu.org/software/autoconf/autoconf.html} -@item automake: @uref{http://www.gnu.org/software/automake/} -@item pixman: @uref{http://www.pixman.org/} -@end enumerate - -* You may find it easiest to get these from a third-party packager -such as Homebrew, Macports, or Fink. - -After downloading the QEMU source code, double-click it to expand it. - -Then configure and make QEMU: -@example -./configure -make -@end example - -If you have a recent version of Mac OS X (OSX 10.7 or better -with Xcode 4.2 or better) we recommend building QEMU with the -default compiler provided by Apple, for your version of Mac OS X -(which will be 'clang'). The configure script will -automatically pick this. - -Note: If after the configure step you see a message like this: -@example -ERROR: Your compiler does not support the __thread specifier for - Thread-Local Storage (TLS). Please upgrade to a version that does. -@end example -you may have to build your own version of gcc from source. Expect that to take -several hours. More information can be found here: -@uref{https://gcc.gnu.org/install/} @* - -These are some of the third party binaries of gcc available for download: -@itemize -@item Homebrew: @uref{http://brew.sh/} -@item @uref{https://www.litebeam.net/gcc/gcc_472.pkg} -@item @uref{http://www.macports.org/ports.php?by=name&substr=gcc} -@end itemize - -You can have several versions of GCC on your system. To specify a certain version, -use the --cc and --cxx options. -@example -./configure --cxx= --cc= -@end example - -@node Make targets -@section Make targets - -@table @code - -@item make -@item make all -Make everything which is typically needed. - -@item install -TODO - -@item install-doc -TODO - -@item make clean -Remove most files which were built during make. - -@item make distclean -Remove everything which was built during make. - -@item make dvi -@item make html -@item make info -@item make pdf -Create documentation in dvi, html, info or pdf format. - -@item make cscope -TODO - -@item make defconfig -(Re-)create some build configuration files. -User made changes will be overwritten. - -@item tar -@item tarbin -TODO - -@end table @node License @appendix License From bf28a69eeb53e9e45166fbdda032454e7b1e3f29 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 6 Oct 2016 15:10:10 +0200 Subject: [PATCH 545/723] qemu-tech: move text from qemu-tech to tcg/README Reviewed-by: Emilio G. Cota Signed-off-by: Paolo Bonzini --- qemu-tech.texi | 12 ++---------- tcg/README | 5 +++++ 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/qemu-tech.texi b/qemu-tech.texi index 2ab7cd4cc30..082b62c8e06 100644 --- a/qemu-tech.texi +++ b/qemu-tech.texi @@ -287,16 +287,8 @@ are very complicated and highly CPU dependent. QEMU uses some tricks which make it relatively easily portable and simple while achieving good performances. -After the release of version 0.9.1, QEMU switched to a new method of -generating code, Tiny Code Generator or TCG. TCG relaxes the -dependency on the exact version of the compiler used. The basic idea -is to split every target instruction into a couple of RISC-like TCG -ops (see @code{target-i386/translate.c}). Some optimizations can be -performed at this stage, including liveness analysis and trivial -constant expression evaluation. TCG ops are then implemented in the -host CPU back end, also known as TCG target (see -@code{tcg/i386/tcg-target.inc.c}). For more information, please take a -look at @code{tcg/README}. +QEMU's dynamic translation backend is called TCG, for "Tiny Code +Generator". For more information, please take a look at @code{tcg/README}. @node Condition code optimisations @section Condition code optimisations diff --git a/tcg/README b/tcg/README index 1d48aa963f1..ae31388c59e 100644 --- a/tcg/README +++ b/tcg/README @@ -8,6 +8,11 @@ in the QOP code generator written by Paul Brook. 2) Definitions +TCG receives RISC-like "TCG ops" and performs some optimizations on them, +including liveness analysis and trivial constant expression +evaluation. TCG ops are then implemented in the host CPU back end, +also known as the TCG "target". + The TCG "target" is the architecture for which we generate the code. It is of course not the same as the "target" of QEMU which is the emulated architecture. As TCG started as a generic C backend used From c3ce5a235741cb027b1328288ddec06470254813 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 6 Oct 2016 15:10:57 +0200 Subject: [PATCH 546/723] qemu-tech: document lazy condition code evaluation in cpu.h Unlike the other sections, they are pretty specific to a particular CPU. Reviewed-by: Emilio G. Cota Signed-off-by: Paolo Bonzini --- qemu-tech.texi | 25 ------------------------- target-cris/cpu.h | 7 +++++++ target-i386/cpu.h | 7 +++++++ target-m68k/cpu.h | 8 ++++++++ target-s390x/cpu.h | 7 +++++++ target-sparc/cpu.h | 5 +++++ 6 files changed, 34 insertions(+), 25 deletions(-) diff --git a/qemu-tech.texi b/qemu-tech.texi index 082b62c8e06..75ceea408cf 100644 --- a/qemu-tech.texi +++ b/qemu-tech.texi @@ -214,7 +214,6 @@ SH4 @menu * QEMU compared to other emulators:: * Portable dynamic translation:: -* Condition code optimisations:: * CPU state optimisations:: * Translation cache:: * Direct block chaining:: @@ -290,30 +289,6 @@ performances. QEMU's dynamic translation backend is called TCG, for "Tiny Code Generator". For more information, please take a look at @code{tcg/README}. -@node Condition code optimisations -@section Condition code optimisations - -Lazy evaluation of CPU condition codes (@code{EFLAGS} register on x86) -is important for CPUs where every instruction sets the condition -codes. It tends to be less important on conventional RISC systems -where condition codes are only updated when explicitly requested. On -Sparc64, costly update of both 32 and 64 bit condition codes can be -avoided with lazy evaluation. - -Instead of computing the condition codes after each x86 instruction, -QEMU just stores one operand (called @code{CC_SRC}), the result -(called @code{CC_DST}) and the type of operation (called -@code{CC_OP}). When the condition codes are needed, the condition -codes can be calculated using this information. In addition, an -optimized calculation can be performed for some instruction types like -conditional branches. - -@code{CC_OP} is almost never explicitly set in the generated code -because it is known at translation time. - -The lazy condition code evaluation is used on x86, m68k, cris and -Sparc. ARM uses a simplified variant for the N and Z flags. - @node CPU state optimisations @section CPU state optimisations diff --git a/target-cris/cpu.h b/target-cris/cpu.h index 7d7fe6eb1cf..43d5f9d1da6 100644 --- a/target-cris/cpu.h +++ b/target-cris/cpu.h @@ -223,6 +223,13 @@ int cpu_cris_signal_handler(int host_signum, void *pinfo, void cris_initialize_tcg(void); void cris_initialize_crisv10_tcg(void); +/* Instead of computing the condition codes after each CRIS instruction, + * QEMU just stores one operand (called CC_SRC), the result + * (called CC_DEST) and the type of operation (called CC_OP). When the + * condition codes are needed, the condition codes can be calculated + * using this information. Condition codes are not generated if they + * are only needed for conditional branches. + */ enum { CC_OP_DYNAMIC, /* Use env->cc_op */ CC_OP_FLAGS, diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 1cb32ae456c..e64569854fe 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -698,6 +698,13 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS]; /* Use a clearer name for this. */ #define CPU_INTERRUPT_INIT CPU_INTERRUPT_RESET +/* Instead of computing the condition codes after each x86 instruction, + * QEMU just stores one operand (called CC_SRC), the result + * (called CC_DST) and the type of operation (called CC_OP). When the + * condition codes are needed, the condition codes can be calculated + * using this information. Condition codes are not generated if they + * are only needed for conditional branches. + */ typedef enum { CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */ CC_OP_EFLAGS, /* all cc are explicitly computed, CC_SRC = flags */ diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h index c2d40cb1ccc..471f490dc16 100644 --- a/target-m68k/cpu.h +++ b/target-m68k/cpu.h @@ -154,6 +154,14 @@ int cpu_m68k_signal_handler(int host_signum, void *pinfo, void *puc); void cpu_m68k_flush_flags(CPUM68KState *, int); + +/* Instead of computing the condition codes after each m68k instruction, + * QEMU just stores one operand (called CC_SRC), the result + * (called CC_DEST) and the type of operation (called CC_OP). When the + * condition codes are needed, the condition codes can be calculated + * using this information. Condition codes are not generated if they + * are only needed for conditional branches. + */ enum { CC_OP_DYNAMIC, /* Use env->cc_op */ CC_OP_FLAGS, /* CC_DEST = CVZN, CC_SRC = unused */ diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 4fb34b598d6..4e58cdee3e5 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -671,6 +671,13 @@ ObjectClass *s390_cpu_class_by_name(const char *name); /* CC optimization */ +/* Instead of computing the condition codes after each x86 instruction, + * QEMU just stores the result (called CC_DST), the type of operation + * (called CC_OP) and whatever operands are needed (CC_SRC and possibly + * CC_VR). When the condition codes are needed, the condition codes can + * be calculated using this information. Condition codes are not generated + * if they are only needed for conditional branches. + */ enum cc_op { CC_OP_CONST0 = 0, /* CC is 0 */ CC_OP_CONST1, /* CC is 1 */ diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index a3d64a4e529..646a1035137 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -102,6 +102,11 @@ #define CC_DST (env->cc_dst) #define CC_OP (env->cc_op) +/* Even though lazy evaluation of CPU condition codes tends to be less + * important on RISC systems where condition codes are only updated + * when explicitly requested, SPARC uses it to update 32-bit and 64-bit + * condition codes. + */ enum { CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */ CC_OP_FLAGS, /* all cc are back in status register */ From 0722cc42d472c64edb28cfdee04be815a3c1c7fa Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 6 Oct 2016 15:22:05 +0200 Subject: [PATCH 547/723] qemu-tech: move user mode emulation features from qemu-tech These are interesting for users too, since nowadays most qemu-user users are going to be somewhat technical rather than just people that want to run Wine. Some detail is lost, on the other hand some of the information I removed (e.g. basic block unchaining) was obsolete. Reviewed-by: Emilio G. Cota Signed-off-by: Paolo Bonzini --- qemu-doc.texi | 34 ++++++++++++++++++++++++ qemu-tech.texi | 71 -------------------------------------------------- 2 files changed, 34 insertions(+), 71 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index e60c46b5c9d..227c2b0b453 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -2629,6 +2629,7 @@ so should only be used with trusted guest OS. @menu * Supported Operating Systems :: +* Features:: * Linux User space emulator:: * BSD User space emulator :: @end menu @@ -2645,6 +2646,39 @@ Linux (referred as qemu-linux-user) BSD (referred as qemu-bsd-user) @end itemize +@node Features +@section Features + +QEMU user space emulation has the following notable features: + +@table @strong +@item System call translation: +QEMU includes a generic system call translator. This means that +the parameters of the system calls can be converted to fix +endianness and 32/64-bit mismatches between hosts and targets. +IOCTLs can be converted too. + +@item POSIX signal handling: +QEMU can redirect to the running program all signals coming from +the host (such as @code{SIGALRM}), as well as synthesize signals from +virtual CPU exceptions (for example @code{SIGFPE} when the program +executes a division by zero). + +QEMU relies on the host kernel to emulate most signal system +calls, for example to emulate the signal mask. On Linux, QEMU +supports both normal and real-time signals. + +@item Threading: +On Linux, QEMU can emulate the @code{clone} syscall and create a real +host thread (with a separate virtual CPU) for each emulated thread. +Note that not all targets currently emulate atomic operations correctly. +x86 and ARM use a global lock in order to preserve their semantics. +@end table + +QEMU was conceived so that ultimately it can emulate itself. Although +it is not very useful, it is an important test to show the power of the +emulator. + @node Linux User space emulator @section Linux User space emulator diff --git a/qemu-tech.texi b/qemu-tech.texi index 75ceea408cf..16780a1503a 100644 --- a/qemu-tech.texi +++ b/qemu-tech.texi @@ -221,8 +221,6 @@ SH4 * Exception support:: * MMU emulation:: * Device emulation:: -* Hardware interrupts:: -* User emulation specific details:: * Bibliography:: @end menu @@ -410,75 +408,6 @@ Usually the devices implement a reset method and register support for saving and loading of the device state. The devices can also use timers, especially together with the use of bottom halves (BHs). -@node Hardware interrupts -@section Hardware interrupts - -In order to be faster, QEMU does not check at every basic block if a -hardware interrupt is pending. Instead, the user must asynchronously -call a specific function to tell that an interrupt is pending. This -function resets the chaining of the currently executing basic -block. It ensures that the execution will return soon in the main loop -of the CPU emulator. Then the main loop can test if the interrupt is -pending and handle it. - -@node User emulation specific details -@section User emulation specific details - -@subsection Linux system call translation - -QEMU includes a generic system call translator for Linux. It means that -the parameters of the system calls can be converted to fix the -endianness and 32/64 bit issues. The IOCTLs are converted with a generic -type description system (see @file{ioctls.h} and @file{thunk.c}). - -QEMU supports host CPUs which have pages bigger than 4KB. It records all -the mappings the process does and try to emulated the @code{mmap()} -system calls in cases where the host @code{mmap()} call would fail -because of bad page alignment. - -@subsection Linux signals - -Normal and real-time signals are queued along with their information -(@code{siginfo_t}) as it is done in the Linux kernel. Then an interrupt -request is done to the virtual CPU. When it is interrupted, one queued -signal is handled by generating a stack frame in the virtual CPU as the -Linux kernel does. The @code{sigreturn()} system call is emulated to return -from the virtual signal handler. - -Some signals (such as SIGALRM) directly come from the host. Other -signals are synthesized from the virtual CPU exceptions such as SIGFPE -when a division by zero is done (see @code{main.c:cpu_loop()}). - -The blocked signal mask is still handled by the host Linux kernel so -that most signal system calls can be redirected directly to the host -Linux kernel. Only the @code{sigaction()} and @code{sigreturn()} system -calls need to be fully emulated (see @file{signal.c}). - -@subsection clone() system call and threads - -The Linux clone() system call is usually used to create a thread. QEMU -uses the host clone() system call so that real host threads are created -for each emulated thread. One virtual CPU instance is created for each -thread. - -The virtual x86 CPU atomic operations are emulated with a global lock so -that their semantic is preserved. - -Note that currently there are still some locking issues in QEMU. In -particular, the translated cache flush is not protected yet against -reentrancy. - -@subsection Self-virtualization - -QEMU was conceived so that ultimately it can emulate itself. Although -it is not very useful, it is an important test to show the power of the -emulator. - -Achieving self-virtualization is not easy because there may be address -space conflicts. QEMU user emulators solve this problem by being an -executable ELF shared object as the ld-linux.so ELF interpreter. That -way, it can be relocated at load time. - @node Bibliography @section Bibliography From 72bd94c578a4459924e415115b43c21b8ad6cdbd Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 6 Oct 2016 15:28:46 +0200 Subject: [PATCH 548/723] qemu-tech: move TCG test documentation to tests/tcg/README Reviewed-by: Emilio G. Cota Signed-off-by: Paolo Bonzini --- qemu-tech.texi | 35 ---------------------- tests/tcg/README | 76 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 35 deletions(-) create mode 100644 tests/tcg/README diff --git a/qemu-tech.texi b/qemu-tech.texi index 16780a1503a..adfb53b7f9b 100644 --- a/qemu-tech.texi +++ b/qemu-tech.texi @@ -31,7 +31,6 @@ @menu * Introduction:: * QEMU Internals:: -* Regression Tests:: @end menu @end ifnottex @@ -464,38 +463,4 @@ QEMU-SystemC, a hardware co-simulator. @end table -@node Regression Tests -@chapter Regression Tests - -In the directory @file{tests/}, various interesting testing programs -are available. They are used for regression testing. - -@menu -* test-i386:: -* linux-test:: -@end menu - -@node test-i386 -@section @file{test-i386} - -This program executes most of the 16 bit and 32 bit x86 instructions and -generates a text output. It can be compared with the output obtained with -a real CPU or another emulator. The target @code{make test} runs this -program and a @code{diff} on the generated output. - -The Linux system call @code{modify_ldt()} is used to create x86 selectors -to test some 16 bit addressing and 32 bit with segmentation cases. - -The Linux system call @code{vm86()} is used to test vm86 emulation. - -Various exceptions are raised to test most of the x86 user space -exception reporting. - -@node linux-test -@section @file{linux-test} - -This program tests various Linux system calls. It is used to verify -that the system call parameters are correctly converted between target -and host CPUs. - @bye diff --git a/tests/tcg/README b/tests/tcg/README new file mode 100644 index 00000000000..5dcfb4852bd --- /dev/null +++ b/tests/tcg/README @@ -0,0 +1,76 @@ +This directory contains various interesting programs for +regression testing. + +The target "make test" runs the programs and, if applicable, +runs "diff" to detect mismatches between output on the host and +output on QEMU. + +i386 +==== + +test-i386 +--------- + +This program executes most of the 16 bit and 32 bit x86 instructions and +generates a text output, for comparison with the output obtained with +a real CPU or another emulator. + +The Linux system call modify_ldt() is used to create x86 selectors +to test some 16 bit addressing and 32 bit with segmentation cases. + +The Linux system call vm86() is used to test vm86 emulation. + +Various exceptions are raised to test most of the x86 user space +exception reporting. + +linux-test +---------- + +This program tests various Linux system calls. It is used to verify +that the system call parameters are correctly converted between target +and host CPUs. + +test-i386-fprem +--------------- + +runcom +------ + +test-mmap +--------- + +sha1 +---- + +hello-i386 +---------- + + +ARM +=== + +hello-arm +--------- + +test-arm-iwmmxt +--------------- + +MIPS +==== + +hello-mips +---------- + +hello-mipsel +------------ + +CRIS +==== +The testsuite for CRIS is in tests/tcg/cris. You can run it +with "make test-cris". + +LM32 +==== +The testsuite for LM32 is in tests/tcg/cris. You can run it +with "make test-lm32". + From 77d47e16929b063570a78a264746dc0e8adb85e7 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 6 Oct 2016 16:49:03 +0200 Subject: [PATCH 549/723] qemu-tech: reorganize content Split more parts into separate chapters, place comparison last, rename "Introduction" to "CPU emulation". Reviewed-by: Emilio G. Cota Signed-off-by: Paolo Bonzini --- qemu-tech.texi | 171 +++++++++++++++++++++---------------------------- 1 file changed, 74 insertions(+), 97 deletions(-) diff --git a/qemu-tech.texi b/qemu-tech.texi index adfb53b7f9b..2e499a7c5a6 100644 --- a/qemu-tech.texi +++ b/qemu-tech.texi @@ -29,27 +29,29 @@ @top @menu -* Introduction:: -* QEMU Internals:: +* CPU emulation:: +* Translator Internals:: +* Device emulation:: +* QEMU compared to other emulators:: +* Bibliography:: @end menu @end ifnottex @contents -@node Introduction -@chapter Introduction +@node CPU emulation +@chapter CPU emulation @menu -* intro_x86_emulation:: x86 and x86-64 emulation -* intro_arm_emulation:: ARM emulation -* intro_mips_emulation:: MIPS emulation -* intro_ppc_emulation:: PowerPC emulation -* intro_sparc_emulation:: Sparc32 and Sparc64 emulation -* intro_xtensa_emulation:: Xtensa emulation -* intro_other_emulation:: Other CPU emulation +* x86:: x86 and x86-64 emulation +* ARM:: ARM emulation +* MIPS:: MIPS emulation +* PPC:: PowerPC emulation +* SPARC:: Sparc32 and Sparc64 emulation +* Xtensa:: Xtensa emulation @end menu -@node intro_x86_emulation +@node x86 @section x86 and x86-64 emulation QEMU x86 target features: @@ -84,7 +86,7 @@ normal use. @end itemize -@node intro_arm_emulation +@node ARM @section ARM emulation @itemize @@ -97,7 +99,7 @@ normal use. @end itemize -@node intro_mips_emulation +@node MIPS @section MIPS emulation @itemize @@ -124,7 +126,7 @@ Current QEMU limitations: @end itemize -@node intro_ppc_emulation +@node PPC @section PowerPC emulation @itemize @@ -136,7 +138,7 @@ FPU and MMU. @end itemize -@node intro_sparc_emulation +@node SPARC @section Sparc32 and Sparc64 emulation @itemize @@ -164,7 +166,7 @@ Current QEMU limitations: @end itemize -@node intro_xtensa_emulation +@node Xtensa @section Xtensa emulation @itemize @@ -189,94 +191,18 @@ may be created from overlay with minimal amount of hand-written code. @end itemize -@node intro_other_emulation -@section Other CPU emulation - -In addition to the above, QEMU supports emulation of other CPUs with -varying levels of success. These are: - -@itemize - -@item -Alpha -@item -CRIS -@item -M68k -@item -SH4 -@end itemize - -@node QEMU Internals -@chapter QEMU Internals +@node Translator Internals +@chapter Translator Internals @menu -* QEMU compared to other emulators:: -* Portable dynamic translation:: * CPU state optimisations:: * Translation cache:: * Direct block chaining:: * Self-modifying code and translated code invalidation:: * Exception support:: * MMU emulation:: -* Device emulation:: -* Bibliography:: @end menu -@node QEMU compared to other emulators -@section QEMU compared to other emulators - -Like bochs [1], QEMU emulates an x86 CPU. But QEMU is much faster than -bochs as it uses dynamic compilation. Bochs is closely tied to x86 PC -emulation while QEMU can emulate several processors. - -Like Valgrind [2], QEMU does user space emulation and dynamic -translation. Valgrind is mainly a memory debugger while QEMU has no -support for it (QEMU could be used to detect out of bound memory -accesses as Valgrind, but it has no support to track uninitialised data -as Valgrind does). The Valgrind dynamic translator generates better code -than QEMU (in particular it does register allocation) but it is closely -tied to an x86 host and target and has no support for precise exceptions -and system emulation. - -EM86 [3] is the closest project to user space QEMU (and QEMU still uses -some of its code, in particular the ELF file loader). EM86 was limited -to an alpha host and used a proprietary and slow interpreter (the -interpreter part of the FX!32 Digital Win32 code translator [4]). - -TWIN from Willows Software was a Windows API emulator like Wine. It is less -accurate than Wine but includes a protected mode x86 interpreter to launch -x86 Windows executables. Such an approach has greater potential because most -of the Windows API is executed natively but it is far more difficult to -develop because all the data structures and function parameters exchanged -between the API and the x86 code must be converted. - -User mode Linux [5] was the only solution before QEMU to launch a -Linux kernel as a process while not needing any host kernel -patches. However, user mode Linux requires heavy kernel patches while -QEMU accepts unpatched Linux kernels. The price to pay is that QEMU is -slower. - -The Plex86 [6] PC virtualizer is done in the same spirit as the now -obsolete qemu-fast system emulator. It requires a patched Linux kernel -to work (you cannot launch the same kernel on your PC), but the -patches are really small. As it is a PC virtualizer (no emulation is -done except for some privileged instructions), it has the potential of -being faster than QEMU. The downside is that a complicated (and -potentially unsafe) host kernel patch is needed. - -The commercial PC Virtualizers (VMWare [7], VirtualPC [8]) are faster -than QEMU (without virtualization), but they all need specific, proprietary -and potentially unsafe host drivers. Moreover, they are unable to -provide cycle exact simulation as an emulator can. - -VirtualBox [9], Xen [10] and KVM [11] are based on QEMU. QEMU-SystemC -[12] uses QEMU to simulate a system where some hardware devices are -developed in SystemC. - -@node Portable dynamic translation -@section Portable dynamic translation - QEMU is a dynamic translator. When it first encounters a piece of code, it converts it to the host instruction set. Usually dynamic translators are very complicated and highly CPU dependent. QEMU uses some tricks @@ -381,7 +307,7 @@ When MMU mappings change, only the chaining of the basic blocks is reset (i.e. a basic block can no longer jump directly to another one). @node Device emulation -@section Device emulation +@chapter Device emulation Systems emulated by QEMU are organized by boards. At initialization phase, each board instantiates a number of CPUs, devices, RAM and @@ -407,8 +333,59 @@ Usually the devices implement a reset method and register support for saving and loading of the device state. The devices can also use timers, especially together with the use of bottom halves (BHs). +@node QEMU compared to other emulators +@chapter QEMU compared to other emulators + +Like bochs [1], QEMU emulates an x86 CPU. But QEMU is much faster than +bochs as it uses dynamic compilation. Bochs is closely tied to x86 PC +emulation while QEMU can emulate several processors. + +Like Valgrind [2], QEMU does user space emulation and dynamic +translation. Valgrind is mainly a memory debugger while QEMU has no +support for it (QEMU could be used to detect out of bound memory +accesses as Valgrind, but it has no support to track uninitialised data +as Valgrind does). The Valgrind dynamic translator generates better code +than QEMU (in particular it does register allocation) but it is closely +tied to an x86 host and target and has no support for precise exceptions +and system emulation. + +EM86 [3] is the closest project to user space QEMU (and QEMU still uses +some of its code, in particular the ELF file loader). EM86 was limited +to an alpha host and used a proprietary and slow interpreter (the +interpreter part of the FX!32 Digital Win32 code translator [4]). + +TWIN from Willows Software was a Windows API emulator like Wine. It is less +accurate than Wine but includes a protected mode x86 interpreter to launch +x86 Windows executables. Such an approach has greater potential because most +of the Windows API is executed natively but it is far more difficult to +develop because all the data structures and function parameters exchanged +between the API and the x86 code must be converted. + +User mode Linux [5] was the only solution before QEMU to launch a +Linux kernel as a process while not needing any host kernel +patches. However, user mode Linux requires heavy kernel patches while +QEMU accepts unpatched Linux kernels. The price to pay is that QEMU is +slower. + +The Plex86 [6] PC virtualizer is done in the same spirit as the now +obsolete qemu-fast system emulator. It requires a patched Linux kernel +to work (you cannot launch the same kernel on your PC), but the +patches are really small. As it is a PC virtualizer (no emulation is +done except for some privileged instructions), it has the potential of +being faster than QEMU. The downside is that a complicated (and +potentially unsafe) host kernel patch is needed. + +The commercial PC Virtualizers (VMWare [7], VirtualPC [8]) are faster +than QEMU (without virtualization), but they all need specific, proprietary +and potentially unsafe host drivers. Moreover, they are unable to +provide cycle exact simulation as an emulator can. + +VirtualBox [9], Xen [10] and KVM [11] are based on QEMU. QEMU-SystemC +[12] uses QEMU to simulate a system where some hardware devices are +developed in SystemC. + @node Bibliography -@section Bibliography +@chapter Bibliography @table @asis From 36e4970e9d658143cc53e409a94e32ece2a36626 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 6 Oct 2016 16:25:12 +0200 Subject: [PATCH 550/723] qemu-tech: rewrite some parts Drop most the device emulation part and merge the rest into the description of the MMU. Make some bits more up-to-date. Reviewed-by: Emilio G. Cota Signed-off-by: Paolo Bonzini --- qemu-tech.texi | 124 +++++++++++++++++-------------------------------- 1 file changed, 42 insertions(+), 82 deletions(-) diff --git a/qemu-tech.texi b/qemu-tech.texi index 2e499a7c5a6..b418a41b787 100644 --- a/qemu-tech.texi +++ b/qemu-tech.texi @@ -31,7 +31,6 @@ @menu * CPU emulation:: * Translator Internals:: -* Device emulation:: * QEMU compared to other emulators:: * Bibliography:: @end menu @@ -194,15 +193,6 @@ may be created from overlay with minimal amount of hand-written code. @node Translator Internals @chapter Translator Internals -@menu -* CPU state optimisations:: -* Translation cache:: -* Direct block chaining:: -* Self-modifying code and translated code invalidation:: -* Exception support:: -* MMU emulation:: -@end menu - QEMU is a dynamic translator. When it first encounters a piece of code, it converts it to the host instruction set. Usually dynamic translators are very complicated and highly CPU dependent. QEMU uses some tricks @@ -212,33 +202,23 @@ performances. QEMU's dynamic translation backend is called TCG, for "Tiny Code Generator". For more information, please take a look at @code{tcg/README}. -@node CPU state optimisations -@section CPU state optimisations +Some notable features of QEMU's dynamic translator are: +@table @strong + +@item CPU state optimisations: The target CPUs have many internal states which change the way it evaluates instructions. In order to achieve a good speed, the translation phase considers that some state information of the virtual CPU cannot change in it. The state is recorded in the Translation Block (TB). If the state changes (e.g. privilege level), a new TB will be generated and the previous TB won't be used anymore until the state -matches the state recorded in the previous TB. For example, if the SS, +matches the state recorded in the previous TB. The same idea can be applied +to other aspects of the CPU state. For example, on x86, if the SS, DS and ES segments have a zero base, then the translator does not even generate an addition for the segment base. -[The FPU stack pointer register is not handled that way yet]. - -@node Translation cache -@section Translation cache - -A 32 MByte cache holds the most recently used translations. For -simplicity, it is completely flushed when it is full. A translation unit -contains just a single basic block (a block of x86 instructions -terminated by a jump or by a virtual CPU state change which the -translator cannot deduce statically). - -@node Direct block chaining -@section Direct block chaining - +@item Direct block chaining: After each translated basic block is executed, QEMU uses the simulated Program Counter (PC) and other cpu state information (such as the CS segment base value) to find the next basic block. @@ -252,18 +232,17 @@ it easier to make the jump target modification atomic. On some host architectures (such as x86 or PowerPC), the @code{JUMP} opcode is directly patched so that the block chaining has no overhead. -@node Self-modifying code and translated code invalidation -@section Self-modifying code and translated code invalidation - +@item Self-modifying code and translated code invalidation: Self-modifying code is a special challenge in x86 emulation because no instruction cache invalidation is signaled by the application when code is modified. -When translated code is generated for a basic block, the corresponding -host page is write protected if it is not already read-only. Then, if -a write access is done to the page, Linux raises a SEGV signal. QEMU -then invalidates all the translated code in the page and enables write -accesses to the page. +User-mode emulation marks a host page as write-protected (if it is +not already read-only) every time translated code is generated for a +basic block. Then, if a write access is done to the page, Linux raises +a SEGV signal. QEMU then invalidates all the translated code in the page +and enables write accesses to the page. For system emulation, write +protection is achieved through the software MMU. Correct translated code invalidation is done efficiently by maintaining a linked list of every translated block contained in a given page. Other @@ -275,63 +254,44 @@ necessary. However, QEMU still requires that the generated code always matches the target instructions in memory in order to handle exceptions correctly. -@node Exception support -@section Exception support - +@item Exception support: longjmp() is used when an exception such as division by zero is encountered. The host SIGSEGV and SIGBUS signal handlers are used to get invalid -memory accesses. The simulated program counter is found by -retranslating the corresponding basic block and by looking where the -host program counter was at the exception point. - -The virtual CPU cannot retrieve the exact @code{EFLAGS} register because -in some cases it is not computed because of condition code -optimisations. It is not a big concern because the emulated code can -still be restarted in any cases. - -@node MMU emulation -@section MMU emulation - -For system emulation QEMU supports a soft MMU. In that mode, the MMU +memory accesses. QEMU keeps a map from host program counter to +target program counter, and looks up where the exception happened +based on the host program counter at the exception point. + +On some targets, some bits of the virtual CPU's state are not flushed to the +memory until the end of the translation block. This is done for internal +emulation state that is rarely accessed directly by the program and/or changes +very often throughout the execution of a translation block---this includes +condition codes on x86, delay slots on SPARC, conditional execution on +ARM, and so on. This state is stored for each target instruction, and +looked up on exceptions. + +@item MMU emulation: +For system emulation QEMU uses a software MMU. In that mode, the MMU virtual to physical address translation is done at every memory -access. QEMU uses an address translation cache to speed up the -translation. +access. +QEMU uses an address translation cache (TLB) to speed up the translation. In order to avoid flushing the translated code each time the MMU -mappings change, QEMU uses a physically indexed translation cache. It +mappings change, all caches in QEMU are physically indexed. This means that each basic block is indexed with its physical address. -When MMU mappings change, only the chaining of the basic blocks is -reset (i.e. a basic block can no longer jump directly to another one). - -@node Device emulation -@chapter Device emulation - -Systems emulated by QEMU are organized by boards. At initialization -phase, each board instantiates a number of CPUs, devices, RAM and -ROM. Each device in turn can assign I/O ports or memory areas (for -MMIO) to its handlers. When the emulation starts, an access to the -ports or MMIO memory areas assigned to the device causes the -corresponding handler to be called. +In order to avoid invalidating the basic block chain when MMU mappings +change, chaining is only performed when the destination of the jump +shares a page with the basic block that is performing the jump. -RAM and ROM are handled more optimally, only the offset to the host -memory needs to be added to the guest address. - -The video RAM of VGA and other display cards is special: it can be -read or written directly like RAM, but write accesses cause the memory -to be marked with VGA_DIRTY flag as well. - -QEMU supports some device classes like serial and parallel ports, USB, -drives and network devices, by providing APIs for easier connection to -the generic, higher level implementations. The API hides the -implementation details from the devices, like native device use or -advanced block device formats like QCOW. - -Usually the devices implement a reset method and register support for -saving and loading of the device state. The devices can also use -timers, especially together with the use of bottom halves (BHs). +The MMU can also distinguish RAM and ROM memory areas from MMIO memory +areas. Access is faster for RAM and ROM because the translation cache also +hosts the offset between guest address and host memory. Accessing MMIO +memory areas instead calls out to C code for device emulation. +Finally, the MMU helps tracking dirty pages and pages pointed to by +translation blocks. +@end table @node QEMU compared to other emulators @chapter QEMU compared to other emulators From 78e87797ba0b6612fc1c95216a0b81c744fb85b0 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 6 Oct 2016 16:12:11 +0200 Subject: [PATCH 551/723] qemu-doc: merge qemu-tech and qemu-doc Merge what is left of qemu-tech into the main manual as an appendix. Ultimately we should have a new internals manual built from docs/, and then the "Translator Internals" parts of qemu-tech could move to docs/ as well. The bits on limitation and features of CPU emulation should remain in qemu-doc. Reviewed-by: Emilio G. Cota Signed-off-by: Paolo Bonzini --- .gitignore | 2 -- Makefile | 13 ++++++------ qemu-doc.texi | 3 +++ qemu-tech.texi | 56 +++++++++++--------------------------------------- qemu.nsi | 3 --- ui/cocoa.m | 9 -------- 6 files changed, 21 insertions(+), 65 deletions(-) diff --git a/.gitignore b/.gitignore index c91d018c78c..c88ebf95983 100644 --- a/.gitignore +++ b/.gitignore @@ -39,9 +39,7 @@ /qmp-introspect.[ch] /qmp-marshal.c /qemu-doc.html -/qemu-tech.html /qemu-doc.info -/qemu-tech.info /qemu-img /qemu-nbd /qemu-options.def diff --git a/Makefile b/Makefile index f10361675da..f148077f8f7 100644 --- a/Makefile +++ b/Makefile @@ -93,7 +93,7 @@ LIBS+=-lz $(LIBS_TOOLS) HELPERS-$(CONFIG_LINUX) = qemu-bridge-helper$(EXESUF) ifdef BUILD_DOCS -DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1 qemu-nbd.8 qemu-ga.8 +DOCS=qemu-doc.html qemu.1 qemu-img.1 qemu-nbd.8 qemu-ga.8 ifdef CONFIG_VIRTFS DOCS+=fsdev/virtfs-proxy-helper.1 endif @@ -398,7 +398,6 @@ distclean: clean rm -f qemu-doc.vr rm -f config.log rm -f linux-headers/asm - rm -f qemu-tech.info qemu-tech.aux qemu-tech.cp qemu-tech.dvi qemu-tech.fn qemu-tech.info qemu-tech.ky qemu-tech.log qemu-tech.pdf qemu-tech.pg qemu-tech.toc qemu-tech.tp qemu-tech.vr for d in $(TARGET_DIRS); do \ rm -rf $$d || exit 1 ; \ done @@ -434,7 +433,7 @@ endif install-doc: $(DOCS) $(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)" - $(INSTALL_DATA) qemu-doc.html qemu-tech.html "$(DESTDIR)$(qemu_docdir)" + $(INSTALL_DATA) qemu-doc.html "$(DESTDIR)$(qemu_docdir)" $(INSTALL_DATA) $(SRC_PATH)/docs/qmp-commands.txt "$(DESTDIR)$(qemu_docdir)" ifdef CONFIG_POSIX $(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1" @@ -592,10 +591,10 @@ qemu-ga.8: qemu-ga.texi $(POD2MAN) --section=8 --center=" " --release=" " qemu-ga.pod > $@, \ " GEN $@") -dvi: qemu-doc.dvi qemu-tech.dvi -html: qemu-doc.html qemu-tech.html -info: qemu-doc.info qemu-tech.info -pdf: qemu-doc.pdf qemu-tech.pdf +dvi: qemu-doc.dvi +html: qemu-doc.html +info: qemu-doc.info +pdf: qemu-doc.pdf qemu-doc.dvi qemu-doc.html qemu-doc.info qemu-doc.pdf: \ qemu-img.texi qemu-nbd.texi qemu-options.texi qemu-option-trace.texi \ diff --git a/qemu-doc.texi b/qemu-doc.texi index 227c2b0b453..023c1406cc7 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -35,6 +35,7 @@ * QEMU PC System emulator:: * QEMU System emulator for non PC targets:: * QEMU User space emulator:: +* Implementation notes:: * License:: * Index:: @end menu @@ -2949,6 +2950,8 @@ Run the emulation in single step mode. @end table +@include qemu-tech.texi + @node License @appendix License diff --git a/qemu-tech.texi b/qemu-tech.texi index b418a41b787..52a56ae25ec 100644 --- a/qemu-tech.texi +++ b/qemu-tech.texi @@ -1,32 +1,5 @@ -\input texinfo @c -*- texinfo -*- -@c %**start of header -@setfilename qemu-tech.info - -@documentlanguage en -@documentencoding UTF-8 - -@settitle QEMU Internals -@exampleindent 0 -@paragraphindent 0 -@c %**end of header - -@ifinfo -@direntry -* QEMU Internals: (qemu-tech). The QEMU Emulator Internals. -@end direntry -@end ifinfo - -@iftex -@titlepage -@sp 7 -@center @titlefont{QEMU Internals} -@sp 3 -@end titlepage -@end iftex - -@ifnottex -@node Top -@top +@node Implementation notes +@appendix Implementation notes @menu * CPU emulation:: @@ -34,12 +7,9 @@ * QEMU compared to other emulators:: * Bibliography:: @end menu -@end ifnottex - -@contents @node CPU emulation -@chapter CPU emulation +@section CPU emulation @menu * x86:: x86 and x86-64 emulation @@ -51,7 +21,7 @@ @end menu @node x86 -@section x86 and x86-64 emulation +@subsection x86 and x86-64 emulation QEMU x86 target features: @@ -86,7 +56,7 @@ normal use. @end itemize @node ARM -@section ARM emulation +@subsection ARM emulation @itemize @@ -99,7 +69,7 @@ normal use. @end itemize @node MIPS -@section MIPS emulation +@subsection MIPS emulation @itemize @@ -126,7 +96,7 @@ Current QEMU limitations: @end itemize @node PPC -@section PowerPC emulation +@subsection PowerPC emulation @itemize @@ -138,7 +108,7 @@ FPU and MMU. @end itemize @node SPARC -@section Sparc32 and Sparc64 emulation +@subsection Sparc32 and Sparc64 emulation @itemize @@ -166,7 +136,7 @@ Current QEMU limitations: @end itemize @node Xtensa -@section Xtensa emulation +@subsection Xtensa emulation @itemize @@ -191,7 +161,7 @@ may be created from overlay with minimal amount of hand-written code. @end itemize @node Translator Internals -@chapter Translator Internals +@section Translator Internals QEMU is a dynamic translator. When it first encounters a piece of code, it converts it to the host instruction set. Usually dynamic translators @@ -294,7 +264,7 @@ translation blocks. @end table @node QEMU compared to other emulators -@chapter QEMU compared to other emulators +@section QEMU compared to other emulators Like bochs [1], QEMU emulates an x86 CPU. But QEMU is much faster than bochs as it uses dynamic compilation. Bochs is closely tied to x86 PC @@ -345,7 +315,7 @@ VirtualBox [9], Xen [10] and KVM [11] are based on QEMU. QEMU-SystemC developed in SystemC. @node Bibliography -@chapter Bibliography +@section Bibliography @table @asis @@ -399,5 +369,3 @@ Kernel Based Virtual Machine (KVM). QEMU-SystemC, a hardware co-simulator. @end table - -@bye diff --git a/qemu.nsi b/qemu.nsi index a20f6ef35b4..1a2d7d18a8e 100644 --- a/qemu.nsi +++ b/qemu.nsi @@ -171,10 +171,8 @@ SectionEnd Section "Documentation" SectionDoc SetOutPath "$INSTDIR" File "${BINDIR}\qemu-doc.html" - File "${BINDIR}\qemu-tech.html" CreateDirectory "$SMPROGRAMS\${PRODUCT}" CreateShortCut "$SMPROGRAMS\${PRODUCT}\User Documentation.lnk" "$INSTDIR\qemu-doc.html" "" "$INSTDIR\qemu-doc.html" 0 - CreateShortCut "$SMPROGRAMS\${PRODUCT}\Technical Documentation.lnk" "$INSTDIR\qemu-tech.html" "" "$INSTDIR\qemu-tech.html" 0 SectionEnd !endif @@ -219,7 +217,6 @@ Section "Uninstall" Delete "$INSTDIR\qemu.exe" Delete "$INSTDIR\qemu-system-*.exe" Delete "$INSTDIR\qemu-doc.html" - Delete "$INSTDIR\qemu-tech.html" RMDir /r "$INSTDIR\keymaps" RMDir /r "$INSTDIR\share" ; Remove generated files diff --git a/ui/cocoa.m b/ui/cocoa.m index ba0e98a297f..26d4a1c07f4 100644 --- a/ui/cocoa.m +++ b/ui/cocoa.m @@ -814,7 +814,6 @@ - (void)startEmulationWithArgc:(int)argc argv:(char**)argv; - (void)doToggleFullScreen:(id)sender; - (void)toggleFullScreen:(id)sender; - (void)showQEMUDoc:(id)sender; -- (void)showQEMUTec:(id)sender; - (void)zoomToFit:(id) sender; - (void)displayConsole:(id)sender; - (void)pauseQEMU:(id)sender; @@ -998,13 +997,6 @@ - (void)showQEMUDoc:(id)sender [self openDocumentation: @"qemu-doc.html"]; } -- (void)showQEMUTec:(id)sender -{ - COCOA_DEBUG("QemuCocoaAppController: showQEMUTec\n"); - - [self openDocumentation: @"qemu-tech.html"]; -} - /* Stretches video to fit host monitor size */ - (void)zoomToFit:(id) sender { @@ -1335,7 +1327,6 @@ int main (int argc, const char * argv[]) { // Help menu menu = [[NSMenu alloc] initWithTitle:@"Help"]; [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"QEMU Documentation" action:@selector(showQEMUDoc:) keyEquivalent:@"?"] autorelease]]; // QEMU Help - [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"QEMU Technology" action:@selector(showQEMUTec:) keyEquivalent:@""] autorelease]]; // QEMU Help menuItem = [[[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""] autorelease]; [menuItem setSubmenu:menu]; [[NSApp mainMenu] addItem:menuItem]; From 818bbc86c9f9c47f67d11c0a068116c4333fd0ba Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 4 Oct 2016 10:49:43 +0200 Subject: [PATCH 552/723] block: use bdrv_add_before_write_notifier Register the notifier using the specific API for block devices. Signed-off-by: Paolo Bonzini Reviewed-by: Eric Blake Reviewed-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- block/write-threshold.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/block/write-threshold.c b/block/write-threshold.c index cc2ca71835e..0bd1a01c860 100644 --- a/block/write-threshold.c +++ b/block/write-threshold.c @@ -76,8 +76,7 @@ static int coroutine_fn before_write_notify(NotifierWithReturn *notifier, static void write_threshold_register_notifier(BlockDriverState *bs) { bs->write_threshold_notifier.notify = before_write_notify; - notifier_with_return_list_add(&bs->before_write_notifiers, - &bs->write_threshold_notifier); + bdrv_add_before_write_notifier(bs, &bs->write_threshold_notifier); } static void write_threshold_update(BlockDriverState *bs, From 5b8bb3595a2941e9408021f1080e60ce86d677d2 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 3 Oct 2016 18:14:15 +0200 Subject: [PATCH 553/723] async: add aio_bh_schedule_oneshot qemu_bh_delete is already clearing bh->scheduled at the same time as it's setting bh->deleted. Since it's not using any memory barriers, there is no synchronization going on for bh->deleted, and this makes the bh->deleted checks superfluous in aio_compute_timeout, aio_bh_poll and aio_ctx_check. Just remove them, and put the (bh->scheduled && bh->deleted) combo to work in a new function aio_bh_schedule_oneshot. The new function removes the need to save the QEMUBH pointer between the creation and the execution of the bottom half. Signed-off-by: Paolo Bonzini Signed-off-by: Kevin Wolf --- async.c | 27 +++++++++++++++++++++++---- include/block/aio.h | 6 ++++++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/async.c b/async.c index 3bca9b0adb6..f30d011ebc0 100644 --- a/async.c +++ b/async.c @@ -44,6 +44,25 @@ struct QEMUBH { bool deleted; }; +void aio_bh_schedule_oneshot(AioContext *ctx, QEMUBHFunc *cb, void *opaque) +{ + QEMUBH *bh; + bh = g_new(QEMUBH, 1); + *bh = (QEMUBH){ + .ctx = ctx, + .cb = cb, + .opaque = opaque, + }; + qemu_mutex_lock(&ctx->bh_lock); + bh->next = ctx->first_bh; + bh->scheduled = 1; + bh->deleted = 1; + /* Make sure that the members are ready before putting bh into list */ + smp_wmb(); + ctx->first_bh = bh; + qemu_mutex_unlock(&ctx->bh_lock); +} + QEMUBH *aio_bh_new(AioContext *ctx, QEMUBHFunc *cb, void *opaque) { QEMUBH *bh; @@ -86,7 +105,7 @@ int aio_bh_poll(AioContext *ctx) * thread sees the zero before bh->cb has run, and thus will call * aio_notify again if necessary. */ - if (!bh->deleted && atomic_xchg(&bh->scheduled, 0)) { + if (atomic_xchg(&bh->scheduled, 0)) { /* Idle BHs and the notify BH don't count as progress */ if (!bh->idle && bh != ctx->notify_dummy_bh) { ret = 1; @@ -104,7 +123,7 @@ int aio_bh_poll(AioContext *ctx) bhp = &ctx->first_bh; while (*bhp) { bh = *bhp; - if (bh->deleted) { + if (bh->deleted && !bh->scheduled) { *bhp = bh->next; g_free(bh); } else { @@ -168,7 +187,7 @@ aio_compute_timeout(AioContext *ctx) QEMUBH *bh; for (bh = ctx->first_bh; bh; bh = bh->next) { - if (!bh->deleted && bh->scheduled) { + if (bh->scheduled) { if (bh->idle) { /* idle bottom halves will be polled at least * every 10ms */ @@ -216,7 +235,7 @@ aio_ctx_check(GSource *source) aio_notify_accept(ctx); for (bh = ctx->first_bh; bh; bh = bh->next) { - if (!bh->deleted && bh->scheduled) { + if (bh->scheduled) { return true; } } diff --git a/include/block/aio.h b/include/block/aio.h index 173c1ed4044..b9fe2cb37e4 100644 --- a/include/block/aio.h +++ b/include/block/aio.h @@ -180,6 +180,12 @@ void aio_context_acquire(AioContext *ctx); /* Relinquish ownership of the AioContext. */ void aio_context_release(AioContext *ctx); +/** + * aio_bh_schedule_oneshot: Allocate a new bottom half structure that will run + * only once and as soon as possible. + */ +void aio_bh_schedule_oneshot(AioContext *ctx, QEMUBHFunc *cb, void *opaque); + /** * aio_bh_new: Allocate a new bottom half structure. * From fffb6e12233002c26c0ee9ff92fa87927cd779f2 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 3 Oct 2016 18:14:16 +0200 Subject: [PATCH 554/723] block: use aio_bh_schedule_oneshot This simplifies bottom half handlers by removing calls to qemu_bh_delete and thus removing the need to stash the bottom half pointer in the opaque datum. Signed-off-by: Paolo Bonzini Reviewed-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- block/archipelago.c | 5 +---- block/blkdebug.c | 7 +------ block/blkverify.c | 8 ++------ block/block-backend.c | 23 +++++++---------------- block/curl.c | 7 +------ block/gluster.c | 6 +----- block/io.c | 11 +++-------- block/iscsi.c | 7 ++----- block/nfs.c | 7 ++----- block/null.c | 5 +---- block/qed.c | 6 ++---- block/qed.h | 1 - block/rbd.c | 8 ++------ blockjob.c | 7 ++----- 14 files changed, 27 insertions(+), 81 deletions(-) diff --git a/block/archipelago.c b/block/archipelago.c index 37b8aca78d9..2449cfc702b 100644 --- a/block/archipelago.c +++ b/block/archipelago.c @@ -87,7 +87,6 @@ typedef enum { typedef struct ArchipelagoAIOCB { BlockAIOCB common; - QEMUBH *bh; struct BDRVArchipelagoState *s; QEMUIOVector *qiov; ARCHIPCmd cmd; @@ -154,11 +153,10 @@ static void archipelago_finish_aiocb(AIORequestData *reqdata) } else if (reqdata->aio_cb->ret == reqdata->segreq->total) { reqdata->aio_cb->ret = 0; } - reqdata->aio_cb->bh = aio_bh_new( + aio_bh_schedule_oneshot( bdrv_get_aio_context(reqdata->aio_cb->common.bs), qemu_archipelago_complete_aio, reqdata ); - qemu_bh_schedule(reqdata->aio_cb->bh); } static int wait_reply(struct xseg *xseg, xport srcport, struct xseg_port *port, @@ -313,7 +311,6 @@ static void qemu_archipelago_complete_aio(void *opaque) AIORequestData *reqdata = (AIORequestData *) opaque; ArchipelagoAIOCB *aio_cb = (ArchipelagoAIOCB *) reqdata->aio_cb; - qemu_bh_delete(aio_cb->bh); aio_cb->common.cb(aio_cb->common.opaque, aio_cb->ret); aio_cb->status = 0; diff --git a/block/blkdebug.c b/block/blkdebug.c index d5db1668155..41275714545 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -49,7 +49,6 @@ typedef struct BDRVBlkdebugState { typedef struct BlkdebugAIOCB { BlockAIOCB common; - QEMUBH *bh; int ret; } BlkdebugAIOCB; @@ -410,7 +409,6 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags, static void error_callback_bh(void *opaque) { struct BlkdebugAIOCB *acb = opaque; - qemu_bh_delete(acb->bh); acb->common.cb(acb->common.opaque, acb->ret); qemu_aio_unref(acb); } @@ -421,7 +419,6 @@ static BlockAIOCB *inject_error(BlockDriverState *bs, BDRVBlkdebugState *s = bs->opaque; int error = rule->options.inject.error; struct BlkdebugAIOCB *acb; - QEMUBH *bh; bool immediately = rule->options.inject.immediately; if (rule->options.inject.once) { @@ -436,9 +433,7 @@ static BlockAIOCB *inject_error(BlockDriverState *bs, acb = qemu_aio_get(&blkdebug_aiocb_info, bs, cb, opaque); acb->ret = -error; - bh = aio_bh_new(bdrv_get_aio_context(bs), error_callback_bh, acb); - acb->bh = bh; - qemu_bh_schedule(bh); + aio_bh_schedule_oneshot(bdrv_get_aio_context(bs), error_callback_bh, acb); return &acb->common; } diff --git a/block/blkverify.c b/block/blkverify.c index da62d759696..28f9af6dbae 100644 --- a/block/blkverify.c +++ b/block/blkverify.c @@ -22,7 +22,6 @@ typedef struct { typedef struct BlkverifyAIOCB BlkverifyAIOCB; struct BlkverifyAIOCB { BlockAIOCB common; - QEMUBH *bh; /* Request metadata */ bool is_write; @@ -175,7 +174,6 @@ static BlkverifyAIOCB *blkverify_aio_get(BlockDriverState *bs, bool is_write, { BlkverifyAIOCB *acb = qemu_aio_get(&blkverify_aiocb_info, bs, cb, opaque); - acb->bh = NULL; acb->is_write = is_write; acb->sector_num = sector_num; acb->nb_sectors = nb_sectors; @@ -191,7 +189,6 @@ static void blkverify_aio_bh(void *opaque) { BlkverifyAIOCB *acb = opaque; - qemu_bh_delete(acb->bh); if (acb->buf) { qemu_iovec_destroy(&acb->raw_qiov); qemu_vfree(acb->buf); @@ -218,9 +215,8 @@ static void blkverify_aio_cb(void *opaque, int ret) acb->verify(acb); } - acb->bh = aio_bh_new(bdrv_get_aio_context(acb->common.bs), - blkverify_aio_bh, acb); - qemu_bh_schedule(acb->bh); + aio_bh_schedule_oneshot(bdrv_get_aio_context(acb->common.bs), + blkverify_aio_bh, acb); break; } } diff --git a/block/block-backend.c b/block/block-backend.c index 639294b8e6b..11b0d8b4c18 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -65,7 +65,6 @@ struct BlockBackend { typedef struct BlockBackendAIOCB { BlockAIOCB common; - QEMUBH *bh; BlockBackend *blk; int ret; } BlockBackendAIOCB; @@ -898,7 +897,6 @@ int blk_make_zero(BlockBackend *blk, BdrvRequestFlags flags) static void error_callback_bh(void *opaque) { struct BlockBackendAIOCB *acb = opaque; - qemu_bh_delete(acb->bh); acb->common.cb(acb->common.opaque, acb->ret); qemu_aio_unref(acb); } @@ -908,16 +906,12 @@ BlockAIOCB *blk_abort_aio_request(BlockBackend *blk, void *opaque, int ret) { struct BlockBackendAIOCB *acb; - QEMUBH *bh; acb = blk_aio_get(&block_backend_aiocb_info, blk, cb, opaque); acb->blk = blk; acb->ret = ret; - bh = aio_bh_new(blk_get_aio_context(blk), error_callback_bh, acb); - acb->bh = bh; - qemu_bh_schedule(bh); - + aio_bh_schedule_oneshot(blk_get_aio_context(blk), error_callback_bh, acb); return &acb->common; } @@ -926,7 +920,6 @@ typedef struct BlkAioEmAIOCB { BlkRwCo rwco; int bytes; bool has_returned; - QEMUBH* bh; } BlkAioEmAIOCB; static const AIOCBInfo blk_aio_em_aiocb_info = { @@ -935,10 +928,6 @@ static const AIOCBInfo blk_aio_em_aiocb_info = { static void blk_aio_complete(BlkAioEmAIOCB *acb) { - if (acb->bh) { - assert(acb->has_returned); - qemu_bh_delete(acb->bh); - } if (acb->has_returned) { acb->common.cb(acb->common.opaque, acb->rwco.ret); qemu_aio_unref(acb); @@ -947,7 +936,10 @@ static void blk_aio_complete(BlkAioEmAIOCB *acb) static void blk_aio_complete_bh(void *opaque) { - blk_aio_complete(opaque); + BlkAioEmAIOCB *acb = opaque; + + assert(acb->has_returned); + blk_aio_complete(acb); } static BlockAIOCB *blk_aio_prwv(BlockBackend *blk, int64_t offset, int bytes, @@ -967,7 +959,6 @@ static BlockAIOCB *blk_aio_prwv(BlockBackend *blk, int64_t offset, int bytes, .ret = NOT_DONE, }; acb->bytes = bytes; - acb->bh = NULL; acb->has_returned = false; co = qemu_coroutine_create(co_entry, acb); @@ -975,8 +966,8 @@ static BlockAIOCB *blk_aio_prwv(BlockBackend *blk, int64_t offset, int bytes, acb->has_returned = true; if (acb->rwco.ret != NOT_DONE) { - acb->bh = aio_bh_new(blk_get_aio_context(blk), blk_aio_complete_bh, acb); - qemu_bh_schedule(acb->bh); + aio_bh_schedule_oneshot(blk_get_aio_context(blk), + blk_aio_complete_bh, acb); } return &acb->common; diff --git a/block/curl.c b/block/curl.c index 571f24cac24..e5eaa7ba0a5 100644 --- a/block/curl.c +++ b/block/curl.c @@ -96,7 +96,6 @@ struct BDRVCURLState; typedef struct CURLAIOCB { BlockAIOCB common; - QEMUBH *bh; QEMUIOVector *qiov; int64_t sector_num; @@ -739,9 +738,6 @@ static void curl_readv_bh_cb(void *p) CURLAIOCB *acb = p; BDRVCURLState *s = acb->common.bs->opaque; - qemu_bh_delete(acb->bh); - acb->bh = NULL; - size_t start = acb->sector_num * SECTOR_SIZE; size_t end; @@ -805,8 +801,7 @@ static BlockAIOCB *curl_aio_readv(BlockDriverState *bs, acb->sector_num = sector_num; acb->nb_sectors = nb_sectors; - acb->bh = aio_bh_new(bdrv_get_aio_context(bs), curl_readv_bh_cb, acb); - qemu_bh_schedule(acb->bh); + aio_bh_schedule_oneshot(bdrv_get_aio_context(bs), curl_readv_bh_cb, acb); return &acb->common; } diff --git a/block/gluster.c b/block/gluster.c index e7bd13cce3c..af76d7d59a1 100644 --- a/block/gluster.c +++ b/block/gluster.c @@ -38,7 +38,6 @@ typedef struct GlusterAIOCB { int64_t size; int ret; - QEMUBH *bh; Coroutine *coroutine; AioContext *aio_context; } GlusterAIOCB; @@ -622,8 +621,6 @@ static void qemu_gluster_complete_aio(void *opaque) { GlusterAIOCB *acb = (GlusterAIOCB *)opaque; - qemu_bh_delete(acb->bh); - acb->bh = NULL; qemu_coroutine_enter(acb->coroutine); } @@ -642,8 +639,7 @@ static void gluster_finish_aiocb(struct glfs_fd *fd, ssize_t ret, void *arg) acb->ret = -EIO; /* Partial read/write - fail it */ } - acb->bh = aio_bh_new(acb->aio_context, qemu_gluster_complete_aio, acb); - qemu_bh_schedule(acb->bh); + aio_bh_schedule_oneshot(acb->aio_context, qemu_gluster_complete_aio, acb); } static void qemu_gluster_parse_flags(int bdrv_flags, int *open_flags) diff --git a/block/io.c b/block/io.c index 57a2eeb512f..b136c89ae01 100644 --- a/block/io.c +++ b/block/io.c @@ -171,7 +171,6 @@ static void bdrv_drain_recurse(BlockDriverState *bs) typedef struct { Coroutine *co; BlockDriverState *bs; - QEMUBH *bh; bool done; } BdrvCoDrainData; @@ -191,7 +190,6 @@ static void bdrv_co_drain_bh_cb(void *opaque) BdrvCoDrainData *data = opaque; Coroutine *co = data->co; - qemu_bh_delete(data->bh); bdrv_drain_poll(data->bs); data->done = true; qemu_coroutine_enter(co); @@ -210,9 +208,9 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs) .co = qemu_coroutine_self(), .bs = bs, .done = false, - .bh = aio_bh_new(bdrv_get_aio_context(bs), bdrv_co_drain_bh_cb, &data), }; - qemu_bh_schedule(data.bh); + aio_bh_schedule_oneshot(bdrv_get_aio_context(bs), + bdrv_co_drain_bh_cb, &data); qemu_coroutine_yield(); /* If we are resumed from some other event (such as an aio completion or a @@ -2095,7 +2093,6 @@ typedef struct BlockAIOCBCoroutine { bool is_write; bool need_bh; bool *done; - QEMUBH* bh; } BlockAIOCBCoroutine; static const AIOCBInfo bdrv_em_co_aiocb_info = { @@ -2115,7 +2112,6 @@ static void bdrv_co_em_bh(void *opaque) BlockAIOCBCoroutine *acb = opaque; assert(!acb->need_bh); - qemu_bh_delete(acb->bh); bdrv_co_complete(acb); } @@ -2125,8 +2121,7 @@ static void bdrv_co_maybe_schedule_bh(BlockAIOCBCoroutine *acb) if (acb->req.error != -EINPROGRESS) { BlockDriverState *bs = acb->common.bs; - acb->bh = aio_bh_new(bdrv_get_aio_context(bs), bdrv_co_em_bh, acb); - qemu_bh_schedule(acb->bh); + aio_bh_schedule_oneshot(bdrv_get_aio_context(bs), bdrv_co_em_bh, acb); } } diff --git a/block/iscsi.c b/block/iscsi.c index dff548a139f..46ddc355aca 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -95,7 +95,6 @@ typedef struct IscsiTask { int do_retry; struct scsi_task *task; Coroutine *co; - QEMUBH *bh; IscsiLun *iscsilun; QEMUTimer retry_timer; int err_code; @@ -167,7 +166,6 @@ static void iscsi_co_generic_bh_cb(void *opaque) { struct IscsiTask *iTask = opaque; iTask->complete = 1; - qemu_bh_delete(iTask->bh); qemu_coroutine_enter(iTask->co); } @@ -299,9 +297,8 @@ iscsi_co_generic_cb(struct iscsi_context *iscsi, int status, out: if (iTask->co) { - iTask->bh = aio_bh_new(iTask->iscsilun->aio_context, - iscsi_co_generic_bh_cb, iTask); - qemu_bh_schedule(iTask->bh); + aio_bh_schedule_oneshot(iTask->iscsilun->aio_context, + iscsi_co_generic_bh_cb, iTask); } else { iTask->complete = 1; } diff --git a/block/nfs.c b/block/nfs.c index 8602a442111..c3db2ec58d7 100644 --- a/block/nfs.c +++ b/block/nfs.c @@ -57,7 +57,6 @@ typedef struct NFSRPC { QEMUIOVector *iov; struct stat *st; Coroutine *co; - QEMUBH *bh; NFSClient *client; } NFSRPC; @@ -103,7 +102,6 @@ static void nfs_co_generic_bh_cb(void *opaque) { NFSRPC *task = opaque; task->complete = 1; - qemu_bh_delete(task->bh); qemu_coroutine_enter(task->co); } @@ -127,9 +125,8 @@ nfs_co_generic_cb(int ret, struct nfs_context *nfs, void *data, error_report("NFS Error: %s", nfs_get_error(nfs)); } if (task->co) { - task->bh = aio_bh_new(task->client->aio_context, - nfs_co_generic_bh_cb, task); - qemu_bh_schedule(task->bh); + aio_bh_schedule_oneshot(task->client->aio_context, + nfs_co_generic_bh_cb, task); } else { task->complete = 1; } diff --git a/block/null.c b/block/null.c index b511010ba54..b3003909443 100644 --- a/block/null.c +++ b/block/null.c @@ -124,7 +124,6 @@ static coroutine_fn int null_co_flush(BlockDriverState *bs) typedef struct { BlockAIOCB common; - QEMUBH *bh; QEMUTimer timer; } NullAIOCB; @@ -136,7 +135,6 @@ static void null_bh_cb(void *opaque) { NullAIOCB *acb = opaque; acb->common.cb(acb->common.opaque, 0); - qemu_bh_delete(acb->bh); qemu_aio_unref(acb); } @@ -164,8 +162,7 @@ static inline BlockAIOCB *null_aio_common(BlockDriverState *bs, timer_mod_ns(&acb->timer, qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + s->latency_ns); } else { - acb->bh = aio_bh_new(bdrv_get_aio_context(bs), null_bh_cb, acb); - qemu_bh_schedule(acb->bh); + aio_bh_schedule_oneshot(bdrv_get_aio_context(bs), null_bh_cb, acb); } return &acb->common; } diff --git a/block/qed.c b/block/qed.c index 426f3cb4477..3ee879b52ed 100644 --- a/block/qed.c +++ b/block/qed.c @@ -909,7 +909,6 @@ static void qed_aio_complete_bh(void *opaque) void *user_opaque = acb->common.opaque; int ret = acb->bh_ret; - qemu_bh_delete(acb->bh); qemu_aio_unref(acb); /* Invoke callback */ @@ -934,9 +933,8 @@ static void qed_aio_complete(QEDAIOCB *acb, int ret) /* Arrange for a bh to invoke the completion function */ acb->bh_ret = ret; - acb->bh = aio_bh_new(bdrv_get_aio_context(acb->common.bs), - qed_aio_complete_bh, acb); - qemu_bh_schedule(acb->bh); + aio_bh_schedule_oneshot(bdrv_get_aio_context(acb->common.bs), + qed_aio_complete_bh, acb); /* Start next allocating write request waiting behind this one. Note that * requests enqueue themselves when they first hit an unallocated cluster diff --git a/block/qed.h b/block/qed.h index 22b3198751e..9676ab94793 100644 --- a/block/qed.h +++ b/block/qed.h @@ -130,7 +130,6 @@ enum { typedef struct QEDAIOCB { BlockAIOCB common; - QEMUBH *bh; int bh_ret; /* final return status for completion bh */ QSIMPLEQ_ENTRY(QEDAIOCB) next; /* next request */ int flags; /* QED_AIOCB_* bits ORed together */ diff --git a/block/rbd.c b/block/rbd.c index 0106fea45f6..6f9eb6fb9c7 100644 --- a/block/rbd.c +++ b/block/rbd.c @@ -71,7 +71,6 @@ typedef enum { typedef struct RBDAIOCB { BlockAIOCB common; - QEMUBH *bh; int64_t ret; QEMUIOVector *qiov; char *bounce; @@ -602,7 +601,6 @@ static const AIOCBInfo rbd_aiocb_info = { static void rbd_finish_bh(void *opaque) { RADOSCB *rcb = opaque; - qemu_bh_delete(rcb->acb->bh); qemu_rbd_complete_aio(rcb); } @@ -621,9 +619,8 @@ static void rbd_finish_aiocb(rbd_completion_t c, RADOSCB *rcb) rcb->ret = rbd_aio_get_return_value(c); rbd_aio_release(c); - acb->bh = aio_bh_new(bdrv_get_aio_context(acb->common.bs), - rbd_finish_bh, rcb); - qemu_bh_schedule(acb->bh); + aio_bh_schedule_oneshot(bdrv_get_aio_context(acb->common.bs), + rbd_finish_bh, rcb); } static int rbd_aio_discard_wrapper(rbd_image_t image, @@ -679,7 +676,6 @@ static BlockAIOCB *rbd_start_aio(BlockDriverState *bs, acb->ret = 0; acb->error = 0; acb->s = s; - acb->bh = NULL; if (cmd == RBD_AIO_WRITE) { qemu_iovec_to_buf(acb->qiov, 0, acb->bounce, qiov->size); diff --git a/blockjob.c b/blockjob.c index a167f96fd47..43fecbe13ee 100644 --- a/blockjob.c +++ b/blockjob.c @@ -588,7 +588,6 @@ BlockErrorAction block_job_error_action(BlockJob *job, BlockdevOnError on_err, typedef struct { BlockJob *job; - QEMUBH *bh; AioContext *aio_context; BlockJobDeferToMainLoopFn *fn; void *opaque; @@ -599,8 +598,6 @@ static void block_job_defer_to_main_loop_bh(void *opaque) BlockJobDeferToMainLoopData *data = opaque; AioContext *aio_context; - qemu_bh_delete(data->bh); - /* Prevent race with block_job_defer_to_main_loop() */ aio_context_acquire(data->aio_context); @@ -624,13 +621,13 @@ void block_job_defer_to_main_loop(BlockJob *job, { BlockJobDeferToMainLoopData *data = g_malloc(sizeof(*data)); data->job = job; - data->bh = qemu_bh_new(block_job_defer_to_main_loop_bh, data); data->aio_context = blk_get_aio_context(job->blk); data->fn = fn; data->opaque = opaque; job->deferred_to_main_loop = true; - qemu_bh_schedule(data->bh); + aio_bh_schedule_oneshot(qemu_get_aio_context(), + block_job_defer_to_main_loop_bh, data); } BlockJobTxn *block_job_txn_new(void) From c5f3014b82adc0e8f50bf5052031503d3467bea3 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 6 Oct 2016 11:33:17 +0200 Subject: [PATCH 555/723] block: Add bdrv_runtime_opts to query-command-line-options Recently we moved a few options from QemuOptsLists in blockdev.c to bdrv_runtime_opts in block.c in order to make them accissble using blockdev-add. However, this has the side effect that these options are missing from query-command-line-options now, and libvirt consequently disables the corresponding feature. This problem was reported as a regression for the 'discard' option, introduced in commit 818584a4. However, it is more general than that. Fix it by adding bdrv_runtime_opts to the list of QemuOptsLists that are returned in query-command-line-options. For the future, libvirt is advised to use QMP schema introspection for block device options. Reported-by: Michal Privoznik Signed-off-by: Kevin Wolf Tested-by: Michal Privoznik Tested-by: Gerd Hoffmann --- block.c | 2 +- include/sysemu/sysemu.h | 1 + util/qemu-config.c | 2 +- vl.c | 1 + 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/block.c b/block.c index bb1f1ec9576..40eb570389b 100644 --- a/block.c +++ b/block.c @@ -926,7 +926,7 @@ static void bdrv_assign_node_name(BlockDriverState *bs, g_free(gen_node_name); } -static QemuOptsList bdrv_runtime_opts = { +QemuOptsList bdrv_runtime_opts = { .name = "bdrv_common", .head = QTAILQ_HEAD_INITIALIZER(bdrv_runtime_opts.head), .desc = { diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index ef2c50bb04e..b66883328df 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -235,6 +235,7 @@ bool defaults_enabled(void); extern QemuOptsList qemu_legacy_drive_opts; extern QemuOptsList qemu_common_drive_opts; extern QemuOptsList qemu_drive_opts; +extern QemuOptsList bdrv_runtime_opts; extern QemuOptsList qemu_chardev_opts; extern QemuOptsList qemu_device_opts; extern QemuOptsList qemu_netdev_opts; diff --git a/util/qemu-config.c b/util/qemu-config.c index fb973074d30..5527100a012 100644 --- a/util/qemu-config.c +++ b/util/qemu-config.c @@ -6,7 +6,7 @@ #include "qmp-commands.h" static QemuOptsList *vm_config_groups[48]; -static QemuOptsList *drive_config_groups[4]; +static QemuOptsList *drive_config_groups[5]; static QemuOptsList *find_list(QemuOptsList **lists, const char *group, Error **errp) diff --git a/vl.c b/vl.c index f3abd99eb2f..9a2e7d5a5e4 100644 --- a/vl.c +++ b/vl.c @@ -3035,6 +3035,7 @@ int main(int argc, char **argv, char **envp) qemu_add_drive_opts(&qemu_legacy_drive_opts); qemu_add_drive_opts(&qemu_common_drive_opts); qemu_add_drive_opts(&qemu_drive_opts); + qemu_add_drive_opts(&bdrv_runtime_opts); qemu_add_opts(&qemu_chardev_opts); qemu_add_opts(&qemu_device_opts); qemu_add_opts(&qemu_netdev_opts); From 2bf7e10f78ebf67fbef364dce37ae844ba3c7a62 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 29 Sep 2016 16:47:58 +0200 Subject: [PATCH 556/723] block: Add node name to BLOCK_IO_ERROR event The event currently only contains the BlockBackend name. However, with anonymous BlockBackends, this is always the empty string. Add the node name so that the user can still see which block device caused the event. Signed-off-by: Kevin Wolf Reviewed-by: Max Reitz --- block/block-backend.c | 5 +++-- docs/qmp-events.txt | 8 +++++++- qapi/block-core.json | 10 ++++++++-- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/block/block-backend.c b/block/block-backend.c index 11b0d8b4c18..27ddacb3cf3 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -1197,8 +1197,9 @@ static void send_qmp_error_event(BlockBackend *blk, IoOperationType optype; optype = is_read ? IO_OPERATION_TYPE_READ : IO_OPERATION_TYPE_WRITE; - qapi_event_send_block_io_error(blk_name(blk), optype, action, - blk_iostatus_is_enabled(blk), + qapi_event_send_block_io_error(blk_name(blk), + bdrv_get_node_name(blk_bs(blk)), optype, + action, blk_iostatus_is_enabled(blk), error == ENOSPC, strerror(error), &error_abort); } diff --git a/docs/qmp-events.txt b/docs/qmp-events.txt index 7967ec4c5a2..62a9f9ca669 100644 --- a/docs/qmp-events.txt +++ b/docs/qmp-events.txt @@ -65,7 +65,12 @@ Emitted when a disk I/O error occurs. Data: -- "device": device name (json-string) +- "device": device name. This is always present for compatibility + reasons, but it can be empty ("") if the image does not + have a device name associated. (json-string) +- "node-name": node name. Note that errors may be reported for the root node + that is directly attached to a guest device rather than for the + node where the error occurred. (json-string) - "operation": I/O operation (json-string, "read" or "write") - "action": action that has been taken, it's one of the following (json-string): "ignore": error has been ignored @@ -76,6 +81,7 @@ Example: { "event": "BLOCK_IO_ERROR", "data": { "device": "ide0-hd1", + "node-name": "#block212", "operation": "write", "action": "stop" }, "timestamp": { "seconds": 1265044230, "microseconds": 450486 } } diff --git a/qapi/block-core.json b/qapi/block-core.json index 9d797b8fe00..3d3c0be75dc 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -2545,7 +2545,13 @@ # # Emitted when a disk I/O error occurs # -# @device: device name +# @device: device name. This is always present for compatibility +# reasons, but it can be empty ("") if the image does not +# have a device name associated. +# +# @node-name: node name. Note that errors may be reported for the root node +# that is directly attached to a guest device rather than for the +# node where the error occurred. (Since: 2.8) # # @operation: I/O operation # @@ -2566,7 +2572,7 @@ # Since: 0.13.0 ## { 'event': 'BLOCK_IO_ERROR', - 'data': { 'device': 'str', 'operation': 'IoOperationType', + 'data': { 'device': 'str', 'node-name': 'str', 'operation': 'IoOperationType', 'action': 'BlockErrorAction', '*nospace': 'bool', 'reason': 'str' } } From bbc8ea98bc8a2ba8174d106184f3089248d5ec5d Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 29 Sep 2016 18:47:03 +0200 Subject: [PATCH 557/723] block-backend: Remember if attached device is non-qdev Almost all block devices are qdevified by now. This allows us to go back from the BlockBackend to the DeviceState. xen_disk is the last device that is missing. We'll remember in the BlockBackend if a xen_disk is attached and can then disable any features that require going from a BB to the DeviceState. While at it, clearly mark the function used by xen_disk as legacy even in its name, not just in TODO comments. Signed-off-by: Kevin Wolf Reviewed-by: Max Reitz --- block/block-backend.c | 28 ++++++++++++++++++++-------- hw/block/xen_disk.c | 2 +- include/sysemu/block-backend.h | 4 ++-- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/block/block-backend.c b/block/block-backend.c index 27ddacb3cf3..d97afa1ef00 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -38,6 +38,7 @@ struct BlockBackend { BlockBackendPublic public; void *dev; /* attached device model, if any */ + bool legacy_dev; /* true if dev is not a DeviceState */ /* TODO change to DeviceState when all users are qdevified */ const BlockDevOps *dev_ops; void *dev_opaque; @@ -506,32 +507,38 @@ void blk_insert_bs(BlockBackend *blk, BlockDriverState *bs) } } -/* - * Attach device model @dev to @blk. - * Return 0 on success, -EBUSY when a device model is attached already. - */ -int blk_attach_dev(BlockBackend *blk, void *dev) -/* TODO change to DeviceState *dev when all users are qdevified */ +static int blk_do_attach_dev(BlockBackend *blk, void *dev) { if (blk->dev) { return -EBUSY; } blk_ref(blk); blk->dev = dev; + blk->legacy_dev = false; blk_iostatus_reset(blk); return 0; } +/* + * Attach device model @dev to @blk. + * Return 0 on success, -EBUSY when a device model is attached already. + */ +int blk_attach_dev(BlockBackend *blk, DeviceState *dev) +{ + return blk_do_attach_dev(blk, dev); +} + /* * Attach device model @dev to @blk. * @blk must not have a device model attached already. * TODO qdevified devices don't use this, remove when devices are qdevified */ -void blk_attach_dev_nofail(BlockBackend *blk, void *dev) +void blk_attach_dev_legacy(BlockBackend *blk, void *dev) { - if (blk_attach_dev(blk, dev) < 0) { + if (blk_do_attach_dev(blk, dev) < 0) { abort(); } + blk->legacy_dev = true; } /* @@ -585,6 +592,11 @@ BlockBackend *blk_by_dev(void *dev) void blk_set_dev_ops(BlockBackend *blk, const BlockDevOps *ops, void *opaque) { + /* All drivers that use blk_set_dev_ops() are qdevified and we want to keep + * it that way, so we can assume blk->dev is a DeviceState if blk->dev_ops + * is set. */ + assert(!blk->legacy_dev); + blk->dev_ops = ops; blk->dev_opaque = opaque; } diff --git a/hw/block/xen_disk.c b/hw/block/xen_disk.c index 5aa350a1bf5..1292a4b459a 100644 --- a/hw/block/xen_disk.c +++ b/hw/block/xen_disk.c @@ -1079,7 +1079,7 @@ static int blk_connect(struct XenDevice *xendev) * so we can blk_unref() unconditionally */ blk_ref(blkdev->blk); } - blk_attach_dev_nofail(blkdev->blk, blkdev); + blk_attach_dev_legacy(blkdev->blk, blkdev); blkdev->file_size = blk_getlength(blkdev->blk); if (blkdev->file_size < 0) { BlockDriverState *bs = blk_bs(blkdev->blk); diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h index a7993afcda6..b07159b6395 100644 --- a/include/sysemu/block-backend.h +++ b/include/sysemu/block-backend.h @@ -107,8 +107,8 @@ BlockDeviceIoStatus blk_iostatus(const BlockBackend *blk); void blk_iostatus_disable(BlockBackend *blk); void blk_iostatus_reset(BlockBackend *blk); void blk_iostatus_set_err(BlockBackend *blk, int error); -int blk_attach_dev(BlockBackend *blk, void *dev); -void blk_attach_dev_nofail(BlockBackend *blk, void *dev); +int blk_attach_dev(BlockBackend *blk, DeviceState *dev); +void blk_attach_dev_legacy(BlockBackend *blk, void *dev); void blk_detach_dev(BlockBackend *blk, void *dev); void *blk_get_attached_dev(BlockBackend *blk); BlockBackend *blk_by_dev(void *dev); From 2d76e724cf9e3f9fec6070a8af79c7ee4c2e763e Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 29 Sep 2016 18:30:53 +0200 Subject: [PATCH 558/723] block: Add qdev ID to DEVICE_TRAY_MOVED The event currently only contains the BlockBackend name. However, with anonymous BlockBackends, this is always the empty string. Add the qdev ID (or if none was given, the QOM path) so that the user can still see which device caused the event. Event generation has to be moved from bdrv_eject() to the BlockBackend because the BDS doesn't know the attached device, but that's easy because blk_eject() is the only user of it. Signed-off-by: Kevin Wolf Reviewed-by: Max Reitz --- block.c | 7 ------- block/block-backend.c | 33 ++++++++++++++++++++++++++++++++- docs/qmp-commands.txt | 3 +++ docs/qmp-events.txt | 6 +++++- qapi/block.json | 8 ++++++-- 5 files changed, 46 insertions(+), 11 deletions(-) diff --git a/block.c b/block.c index 40eb570389b..7f3e7bcdc34 100644 --- a/block.c +++ b/block.c @@ -3360,17 +3360,10 @@ int bdrv_media_changed(BlockDriverState *bs) void bdrv_eject(BlockDriverState *bs, bool eject_flag) { BlockDriver *drv = bs->drv; - const char *device_name; if (drv && drv->bdrv_eject) { drv->bdrv_eject(bs, eject_flag); } - - device_name = bdrv_get_device_name(bs); - if (device_name[0] != '\0') { - qapi_event_send_device_tray_moved(device_name, - eject_flag, &error_abort); - } } /** diff --git a/block/block-backend.c b/block/block-backend.c index d97afa1ef00..1a724a8d89f 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -565,6 +565,23 @@ void *blk_get_attached_dev(BlockBackend *blk) return blk->dev; } +/* Return the qdev ID, or if no ID is assigned the QOM path, of the block + * device attached to the BlockBackend. */ +static char *blk_get_attached_dev_id(BlockBackend *blk) +{ + DeviceState *dev; + + assert(!blk->legacy_dev); + dev = blk->dev; + + if (!dev) { + return g_strdup(""); + } else if (dev->id) { + return g_strdup(dev->id); + } + return object_get_canonical_path(OBJECT(dev)); +} + /* * Return the BlockBackend which has the device model @dev attached if it * exists, else null. @@ -612,13 +629,17 @@ void blk_dev_change_media_cb(BlockBackend *blk, bool load) if (blk->dev_ops && blk->dev_ops->change_media_cb) { bool tray_was_open, tray_is_open; + assert(!blk->legacy_dev); + tray_was_open = blk_dev_is_tray_open(blk); blk->dev_ops->change_media_cb(blk->dev_opaque, load); tray_is_open = blk_dev_is_tray_open(blk); if (tray_was_open != tray_is_open) { - qapi_event_send_device_tray_moved(blk_name(blk), tray_is_open, + char *id = blk_get_attached_dev_id(blk); + qapi_event_send_device_tray_moved(blk_name(blk), id, tray_is_open, &error_abort); + g_free(id); } } } @@ -1316,9 +1337,19 @@ void blk_lock_medium(BlockBackend *blk, bool locked) void blk_eject(BlockBackend *blk, bool eject_flag) { BlockDriverState *bs = blk_bs(blk); + char *id; + + /* blk_eject is only called by qdevified devices */ + assert(!blk->legacy_dev); if (bs) { bdrv_eject(bs, eject_flag); + + id = blk_get_attached_dev_id(blk); + qapi_event_send_device_tray_moved(blk_name(blk), id, + eject_flag, &error_abort); + g_free(id); + } } diff --git a/docs/qmp-commands.txt b/docs/qmp-commands.txt index e0adcebc67c..e044029ffc5 100644 --- a/docs/qmp-commands.txt +++ b/docs/qmp-commands.txt @@ -3239,6 +3239,7 @@ Example: "microseconds": 716996 }, "event": "DEVICE_TRAY_MOVED", "data": { "device": "ide1-cd0", + "id": "ide0-1-0", "tray-open": true } } <- { "return": {} } @@ -3267,6 +3268,7 @@ Example: "microseconds": 272147 }, "event": "DEVICE_TRAY_MOVED", "data": { "device": "ide1-cd0", + "id": "ide0-1-0", "tray-open": false } } <- { "return": {} } @@ -3303,6 +3305,7 @@ Example: "microseconds": 549958 }, "event": "DEVICE_TRAY_MOVED", "data": { "device": "ide1-cd0", + "id": "ide0-1-0", "tray-open": true } } <- { "return": {} } diff --git a/docs/qmp-events.txt b/docs/qmp-events.txt index 62a9f9ca669..e0a2365c63d 100644 --- a/docs/qmp-events.txt +++ b/docs/qmp-events.txt @@ -220,12 +220,16 @@ or by HMP/QMP commands. Data: -- "device": device name (json-string) +- "device": Block device name. This is always present for compatibility + reasons, but it can be empty ("") if the image does not have a + device name associated. (json-string) +- "id": The name or QOM path of the guest device (json-string) - "tray-open": true if the tray has been opened or false if it has been closed (json-bool) { "event": "DEVICE_TRAY_MOVED", "data": { "device": "ide1-cd0", + "id": "/machine/unattached/device[22]", "tray-open": true }, "timestamp": { "seconds": 1265044230, "microseconds": 450486 } } diff --git a/qapi/block.json b/qapi/block.json index c896bd1d3bb..4661fc93c83 100644 --- a/qapi/block.json +++ b/qapi/block.json @@ -195,14 +195,18 @@ # Emitted whenever the tray of a removable device is moved by the guest or by # HMP/QMP commands # -# @device: device name +# @device: Block device name. This is always present for compatibility +# reasons, but it can be empty ("") if the image does not +# have a device name associated. +# +# @id: The name or QOM path of the guest device # # @tray-open: true if the tray has been opened or false if it has been closed # # Since: 1.1 ## { 'event': 'DEVICE_TRAY_MOVED', - 'data': { 'device': 'str', 'tray-open': 'bool' } } + 'data': { 'device': 'str', 'id': 'str', 'tray-open': 'bool' } } ## # @QuorumOpType From 159975f38b2c88cd7b1fef511ba86dd7266a9f4e Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Mon, 5 Sep 2016 10:50:43 +0800 Subject: [PATCH 559/723] scripts: Allow block module to not define BlockDriver Signed-off-by: Fam Zheng Message-id: 1473043845-13197-2-git-send-email-famz@redhat.com Reviewed-by: Stefan Hajnoczi Signed-off-by: Max Reitz --- scripts/modules/module_block.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/scripts/modules/module_block.py b/scripts/modules/module_block.py index db4fb540cdc..3f730076400 100644 --- a/scripts/modules/module_block.py +++ b/scripts/modules/module_block.py @@ -37,7 +37,6 @@ def add_module(fheader, library, format_name, protocol_name): def process_file(fheader, filename): # This parser assumes the coding style rules are being followed with open(filename, "r") as cfile: - found_something = False found_start = False library, _ = os.path.splitext(os.path.basename(filename)) for line in cfile: @@ -51,16 +50,10 @@ def process_file(fheader, filename): add_module(fheader, library, format_name, protocol_name) found_start = False elif line.find("static BlockDriver") != -1: - found_something = True found_start = True format_name = "" protocol_name = "" - if not found_something: - print("No BlockDriver struct found in " + filename + ". \ - Is this really a module?", file=sys.stderr) - sys.exit(1) - def print_top(fheader): fheader.write('''/* AUTOMATICALLY GENERATED, DO NOT MODIFY */ /* From dffa41b48651c4002af02e80b7459e56a77152c7 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Mon, 5 Sep 2016 10:50:44 +0800 Subject: [PATCH 560/723] module: Don't load the same module if requested multiple times Use a hash table to keep record of all loaded modules, and return early if the requested module is already loaded. Signed-off-by: Fam Zheng Message-id: 1473043845-13197-3-git-send-email-famz@redhat.com Reviewed-by: Stefan Hajnoczi Signed-off-by: Max Reitz --- util/module.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/util/module.c b/util/module.c index a5f7fbd9413..c90973721ff 100644 --- a/util/module.c +++ b/util/module.c @@ -163,14 +163,28 @@ void module_load_one(const char *prefix, const char *lib_name) char *fname = NULL; char *exec_dir; char *dirs[3]; + char *module_name; int i = 0; int ret; + static GHashTable *loaded_modules; if (!g_module_supported()) { fprintf(stderr, "Module is not supported by system.\n"); return; } + if (!loaded_modules) { + loaded_modules = g_hash_table_new(g_str_hash, g_str_equal); + } + + module_name = g_strdup_printf("%s%s", prefix, lib_name); + + if (g_hash_table_lookup(loaded_modules, module_name)) { + g_free(module_name); + return; + } + g_hash_table_insert(loaded_modules, module_name, module_name); + exec_dir = qemu_get_exec_dir(); dirs[i++] = g_strdup_printf("%s", CONFIG_QEMU_MODDIR); dirs[i++] = g_strdup_printf("%s/..", exec_dir ? : ""); @@ -180,8 +194,8 @@ void module_load_one(const char *prefix, const char *lib_name) exec_dir = NULL; for (i = 0; i < ARRAY_SIZE(dirs); i++) { - fname = g_strdup_printf("%s/%s%s%s", - dirs[i], prefix, lib_name, HOST_DSOSUF); + fname = g_strdup_printf("%s/%s%s", + dirs[i], module_name, HOST_DSOSUF); ret = module_load_file(fname); g_free(fname); fname = NULL; From 27685a8dd08c051fa6d641fe46106fc0dfa51073 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Mon, 5 Sep 2016 10:50:45 +0800 Subject: [PATCH 561/723] dmg: Move libbz2 code to dmg-bz2.so dmg.o was moved to block-obj-m in 5505e8b76 to become a separate module, so that its reference to libbz2, since 6b383c08c, doesn't add an extra library to the main executable. Until recently, commit 06e60f70a (blockdev: Add dynamic module loading for block drivers) moved it back to block-obj-y to simplify the design of dynamic loading of block modules. But we don't want to lose the feature of less library dependency on the main executable. The solution here is to move only the bz2 related code to a separate DSO file, and load it when dmg_open is called. dmg_probe doesn't depend on bz2 support to work, and is the only code in this file which can run before dmg_open. While we are at it, fix the unhelpful cast of last argument passed to dmg_uncompress_bz2. Signed-off-by: Fam Zheng Message-id: 1473043845-13197-4-git-send-email-famz@redhat.com Reviewed-by: Stefan Hajnoczi Signed-off-by: Max Reitz --- block/Makefile.objs | 3 +- block/dmg-bz2.c | 61 +++++++++++++++++++++++++++++++++++++++ block/dmg.c | 69 +++++++++++---------------------------------- block/dmg.h | 59 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 139 insertions(+), 53 deletions(-) create mode 100644 block/dmg-bz2.c create mode 100644 block/dmg.h diff --git a/block/Makefile.objs b/block/Makefile.objs index 7d4031dae5c..67a036a1df0 100644 --- a/block/Makefile.objs +++ b/block/Makefile.objs @@ -41,6 +41,7 @@ gluster.o-libs := $(GLUSTERFS_LIBS) ssh.o-cflags := $(LIBSSH2_CFLAGS) ssh.o-libs := $(LIBSSH2_LIBS) archipelago.o-libs := $(ARCHIPELAGO_LIBS) -dmg.o-libs := $(BZIP2_LIBS) +block-obj-$(if $(CONFIG_BZIP2),m,n) += dmg-bz2.o +dmg-bz2.o-libs := $(BZIP2_LIBS) qcow.o-libs := -lz linux-aio.o-libs := -laio diff --git a/block/dmg-bz2.c b/block/dmg-bz2.c new file mode 100644 index 00000000000..9059492a9f0 --- /dev/null +++ b/block/dmg-bz2.c @@ -0,0 +1,61 @@ +/* + * DMG bzip2 uncompression + * + * Copyright (c) 2004 Johannes E. Schindelin + * Copyright (c) 2016 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "dmg.h" +#include + +static int dmg_uncompress_bz2_do(char *next_in, unsigned int avail_in, + char *next_out, unsigned int avail_out) +{ + int ret; + uint64_t total_out; + bz_stream bzstream = {}; + + ret = BZ2_bzDecompressInit(&bzstream, 0, 0); + if (ret != BZ_OK) { + return -1; + } + bzstream.next_in = next_in; + bzstream.avail_in = avail_in; + bzstream.next_out = next_out; + bzstream.avail_out = avail_out; + ret = BZ2_bzDecompress(&bzstream); + total_out = ((uint64_t)bzstream.total_out_hi32 << 32) + + bzstream.total_out_lo32; + BZ2_bzDecompressEnd(&bzstream); + if (ret != BZ_STREAM_END || + total_out != avail_out) { + return -1; + } + return 0; +} + +__attribute__((constructor)) +static void dmg_bz2_init(void) +{ + assert(!dmg_uncompress_bz2); + dmg_uncompress_bz2 = dmg_uncompress_bz2_do; +} diff --git a/block/dmg.c b/block/dmg.c index b0ed89baa70..58a3ae86c1d 100644 --- a/block/dmg.c +++ b/block/dmg.c @@ -28,10 +28,10 @@ #include "qemu/bswap.h" #include "qemu/error-report.h" #include "qemu/module.h" -#include -#ifdef CONFIG_BZIP2 -#include -#endif +#include "dmg.h" + +int (*dmg_uncompress_bz2)(char *next_in, unsigned int avail_in, + char *next_out, unsigned int avail_out); enum { /* Limit chunk sizes to prevent unreasonable amounts of memory being used @@ -41,31 +41,6 @@ enum { DMG_SECTORCOUNTS_MAX = DMG_LENGTHS_MAX / 512, }; -typedef struct BDRVDMGState { - CoMutex lock; - /* each chunk contains a certain number of sectors, - * offsets[i] is the offset in the .dmg file, - * lengths[i] is the length of the compressed chunk, - * sectors[i] is the sector beginning at offsets[i], - * sectorcounts[i] is the number of sectors in that chunk, - * the sectors array is ordered - * 0<=iread_only = true; s->n_chunks = 0; @@ -587,9 +562,6 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num) if (!is_sector_in_chunk(s, s->current_chunk, sector_num)) { int ret; uint32_t chunk = search_chunk(s, sector_num); -#ifdef CONFIG_BZIP2 - uint64_t total_out; -#endif if (chunk >= s->n_chunks) { return -1; @@ -620,8 +592,10 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num) return -1; } break; } -#ifdef CONFIG_BZIP2 case 0x80000006: /* bzip2 compressed */ + if (!dmg_uncompress_bz2) { + break; + } /* we need to buffer, because only the chunk as whole can be * inflated. */ ret = bdrv_pread(bs->file, s->offsets[chunk], @@ -630,24 +604,15 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num) return -1; } - ret = BZ2_bzDecompressInit(&s->bzstream, 0, 0); - if (ret != BZ_OK) { - return -1; - } - s->bzstream.next_in = (char *)s->compressed_chunk; - s->bzstream.avail_in = (unsigned int) s->lengths[chunk]; - s->bzstream.next_out = (char *)s->uncompressed_chunk; - s->bzstream.avail_out = (unsigned int) 512 * s->sectorcounts[chunk]; - ret = BZ2_bzDecompress(&s->bzstream); - total_out = ((uint64_t)s->bzstream.total_out_hi32 << 32) + - s->bzstream.total_out_lo32; - BZ2_bzDecompressEnd(&s->bzstream); - if (ret != BZ_STREAM_END || - total_out != 512 * s->sectorcounts[chunk]) { - return -1; + ret = dmg_uncompress_bz2((char *)s->compressed_chunk, + (unsigned int) s->lengths[chunk], + (char *)s->uncompressed_chunk, + (unsigned int) + (512 * s->sectorcounts[chunk])); + if (ret < 0) { + return ret; } break; -#endif /* CONFIG_BZIP2 */ case 1: /* copy */ ret = bdrv_pread(bs->file, s->offsets[chunk], s->uncompressed_chunk, s->lengths[chunk]); diff --git a/block/dmg.h b/block/dmg.h new file mode 100644 index 00000000000..b592d6fa8b7 --- /dev/null +++ b/block/dmg.h @@ -0,0 +1,59 @@ +/* + * Header for DMG driver + * + * Copyright (c) 2004-2006 Fabrice Bellard + * Copyright (c) 2016 Red hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef BLOCK_DMG_H +#define BLOCK_DMG_H + +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "block/block_int.h" +#include + +typedef struct BDRVDMGState { + CoMutex lock; + /* each chunk contains a certain number of sectors, + * offsets[i] is the offset in the .dmg file, + * lengths[i] is the length of the compressed chunk, + * sectors[i] is the sector beginning at offsets[i], + * sectorcounts[i] is the number of sectors in that chunk, + * the sectors array is ordered + * 0<=i Date: Tue, 4 Oct 2016 16:02:49 -0400 Subject: [PATCH 562/723] bsd-user: fix FreeBSD build after d148d90e Signed-off-by: Ed Maste Message-id: 1475611369-74971-1-git-send-email-emaste@freebsd.org Signed-off-by: Peter Maydell --- bsd-user/main.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/bsd-user/main.c b/bsd-user/main.c index d803d3e10ce..d8367bda467 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -695,6 +695,16 @@ static void usage(void) THREAD CPUState *thread_cpu; +bool qemu_cpu_is_self(CPUState *cpu) +{ + return thread_cpu == cpu; +} + +void qemu_cpu_kick(CPUState *cpu) +{ + cpu_exit(cpu); +} + /* Assumes contents are already zeroed. */ void init_task_state(TaskState *ts) { From 5d0cbbcfeb59e1e3f5ee7d26b8a215382f6d9abd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Fri, 30 Sep 2016 13:59:46 +0400 Subject: [PATCH 563/723] qapi: add assert about root value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit qiv->root should not be null, make that clearer with some assert. Signed-off-by: Marc-André Lureau Reviewed-by: Eric Blake Message-Id: <20160930095948.3154-2-marcandre.lureau@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- qapi/qmp-input-visitor.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c index fc91e748940..c7deca95b3e 100644 --- a/qapi/qmp-input-visitor.c +++ b/qapi/qmp-input-visitor.c @@ -64,6 +64,7 @@ static QObject *qmp_input_get_object(QmpInputVisitor *qiv, if (QSLIST_EMPTY(&qiv->stack)) { /* Starting at root, name is ignored. */ + assert(qiv->root); return qiv->root; } @@ -395,6 +396,7 @@ Visitor *qmp_input_visitor_new(QObject *obj, bool strict) { QmpInputVisitor *v; + assert(obj); v = g_malloc0(sizeof(*v)); v->visitor.type = VISITOR_INPUT; From eac8e79ff749fc15e1dca4caccf1f38664ab4915 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Fri, 30 Sep 2016 13:59:47 +0400 Subject: [PATCH 564/723] qapi: assert list entry has a value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This helps to figure out the expectations. Signed-off-by: Marc-André Lureau Reviewed-by: Eric Blake Message-Id: <20160930095948.3154-3-marcandre.lureau@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- qapi/qmp-input-visitor.c | 1 + 1 file changed, 1 insertion(+) diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c index c7deca95b3e..fe097c99b31 100644 --- a/qapi/qmp-input-visitor.c +++ b/qapi/qmp-input-visitor.c @@ -84,6 +84,7 @@ static QObject *qmp_input_get_object(QmpInputVisitor *qiv, assert(qobject_type(qobj) == QTYPE_QLIST); assert(!name); ret = qlist_entry_obj(tos->entry); + assert(ret); if (consume) { tos->entry = qlist_next(tos->entry); } From 1382d4abdf9619985e4078e37e49e487cea9935e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Fri, 30 Sep 2016 13:59:48 +0400 Subject: [PATCH 565/723] qapi: return a 'missing parameter' error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 'old' dispatch code returned a QERR_MISSING_PARAMETER for missing parameters, but the qapi qmp_dispatch() code uses QERR_INVALID_PARAMETER_TYPE. Improve qapi code to return QERR_MISSING_PARAMETER where appropriate. Fix expected error message in iotests. Signed-off-by: Marc-André Lureau Reviewed-by: Alberto Garcia Reviewed-by: Eric Blake Message-Id: <20160930095948.3154-4-marcandre.lureau@redhat.com> [Drop incorrect error_setg() from qmp_input_type_any() and qmp_input_type_null()] Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- qapi/qmp-input-visitor.c | 67 +++++++++++++++++++++++++++----------- tests/qemu-iotests/087.out | 2 +- 2 files changed, 49 insertions(+), 20 deletions(-) diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c index fe097c99b31..37a8e1f9311 100644 --- a/qapi/qmp-input-visitor.c +++ b/qapi/qmp-input-visitor.c @@ -56,7 +56,7 @@ static QmpInputVisitor *to_qiv(Visitor *v) static QObject *qmp_input_get_object(QmpInputVisitor *qiv, const char *name, - bool consume) + bool consume, Error **errp) { StackObject *tos; QObject *qobj; @@ -80,6 +80,9 @@ static QObject *qmp_input_get_object(QmpInputVisitor *qiv, bool removed = g_hash_table_remove(tos->h, name); assert(removed); } + if (!ret) { + error_setg(errp, QERR_MISSING_PARAMETER, name); + } } else { assert(qobject_type(qobj) == QTYPE_QLIST); assert(!name); @@ -165,13 +168,16 @@ static void qmp_input_start_struct(Visitor *v, const char *name, void **obj, size_t size, Error **errp) { QmpInputVisitor *qiv = to_qiv(v); - QObject *qobj = qmp_input_get_object(qiv, name, true); + QObject *qobj = qmp_input_get_object(qiv, name, true, errp); Error *err = NULL; if (obj) { *obj = NULL; } - if (!qobj || qobject_type(qobj) != QTYPE_QDICT) { + if (!qobj) { + return; + } + if (qobject_type(qobj) != QTYPE_QDICT) { error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "QDict"); return; @@ -193,10 +199,13 @@ static void qmp_input_start_list(Visitor *v, const char *name, GenericList **list, size_t size, Error **errp) { QmpInputVisitor *qiv = to_qiv(v); - QObject *qobj = qmp_input_get_object(qiv, name, true); + QObject *qobj = qmp_input_get_object(qiv, name, true, errp); const QListEntry *entry; - if (!qobj || qobject_type(qobj) != QTYPE_QLIST) { + if (!qobj) { + return; + } + if (qobject_type(qobj) != QTYPE_QLIST) { if (list) { *list = NULL; } @@ -234,11 +243,10 @@ static void qmp_input_start_alternate(Visitor *v, const char *name, bool promote_int, Error **errp) { QmpInputVisitor *qiv = to_qiv(v); - QObject *qobj = qmp_input_get_object(qiv, name, false); + QObject *qobj = qmp_input_get_object(qiv, name, false, errp); if (!qobj) { *obj = NULL; - error_setg(errp, QERR_MISSING_PARAMETER, name ? name : "null"); return; } *obj = g_malloc0(size); @@ -252,8 +260,13 @@ static void qmp_input_type_int64(Visitor *v, const char *name, int64_t *obj, Error **errp) { QmpInputVisitor *qiv = to_qiv(v); - QInt *qint = qobject_to_qint(qmp_input_get_object(qiv, name, true)); + QObject *qobj = qmp_input_get_object(qiv, name, true, errp); + QInt *qint; + if (!qobj) { + return; + } + qint = qobject_to_qint(qobj); if (!qint) { error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "integer"); @@ -268,8 +281,13 @@ static void qmp_input_type_uint64(Visitor *v, const char *name, uint64_t *obj, { /* FIXME: qobject_to_qint mishandles values over INT64_MAX */ QmpInputVisitor *qiv = to_qiv(v); - QInt *qint = qobject_to_qint(qmp_input_get_object(qiv, name, true)); + QObject *qobj = qmp_input_get_object(qiv, name, true, errp); + QInt *qint; + if (!qobj) { + return; + } + qint = qobject_to_qint(qobj); if (!qint) { error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "integer"); @@ -283,8 +301,13 @@ static void qmp_input_type_bool(Visitor *v, const char *name, bool *obj, Error **errp) { QmpInputVisitor *qiv = to_qiv(v); - QBool *qbool = qobject_to_qbool(qmp_input_get_object(qiv, name, true)); + QObject *qobj = qmp_input_get_object(qiv, name, true, errp); + QBool *qbool; + if (!qobj) { + return; + } + qbool = qobject_to_qbool(qobj); if (!qbool) { error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "boolean"); @@ -298,10 +321,15 @@ static void qmp_input_type_str(Visitor *v, const char *name, char **obj, Error **errp) { QmpInputVisitor *qiv = to_qiv(v); - QString *qstr = qobject_to_qstring(qmp_input_get_object(qiv, name, true)); + QObject *qobj = qmp_input_get_object(qiv, name, true, errp); + QString *qstr; + *obj = NULL; + if (!qobj) { + return; + } + qstr = qobject_to_qstring(qobj); if (!qstr) { - *obj = NULL; error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "string"); return; @@ -314,10 +342,13 @@ static void qmp_input_type_number(Visitor *v, const char *name, double *obj, Error **errp) { QmpInputVisitor *qiv = to_qiv(v); - QObject *qobj = qmp_input_get_object(qiv, name, true); + QObject *qobj = qmp_input_get_object(qiv, name, true, errp); QInt *qint; QFloat *qfloat; + if (!qobj) { + return; + } qint = qobject_to_qint(qobj); if (qint) { *obj = qint_get_int(qobject_to_qint(qobj)); @@ -338,11 +369,10 @@ static void qmp_input_type_any(Visitor *v, const char *name, QObject **obj, Error **errp) { QmpInputVisitor *qiv = to_qiv(v); - QObject *qobj = qmp_input_get_object(qiv, name, true); + QObject *qobj = qmp_input_get_object(qiv, name, true, errp); + *obj = NULL; if (!qobj) { - error_setg(errp, QERR_MISSING_PARAMETER, name ? name : "null"); - *obj = NULL; return; } @@ -353,10 +383,9 @@ static void qmp_input_type_any(Visitor *v, const char *name, QObject **obj, static void qmp_input_type_null(Visitor *v, const char *name, Error **errp) { QmpInputVisitor *qiv = to_qiv(v); - QObject *qobj = qmp_input_get_object(qiv, name, true); + QObject *qobj = qmp_input_get_object(qiv, name, true, errp); if (!qobj) { - error_setg(errp, QERR_MISSING_PARAMETER, name ? name : "null"); return; } @@ -369,7 +398,7 @@ static void qmp_input_type_null(Visitor *v, const char *name, Error **errp) static void qmp_input_optional(Visitor *v, const char *name, bool *present) { QmpInputVisitor *qiv = to_qiv(v); - QObject *qobj = qmp_input_get_object(qiv, name, false); + QObject *qobj = qmp_input_get_object(qiv, name, false, NULL); if (!qobj) { *present = false; diff --git a/tests/qemu-iotests/087.out b/tests/qemu-iotests/087.out index cd02eaed4cb..dc6baf93662 100644 --- a/tests/qemu-iotests/087.out +++ b/tests/qemu-iotests/087.out @@ -56,7 +56,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on Testing: -S QMP_VERSION {"return": {}} -{"error": {"class": "GenericError", "desc": "Invalid parameter type for 'driver', expected: string"}} +{"error": {"class": "GenericError", "desc": "Parameter 'driver' is missing"}} {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"} From c833fb4aeb01c124093a7569c0c333f80967d337 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 28 Sep 2016 19:33:41 +0200 Subject: [PATCH 566/723] MAINTAINERS: Pass the HMP staff from Luiz to David David graciously volunteered to take this off Luiz's hands. Signed-off-by: Markus Armbruster Message-Id: <1475084022-30117-2-git-send-email-armbru@redhat.com> Reviewed-by: Dr. David Alan Gilbert Acked-by: Luiz Capitulino --- MAINTAINERS | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 76a0fdb2c41..851cda76be0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1176,12 +1176,11 @@ F: qemu-timer.c F: vl.c Human Monitor (HMP) -M: Luiz Capitulino +M: Dr. David Alan Gilbert S: Maintained F: monitor.c F: hmp.c F: hmp-commands.hx -T: git git://repo.or.cz/qemu/qmp-unstable.git queue/qmp Network device backends M: Jason Wang From daf5dc7806f7bbb825506054a7c00a90b841b7cc Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 28 Sep 2016 19:33:42 +0200 Subject: [PATCH 567/723] MAINTAINERS: Pass the QObject staff from Luiz to Markus QObject is fairly tightly coupled to QAPI these days, and I've been effectively maintaining it together with QAPI for a while. Update MAINTAINERS to reflect that. Signed-off-by: Markus Armbruster Message-Id: <1475084022-30117-3-git-send-email-armbru@redhat.com> Acked-by: Luiz Capitulino --- MAINTAINERS | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 851cda76be0..5355a5edcd6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1245,8 +1245,8 @@ F: qapi/*.json T: git git://repo.or.cz/qemu/armbru.git qapi-next QObject -M: Luiz Capitulino -S: Maintained +M: Markus Armbruster +S: Supported F: qobject/ F: include/qapi/qmp/ X: include/qapi/qmp/dispatch.h @@ -1256,7 +1256,7 @@ F: tests/check-qint.c F: tests/check-qjson.c F: tests/check-qlist.c F: tests/check-qstring.c -T: git git://repo.or.cz/qemu/qmp-unstable.git queue/qmp +T: git git://repo.or.cz/qemu/armbru.git qapi-next QEMU Guest Agent M: Michael Roth From 728b1429b16ebcc09ca7936d8689db9e006acbef Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Wed, 5 Oct 2016 16:49:01 -0300 Subject: [PATCH 568/723] qmp: Disable query-cpu-* commands when they're unavailable Instead of requiring clients to actually call the query-cpu-* commands to find out if they are implemented, remove them from the output of "query-commands", so clients know they are not available. This is implemented by extending the existing hack at qmp_unregister_commands_hack(). I wish I could avoid adding even more #ifdefs to that code, but that's the solution we have today. Signed-off-by: Eduardo Habkost Message-Id: <1475696941-8056-1-git-send-email-ehabkost@redhat.com> Reviewed-by: Eric Blake Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- monitor.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/monitor.c b/monitor.c index 83c4edfce08..4ff74b7fd02 100644 --- a/monitor.c +++ b/monitor.c @@ -992,6 +992,15 @@ static void qmp_unregister_commands_hack(void) #ifndef TARGET_ARM qmp_unregister_command("query-gic-capabilities"); #endif +#if !defined(TARGET_S390X) + qmp_unregister_command("query-cpu-model-expansion"); + qmp_unregister_command("query-cpu-model-baseline"); + qmp_unregister_command("query-cpu-model-comparison"); +#endif +#if !defined(TARGET_PPC) && !defined(TARGET_ARM) && !defined(TARGET_I386) \ + && !defined(TARGET_S390X) + qmp_unregister_command("query-cpu-definitions"); +#endif } static void qmp_init_marshal(void) From fd11080b9ffa50c713137d0c2bc21d87af9074a9 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 22 Sep 2016 14:16:03 +0200 Subject: [PATCH 569/723] docs: Belatedly update for move of qmp-commands.txt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Missed in commit d076a2a and commit bd6092e. Signed-off-by: Markus Armbruster Message-Id: <1474546563-16332-1-git-send-email-armbru@redhat.com> Reviewed-by: Marc-André Lureau --- docs/xen-save-devices-state.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/xen-save-devices-state.txt b/docs/xen-save-devices-state.txt index 92e08dbf6ac..a72ecc80818 100644 --- a/docs/xen-save-devices-state.txt +++ b/docs/xen-save-devices-state.txt @@ -9,7 +9,7 @@ however it is also possible to save the state of all devices to file, without saving the RAM or the block devices of the VM. This operation is called "xen-save-devices-state" (see -QMP/qmp-commands.txt) +qmp-commands.txt) The binary format used in the file is the following: From 77a6da267c37781331c2dc8c4ac7f68d46a2a461 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 6 Oct 2016 17:10:00 +0200 Subject: [PATCH 570/723] docs: Belatedly update for move of QMP/* to docs/ Missed in commit 7537fe0 and commit 9b89b6a. Signed-off-by: Markus Armbruster Message-Id: <1475766600-7273-1-git-send-email-armbru@redhat.com> Reviewed-by: Eric Blake --- docs/qmp-commands.txt | 2 +- docs/writing-qmp-commands.txt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/qmp-commands.txt b/docs/qmp-commands.txt index e0adcebc67c..b289391b4ea 100644 --- a/docs/qmp-commands.txt +++ b/docs/qmp-commands.txt @@ -20,7 +20,7 @@ Also, the following notation is used to denote data flow: -> data issued by the Client <- Server data response -Please, refer to the QMP specification (QMP/qmp-spec.txt) for detailed +Please, refer to the QMP specification (docs/qmp-spec.txt) for detailed information on the Server command and response formats. NOTE: This document is temporary and will be replaced soon. diff --git a/docs/writing-qmp-commands.txt b/docs/writing-qmp-commands.txt index cfa6fe7c0df..44c14db4180 100644 --- a/docs/writing-qmp-commands.txt +++ b/docs/writing-qmp-commands.txt @@ -7,8 +7,8 @@ This document doesn't discuss QMP protocol level details, nor does it dive into the QAPI framework implementation. For an in-depth introduction to the QAPI framework, please refer to -docs/qapi-code-gen.txt. For documentation about the QMP protocol, please -check the files in QMP/. +docs/qapi-code-gen.txt. For documentation about the QMP protocol, +start with docs/qmp-intro.txt. == Overview == From e69f7d2510ab93ed4828ed69452f9c7c84f3f33a Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Mon, 19 Sep 2016 11:56:26 +0100 Subject: [PATCH 571/723] qemu-options.hx: fix -chardev ringbuf typos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clean up the documentation for -chardev ringbuf. There is a stray closing parenthesis and the comma is unnecessary. Signed-off-by: Stefan Hajnoczi Reviewed-by: Marc-André Lureau Signed-off-by: Michael Tokarev --- qemu-options.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qemu-options.hx b/qemu-options.hx index 01f01dfadcb..b1fbdb08cd3 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2374,7 +2374,7 @@ console with the given dimensions. @item -chardev ringbuf ,id=@var{id} [,size=@var{size}] Create a ring buffer with fixed size @option{size}. -@var{size} must be a power of two, and defaults to @code{64K}). +@var{size} must be a power of two and defaults to @code{64K}. @item -chardev file ,id=@var{id} ,path=@var{path} From a1c2bbc87b227dbf8e00b9684544eff9c861fcf7 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 14 Sep 2016 11:57:53 +0200 Subject: [PATCH 572/723] bt-hci-csr: drop unused argument Signed-off-by: Paolo Bonzini Signed-off-by: Michael Tokarev --- hw/arm/nseries.c | 3 +-- hw/bt/hci-csr.c | 2 +- include/hw/bt.h | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/hw/arm/nseries.c b/hw/arm/nseries.c index fea911e3e38..c86cf80514f 100644 --- a/hw/arm/nseries.c +++ b/hw/arm/nseries.c @@ -786,8 +786,7 @@ static void n8x0_cbus_setup(struct n800_s *s) static void n8x0_uart_setup(struct n800_s *s) { - CharDriverState *radio = uart_hci_init( - qdev_get_gpio_in(s->mpu->gpio, N8X0_BT_HOST_WKUP_GPIO)); + CharDriverState *radio = uart_hci_init(); qdev_connect_gpio_out(s->mpu->gpio, N8X0_BT_RESET_GPIO, csrhci_pins_get(radio)[csrhci_pin_reset]); diff --git a/hw/bt/hci-csr.c b/hw/bt/hci-csr.c index d688372ca32..b77c0366e47 100644 --- a/hw/bt/hci-csr.c +++ b/hw/bt/hci-csr.c @@ -458,7 +458,7 @@ qemu_irq *csrhci_pins_get(CharDriverState *chr) return s->pins; } -CharDriverState *uart_hci_init(qemu_irq wakeup) +CharDriverState *uart_hci_init(void) { struct csrhci_s *s = (struct csrhci_s *) g_malloc0(sizeof(struct csrhci_s)); diff --git a/include/hw/bt.h b/include/hw/bt.h index 963f3301385..2fa22bdab69 100644 --- a/include/hw/bt.h +++ b/include/hw/bt.h @@ -128,7 +128,7 @@ enum { __csrhci_pins, }; qemu_irq *csrhci_pins_get(CharDriverState *chr); -CharDriverState *uart_hci_init(qemu_irq wakeup); +CharDriverState *uart_hci_init(void); /* bt-l2cap.c */ struct bt_l2cap_device_s; From 496e079813ac793523213eebc099940b91855fd9 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Tue, 20 Sep 2016 09:43:01 -0500 Subject: [PATCH 573/723] tests: Ignore test executables Commits 9ef8112a and efad6682 introduced new tests, but forgot to ignore the built executables from an in-tree build. Signed-off-by: Eric Blake Reviewed-by: Alberto Garcia Reviewed-by: Fam Zheng Signed-off-by: Michael Tokarev --- tests/.gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/.gitignore b/tests/.gitignore index 0f0c79b1a9c..9f3d2ee0388 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -12,7 +12,9 @@ rcutorture test-aio test-base64 test-bitops +test-blockjob test-blockjob-txn +test-bufferiszero test-clone-visitor test-coroutine test-crypto-afsplit From a3ccdfb5bb37dc8a20702b7ea3b87f73e46b4b62 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 22 Sep 2016 21:16:33 +0200 Subject: [PATCH 574/723] MAINTAINERS: Add files to the Moxie section. The hw/moxie/ folder and default-configs/moxie-softmmu.mak obviously belong to the Moxie CPU. Signed-off-by: Thomas Huth Signed-off-by: Michael Tokarev --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 9bca506365e..adc5e4e1d8d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -157,6 +157,8 @@ M: Anthony Green S: Maintained F: target-moxie/ F: disas/moxie.c +F: hw/moxie/ +F: default-configs/moxie-softmmu.mak OpenRISC M: Jia Liu From c13e9912d9aa2ac485825bc7ca6879b0797cd715 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 22 Sep 2016 21:32:38 +0200 Subject: [PATCH 575/723] MAINTAINERS: Add some more files to the HMP section The hmp-commands-info.hx, hmp.h and include/monitor/hmp-target.h files were classified as unmaintained. Let's add them to the HMP section. Signed-off-by: Thomas Huth Reviewed-by: Luiz Capitulino Reviewed-by: Eric Blake Signed-off-by: Michael Tokarev --- MAINTAINERS | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index adc5e4e1d8d..ba501670881 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1183,8 +1183,9 @@ Human Monitor (HMP) M: Luiz Capitulino S: Maintained F: monitor.c -F: hmp.c -F: hmp-commands.hx +F: hmp.[ch] +F: hmp-commands*.hx +F: include/monitor/hmp-target.h T: git git://repo.or.cz/qemu/qmp-unstable.git queue/qmp Network device backends From a2b245ae2f67ef08b861e17c643ef9f2e77a0a51 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 23 Sep 2016 15:19:10 +0200 Subject: [PATCH 576/723] MAINTAINERS: Add include/hw/audio/ to audio section audio.h and pcspk.h are recognized as maintained files now. Signed-off-by: Thomas Huth Signed-off-by: Michael Tokarev --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index ba501670881..94f14ea1b2d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1046,6 +1046,7 @@ M: Gerd Hoffmann S: Maintained F: audio/ F: hw/audio/ +F: include/hw/audio/ F: tests/ac97-test.c F: tests/es1370-test.c F: tests/intel-hda-test.c From c10a1c787b4894048b688d8111b1f5e135015e04 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 19 Sep 2016 21:58:34 +0200 Subject: [PATCH 577/723] MAINTAINERS: Add some SPARC machine related files And while we're at it, remove Blue Swirl from the list of maintainers. Blue has apparently been inactive for quite a while now, so I assume he's unfortunately not available as maintainer anymore. Signed-off-by: Thomas Huth Signed-off-by: Michael Tokarev --- MAINTAINERS | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 94f14ea1b2d..3ac5fbc1d0e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -673,22 +673,27 @@ F: hw/sh4/shix.c SPARC Machines -------------- Sun4m -M: Blue Swirl M: Mark Cave-Ayland S: Maintained F: hw/sparc/sun4m.c +F: hw/dma/sparc32_dma.c +F: hw/dma/sun4m_iommu.c +F: include/hw/sparc/sparc32_dma.h +F: include/hw/sparc/sun4m.h +F: pc-bios/openbios-sparc32 Sun4u -M: Blue Swirl M: Mark Cave-Ayland S: Maintained F: hw/sparc64/sun4u.c +F: pc-bios/openbios-sparc64 Leon3 M: Fabien Chouteau S: Maintained F: hw/sparc/leon3.c F: hw/*/grlib* +F: include/hw/sparc/grlib.h S390 Machines ------------- From 72fa605decb371d8ebe3c9b3ca33a004b5da3671 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 23 Sep 2016 18:11:21 +0200 Subject: [PATCH 578/723] MAINTAINERS: Add some more files to the virtio section Makefile.objs and trace-events in hw/virtio/ were not covered by MAINTAINERS yet. Signed-off-by: Thomas Huth Signed-off-by: Michael Tokarev --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 3ac5fbc1d0e..9e4ca021b2b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -933,6 +933,8 @@ virtio M: Michael S. Tsirkin S: Supported F: hw/*/virtio* +F: hw/virtio/Makefile.objs +F: hw/virtio/trace-events F: net/vhost-user.c F: include/hw/virtio/ F: tests/virtio-balloon-test.c From c9b900903b10467f06ca1df10548bc43272d8529 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 23 Sep 2016 18:08:46 +0200 Subject: [PATCH 579/723] MAINTAINERS: Add header files to CRIS section etraxfs_dma.h and etraxfs.h in include/hw/cris/ obviously belong to the CRIS section in MAINTAINERS. Signed-off-by: Thomas Huth Reviewed-by: Edgar E. Iglesias Signed-off-by: Michael Tokarev --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 9e4ca021b2b..a5751a67bdd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -116,6 +116,7 @@ M: Edgar E. Iglesias S: Maintained F: target-cris/ F: hw/cris/ +F: include/hw/cris/ F: tests/tcg/cris/ F: disas/cris.c From de85094825834df939d1f6f09bdc573d2b72f7ae Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 27 Sep 2016 16:33:46 +0200 Subject: [PATCH 580/723] MAINTAINERS: Add some more rocker related files The files in tests/rocker/ and docs/specs/rocker.txt should be listed in the Rocker section of MAINTAINERS. Signed-off-by: Thomas Huth Signed-off-by: Michael Tokarev --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index a5751a67bdd..4b17a050c1c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1023,6 +1023,8 @@ Rocker M: Jiri Pirko S: Maintained F: hw/net/rocker/ +F: tests/rocker/ +F: docs/specs/rocker.txt NVDIMM M: Xiao Guangrong From 03972660f74aee433274ec8ab5018a83bf6af67e Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 29 Sep 2016 09:43:31 +0200 Subject: [PATCH 581/723] MAINTAINERS: Add some more pattern to recognize all win32 related files The get_maintainer.pl script currently thinks that the win32 related files in the util and include folders are currently unmaintained. Thus let's add some additional wildcards to match these files. Signed-off-by: Thomas Huth Reviewed-by: Stefan Weil Signed-off-by: Michael Tokarev --- MAINTAINERS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 4b17a050c1c..f0ab48ffcb3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -322,6 +322,9 @@ L: qemu-devel@nongnu.org M: Stefan Weil S: Maintained F: *win32* +F: */*win32* +F: include/*/*win32* +X: qga/*win32* F: qemu.nsi ARM Machines From ccf0a57b45c1ff49d21d5b8c0322ea40b5f4f2c7 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 30 Sep 2016 09:07:15 +0200 Subject: [PATCH 582/723] MAINTAINERS: Add usermode related config files The default-configs/*-linux-user.mak belong to Linux usermode emulation, and default-configs/*-bsd-user.mak belong to BSD usermode emulation. Signed-off-by: Thomas Huth Signed-off-by: Michael Tokarev --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index f0ab48ffcb3..4a72b77f362 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1425,11 +1425,13 @@ F: user-exec.c BSD user S: Orphan F: bsd-user/ +F: default-configs/*-bsd-user.mak Linux user M: Riku Voipio S: Maintained F: linux-user/ +F: default-configs/*-linux-user.mak Tiny Code Generator (TCG) ------------------------- From 5995db887161ec74a7b43f4969de8a0c06e70cc0 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 30 Sep 2016 09:26:51 +0200 Subject: [PATCH 583/723] MAINTAINERS: Add some more MIPS related files The MIPS section is missing some related header files, and files in the hw/misc/, hw/intc/ and hw/timer/ folders. Signed-off-by: Thomas Huth Signed-off-by: Michael Tokarev --- MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 4a72b77f362..2d77759e6d1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -150,6 +150,13 @@ M: Yongbok Kim S: Maintained F: target-mips/ F: hw/mips/ +F: hw/misc/mips_* +F: hw/intc/mips_gic.c +F: hw/timer/mips_gictimer.c +F: include/hw/mips/ +F: include/hw/misc/mips_* +F: include/hw/intc/mips_gic.h +F: include/hw/timer/mips_gictimer.h F: tests/tcg/mips/ F: disas/mips.c From 81527b94ad14d9f2b33b88ba31b68e2775a5e4fc Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 30 Sep 2016 11:32:02 +0200 Subject: [PATCH 584/723] MAINTAINERS: Some updates related to the SH4 machines hw/intc/sh_intc.c and hw/timer/sh_timer.c seem to belong to the R2D machine, as far as I can see. And concerning the Shix machine, it does not make much sense to have a "M:" entry here and the "S:" set to "Orphan". So I'd like to suggest to use "Odd Fixes" here instead. Signed-off-by: Thomas Huth Signed-off-by: Michael Tokarev --- MAINTAINERS | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 2d77759e6d1..64f57c6451c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -675,10 +675,12 @@ R2D M: Magnus Damm S: Maintained F: hw/sh4/r2d.c +F: hw/intc/sh_intc.c +F: hw/timer/sh_timer.c Shix M: Magnus Damm -S: Orphan +S: Odd Fixes F: hw/sh4/shix.c SPARC Machines From 7a488b5b2426cfb1d0d0ab01960e29cf9127792b Mon Sep 17 00:00:00 2001 From: Lin Ma Date: Fri, 23 Sep 2016 17:16:06 +0800 Subject: [PATCH 585/723] maint: Add module_block.h to .gitignore Commit 0c0c1fd9 generated module_block.h automatically, Add it to .gitignore to avoid checking in it by 'git add .'. Signed-off-by: Lin Ma Reviewed-by: Fam Zheng Signed-off-by: Michael Tokarev --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index c91d018c78c..97aca6c6b2f 100644 --- a/.gitignore +++ b/.gitignore @@ -55,6 +55,7 @@ /qemu-monitor-info.texi /qemu-version.h /qemu-version.h.tmp +/module_block.h /vscclient /fsdev/virtfs-proxy-helper *.[1-9] From a43edcf20a14aab81373fe64a6ed8cf84eb2a7f3 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 21 Sep 2016 21:00:19 -0700 Subject: [PATCH 586/723] qapi: make the json schema files more regular. This makes it easier to parse the schema file for tool generation: each paragraph is either a non-docstring comment, or a docstring immediately followed by a Python dict describing an API item. Signed-off-by: David Anderson Reviewed-by: Eric Blake Signed-off-by: Michael Tokarev --- qapi-schema.json | 3 +-- qapi/block-core.json | 5 ----- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/qapi-schema.json b/qapi-schema.json index c3dcf11a4ac..9e47b47cc78 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -752,6 +752,7 @@ 'cpu-throttle-increment': 'int', 'tls-creds': 'str', 'tls-hostname': 'str'} } + ## # @query-migrate-parameters # @@ -4118,7 +4119,6 @@ # # Since 1.6 ## - { 'struct': 'RxFilterInfo', 'data': { 'name': 'str', @@ -4338,7 +4338,6 @@ # # Since: 2.1 ## - { 'struct': 'Memdev', 'data': { 'size': 'size', diff --git a/qapi/block-core.json b/qapi/block-core.json index 9d797b8fe00..4badb973730 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -25,7 +25,6 @@ # Since: 1.3 # ## - { 'struct': 'SnapshotInfo', 'data': { 'id': 'str', 'name': 'str', 'vm-state-size': 'int', 'date-sec': 'int', 'date-nsec': 'int', @@ -81,7 +80,6 @@ # # Since: 1.7 ## - { 'union': 'ImageInfoSpecific', 'data': { 'qcow2': 'ImageInfoSpecificQCow2', @@ -129,7 +127,6 @@ # Since: 1.3 # ## - { 'struct': 'ImageInfo', 'data': {'filename': 'str', 'format': 'str', '*dirty-flag': 'bool', '*actual-size': 'int', 'virtual-size': 'int', @@ -181,7 +178,6 @@ # Since: 1.4 # ## - { 'struct': 'ImageCheck', 'data': {'filename': 'str', 'format': 'str', 'check-errors': 'int', '*image-end-offset': 'int', '*corruptions': 'int', '*leaks': 'int', @@ -518,7 +514,6 @@ # # Since: 2.5 ## - { 'struct': 'BlockDeviceTimedStats', 'data': { 'interval_length': 'int', 'min_rd_latency_ns': 'int', 'max_rd_latency_ns': 'int', 'avg_rd_latency_ns': 'int', From b16c129daf0fed91febbb88de23dae8271c8898a Mon Sep 17 00:00:00 2001 From: Li Qiang Date: Sun, 18 Sep 2016 19:48:35 -0700 Subject: [PATCH 587/723] usb: ehci: fix memory leak in ehci_process_itd While processing isochronous transfer descriptors(iTD), if the page select(PG) field value is out of bands it will return. In this situation the ehci's sg list is not freed thus leading to a memory leak issue. This patch avoid this. Signed-off-by: Li Qiang Reviewed-by: Thomas Huth Signed-off-by: Michael Tokarev --- hw/usb/hcd-ehci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index b093db729c0..f4ece9abed9 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -1426,6 +1426,7 @@ static int ehci_process_itd(EHCIState *ehci, if (off + len > 4096) { /* transfer crosses page border */ if (pg == 6) { + qemu_sglist_destroy(&ehci->isgl); return -1; /* avoid page pg + 1 */ } ptr2 = (itd->bufptr[pg + 1] & ITD_BUFPTR_MASK); From efee678d6df6ea2f531425e38825883008b3c1a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 28 Sep 2016 16:37:20 +0400 Subject: [PATCH 588/723] exec: remove unused compacted argument MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit b35ba30f8f when it was introduced, phys_page_compact() takes an unused compacted argument. ubsan complains about it when launching qemu-x86_64 without arguments: qemu/exec.c:310:5: runtime error: variable length array bound evaluates to non-positive value 0 Signed-off-by: Marc-André Lureau Signed-off-by: Michael Tokarev --- exec.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/exec.c b/exec.c index c8389f93c3a..374c364dff6 100644 --- a/exec.c +++ b/exec.c @@ -255,7 +255,7 @@ static void phys_page_set(AddressSpaceDispatch *d, /* Compact a non leaf page entry. Simply detect that the entry has a single child, * and update our entry so we can skip it and go directly to the destination. */ -static void phys_page_compact(PhysPageEntry *lp, Node *nodes, unsigned long *compacted) +static void phys_page_compact(PhysPageEntry *lp, Node *nodes) { unsigned valid_ptr = P_L2_SIZE; int valid = 0; @@ -275,7 +275,7 @@ static void phys_page_compact(PhysPageEntry *lp, Node *nodes, unsigned long *com valid_ptr = i; valid++; if (p[i].skip) { - phys_page_compact(&p[i], nodes, compacted); + phys_page_compact(&p[i], nodes); } } @@ -307,10 +307,8 @@ static void phys_page_compact(PhysPageEntry *lp, Node *nodes, unsigned long *com static void phys_page_compact_all(AddressSpaceDispatch *d, int nodes_nb) { - DECLARE_BITMAP(compacted, nodes_nb); - if (d->phys_map.skip) { - phys_page_compact(&d->phys_map, d->map.nodes, compacted); + phys_page_compact(&d->phys_map, d->map.nodes); } } From cbf061bd1fdb5017bfadde2164bdd6183d53a43d Mon Sep 17 00:00:00 2001 From: Greg Ungerer Date: Wed, 28 Sep 2016 10:06:39 +1000 Subject: [PATCH 589/723] m68k: change default system clock for m5208evb The shipping default setting for the Freescale M5208EVB board is to run the CPU at 166.67MHz. The current qemu emulation code for this board is defaulting to 66MHz. This results in time appearing to run way to slowly. So a "sleep 5" in a standard ColdFire Linux build takes almost 15 seconds in real time to actually complete. Change the hard coded default to match the default hardware setting. Signed-off-by: Greg Ungerer Reviewed-by: Laurent Vivier Reviewed-by: Thomas Huth Signed-off-by: Michael Tokarev --- hw/m68k/mcf5208.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/m68k/mcf5208.c b/hw/m68k/mcf5208.c index 9240ebf9af4..3438314c351 100644 --- a/hw/m68k/mcf5208.c +++ b/hw/m68k/mcf5208.c @@ -21,7 +21,7 @@ #include "elf.h" #include "exec/address-spaces.h" -#define SYS_FREQ 66000000 +#define SYS_FREQ 166666666 #define PCSR_EN 0x0001 #define PCSR_RLD 0x0002 From 88071589e8c6665c40c39bdefc59ad615693b325 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Fri, 23 Sep 2016 16:35:08 +0400 Subject: [PATCH 590/723] build-sys: fix find-in-path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix spelling, the GNU make text functions is not called "find-string" but "findstring". Broken in commit 2b2e59e. Fairly harmless: its only use is in tests/tcg/Makefile, where the bug can cause the I386_TESTS not to run when they should. Signed-off-by: Marc-André Lureau Reviewed-by: Markus Armbruster Signed-off-by: Michael Tokarev --- rules.mak | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rules.mak b/rules.mak index 3fdb261e32c..0333ae3c958 100644 --- a/rules.mak +++ b/rules.mak @@ -138,7 +138,7 @@ endef # Looks in the PATH if the argument contains no slash, else only considers one # specific directory. Returns an # empty string if the program doesn't exist # there. -find-in-path = $(if $(find-string /, $1), \ +find-in-path = $(if $(findstring /, $1), \ $(wildcard $1), \ $(wildcard $(patsubst %, %/$1, $(subst :, ,$(PATH))))) From cb57fb37051b11d04f1ddce736b0ec3f936e978e Mon Sep 17 00:00:00 2001 From: Wei Yang Date: Sat, 5 Mar 2016 13:47:08 +0000 Subject: [PATCH 591/723] bitmap: refine and move BITMAP_{FIRST/LAST}_WORD_MASK According to linux kernel commit <89c1e79eb30> ("linux/bitmap.h: improve BITMAP_{LAST,FIRST}_WORD_MASK"), these two macro could be improved. This patch takes this change and also move them all in header file. Signed-off-by: Wei Yang Signed-off-by: Michael Tokarev --- include/qemu/bitmap.h | 7 ++----- util/bitmap.c | 2 -- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/include/qemu/bitmap.h b/include/qemu/bitmap.h index 7247f147889..63ea2d0b1e4 100644 --- a/include/qemu/bitmap.h +++ b/include/qemu/bitmap.h @@ -57,11 +57,8 @@ * find_next_bit(addr, nbits, bit) Position next set bit in *addr >= bit */ -#define BITMAP_LAST_WORD_MASK(nbits) \ - ( \ - ((nbits) % BITS_PER_LONG) ? \ - (1UL<<((nbits) % BITS_PER_LONG))-1 : ~0UL \ - ) +#define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) & (BITS_PER_LONG - 1))) +#define BITMAP_LAST_WORD_MASK(nbits) (~0UL >> (-(nbits) & (BITS_PER_LONG - 1))) #define DECLARE_BITMAP(name,bits) \ unsigned long name[BITS_TO_LONGS(bits)] diff --git a/util/bitmap.c b/util/bitmap.c index 40aadfb4f32..43ed0117204 100644 --- a/util/bitmap.c +++ b/util/bitmap.c @@ -157,8 +157,6 @@ int slow_bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1, return result != 0; } -#define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) % BITS_PER_LONG)) - void bitmap_set(unsigned long *map, long start, long nr) { unsigned long *p = map + BIT_WORD(start); From 56bef8511a576deef32d3e763b993b5001015c2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Neusch=C3=A4fer?= Date: Fri, 30 Sep 2016 02:04:28 +0200 Subject: [PATCH 592/723] CODING_STYLE: Fix a typo ("have" vs. "has") MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jonathan Neuschäfer Reviewed-by: Peter Maydell Signed-off-by: Michael Tokarev --- CODING_STYLE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CODING_STYLE b/CODING_STYLE index e7fde150038..f53180bf3ff 100644 --- a/CODING_STYLE +++ b/CODING_STYLE @@ -9,7 +9,7 @@ patches before submitting. Of course, the most important aspect in any coding style is whitespace. Crusty old coders who have trouble spotting the glasses on their noses can tell the difference between a tab and eight spaces from a distance -of approximately fifteen parsecs. Many a flamewar have been fought and +of approximately fifteen parsecs. Many a flamewar has been fought and lost on this issue. QEMU indents are four spaces. Tabs are never used, except in Makefiles From 660a2d83e026496db6b3eaec2256a2cdd6c74de8 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Fri, 30 Sep 2016 16:02:01 +0100 Subject: [PATCH 593/723] char: fix missing return in error path for chardev TLS init If the qio_channel_tls_new_(server|client) methods fail, we disconnect the client. Unfortunately a missing return means we then go on to try and run the TLS handshake on a NULL I/O channel. This gives predictably segfaulty results. The main way to trigger this is to request a bogus TLS priority string for the TLS credentials. e.g. -object tls-creds-x509,id=tls0,priority=wibble,... Most other ways appear impossible to trigger except perhaps if OOM conditions cause gnutls initialization to fail. Signed-off-by: Daniel P. Berrange Reviewed-by: Eric Blake Signed-off-by: Michael Tokarev --- qemu-char.c | 1 + 1 file changed, 1 insertion(+) diff --git a/qemu-char.c b/qemu-char.c index fb456cec345..48a45ef5838 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -3132,6 +3132,7 @@ static void tcp_chr_tls_init(CharDriverState *chr) if (tioc == NULL) { error_free(err); tcp_chr_disconnect(chr); + return; } object_unref(OBJECT(s->ioc)); s->ioc = QIO_CHANNEL(tioc); From 0839f11cda08039d15b3e7621390de3e512b24e7 Mon Sep 17 00:00:00 2001 From: Felix Janda Date: Fri, 30 Sep 2016 19:40:21 -0400 Subject: [PATCH 594/723] linux-user: include instead of This removes the last usage of in the code base. Signed-off-by: Felix Janda Signed-off-by: Michael Tokarev --- linux-user/syscall.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 0815f309654..52012d4aa52 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -42,7 +42,7 @@ int __clone2(int (*fn)(void *), void *child_stack_base, #include #include #include -#include +#include #include #include #include From 7a25126d8a4155536a8a3d350e0ab185607bc819 Mon Sep 17 00:00:00 2001 From: Chen Fan Date: Thu, 29 Sep 2016 12:04:40 +0800 Subject: [PATCH 595/723] virtio: rename the bar index field name in VirtIOPCIProxy the bar index names are much similar to the bar memory regions, distinguish them to improve the code readability. Signed-off-by: Chen Fan Signed-off-by: Michael Tokarev --- hw/display/virtio-vga.c | 4 ++-- hw/virtio/virtio-pci.c | 20 ++++++++++---------- hw/virtio/virtio-pci.h | 8 ++++---- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/hw/display/virtio-vga.c b/hw/display/virtio-vga.c index f77b4012642..f9b017d86bb 100644 --- a/hw/display/virtio-vga.c +++ b/hw/display/virtio-vga.c @@ -120,8 +120,8 @@ static void virtio_vga_realize(VirtIOPCIProxy *vpci_dev, Error **errp) * virtio regions are moved to the end of bar #2, to make room for * the stdvga mmio registers at the start of bar #2. */ - vpci_dev->modern_mem_bar = 2; - vpci_dev->msix_bar = 4; + vpci_dev->modern_mem_bar_idx = 2; + vpci_dev->msix_bar_idx = 4; if (!(vpci_dev->flags & VIRTIO_PCI_FLAG_PAGE_PER_VQ)) { /* diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 2d60a005b66..06831de5ff8 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1551,7 +1551,7 @@ static void virtio_pci_modern_mem_region_map(VirtIOPCIProxy *proxy, struct virtio_pci_cap *cap) { virtio_pci_modern_region_map(proxy, region, cap, - &proxy->modern_bar, proxy->modern_mem_bar); + &proxy->modern_bar, proxy->modern_mem_bar_idx); } static void virtio_pci_modern_io_region_map(VirtIOPCIProxy *proxy, @@ -1559,7 +1559,7 @@ static void virtio_pci_modern_io_region_map(VirtIOPCIProxy *proxy, struct virtio_pci_cap *cap) { virtio_pci_modern_region_map(proxy, region, cap, - &proxy->io_bar, proxy->modern_io_bar); + &proxy->io_bar, proxy->modern_io_bar_idx); } static void virtio_pci_modern_mem_region_unmap(VirtIOPCIProxy *proxy, @@ -1670,14 +1670,14 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) memory_region_init(&proxy->io_bar, OBJECT(proxy), "virtio-pci-io", 0x4); - pci_register_bar(&proxy->pci_dev, proxy->modern_io_bar, + pci_register_bar(&proxy->pci_dev, proxy->modern_io_bar_idx, PCI_BASE_ADDRESS_SPACE_IO, &proxy->io_bar); virtio_pci_modern_io_region_map(proxy, &proxy->notify_pio, ¬ify_pio.cap); } - pci_register_bar(&proxy->pci_dev, proxy->modern_mem_bar, + pci_register_bar(&proxy->pci_dev, proxy->modern_mem_bar_idx, PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_PREFETCH | PCI_BASE_ADDRESS_MEM_TYPE_64, @@ -1693,7 +1693,7 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) if (proxy->nvectors) { int err = msix_init_exclusive_bar(&proxy->pci_dev, proxy->nvectors, - proxy->msix_bar); + proxy->msix_bar_idx); if (err) { /* Notice when a system that supports MSIx can't initialize it. */ if (err != -ENOTSUP) { @@ -1716,7 +1716,7 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) &virtio_pci_config_ops, proxy, "virtio-pci", size); - pci_register_bar(&proxy->pci_dev, proxy->legacy_io_bar, + pci_register_bar(&proxy->pci_dev, proxy->legacy_io_bar_idx, PCI_BASE_ADDRESS_SPACE_IO, &proxy->bar); } @@ -1760,10 +1760,10 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp) * region 4+5 -- virtio modern memory (64bit) bar * */ - proxy->legacy_io_bar = 0; - proxy->msix_bar = 1; - proxy->modern_io_bar = 2; - proxy->modern_mem_bar = 4; + proxy->legacy_io_bar_idx = 0; + proxy->msix_bar_idx = 1; + proxy->modern_io_bar_idx = 2; + proxy->modern_mem_bar_idx = 4; proxy->common.offset = 0x0; proxy->common.size = 0x1000; diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h index 541cbdbc2bd..b4edea69874 100644 --- a/hw/virtio/virtio-pci.h +++ b/hw/virtio/virtio-pci.h @@ -143,10 +143,10 @@ struct VirtIOPCIProxy { MemoryRegion io_bar; MemoryRegion modern_cfg; AddressSpace modern_as; - uint32_t legacy_io_bar; - uint32_t msix_bar; - uint32_t modern_io_bar; - uint32_t modern_mem_bar; + uint32_t legacy_io_bar_idx; + uint32_t msix_bar_idx; + uint32_t modern_io_bar_idx; + uint32_t modern_mem_bar_idx; int config_cap; uint32_t flags; bool disable_modern; From 52cfcb464255b4da5115408e2a6ce3327bbcb9df Mon Sep 17 00:00:00 2001 From: Zhang Chen Date: Fri, 30 Sep 2016 10:27:58 +0800 Subject: [PATCH 596/723] net/filter-mirror: Fix mirror initial check typo Signed-off-by: Zhang Chen Reviewed-by: Eric Blake Signed-off-by: Michael Tokarev --- net/filter-mirror.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/filter-mirror.c b/net/filter-mirror.c index 35df37451da..0ee58d905ec 100644 --- a/net/filter-mirror.c +++ b/net/filter-mirror.c @@ -198,7 +198,7 @@ static void filter_mirror_setup(NetFilterState *nf, Error **errp) MirrorState *s = FILTER_MIRROR(nf); if (!s->outdev) { - error_setg(errp, "filter filter mirror needs 'outdev' " + error_setg(errp, "filter mirror needs 'outdev' " "property set"); return; } @@ -315,7 +315,7 @@ filter_mirror_set_outdev(Object *obj, const char *value, Error **errp) g_free(s->outdev); s->outdev = g_strdup(value); if (!s->outdev) { - error_setg(errp, "filter filter mirror needs 'outdev' " + error_setg(errp, "filter mirror needs 'outdev' " "property set"); return; } From 17871f71fd2ff5d76196051470e9604bfb6f0c09 Mon Sep 17 00:00:00 2001 From: Liang Li Date: Tue, 9 Aug 2016 08:30:42 +0800 Subject: [PATCH 597/723] virtio-balloon: Remove needless precompiled directive Since there in wrapper around madvise(), the virtio-balloon code is able to work without the precompiled directive, the directive can be removed. Signed-off-by: Liang Li Suggested-by: Thomas Huth Reviewd-by: Dr. David Alan Gilbert Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-balloon.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index 49a2f4aade1..eb572e6cdbf 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -34,13 +34,11 @@ static void balloon_page(void *addr, int deflate) { -#if defined(__linux__) if (!qemu_balloon_is_inhibited() && (!kvm_enabled() || kvm_has_sync_mmu())) { qemu_madvise(addr, BALLOON_PAGE_SIZE, deflate ? QEMU_MADV_WILLNEED : QEMU_MADV_DONTNEED); } -#endif } static const char *balloon_stat_names[] = { From 09da01c3f205b008ce0c7a960092bcc03b383b50 Mon Sep 17 00:00:00 2001 From: Sascha Silbe Date: Tue, 27 Sep 2016 15:43:36 +0200 Subject: [PATCH 598/723] virtio-serial: add plumbing for virtio console emergency write support Add the infrastructure required for the virtio 1.0 "emergency write" (VIRTIO_CONSOLE_F_EMERG_WRITE) feature. Because we don't touch the size of the configuration area, guests will not be able to actually make use of this without further patches. Reviewed-by: Cornelia Huck Signed-off-by: Sascha Silbe Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/char/virtio-serial-bus.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c index db57a385464..57419b2b6a0 100644 --- a/hw/char/virtio-serial-bus.c +++ b/hw/char/virtio-serial-bus.c @@ -75,6 +75,19 @@ static VirtIOSerialPort *find_port_by_name(char *name) return NULL; } +static VirtIOSerialPort *find_first_connected_console(VirtIOSerial *vser) +{ + VirtIOSerialPort *port; + + QTAILQ_FOREACH(port, &vser->ports, next) { + VirtIOSerialPortClass const *vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port); + if (vsc->is_console && port->host_connected) { + return port; + } + } + return NULL; +} + static bool use_multiport(VirtIOSerial *vser) { VirtIODevice *vdev = VIRTIO_DEVICE(vser); @@ -547,6 +560,29 @@ static void get_config(VirtIODevice *vdev, uint8_t *config_data) vser->serial.max_virtserial_ports); } +/* Guest sent new config info */ +static void set_config(VirtIODevice *vdev, const uint8_t *config_data) +{ + VirtIOSerial *vser = VIRTIO_SERIAL(vdev); + struct virtio_console_config *config = + (struct virtio_console_config *)config_data; + uint8_t emerg_wr_lo = le32_to_cpu(config->emerg_wr); + VirtIOSerialPort *port = find_first_connected_console(vser); + VirtIOSerialPortClass *vsc; + + if (!config->emerg_wr) { + return; + } + /* Make sure we don't misdetect an emergency write when the guest + * does a short config write after an emergency write. */ + config->emerg_wr = 0; + if (!port) { + return; + } + vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port); + (void)vsc->have_data(port, &emerg_wr_lo, 1); +} + static void guest_reset(VirtIOSerial *vser) { VirtIOSerialPort *port; @@ -1098,6 +1134,7 @@ static void virtio_serial_class_init(ObjectClass *klass, void *data) vdc->unrealize = virtio_serial_device_unrealize; vdc->get_features = get_features; vdc->get_config = get_config; + vdc->set_config = set_config; vdc->set_status = set_status; vdc->reset = vser_reset; vdc->save = virtio_serial_save_device; From a06b1dae4706fccb9394b35e88d1905dabec85e7 Mon Sep 17 00:00:00 2001 From: Sascha Silbe Date: Tue, 27 Sep 2016 15:43:37 +0200 Subject: [PATCH 599/723] virtio-serial: enable virtio console emergency write feature Add support for enabling the virtio 1.0 "emergency write" (VIRTIO_CONSOLE_F_EMERG_WRITE) feature. The previous patch introduced the plumbing required for this; now we expose the virtio feature to the guest. The feature is disabled for compatibility machines to avoid exposing a new feature to existing guests. As required by the virtio 1.0 spec, the emergency write functionality is available to the guest even if the guest doesn't negotatiate the feature, as well as before feature negotation. Reviewed-by: Cornelia Huck Signed-off-by: Sascha Silbe Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/char/virtio-serial-bus.c | 12 +++++++++--- include/hw/compat.h | 4 ++++ include/hw/virtio/virtio-serial.h | 2 ++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c index 57419b2b6a0..db2a9f19bc2 100644 --- a/hw/char/virtio-serial-bus.c +++ b/hw/char/virtio-serial-bus.c @@ -541,6 +541,7 @@ static uint64_t get_features(VirtIODevice *vdev, uint64_t features, vser = VIRTIO_SERIAL(vdev); + features |= vser->host_features; if (vser->bus.max_nr_ports > 1) { virtio_add_feature(&features, VIRTIO_CONSOLE_F_MULTIPORT); } @@ -1003,6 +1004,7 @@ static void virtio_serial_device_realize(DeviceState *dev, Error **errp) VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIOSerial *vser = VIRTIO_SERIAL(dev); uint32_t i, max_supported_ports; + size_t config_size = sizeof(struct virtio_console_config); if (!vser->serial.max_virtserial_ports) { error_setg(errp, "Maximum number of serial ports not specified"); @@ -1017,10 +1019,12 @@ static void virtio_serial_device_realize(DeviceState *dev, Error **errp) return; } - /* We don't support emergency write, skip it for now. */ - /* TODO: cleaner fix, depending on host features. */ + if (!virtio_has_feature(vser->host_features, + VIRTIO_CONSOLE_F_EMERG_WRITE)) { + config_size = offsetof(struct virtio_console_config, emerg_wr); + } virtio_init(vdev, "virtio-serial", VIRTIO_ID_CONSOLE, - offsetof(struct virtio_console_config, emerg_wr)); + config_size); /* Spawn a new virtio-serial bus on which the ports will ride as devices */ qbus_create_inplace(&vser->bus, sizeof(vser->bus), TYPE_VIRTIO_SERIAL_BUS, @@ -1116,6 +1120,8 @@ VMSTATE_VIRTIO_DEVICE(console, 3, virtio_serial_load, virtio_vmstate_save); static Property virtio_serial_properties[] = { DEFINE_PROP_UINT32("max_ports", VirtIOSerial, serial.max_virtserial_ports, 31), + DEFINE_PROP_BIT64("emergency-write", VirtIOSerial, host_features, + VIRTIO_CONSOLE_F_EMERG_WRITE, true), DEFINE_PROP_END_OF_LIST(), }; diff --git a/include/hw/compat.h b/include/hw/compat.h index 46412b229a7..ef3fae3e1be 100644 --- a/include/hw/compat.h +++ b/include/hw/compat.h @@ -6,6 +6,10 @@ .driver = "virtio-pci",\ .property = "page-per-vq",\ .value = "on",\ + },{\ + .driver = "virtio-serial-device",\ + .property = "emergency-write",\ + .value = "off",\ },{\ .driver = "ioapic",\ .property = "version",\ diff --git a/include/hw/virtio/virtio-serial.h b/include/hw/virtio/virtio-serial.h index 730c88d2a78..b19c44727f5 100644 --- a/include/hw/virtio/virtio-serial.h +++ b/include/hw/virtio/virtio-serial.h @@ -184,6 +184,8 @@ struct VirtIOSerial { struct VirtIOSerialPostLoad *post_load; virtio_serial_conf serial; + + uint64_t host_features; }; /* Interface to the virtio-serial bus */ From 6bea1ddf8b411dcb0ba5d3a83c4479492185a409 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Wed, 5 Oct 2016 17:51:23 +0200 Subject: [PATCH 600/723] numa: reduce code duplication by adding helper numa_get_node_for_cpu() Replace repeated pattern for (i = 0; i < nb_numa_nodes; i++) { if (test_bit(idx, numa_info[i].node_cpu)) { ... break; with a helper function to lookup numa node index for cpu. Suggested-by: Michael S. Tsirkin Signed-off-by: Igor Mammedov Reviewed-by: David Gibson Reviewed-by: Shannon Zhao Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/arm/virt-acpi-build.c | 6 ++---- hw/arm/virt.c | 7 +++---- hw/i386/acpi-build.c | 7 ++----- hw/i386/pc.c | 8 +++----- hw/ppc/spapr_cpu_core.c | 6 ++---- include/sysemu/numa.h | 3 +++ numa.c | 12 ++++++++++++ 7 files changed, 27 insertions(+), 22 deletions(-) diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index 7b39b1d2d67..c77525d33a0 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -427,11 +427,9 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) uint32_t *cpu_node = g_malloc0(guest_info->smp_cpus * sizeof(uint32_t)); for (i = 0; i < guest_info->smp_cpus; i++) { - for (j = 0; j < nb_numa_nodes; j++) { - if (test_bit(i, numa_info[j].node_cpu)) { + j = numa_get_node_for_cpu(i); + if (j < nb_numa_nodes) { cpu_node[i] = j; - break; - } } } diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 0f6305d3c7f..795740d9bfd 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -413,10 +413,9 @@ static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi) armcpu->mp_affinity); } - for (i = 0; i < nb_numa_nodes; i++) { - if (test_bit(cpu, numa_info[i].node_cpu)) { - qemu_fdt_setprop_cell(vbi->fdt, nodename, "numa-node-id", i); - } + i = numa_get_node_for_cpu(cpu); + if (i < nb_numa_nodes) { + qemu_fdt_setprop_cell(vbi->fdt, nodename, "numa-node-id", i); } g_free(nodename); diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index c20bc71a676..e9996549cca 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -2410,18 +2410,15 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine) srat->reserved1 = cpu_to_le32(1); for (i = 0; i < apic_ids->len; i++) { - int j; + int j = numa_get_node_for_cpu(i); int apic_id = apic_ids->cpus[i].arch_id; core = acpi_data_push(table_data, sizeof *core); core->type = ACPI_SRAT_PROCESSOR_APIC; core->length = sizeof(*core); core->local_apic_id = apic_id; - for (j = 0; j < nb_numa_nodes; j++) { - if (test_bit(i, numa_info[j].node_cpu)) { + if (j < nb_numa_nodes) { core->proximity_lo = j; - break; - } } memset(core->proximity_hi, 0, 3); core->local_sapic_eid = 0; diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 2d6d7920ffe..93ff49c60b6 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -779,11 +779,9 @@ static FWCfgState *bochs_bios_init(AddressSpace *as, PCMachineState *pcms) for (i = 0; i < max_cpus; i++) { unsigned int apic_id = x86_cpu_apic_id_from_index(i); assert(apic_id < pcms->apic_id_limit); - for (j = 0; j < nb_numa_nodes; j++) { - if (test_bit(i, numa_info[j].node_cpu)) { - numa_fw_cfg[apic_id + 1] = cpu_to_le64(j); - break; - } + j = numa_get_node_for_cpu(i); + if (j < nb_numa_nodes) { + numa_fw_cfg[apic_id + 1] = cpu_to_le64(j); } } for (i = 0; i < nb_numa_nodes; i++) { diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index 35d1873b9ff..bc922bc86f6 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -69,11 +69,9 @@ void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu, Error **errp) } /* Set NUMA node for the added CPUs */ - for (i = 0; i < nb_numa_nodes; i++) { - if (test_bit(cs->cpu_index, numa_info[i].node_cpu)) { + i = numa_get_node_for_cpu(cs->cpu_index); + if (i < nb_numa_nodes) { cs->numa_node = i; - break; - } } xics_cpu_setup(spapr->xics, cpu); diff --git a/include/sysemu/numa.h b/include/sysemu/numa.h index bb184c9cfeb..4da808a6e90 100644 --- a/include/sysemu/numa.h +++ b/include/sysemu/numa.h @@ -32,4 +32,7 @@ void numa_set_mem_node_id(ram_addr_t addr, uint64_t size, uint32_t node); void numa_unset_mem_node_id(ram_addr_t addr, uint64_t size, uint32_t node); uint32_t numa_get_node(ram_addr_t addr, Error **errp); +/* on success returns node index in numa_info, + * on failure returns nb_numa_nodes */ +int numa_get_node_for_cpu(int idx); #endif diff --git a/numa.c b/numa.c index 6289f469bd7..9c09e45e7d4 100644 --- a/numa.c +++ b/numa.c @@ -550,3 +550,15 @@ MemdevList *qmp_query_memdev(Error **errp) object_child_foreach(obj, query_memdev, &list); return list; } + +int numa_get_node_for_cpu(int idx) +{ + int i; + + for (i = 0; i < nb_numa_nodes; i++) { + if (test_bit(idx, numa_info[i].node_cpu)) { + break; + } + } + return i; +} From 271119313ca5e179c47cc35c2182ea3ad96d0983 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Wed, 5 Oct 2016 17:51:24 +0200 Subject: [PATCH 601/723] acpi: provide _PXM method for CPU devices if QEMU is started numa enabled Workaround for long standing issue where Linux kernel assigns hotplugged CPU to 1st numa node as it discards proximity for possible CPUs from SRAT after it's parsed. _PXM method allows linux query proximity directly from hotplugged CPU object, which allows Linux to assing CPU to the correct numa node. Signed-off-by: Igor Mammedov Reviewed-by: Marcel Apfelbaum Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/cpu.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c index c13b65c2c91..902f5c90a80 100644 --- a/hw/acpi/cpu.c +++ b/hw/acpi/cpu.c @@ -4,6 +4,7 @@ #include "qapi/error.h" #include "qapi-event.h" #include "trace.h" +#include "sysemu/numa.h" #define ACPI_CPU_HOTPLUG_REG_LEN 12 #define ACPI_CPU_SELECTOR_OFFSET_WR 0 @@ -503,6 +504,7 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, /* build Processor object for each processor */ for (i = 0; i < arch_ids->len; i++) { + int j; Aml *dev; Aml *uid = aml_int(i); GArray *madt_buf = g_array_new(0, 1, 1); @@ -546,6 +548,16 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, aml_arg(1), aml_arg(2)) ); aml_append(dev, method); + + /* Linux guests discard SRAT info for non-present CPUs + * as a result _PXM is required for all CPUs which might + * be hot-plugged. For simplicity, add it for all CPUs. + */ + j = numa_get_node_for_cpu(i); + if (j < nb_numa_nodes) { + aml_append(dev, aml_name_decl("_PXM", aml_int(j))); + } + aml_append(cpus_dev, dev); } } From d6309c170eb99950c9f1d881a5ff7163ae28d353 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Wed, 5 Oct 2016 17:51:25 +0200 Subject: [PATCH 602/723] tests: acpi: extend cphp testcase with numa check so it would be possible to verify _PXM generation in DSDT and SRAT tables. Signed-off-by: Igor Mammedov Reviewed-by: Marcel Apfelbaum Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/bios-tables-test.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c index 7e27ea95ade..6ea2b6d00a7 100644 --- a/tests/bios-tables-test.c +++ b/tests/bios-tables-test.c @@ -811,7 +811,8 @@ static void test_acpi_piix4_tcg_cphp(void) memset(&data, 0, sizeof(data)); data.machine = MACHINE_PC; data.variant = ".cphp"; - test_acpi_one("-smp 2,cores=3,sockets=2,maxcpus=6", + test_acpi_one("-smp 2,cores=3,sockets=2,maxcpus=6" + " -numa node -numa node", &data); free_test_data(&data); } @@ -823,7 +824,8 @@ static void test_acpi_q35_tcg_cphp(void) memset(&data, 0, sizeof(data)); data.machine = MACHINE_Q35; data.variant = ".cphp"; - test_acpi_one(" -smp 2,cores=3,sockets=2,maxcpus=6", + test_acpi_one(" -smp 2,cores=3,sockets=2,maxcpus=6" + " -numa node -numa node", &data); free_test_data(&data); } From af78c91f574dcde3f0bd90914417e3570c5e9c69 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Wed, 5 Oct 2016 17:51:26 +0200 Subject: [PATCH 603/723] tests: acpi tables expected blobs update Signed-off-by: Igor Mammedov Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/acpi-test-data/pc/DSDT.cphp | Bin 6435 -> 6471 bytes tests/acpi-test-data/pc/SRAT.cphp | Bin 0 -> 304 bytes tests/acpi-test-data/q35/DSDT.cphp | Bin 9197 -> 9233 bytes tests/acpi-test-data/q35/SRAT.cphp | Bin 0 -> 304 bytes 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/acpi-test-data/pc/SRAT.cphp create mode 100644 tests/acpi-test-data/q35/SRAT.cphp diff --git a/tests/acpi-test-data/pc/DSDT.cphp b/tests/acpi-test-data/pc/DSDT.cphp index e8b146208eb3877e1cde2cc361c5afd270d194c6..9f405cfd83d39a8e06bc08428e160a0192fc9704 100644 GIT binary patch delta 122 zcmZ2%blix`CD^<3<8^QCN+{En;m-Cx^2F7EIZuXlj#sifD^AdR6*}$eSZeGq)!vg?MeIj%K delta 85 zcmX?ZwAhHtCD!Wg5-^ diff --git a/tests/acpi-test-data/pc/SRAT.cphp b/tests/acpi-test-data/pc/SRAT.cphp new file mode 100644 index 0000000000000000000000000000000000000000..ff2137642f488ec70b85207ed6c20e7351d61e98 GIT binary patch literal 304 zcmWFzattwGWME)4bMklg2v%^42yhMtiUEZfKx_~V!f+sf!DmF1XF}yOvY_!<(fDl0 pd`1npO;83GTmZW|po75R12aq^syaB21u74tQT&BzFU&Ml8UVWm2>}2A literal 0 HcmV?d00001 diff --git a/tests/acpi-test-data/q35/DSDT.cphp b/tests/acpi-test-data/q35/DSDT.cphp index 6cc28c6daec2b331030ab0600a4d79034c1dfc40..a0ce6b3264c69999c6e82a8ae7bab49338e4819b 100644 GIT binary patch delta 122 zcmaFsKGB2ACD}2A literal 0 HcmV?d00001 From 2640d2a5ff08978d67bd87518d05d6b499488c9a Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Mon, 19 Sep 2016 14:28:03 +0100 Subject: [PATCH 604/723] virtio: add virtio_detach_element() During device reset or similar situations a VirtQueueElement needs to be freed without pushing it onto the used ring or rewinding the virtqueue. Extract a new function to do this. Later patches add virtio_detach_element() calls to existing device so that scatter-gather lists are unmapped and vq->inuse goes back to zero during device reset. Currently some devices don't bother and simply call g_free(elem) which is not a clean way to throw away a VirtQueueElement. Signed-off-by: Stefan Hajnoczi Acked-by: Greg Kurz Reviewed-by: Ladi Prosek Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio.c | 27 +++++++++++++++++++++++++-- include/hw/virtio/virtio.h | 2 ++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 18ce3334572..46f79c9e145 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -264,12 +264,35 @@ static void virtqueue_unmap_sg(VirtQueue *vq, const VirtQueueElement *elem, 0, elem->out_sg[i].iov_len); } +/* virtqueue_detach_element: + * @vq: The #VirtQueue + * @elem: The #VirtQueueElement + * @len: number of bytes written + * + * Detach the element from the virtqueue. This function is suitable for device + * reset or other situations where a #VirtQueueElement is simply freed and will + * not be pushed or discarded. + */ +void virtqueue_detach_element(VirtQueue *vq, const VirtQueueElement *elem, + unsigned int len) +{ + vq->inuse--; + virtqueue_unmap_sg(vq, elem, len); +} + +/* virtqueue_discard: + * @vq: The #VirtQueue + * @elem: The #VirtQueueElement + * @len: number of bytes written + * + * Pretend the most recent element wasn't popped from the virtqueue. The next + * call to virtqueue_pop() will refetch the element. + */ void virtqueue_discard(VirtQueue *vq, const VirtQueueElement *elem, unsigned int len) { vq->last_avail_idx--; - vq->inuse--; - virtqueue_unmap_sg(vq, elem, len); + virtqueue_detach_element(vq, elem, len); } /* virtqueue_rewind: diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index 888c8debe6a..e25ec4f0b52 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -155,6 +155,8 @@ void *virtqueue_alloc_element(size_t sz, unsigned out_num, unsigned in_num); void virtqueue_push(VirtQueue *vq, const VirtQueueElement *elem, unsigned int len); void virtqueue_flush(VirtQueue *vq, unsigned int count); +void virtqueue_detach_element(VirtQueue *vq, const VirtQueueElement *elem, + unsigned int len); void virtqueue_discard(VirtQueue *vq, const VirtQueueElement *elem, unsigned int len); bool virtqueue_rewind(VirtQueue *vq, unsigned int num); From 97b93c8ad2242c5a5f89ac50f9e696289c5b4947 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Mon, 19 Sep 2016 14:28:04 +0100 Subject: [PATCH 605/723] virtio-blk: add missing virtio_detach_element() call Make sure to unmap the scatter-gather list and decrement vq->inuse before freeing requests in virtio_blk_reset(). Signed-off-by: Stefan Hajnoczi Reviewed-by: Ladi Prosek Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/block/virtio-blk.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index 3a6112fbf4c..c7ca4d6769c 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -665,6 +665,7 @@ static void virtio_blk_reset(VirtIODevice *vdev) while (s->rq) { req = s->rq; s->rq = req->next; + virtqueue_detach_element(req->vq, &req->elem, 0); virtio_blk_free_request(req); } From d4c19cdeeb2f1e474bc426a6da261f1d7346eb5b Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Mon, 19 Sep 2016 14:28:05 +0100 Subject: [PATCH 606/723] virtio-serial: add missing virtio_detach_element() call Ports enter a "throttled" state when writing to the chardev would block. The current output VirtQueueElement is kept around until the chardev becomes writable again. There are several places in the virtio-serial lifecycle where the VirtQueueElement should be thrown away. For example, if the virtio device is reset then virtqueue elements are no longer valid. This patch adds the discard_throttle_data() function to unmap the scatter-gather list and decrement vq->inuse. This ensures that the VirtQueueElement is freed properly. Cc: amit.shah@redhat.com Signed-off-by: Stefan Hajnoczi Tested-by: Ladi Prosek Reviewed-by: Ladi Prosek Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/char/virtio-serial-bus.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c index db2a9f19bc2..3955f0f7418 100644 --- a/hw/char/virtio-serial-bus.c +++ b/hw/char/virtio-serial-bus.c @@ -145,6 +145,15 @@ static void discard_vq_data(VirtQueue *vq, VirtIODevice *vdev) virtio_notify(vdev, vq); } +static void discard_throttle_data(VirtIOSerialPort *port) +{ + if (port->elem) { + virtqueue_detach_element(port->ovq, port->elem, 0); + g_free(port->elem); + port->elem = NULL; + } +} + static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq, VirtIODevice *vdev) { @@ -267,6 +276,7 @@ int virtio_serial_close(VirtIOSerialPort *port) * consume, reset the throttling flag and discard the data. */ port->throttled = false; + discard_throttle_data(port); discard_vq_data(port->ovq, VIRTIO_DEVICE(port->vser)); send_control_event(port->vser, port->id, VIRTIO_CONSOLE_PORT_OPEN, 0); @@ -591,6 +601,9 @@ static void guest_reset(VirtIOSerial *vser) QTAILQ_FOREACH(port, &vser->ports, next) { vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port); + + discard_throttle_data(port); + if (port->guest_connected) { port->guest_connected = false; if (vsc->set_guest_connected) { @@ -901,6 +914,7 @@ static void remove_port(VirtIOSerial *vser, uint32_t port_id) assert(port); /* Flush out any unconsumed buffers first */ + discard_throttle_data(port); discard_vq_data(port->ovq, VIRTIO_DEVICE(port->vser)); send_control_event(vser, port->id, VIRTIO_CONSOLE_PORT_REMOVE, 1); From e8582891cb10d30e83dd91821e8752098b0b1138 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Fri, 30 Sep 2016 17:12:41 +0200 Subject: [PATCH 607/723] virtio-9p: add parentheses to sizeof operator Signed-off-by: Greg Kurz Reviewed-by: Cornelia Huck Reviewed-by: Stefan Hajnoczi Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/9pfs/virtio-9p-device.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c index 009b43f6d04..e7ea0e45f3d 100644 --- a/hw/9pfs/virtio-9p-device.c +++ b/hw/9pfs/virtio-9p-device.c @@ -57,12 +57,12 @@ static void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq) } BUG_ON(elem->out_num == 0 || elem->in_num == 0); - QEMU_BUILD_BUG_ON(sizeof out != 7); + QEMU_BUILD_BUG_ON(sizeof(out) != 7); v->elems[pdu->idx] = elem; len = iov_to_buf(elem->out_sg, elem->out_num, 0, - &out, sizeof out); - BUG_ON(len != sizeof out); + &out, sizeof(out)); + BUG_ON(len != sizeof(out)); pdu->size = le32_to_cpu(out.size_le); From d14dde5ec7a38df2e00a6f1b58e96ba38359dbb0 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Fri, 30 Sep 2016 17:12:50 +0200 Subject: [PATCH 608/723] virtio-blk: make some functions static Some functions that were called from the dataplane code are now only used locally: virtio_blk_init_request() virtio_blk_handle_request() virtio_blk_submit_multireq() since commit "03de2f527499 virtio-blk: do not use vring in dataplane", and virtio_blk_free_request() since commit "6aa46d8ff1ee virtio: move VirtQueueElement at the beginning of the structs". This patch converts them to static. Signed-off-by: Greg Kurz Reviewed-by: Stefan Hajnoczi Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/block/virtio-blk.c | 10 +++++----- include/hw/virtio/virtio-blk.h | 8 -------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index c7ca4d6769c..bbacd562cef 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -29,8 +29,8 @@ #include "hw/virtio/virtio-bus.h" #include "hw/virtio/virtio-access.h" -void virtio_blk_init_request(VirtIOBlock *s, VirtQueue *vq, - VirtIOBlockReq *req) +static void virtio_blk_init_request(VirtIOBlock *s, VirtQueue *vq, + VirtIOBlockReq *req) { req->dev = s; req->vq = vq; @@ -40,7 +40,7 @@ void virtio_blk_init_request(VirtIOBlock *s, VirtQueue *vq, req->mr_next = NULL; } -void virtio_blk_free_request(VirtIOBlockReq *req) +static void virtio_blk_free_request(VirtIOBlockReq *req) { if (req) { g_free(req); @@ -381,7 +381,7 @@ static int multireq_compare(const void *a, const void *b) } } -void virtio_blk_submit_multireq(BlockBackend *blk, MultiReqBuffer *mrb) +static void virtio_blk_submit_multireq(BlockBackend *blk, MultiReqBuffer *mrb) { int i = 0, start = 0, num_reqs = 0, niov = 0, nb_sectors = 0; uint32_t max_transfer; @@ -468,7 +468,7 @@ static bool virtio_blk_sect_range_ok(VirtIOBlock *dev, return true; } -void virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb) +static void virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb) { uint32_t type; struct iovec *in_iov = req->elem.in_sg; diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h index 180bd8db5df..9734b4c446c 100644 --- a/include/hw/virtio/virtio-blk.h +++ b/include/hw/virtio/virtio-blk.h @@ -80,14 +80,6 @@ typedef struct MultiReqBuffer { bool is_write; } MultiReqBuffer; -void virtio_blk_init_request(VirtIOBlock *s, VirtQueue *vq, - VirtIOBlockReq *req); -void virtio_blk_free_request(VirtIOBlockReq *req); - -void virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb); - -void virtio_blk_submit_multireq(BlockBackend *blk, MultiReqBuffer *mrb); - void virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq); #endif From d3d74d6fe095e2e49d030e0c163cecfb9c20f1d4 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Fri, 30 Sep 2016 17:12:58 +0200 Subject: [PATCH 609/723] virtio-9p: handle handle_9p_output() error A broken guest may send a request without providing buffers for the reply or for the request itself, and virtqueue_pop() will return an element with either in_num == 0 or out_num == 0. All 9P requests are expected to start with the following 7-byte header: uint32_t size_le; uint8_t id; uint16_t tag_le; If iov_to_buf() fails to return these 7 bytes, then something is wrong in the guest. In both cases, it is wrong to crash QEMU, since the root cause lies in the guest. This patch hence does the following: - keep the check of in_num since pdu_complete() assumes it has enough space to store the reply and we will send something broken to the guest - let iov_to_buf() handle out_num == 0, since it will return 0 just like if the guest had provided an zero-sized buffer. - call virtio_error() to inform the guest that the device is now broken, instead of aborting - detach the request from the virtqueue and free it Signed-off-by: Greg Kurz Reviewed-by: Stefan Hajnoczi Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/9pfs/virtio-9p-device.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c index e7ea0e45f3d..a338f640026 100644 --- a/hw/9pfs/virtio-9p-device.c +++ b/hw/9pfs/virtio-9p-device.c @@ -41,6 +41,7 @@ static void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq) V9fsState *s = &v->state; V9fsPDU *pdu; ssize_t len; + VirtQueueElement *elem; while ((pdu = pdu_alloc(s))) { struct { @@ -48,21 +49,28 @@ static void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq) uint8_t id; uint16_t tag_le; } QEMU_PACKED out; - VirtQueueElement *elem; elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); if (!elem) { - pdu_free(pdu); - break; + goto out_free_pdu; } - BUG_ON(elem->out_num == 0 || elem->in_num == 0); + if (elem->in_num == 0) { + virtio_error(vdev, + "The guest sent a VirtFS request without space for " + "the reply"); + goto out_free_req; + } QEMU_BUILD_BUG_ON(sizeof(out) != 7); v->elems[pdu->idx] = elem; len = iov_to_buf(elem->out_sg, elem->out_num, 0, &out, sizeof(out)); - BUG_ON(len != sizeof(out)); + if (len != sizeof(out)) { + virtio_error(vdev, "The guest sent a malformed VirtFS request: " + "header size is %zd, should be 7", len); + goto out_free_req; + } pdu->size = le32_to_cpu(out.size_le); @@ -72,6 +80,14 @@ static void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq) qemu_co_queue_init(&pdu->complete); pdu_submit(pdu); } + + return; + +out_free_req: + virtqueue_detach_element(vq, elem, 0); + g_free(elem); +out_free_pdu: + pdu_free(pdu); } static uint64_t virtio_9p_get_features(VirtIODevice *vdev, uint64_t features, From 20ea686a0cacdec1bde9a39e74afd38bf672424d Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Fri, 30 Sep 2016 17:13:07 +0200 Subject: [PATCH 610/723] virtio-blk: handle virtio_blk_handle_request() errors All these errors are caused by a buggy guest: QEMU should not exit. With this patch, if virtio_blk_handle_request() detects a buggy request, it marks the device as broken and returns an error to the caller so it takes appropriate action. In the case of virtio_blk_handle_vq(), we detach the request from the virtqueue, free its allocated memory and stop popping new requests. We don't need to bother about multireq since virtio_blk_handle_request() errors out early and mrb.num_reqs == 0. In the case of virtio_blk_dma_restart_bh(), we need to detach and free all queued requests as well. Signed-off-by: Greg Kurz Reviewed-by: Stefan Hajnoczi Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/block/virtio-blk.c | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index bbacd562cef..0ddd7fbbe54 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -468,30 +468,32 @@ static bool virtio_blk_sect_range_ok(VirtIOBlock *dev, return true; } -static void virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb) +static int virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb) { uint32_t type; struct iovec *in_iov = req->elem.in_sg; struct iovec *iov = req->elem.out_sg; unsigned in_num = req->elem.in_num; unsigned out_num = req->elem.out_num; + VirtIOBlock *s = req->dev; + VirtIODevice *vdev = VIRTIO_DEVICE(s); if (req->elem.out_num < 1 || req->elem.in_num < 1) { - error_report("virtio-blk missing headers"); - exit(1); + virtio_error(vdev, "virtio-blk missing headers"); + return -1; } if (unlikely(iov_to_buf(iov, out_num, 0, &req->out, sizeof(req->out)) != sizeof(req->out))) { - error_report("virtio-blk request outhdr too short"); - exit(1); + virtio_error(vdev, "virtio-blk request outhdr too short"); + return -1; } iov_discard_front(&iov, &out_num, sizeof(req->out)); if (in_iov[in_num - 1].iov_len < sizeof(struct virtio_blk_inhdr)) { - error_report("virtio-blk request inhdr too short"); - exit(1); + virtio_error(vdev, "virtio-blk request inhdr too short"); + return -1; } /* We always touch the last byte, so just see how big in_iov is. */ @@ -529,7 +531,7 @@ static void virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb) block_acct_invalid(blk_get_stats(req->dev->blk), is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ); virtio_blk_free_request(req); - return; + return 0; } block_acct_start(blk_get_stats(req->dev->blk), @@ -576,6 +578,7 @@ static void virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb) virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP); virtio_blk_free_request(req); } + return 0; } void virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq) @@ -586,7 +589,11 @@ void virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq) blk_io_plug(s->blk); while ((req = virtio_blk_get_request(s, vq))) { - virtio_blk_handle_request(req, &mrb); + if (virtio_blk_handle_request(req, &mrb)) { + virtqueue_detach_element(req->vq, &req->elem, 0); + virtio_blk_free_request(req); + break; + } } if (mrb.num_reqs) { @@ -625,7 +632,18 @@ static void virtio_blk_dma_restart_bh(void *opaque) while (req) { VirtIOBlockReq *next = req->next; - virtio_blk_handle_request(req, &mrb); + if (virtio_blk_handle_request(req, &mrb)) { + /* Device is now broken and won't do any processing until it gets + * reset. Already queued requests will be lost: let's purge them. + */ + while (req) { + next = req->next; + virtqueue_detach_element(req->vq, &req->elem, 0); + virtio_blk_free_request(req); + req = next; + } + break; + } req = next; } From ba7eadb5927633d487064b518bf6fd001369e30c Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Fri, 30 Sep 2016 17:13:16 +0200 Subject: [PATCH 611/723] virtio-net: handle virtio_net_handle_ctrl() error This error is caused by a buggy guest: let's switch the device to the broken state instead of terminating QEMU. Also we detach the element from the virtqueue and free it. Signed-off-by: Greg Kurz Reviewed-by: Stefan Hajnoczi Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/net/virtio-net.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 6b8ae2c1faf..a1584e1e67e 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -880,6 +880,7 @@ static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd, return VIRTIO_NET_OK; } + static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) { VirtIONet *n = VIRTIO_NET(vdev); @@ -897,8 +898,10 @@ static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) } if (iov_size(elem->in_sg, elem->in_num) < sizeof(status) || iov_size(elem->out_sg, elem->out_num) < sizeof(ctrl)) { - error_report("virtio-net ctrl missing headers"); - exit(1); + virtio_error(vdev, "virtio-net ctrl missing headers"); + virtqueue_detach_element(vq, elem, 0); + g_free(elem); + break; } iov_cnt = elem->out_num; From ba10b9c0038e201d7ea28a9e3908928439ff7fa4 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Fri, 30 Sep 2016 17:13:24 +0200 Subject: [PATCH 612/723] virtio-net: handle virtio_net_receive() errors All these errors are caused by a buggy guest: let's switch the device to the broken state instead of terminating QEMU. Also we detach the element from the virtqueue and free it. Signed-off-by: Greg Kurz Reviewed-by: Cornelia Huck Reviewed-by: Stefan Hajnoczi Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/net/virtio-net.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index a1584e1e67e..5c0b2e0db5c 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -1130,21 +1130,24 @@ static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t elem = virtqueue_pop(q->rx_vq, sizeof(VirtQueueElement)); if (!elem) { - if (i == 0) - return -1; - error_report("virtio-net unexpected empty queue: " - "i %zd mergeable %d offset %zd, size %zd, " - "guest hdr len %zd, host hdr len %zd " - "guest features 0x%" PRIx64, - i, n->mergeable_rx_bufs, offset, size, - n->guest_hdr_len, n->host_hdr_len, - vdev->guest_features); - exit(1); + if (i) { + virtio_error(vdev, "virtio-net unexpected empty queue: " + "i %zd mergeable %d offset %zd, size %zd, " + "guest hdr len %zd, host hdr len %zd " + "guest features 0x%" PRIx64, + i, n->mergeable_rx_bufs, offset, size, + n->guest_hdr_len, n->host_hdr_len, + vdev->guest_features); + } + return -1; } if (elem->in_num < 1) { - error_report("virtio-net receive queue contains no in buffers"); - exit(1); + virtio_error(vdev, + "virtio-net receive queue contains no in buffers"); + virtqueue_detach_element(q->rx_vq, elem, 0); + g_free(elem); + return -1; } sg = elem->in_sg; From fa5e56c2a73501427203c34d702fccc2fbcb5eab Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Fri, 30 Sep 2016 17:13:32 +0200 Subject: [PATCH 613/723] virtio-net: handle virtio_net_flush_tx() errors All these errors are caused by a buggy guest: let's switch the device to the broken state instead of terminating QEMU. Also we detach the element from the virtqueue and free it. If this happens, virtio_net_flush_tx() also returns -EINVAL, so that all callers can stop processing the virtqueue immediatly. Signed-off-by: Greg Kurz Reviewed-by: Stefan Hajnoczi Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/net/virtio-net.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 5c0b2e0db5c..ca1b46956bc 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -1249,15 +1249,19 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q) out_num = elem->out_num; out_sg = elem->out_sg; if (out_num < 1) { - error_report("virtio-net header not in first element"); - exit(1); + virtio_error(vdev, "virtio-net header not in first element"); + virtqueue_detach_element(q->tx_vq, elem, 0); + g_free(elem); + return -EINVAL; } if (n->has_vnet_hdr) { if (iov_to_buf(out_sg, out_num, 0, &mhdr, n->guest_hdr_len) < n->guest_hdr_len) { - error_report("virtio-net header incorrect"); - exit(1); + virtio_error(vdev, "virtio-net header incorrect"); + virtqueue_detach_element(q->tx_vq, elem, 0); + g_free(elem); + return -EINVAL; } if (n->needs_vnet_hdr_swap) { virtio_net_hdr_swap(vdev, (void *) &mhdr); @@ -1325,7 +1329,9 @@ static void virtio_net_handle_tx_timer(VirtIODevice *vdev, VirtQueue *vq) virtio_queue_set_notification(vq, 1); timer_del(q->tx_timer); q->tx_waiting = 0; - virtio_net_flush_tx(q); + if (virtio_net_flush_tx(q) == -EINVAL) { + return; + } } else { timer_mod(q->tx_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + n->tx_timeout); @@ -1396,8 +1402,9 @@ static void virtio_net_tx_bh(void *opaque) } ret = virtio_net_flush_tx(q); - if (ret == -EBUSY) { - return; /* Notification re-enable handled by tx_complete */ + if (ret == -EBUSY || ret == -EINVAL) { + return; /* Notification re-enable handled by tx_complete or device + * broken */ } /* If we flush a full burst of packets, assume there are @@ -1412,7 +1419,10 @@ static void virtio_net_tx_bh(void *opaque) * anything that may have come in while we weren't looking. If * we find something, assume the guest is still active and reschedule */ virtio_queue_set_notification(q->tx_vq, 1); - if (virtio_net_flush_tx(q) > 0) { + ret = virtio_net_flush_tx(q); + if (ret == -EINVAL) { + return; + } else if (ret > 0) { virtio_queue_set_notification(q->tx_vq, 0); qemu_bh_schedule(q->tx_bh); q->tx_waiting = 1; From 661e32fb3cb71c7e019daee375be4bb487b9917c Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Fri, 30 Sep 2016 17:13:40 +0200 Subject: [PATCH 614/723] virtio-scsi: convert virtio_scsi_bad_req() to use virtio_error() The virtio_scsi_bad_req() function is called when a guest sends a request with missing or ill-sized headers. This generally happens when the virtio_scsi_parse_req() function returns an error. With this patch, virtio_scsi_bad_req() will mark the device as broken, detach the request from the virtqueue and free it, instead of forcing QEMU to exit. In nearly all locations where virtio_scsi_bad_req() is called, the only thing to do next is to return to the caller. The virtio_scsi_handle_cmd_req_prepare() function is an exception though. It is called in a loop by virtio_scsi_handle_cmd_vq() and passed requests freshly popped from a cmd virtqueue; virtio_scsi_handle_cmd_req_prepare() does some sanity checks on the request and returns a boolean flag to indicate whether the request should be queued or not. In the latter case, virtio_scsi_handle_cmd_req_prepare() has detected a non-fatal error and sent a response back to the guest. We have now a new condition to take into account: the device is broken and should stop all processing. The return value of virtio_scsi_handle_cmd_req_prepare() is hence changed to an int. A return value of zero means that the request should be queued. Other non-fatal error cases where the request shoudn't be queued return a negative errno (values are vaguely inspired by the error condition, but the only goal here is to discriminate the case we're interested in). And finally, if virtio_scsi_bad_req() was called, -EINVAL is returned. In this case, virtio_scsi_handle_cmd_vq() detaches and frees already queued requests, instead of submitting them. Signed-off-by: Greg Kurz Reviewed-by: Stefan Hajnoczi Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/scsi/virtio-scsi.c | 46 ++++++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index e596b647413..b58de956b68 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -81,10 +81,11 @@ static void virtio_scsi_complete_req(VirtIOSCSIReq *req) virtio_scsi_free_req(req); } -static void virtio_scsi_bad_req(void) +static void virtio_scsi_bad_req(VirtIOSCSIReq *req) { - error_report("wrong size for virtio-scsi headers"); - exit(1); + virtio_error(VIRTIO_DEVICE(req->dev), "wrong size for virtio-scsi headers"); + virtqueue_detach_element(req->vq, &req->elem, 0); + virtio_scsi_free_req(req); } static size_t qemu_sgl_concat(VirtIOSCSIReq *req, struct iovec *iov, @@ -387,7 +388,7 @@ static void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req) if (iov_to_buf(req->elem.out_sg, req->elem.out_num, 0, &type, sizeof(type)) < sizeof(type)) { - virtio_scsi_bad_req(); + virtio_scsi_bad_req(req); return; } @@ -395,7 +396,8 @@ static void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req) if (type == VIRTIO_SCSI_T_TMF) { if (virtio_scsi_parse_req(req, sizeof(VirtIOSCSICtrlTMFReq), sizeof(VirtIOSCSICtrlTMFResp)) < 0) { - virtio_scsi_bad_req(); + virtio_scsi_bad_req(req); + return; } else { r = virtio_scsi_do_tmf(s, req); } @@ -404,7 +406,8 @@ static void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req) type == VIRTIO_SCSI_T_AN_SUBSCRIBE) { if (virtio_scsi_parse_req(req, sizeof(VirtIOSCSICtrlANReq), sizeof(VirtIOSCSICtrlANResp)) < 0) { - virtio_scsi_bad_req(); + virtio_scsi_bad_req(req); + return; } else { req->resp.an.event_actual = 0; req->resp.an.response = VIRTIO_SCSI_S_OK; @@ -521,7 +524,7 @@ static void virtio_scsi_fail_cmd_req(VirtIOSCSIReq *req) virtio_scsi_complete_cmd_req(req); } -static bool virtio_scsi_handle_cmd_req_prepare(VirtIOSCSI *s, VirtIOSCSIReq *req) +static int virtio_scsi_handle_cmd_req_prepare(VirtIOSCSI *s, VirtIOSCSIReq *req) { VirtIOSCSICommon *vs = &s->parent_obj; SCSIDevice *d; @@ -532,17 +535,18 @@ static bool virtio_scsi_handle_cmd_req_prepare(VirtIOSCSI *s, VirtIOSCSIReq *req if (rc < 0) { if (rc == -ENOTSUP) { virtio_scsi_fail_cmd_req(req); + return -ENOTSUP; } else { - virtio_scsi_bad_req(); + virtio_scsi_bad_req(req); + return -EINVAL; } - return false; } d = virtio_scsi_device_find(s, req->req.cmd.lun); if (!d) { req->resp.cmd.response = VIRTIO_SCSI_S_BAD_TARGET; virtio_scsi_complete_cmd_req(req); - return false; + return -ENOENT; } virtio_scsi_ctx_check(s, d); req->sreq = scsi_req_new(d, req->req.cmd.tag, @@ -554,11 +558,11 @@ static bool virtio_scsi_handle_cmd_req_prepare(VirtIOSCSI *s, VirtIOSCSIReq *req req->sreq->cmd.xfer > req->qsgl.size)) { req->resp.cmd.response = VIRTIO_SCSI_S_OVERRUN; virtio_scsi_complete_cmd_req(req); - return false; + return -ENOBUFS; } scsi_req_ref(req->sreq); blk_io_plug(d->conf.blk); - return true; + return 0; } static void virtio_scsi_handle_cmd_req_submit(VirtIOSCSI *s, VirtIOSCSIReq *req) @@ -574,11 +578,24 @@ static void virtio_scsi_handle_cmd_req_submit(VirtIOSCSI *s, VirtIOSCSIReq *req) void virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq) { VirtIOSCSIReq *req, *next; + int ret; + QTAILQ_HEAD(, VirtIOSCSIReq) reqs = QTAILQ_HEAD_INITIALIZER(reqs); while ((req = virtio_scsi_pop_req(s, vq))) { - if (virtio_scsi_handle_cmd_req_prepare(s, req)) { + ret = virtio_scsi_handle_cmd_req_prepare(s, req); + if (!ret) { QTAILQ_INSERT_TAIL(&reqs, req, next); + } else if (ret == -EINVAL) { + /* The device is broken and shouldn't process any request */ + while (!QTAILQ_EMPTY(&reqs)) { + req = QTAILQ_FIRST(&reqs); + QTAILQ_REMOVE(&reqs, req, next); + blk_io_unplug(req->sreq->dev->conf.blk); + scsi_req_unref(req->sreq); + virtqueue_detach_element(req->vq, &req->elem, 0); + virtio_scsi_free_req(req); + } } } @@ -708,7 +725,8 @@ void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, } if (virtio_scsi_parse_req(req, 0, sizeof(VirtIOSCSIEvent))) { - virtio_scsi_bad_req(); + virtio_scsi_bad_req(req); + goto out; } evt = &req->resp.event; From ad14a46a36c6a17bd3d3445a8b0e1f6d421feac2 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Fri, 30 Sep 2016 17:13:48 +0200 Subject: [PATCH 615/723] virtio-scsi: handle virtio_scsi_set_config() error This error is caused by a buggy guest: let's switch the device to the broken state instead of terminating QEMU. Signed-off-by: Greg Kurz Reviewed-by: Stefan Hajnoczi Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/scsi/virtio-scsi.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index b58de956b68..6eaadd8d7c7 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -644,8 +644,9 @@ static void virtio_scsi_set_config(VirtIODevice *vdev, if ((uint32_t) virtio_ldl_p(vdev, &scsiconf->sense_size) >= 65536 || (uint32_t) virtio_ldl_p(vdev, &scsiconf->cdb_size) >= 256) { - error_report("bad data written to virtio-scsi configuration space"); - exit(1); + virtio_error(vdev, + "bad data written to virtio-scsi configuration space"); + return; } vs->sense_size = virtio_ldl_p(vdev, &scsiconf->sense_size); From 0a73336d96397c80881219d080518fac6f1ecacb Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Fri, 7 Oct 2016 13:18:34 +0100 Subject: [PATCH 616/723] net: don't poke at chardev internal QemuOpts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The vhost-user & colo code is poking at the QemuOpts instance in the CharDriverState struct, not realizing that it is valid for this to be NULL. e.g. the following crash shows a codepath where it will be NULL: Program terminated with signal SIGSEGV, Segmentation fault. #0 0x000055baf6ab4adc in qemu_opt_foreach (opts=0x0, func=0x55baf696b650 , opaque=0x7ffc51368c00, errp=0x7ffc51368e48) at util/qemu-option.c:617 617 QTAILQ_FOREACH(opt, &opts->head, next) { [Current thread is 1 (Thread 0x7f1d4970bb40 (LWP 6603))] (gdb) bt #0 0x000055baf6ab4adc in qemu_opt_foreach (opts=0x0, func=0x55baf696b650 , opaque=0x7ffc51368c00, errp=0x7ffc51368e48) at util/qemu-option.c:617 #1 0x000055baf696b7da in net_vhost_parse_chardev (opts=0x55baf8ff9260, errp=0x7ffc51368e48) at net/vhost-user.c:314 #2 0x000055baf696b985 in net_init_vhost_user (netdev=0x55baf8ff9250, name=0x55baf879d270 "hostnet2", peer=0x0, errp=0x7ffc51368e48) at net/vhost-user.c:360 #3 0x000055baf6960216 in net_client_init1 (object=0x55baf8ff9250, is_netdev=true, errp=0x7ffc51368e48) at net/net.c:1051 #4 0x000055baf6960518 in net_client_init (opts=0x55baf776e7e0, is_netdev=true, errp=0x7ffc51368f00) at net/net.c:1108 #5 0x000055baf696083f in netdev_add (opts=0x55baf776e7e0, errp=0x7ffc51368f00) at net/net.c:1186 #6 0x000055baf69608c7 in qmp_netdev_add (qdict=0x55baf7afaf60, ret=0x7ffc51368f50, errp=0x7ffc51368f48) at net/net.c:1205 #7 0x000055baf6622135 in handle_qmp_command (parser=0x55baf77fb590, tokens=0x7f1d24011960) at /path/to/qemu.git/monitor.c:3978 #8 0x000055baf6a9d099 in json_message_process_token (lexer=0x55baf77fb598, input=0x55baf75acd20, type=JSON_RCURLY, x=113, y=19) at qobject/json-streamer.c:105 #9 0x000055baf6abf7aa in json_lexer_feed_char (lexer=0x55baf77fb598, ch=125 '}', flush=false) at qobject/json-lexer.c:319 #10 0x000055baf6abf8f2 in json_lexer_feed (lexer=0x55baf77fb598, buffer=0x7ffc51369170 "}R\204\367\272U", size=1) at qobject/json-lexer.c:369 #11 0x000055baf6a9d13c in json_message_parser_feed (parser=0x55baf77fb590, buffer=0x7ffc51369170 "}R\204\367\272U", size=1) at qobject/json-streamer.c:124 #12 0x000055baf66221f7 in monitor_qmp_read (opaque=0x55baf77fb530, buf=0x7ffc51369170 "}R\204\367\272U", size=1) at /path/to/qemu.git/monitor.c:3994 #13 0x000055baf6757014 in qemu_chr_be_write_impl (s=0x55baf7610a40, buf=0x7ffc51369170 "}R\204\367\272U", len=1) at qemu-char.c:387 #14 0x000055baf6757076 in qemu_chr_be_write (s=0x55baf7610a40, buf=0x7ffc51369170 "}R\204\367\272U", len=1) at qemu-char.c:399 #15 0x000055baf675b3b0 in tcp_chr_read (chan=0x55baf90244b0, cond=G_IO_IN, opaque=0x55baf7610a40) at qemu-char.c:2927 #16 0x000055baf6a5d655 in qio_channel_fd_source_dispatch (source=0x55baf7610df0, callback=0x55baf675b25a , user_data=0x55baf7610a40) at io/channel-watch.c:84 #17 0x00007f1d3e80cbbd in g_main_context_dispatch () from /usr/lib64/libglib-2.0.so.0 #18 0x000055baf69d3720 in glib_pollfds_poll () at main-loop.c:213 #19 0x000055baf69d37fd in os_host_main_loop_wait (timeout=126000000) at main-loop.c:258 #20 0x000055baf69d38ad in main_loop_wait (nonblocking=0) at main-loop.c:506 #21 0x000055baf676587b in main_loop () at vl.c:1908 #22 0x000055baf676d3bf in main (argc=101, argv=0x7ffc5136a6c8, envp=0x7ffc5136a9f8) at vl.c:4604 (gdb) p opts $1 = (QemuOpts *) 0x0 The crash occurred when attaching vhost-user net via QMP: { "execute": "chardev-add", "arguments": { "id": "charnet2", "backend": { "type": "socket", "data": { "addr": { "type": "unix", "data": { "path": "/var/run/openvswitch/vhost-user1" } }, "wait": false, "server": false } } }, "id": "libvirt-19" } { "return": { }, "id": "libvirt-19" } { "execute": "netdev_add", "arguments": { "type": "vhost-user", "chardev": "charnet2", "id": "hostnet2" }, "id": "libvirt-20" } Code using chardevs should not be poking at the internals of the CharDriverState struct. What vhost-user wants is a chardev that is operating as reconnectable network service, along with the ability to do FD passing over the connection. The colo code simply wants a network service. Add a feature concept to the char drivers so that chardev users can query the actual features they wish to have supported. The QemuOpts member is removed to prevent future mistakes in this area. Signed-off-by: Daniel P. Berrange Reviewed-by: Marc-André Lureau Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hmp.c | 1 + include/sysemu/char.h | 21 ++++++++++++++++++++- net/colo-compare.c | 30 ++---------------------------- net/vhost-user.c | 41 +++++++---------------------------------- qemu-char.c | 22 +++++++++++++++++++--- 5 files changed, 49 insertions(+), 66 deletions(-) diff --git a/hmp.c b/hmp.c index 336e7bf0769..3c421828ff3 100644 --- a/hmp.c +++ b/hmp.c @@ -1909,6 +1909,7 @@ void hmp_chardev_add(Monitor *mon, const QDict *qdict) error_setg(&err, "Parsing chardev args failed"); } else { qemu_chr_new_from_opts(opts, NULL, &err); + qemu_opts_del(opts); } hmp_handle_error(mon, &err); } diff --git a/include/sysemu/char.h b/include/sysemu/char.h index 0d0465ae0e0..19dad3fb9c7 100644 --- a/include/sysemu/char.h +++ b/include/sysemu/char.h @@ -9,6 +9,7 @@ #include "qapi/qmp/qobject.h" #include "qapi/qmp/qstring.h" #include "qemu/main-loop.h" +#include "qemu/bitmap.h" /* character device */ @@ -58,6 +59,20 @@ struct ParallelIOArg { typedef void IOEventHandler(void *opaque, int event); +typedef enum { + /* Whether the chardev peer is able to close and + * reopen the data channel, thus requiring support + * for qemu_chr_wait_connected() to wait for a + * valid connection */ + QEMU_CHAR_FEATURE_RECONNECTABLE, + /* Whether it is possible to send/recv file descriptors + * over the data channel */ + QEMU_CHAR_FEATURE_FD_PASS, + + QEMU_CHAR_FEATURE_LAST, +} CharDriverFeature; + + struct CharDriverState { QemuMutex chr_write_lock; void (*init)(struct CharDriverState *s); @@ -93,8 +108,8 @@ struct CharDriverState { int avail_connections; int is_mux; guint fd_in_tag; - QemuOpts *opts; bool replay; + DECLARE_BITMAP(features, QEMU_CHAR_FEATURE_LAST); QTAILQ_ENTRY(CharDriverState) next; }; @@ -437,6 +452,10 @@ int qemu_chr_add_client(CharDriverState *s, int fd); CharDriverState *qemu_chr_find(const char *name); bool chr_is_ringbuf(const CharDriverState *chr); +bool qemu_chr_has_feature(CharDriverState *chr, + CharDriverFeature feature); +void qemu_chr_set_feature(CharDriverState *chr, + CharDriverFeature feature); QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename); void register_char_driver(const char *name, ChardevBackendKind kind, diff --git a/net/colo-compare.c b/net/colo-compare.c index 22b1da19f5b..47703c59bc9 100644 --- a/net/colo-compare.c +++ b/net/colo-compare.c @@ -564,29 +564,6 @@ static void compare_sec_rs_finalize(SocketReadState *sec_rs) } } -static int compare_chardev_opts(void *opaque, - const char *name, const char *value, - Error **errp) -{ - CompareChardevProps *props = opaque; - - if (strcmp(name, "backend") == 0 && - strcmp(value, "socket") == 0) { - props->is_socket = true; - return 0; - } else if (strcmp(name, "host") == 0 || - (strcmp(name, "port") == 0) || - (strcmp(name, "server") == 0) || - (strcmp(name, "wait") == 0) || - (strcmp(name, "path") == 0)) { - return 0; - } else { - error_setg(errp, - "COLO-compare does not support a chardev with option %s=%s", - name, value); - return -1; - } -} /* * Return 0 is success. @@ -606,12 +583,9 @@ static int find_and_check_chardev(CharDriverState **chr, } memset(&props, 0, sizeof(props)); - if (qemu_opt_foreach((*chr)->opts, compare_chardev_opts, &props, errp)) { - return 1; - } - if (!props.is_socket) { - error_setg(errp, "chardev \"%s\" is not a tcp socket", + if (!qemu_chr_has_feature(*chr, QEMU_CHAR_FEATURE_RECONNECTABLE)) { + error_setg(errp, "chardev \"%s\" is not reconnectable", chr_name); return 1; } diff --git a/net/vhost-user.c b/net/vhost-user.c index b0595f8781c..5b94c84541b 100644 --- a/net/vhost-user.c +++ b/net/vhost-user.c @@ -27,11 +27,6 @@ typedef struct VhostUserState { bool started; } VhostUserState; -typedef struct VhostUserChardevProps { - bool is_socket; - bool is_unix; -} VhostUserChardevProps; - VHostNetState *vhost_user_get_vhost_net(NetClientState *nc) { VhostUserState *s = DO_UPCAST(VhostUserState, nc, nc); @@ -278,45 +273,23 @@ static int net_vhost_user_init(NetClientState *peer, const char *device, return 0; } -static int net_vhost_chardev_opts(void *opaque, - const char *name, const char *value, - Error **errp) -{ - VhostUserChardevProps *props = opaque; - - if (strcmp(name, "backend") == 0 && strcmp(value, "socket") == 0) { - props->is_socket = true; - } else if (strcmp(name, "path") == 0) { - props->is_unix = true; - } else if (strcmp(name, "server") == 0) { - } else { - error_setg(errp, - "vhost-user does not support a chardev with option %s=%s", - name, value); - return -1; - } - return 0; -} - -static CharDriverState *net_vhost_parse_chardev( +static CharDriverState *net_vhost_claim_chardev( const NetdevVhostUserOptions *opts, Error **errp) { CharDriverState *chr = qemu_chr_find(opts->chardev); - VhostUserChardevProps props; if (chr == NULL) { error_setg(errp, "chardev \"%s\" not found", opts->chardev); return NULL; } - /* inspect chardev opts */ - memset(&props, 0, sizeof(props)); - if (qemu_opt_foreach(chr->opts, net_vhost_chardev_opts, &props, errp)) { + if (!qemu_chr_has_feature(chr, QEMU_CHAR_FEATURE_RECONNECTABLE)) { + error_setg(errp, "chardev \"%s\" is not reconnectable", + opts->chardev); return NULL; } - - if (!props.is_socket || !props.is_unix) { - error_setg(errp, "chardev \"%s\" is not a unix socket", + if (!qemu_chr_has_feature(chr, QEMU_CHAR_FEATURE_FD_PASS)) { + error_setg(errp, "chardev \"%s\" does not support FD passing", opts->chardev); return NULL; } @@ -357,7 +330,7 @@ int net_init_vhost_user(const Netdev *netdev, const char *name, assert(netdev->type == NET_CLIENT_DRIVER_VHOST_USER); vhost_user_opts = &netdev->u.vhost_user; - chr = net_vhost_parse_chardev(vhost_user_opts, errp); + chr = net_vhost_claim_chardev(vhost_user_opts, errp); if (!chr) { return -1; } diff --git a/qemu-char.c b/qemu-char.c index fb456cec345..768150d1f80 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -3996,7 +3996,6 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts, } chr = qemu_chr_find(id); - chr->opts = opts; qapi_out: qapi_free_ChardevBackend(backend); @@ -4005,7 +4004,6 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts, return chr; err: - qemu_opts_del(opts); return NULL; } @@ -4033,6 +4031,7 @@ CharDriverState *qemu_chr_new_noreplay(const char *label, const char *filename, qemu_chr_fe_claim_no_fail(chr); monitor_init(chr, MONITOR_USE_READLINE); } + qemu_opts_del(opts); return chr; } @@ -4132,7 +4131,6 @@ static void qemu_chr_free_common(CharDriverState *chr) { g_free(chr->filename); g_free(chr->label); - qemu_opts_del(chr->opts); if (chr->logfd != -1) { close(chr->logfd); } @@ -4513,6 +4511,11 @@ static CharDriverState *qmp_chardev_open_socket(const char *id, s->addr = QAPI_CLONE(SocketAddress, sock->addr); + qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_RECONNECTABLE); + if (s->is_unix) { + qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_FD_PASS); + } + chr->opaque = s; chr->chr_wait_connected = tcp_chr_wait_connected; chr->chr_write = tcp_chr_write; @@ -4596,6 +4599,19 @@ static CharDriverState *qmp_chardev_open_udp(const char *id, return qemu_chr_open_udp(sioc, common, errp); } + +bool qemu_chr_has_feature(CharDriverState *chr, + CharDriverFeature feature) +{ + return test_bit(feature, chr->features); +} + +void qemu_chr_set_feature(CharDriverState *chr, + CharDriverFeature feature) +{ + return set_bit(feature, chr->features); +} + ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, Error **errp) { From 1a665855d7144bb3df382630a2b5e4039e95e466 Mon Sep 17 00:00:00 2001 From: Halil Pasic Date: Thu, 6 Oct 2016 14:55:39 +0200 Subject: [PATCH 617/723] virtio: prepare change VMSTATE_VIRTIO_DEVICE macro In most cases the functions passed to VMSTATE_VIRTIO_DEVICE only call the virtio_load and virtio_save wrappers. Some include some pre- and post- massaging too. The massaging is better expressed as such in the VMStateDescription. Let us prepare for changing the semantic of the VMSTATE_VIRTIO_DEVICE macro so that it is more similar to the other VMSTATE_*_DEVICE macros in a sense that it is a field definition. The preprocessor conditionals are going to be removed as soon as every usage is converted to the new semantic. Signed-off-by: Halil Pasic Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio.c | 21 +++++++++++++++++++++ include/hw/virtio/virtio.h | 16 ++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 46f79c9e145..62b9c002ffb 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -1645,6 +1645,27 @@ void virtio_vmstate_save(QEMUFile *f, void *opaque, size_t size) virtio_save(VIRTIO_DEVICE(opaque), f); } +/* A wrapper for use as a VMState .put function */ +static void virtio_device_put(QEMUFile *f, void *opaque, size_t size) +{ + virtio_save(VIRTIO_DEVICE(opaque), f); +} + +/* A wrapper for use as a VMState .get function */ +static int virtio_device_get(QEMUFile *f, void *opaque, size_t size) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(opaque); + DeviceClass *dc = DEVICE_CLASS(VIRTIO_DEVICE_GET_CLASS(vdev)); + + return virtio_load(vdev, f, dc->vmsd->version_id); +} + +const VMStateInfo virtio_vmstate_info = { + .name = "virtio", + .get = virtio_device_get, + .put = virtio_device_put, +}; + static int virtio_set_features_nocheck(VirtIODevice *vdev, uint64_t val) { VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index e25ec4f0b52..929fa92c32a 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -179,6 +179,20 @@ void virtio_notify(VirtIODevice *vdev, VirtQueue *vq); void virtio_save(VirtIODevice *vdev, QEMUFile *f); void virtio_vmstate_save(QEMUFile *f, void *opaque, size_t size); +extern const VMStateInfo virtio_vmstate_info; + +#ifdef VMSTATE_VIRTIO_DEVICE_USE_NEW + +#define VMSTATE_VIRTIO_DEVICE \ + { \ + .name = "virtio", \ + .info = &virtio_vmstate_info, \ + .flags = VMS_SINGLE, \ + } + +#else +/* TODO remove conditional as soon as all users are converted */ + #define VMSTATE_VIRTIO_DEVICE(devname, v, getf, putf) \ static const VMStateDescription vmstate_virtio_ ## devname = { \ .name = "virtio-" #devname , \ @@ -198,6 +212,8 @@ void virtio_vmstate_save(QEMUFile *f, void *opaque, size_t size); } \ } +#endif + int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id); void virtio_notify_config(VirtIODevice *vdev); From 977a117f78f3abcad8ea925f6c8282f2b3386f53 Mon Sep 17 00:00:00 2001 From: Halil Pasic Date: Thu, 6 Oct 2016 14:55:40 +0200 Subject: [PATCH 618/723] virtio-blk: convert VMSTATE_VIRTIO_DEVICE Use the new VMSTATE_VIRTIO_DEVICE macro. Signed-off-by: Halil Pasic Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/block/virtio-blk.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index 0ddd7fbbe54..10c5794063f 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -11,6 +11,8 @@ * */ +#define VMSTATE_VIRTIO_DEVICE_USE_NEW + #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu-common.h" @@ -822,13 +824,6 @@ static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status) } } -static void virtio_blk_save(QEMUFile *f, void *opaque, size_t size) -{ - VirtIODevice *vdev = VIRTIO_DEVICE(opaque); - - virtio_save(vdev, f); -} - static void virtio_blk_save_device(VirtIODevice *vdev, QEMUFile *f) { VirtIOBlock *s = VIRTIO_BLK(vdev); @@ -847,14 +842,6 @@ static void virtio_blk_save_device(VirtIODevice *vdev, QEMUFile *f) qemu_put_sbyte(f, 0); } -static int virtio_blk_load(QEMUFile *f, void *opaque, size_t size) -{ - VirtIOBlock *s = opaque; - VirtIODevice *vdev = VIRTIO_DEVICE(s); - - return virtio_load(vdev, f, 2); -} - static int virtio_blk_load_device(VirtIODevice *vdev, QEMUFile *f, int version_id) { @@ -975,7 +962,15 @@ static void virtio_blk_instance_init(Object *obj) DEVICE(obj), NULL); } -VMSTATE_VIRTIO_DEVICE(blk, 2, virtio_blk_load, virtio_blk_save); +static const VMStateDescription vmstate_virtio_blk = { + .name = "virtio-blk", + .minimum_version_id = 2, + .version_id = 2, + .fields = (VMStateField[]) { + VMSTATE_VIRTIO_DEVICE, + VMSTATE_END_OF_LIST() + }, +}; static Property virtio_blk_properties[] = { DEFINE_BLOCK_PROPERTIES(VirtIOBlock, conf.conf), From 4d45dcfbf2bb606316e13f70aeb3f0709384f9f5 Mon Sep 17 00:00:00 2001 From: Halil Pasic Date: Thu, 6 Oct 2016 14:55:41 +0200 Subject: [PATCH 619/723] virtio-net: convert VMSTATE_VIRTIO_DEVICE Use the new VMSTATE_VIRTIO_DEVICE macro. Signed-off-by: Halil Pasic Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/net/virtio-net.c | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index ca1b46956bc..b2198a550ef 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -11,6 +11,8 @@ * */ +#define VMSTATE_VIRTIO_DEVICE_USE_NEW + #include "qemu/osdep.h" #include "qemu/iov.h" #include "hw/virtio/virtio.h" @@ -1514,17 +1516,6 @@ static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue) virtio_net_set_queues(n); } -static void virtio_net_save(QEMUFile *f, void *opaque, size_t size) -{ - VirtIONet *n = opaque; - VirtIODevice *vdev = VIRTIO_DEVICE(n); - - /* At this point, backend must be stopped, otherwise - * it might keep writing to memory. */ - assert(!n->vhost_started); - virtio_save(vdev, f); -} - static void virtio_net_save_device(VirtIODevice *vdev, QEMUFile *f) { VirtIONet *n = VIRTIO_NET(vdev); @@ -1560,14 +1551,6 @@ static void virtio_net_save_device(VirtIODevice *vdev, QEMUFile *f) } } -static int virtio_net_load(QEMUFile *f, void *opaque, size_t size) -{ - VirtIONet *n = opaque; - VirtIODevice *vdev = VIRTIO_DEVICE(n); - - return virtio_load(vdev, f, VIRTIO_NET_VM_VERSION); -} - static int virtio_net_load_device(VirtIODevice *vdev, QEMUFile *f, int version_id) { @@ -1870,8 +1853,25 @@ static void virtio_net_instance_init(Object *obj) DEVICE(n), NULL); } -VMSTATE_VIRTIO_DEVICE(net, VIRTIO_NET_VM_VERSION, virtio_net_load, - virtio_net_save); +static void virtio_net_pre_save(void *opaque) +{ + VirtIONet *n = opaque; + + /* At this point, backend must be stopped, otherwise + * it might keep writing to memory. */ + assert(!n->vhost_started); +} + +static const VMStateDescription vmstate_virtio_net = { + .name = "virtio-net", + .minimum_version_id = VIRTIO_NET_VM_VERSION, + .version_id = VIRTIO_NET_VM_VERSION, + .fields = (VMStateField[]) { + VMSTATE_VIRTIO_DEVICE, + VMSTATE_END_OF_LIST() + }, + .pre_save = virtio_net_pre_save, +}; static Property virtio_net_properties[] = { DEFINE_PROP_BIT("csum", VirtIONet, host_features, VIRTIO_NET_F_CSUM, true), From dcaf8dda4bc6046c5ecc2bff2076a9449192f937 Mon Sep 17 00:00:00 2001 From: Halil Pasic Date: Thu, 6 Oct 2016 14:55:42 +0200 Subject: [PATCH 620/723] virtio-9p: convert VMSTATE_VIRTIO_DEVICE Use the new VMSTATE_VIRTIO_DEVICE macro. Signed-off-by: Halil Pasic Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/9pfs/virtio-9p-device.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c index a338f640026..526ec7d08f7 100644 --- a/hw/9pfs/virtio-9p-device.c +++ b/hw/9pfs/virtio-9p-device.c @@ -11,6 +11,8 @@ * */ +#define VMSTATE_VIRTIO_DEVICE_USE_NEW + #include "qemu/osdep.h" #include "hw/virtio/virtio.h" #include "qemu/sockets.h" @@ -113,11 +115,6 @@ static void virtio_9p_get_config(VirtIODevice *vdev, uint8_t *config) g_free(cfg); } -static int virtio_9p_load(QEMUFile *f, void *opaque, size_t size) -{ - return virtio_load(VIRTIO_DEVICE(opaque), f, 1); -} - static void virtio_9p_device_realize(DeviceState *dev, Error **errp) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); @@ -184,7 +181,15 @@ void virtio_init_iov_from_pdu(V9fsPDU *pdu, struct iovec **piov, /* virtio-9p device */ -VMSTATE_VIRTIO_DEVICE(9p, 1, virtio_9p_load, virtio_vmstate_save); +static const VMStateDescription vmstate_virtio_9p = { + .name = "virtio-9p", + .minimum_version_id = 1, + .version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_VIRTIO_DEVICE, + VMSTATE_END_OF_LIST() + }, +}; static Property virtio_9p_properties[] = { DEFINE_PROP_STRING("mount_tag", V9fsVirtioState, state.fsconf.tag), From 97eed24ff1144fb0718c2fdf600742b5167e87a3 Mon Sep 17 00:00:00 2001 From: Halil Pasic Date: Thu, 6 Oct 2016 14:55:43 +0200 Subject: [PATCH 621/723] virtio-serial: convert VMSTATE_VIRTIO_DEVICE Use the new VMSTATE_VIRTIO_DEVICE macro. Signed-off-by: Halil Pasic Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/char/virtio-serial-bus.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c index 3955f0f7418..c9b0fc83253 100644 --- a/hw/char/virtio-serial-bus.c +++ b/hw/char/virtio-serial-bus.c @@ -18,6 +18,8 @@ * GNU GPL, version 2 or (at your option) any later version. */ +#define VMSTATE_VIRTIO_DEVICE_USE_NEW + #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu/iov.h" @@ -778,12 +780,6 @@ static int fetch_active_ports_list(QEMUFile *f, return 0; } -static int virtio_serial_load(QEMUFile *f, void *opaque, size_t size) -{ - /* The virtio device */ - return virtio_load(VIRTIO_DEVICE(opaque), f, 3); -} - static int virtio_serial_load_device(VirtIODevice *vdev, QEMUFile *f, int version_id) { @@ -1129,7 +1125,15 @@ static void virtio_serial_device_unrealize(DeviceState *dev, Error **errp) } /* Note: 'console' is used for backwards compatibility */ -VMSTATE_VIRTIO_DEVICE(console, 3, virtio_serial_load, virtio_vmstate_save); +static const VMStateDescription vmstate_virtio_console = { + .name = "virtio-console", + .minimum_version_id = 3, + .version_id = 3, + .fields = (VMStateField[]) { + VMSTATE_VIRTIO_DEVICE, + VMSTATE_END_OF_LIST() + }, +}; static Property virtio_serial_properties[] = { DEFINE_PROP_UINT32("max_ports", VirtIOSerial, serial.max_virtserial_ports, From 8a502efd0c4beb0bdd7fbcf67cc722db00eddca1 Mon Sep 17 00:00:00 2001 From: Halil Pasic Date: Thu, 6 Oct 2016 14:55:44 +0200 Subject: [PATCH 622/723] virtio-gpu: convert VMSTATE_VIRTIO_DEVICE Use the new VMSTATE_VIRTIO_DEVICE macro. The device virtio-gpu is special because it actually does not adhere to the virtio migration schema, because device state is last. Signed-off-by: Halil Pasic Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/display/virtio-gpu.c | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 7fe6ed8bf09..4fcd63cdb66 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -11,6 +11,8 @@ * See the COPYING file in the top-level directory. */ +#define VMSTATE_VIRTIO_DEVICE_USE_NEW + #include "qemu/osdep.h" #include "qemu-common.h" #include "qemu/iov.h" @@ -990,12 +992,9 @@ static const VMStateDescription vmstate_virtio_gpu_scanouts = { static void virtio_gpu_save(QEMUFile *f, void *opaque, size_t size) { VirtIOGPU *g = opaque; - VirtIODevice *vdev = VIRTIO_DEVICE(g); struct virtio_gpu_simple_resource *res; int i; - virtio_save(vdev, f); - /* in 2d mode we should never find unprocessed commands here */ assert(QTAILQ_EMPTY(&g->cmdq)); @@ -1020,16 +1019,10 @@ static void virtio_gpu_save(QEMUFile *f, void *opaque, size_t size) static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size) { VirtIOGPU *g = opaque; - VirtIODevice *vdev = VIRTIO_DEVICE(g); struct virtio_gpu_simple_resource *res; struct virtio_gpu_scanout *scanout; uint32_t resource_id, pformat; - int i, ret; - - ret = virtio_load(vdev, f, VIRTIO_GPU_VM_VERSION); - if (ret) { - return ret; - } + int i; resource_id = qemu_get_be32(f); while (resource_id != 0) { @@ -1219,8 +1212,32 @@ static void virtio_gpu_reset(VirtIODevice *vdev) #endif } -VMSTATE_VIRTIO_DEVICE(gpu, VIRTIO_GPU_VM_VERSION, virtio_gpu_load, - virtio_gpu_save); +/* + * For historical reasons virtio_gpu does not adhere to virtio migration + * scheme as described in doc/virtio-migration.txt, in a sense that no + * save/load callback are provided to the core. Instead the device data + * is saved/loaded after the core data. + * + * Because of this we need a special vmsd. + */ +static const VMStateDescription vmstate_virtio_gpu = { + .name = "virtio-gpu", + .minimum_version_id = VIRTIO_GPU_VM_VERSION, + .version_id = VIRTIO_GPU_VM_VERSION, + .fields = (VMStateField[]) { + VMSTATE_VIRTIO_DEVICE /* core */, + { + .name = "virtio-gpu", + .info = &(const VMStateInfo) { + .name = "virtio-gpu", + .get = virtio_gpu_load, + .put = virtio_gpu_save, + }, + .flags = VMS_SINGLE, + } /* device */, + VMSTATE_END_OF_LIST() + }, +}; static Property virtio_gpu_properties[] = { DEFINE_PROP_UINT32("max_outputs", VirtIOGPU, conf.max_outputs, 1), From 73a17349ffa5dd6dec0947ecb09c657becb2f6e5 Mon Sep 17 00:00:00 2001 From: Halil Pasic Date: Thu, 6 Oct 2016 14:55:45 +0200 Subject: [PATCH 623/723] virtio-input: convert VMSTATE_VIRTIO_DEVICE Use the new VMSTATE_VIRTIO_DEVICE macro. Signed-off-by: Halil Pasic Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/input/virtio-input.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/hw/input/virtio-input.c b/hw/input/virtio-input.c index ccdf7308a58..5e31033c4dd 100644 --- a/hw/input/virtio-input.c +++ b/hw/input/virtio-input.c @@ -4,6 +4,8 @@ * top-level directory. */ +#define VMSTATE_VIRTIO_DEVICE_USE_NEW + #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu/iov.h" @@ -217,19 +219,12 @@ static void virtio_input_reset(VirtIODevice *vdev) } } -static int virtio_input_load(QEMUFile *f, void *opaque, size_t size) +static int virtio_input_post_load(void *opaque, int version_id) { VirtIOInput *vinput = opaque; VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(vinput); VirtIODevice *vdev = VIRTIO_DEVICE(vinput); - int ret; - - ret = virtio_load(vdev, f, VIRTIO_INPUT_VM_VERSION); - if (ret) { - return ret; - } - /* post_load() */ vinput->active = vdev->status & VIRTIO_CONFIG_S_DRIVER_OK; if (vic->change_active) { vic->change_active(vinput); @@ -296,8 +291,16 @@ static void virtio_input_device_unrealize(DeviceState *dev, Error **errp) virtio_cleanup(vdev); } -VMSTATE_VIRTIO_DEVICE(input, VIRTIO_INPUT_VM_VERSION, virtio_input_load, - virtio_vmstate_save); +static const VMStateDescription vmstate_virtio_input = { + .name = "virtio-input", + .minimum_version_id = VIRTIO_INPUT_VM_VERSION, + .version_id = VIRTIO_INPUT_VM_VERSION, + .fields = (VMStateField[]) { + VMSTATE_VIRTIO_DEVICE, + VMSTATE_END_OF_LIST() + }, + .post_load = virtio_input_post_load, +}; static Property virtio_input_properties[] = { DEFINE_PROP_STRING("serial", VirtIOInput, serial), From f20476b9e444e11792d49438fe5ec53ac1470f33 Mon Sep 17 00:00:00 2001 From: Halil Pasic Date: Thu, 6 Oct 2016 14:55:46 +0200 Subject: [PATCH 624/723] virtio-scsi: convert VMSTATE_VIRTIO_DEVICE Use the new VMSTATE_VIRTIO_DEVICE macro. Signed-off-by: Halil Pasic Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/scsi/virtio-scsi.c | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 6eaadd8d7c7..9473e1099f6 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -13,6 +13,8 @@ * */ +#define VMSTATE_VIRTIO_DEVICE_USE_NEW + #include "qemu/osdep.h" #include "qapi/error.h" #include "standard-headers/linux/virtio_ids.h" @@ -681,22 +683,6 @@ static void virtio_scsi_reset(VirtIODevice *vdev) s->events_dropped = false; } -/* The device does not have anything to save beyond the virtio data. - * Request data is saved with callbacks from SCSI devices. - */ -static void virtio_scsi_save(QEMUFile *f, void *opaque, size_t size) -{ - VirtIODevice *vdev = VIRTIO_DEVICE(opaque); - virtio_save(vdev, f); -} - -static int virtio_scsi_load(QEMUFile *f, void *opaque, size_t size) -{ - VirtIODevice *vdev = VIRTIO_DEVICE(opaque); - - return virtio_load(vdev, f, 1); -} - void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, uint32_t event, uint32_t reason) { @@ -940,7 +926,15 @@ static Property virtio_scsi_properties[] = { DEFINE_PROP_END_OF_LIST(), }; -VMSTATE_VIRTIO_DEVICE(scsi, 1, virtio_scsi_load, virtio_scsi_save); +static const VMStateDescription vmstate_virtio_scsi = { + .name = "virtio-scsi", + .minimum_version_id = 1, + .version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_VIRTIO_DEVICE, + VMSTATE_END_OF_LIST() + }, +}; static void virtio_scsi_common_class_init(ObjectClass *klass, void *data) { From c5dc16b726e0279330233c0eb09fd1c708af978f Mon Sep 17 00:00:00 2001 From: Halil Pasic Date: Thu, 6 Oct 2016 14:55:47 +0200 Subject: [PATCH 625/723] virtio-balloon: convert VMSTATE_VIRTIO_DEVICE Use the new VMSTATE_VIRTIO_DEVICE macro. Signed-off-by: Halil Pasic Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-balloon.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index eb572e6cdbf..2c68d3dc5ff 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -13,6 +13,8 @@ * */ +#define VMSTATE_VIRTIO_DEVICE_USE_NEW + #include "qemu/osdep.h" #include "qemu/iov.h" #include "qemu/timer.h" @@ -402,11 +404,6 @@ static void virtio_balloon_save_device(VirtIODevice *vdev, QEMUFile *f) qemu_put_be32(f, s->actual); } -static int virtio_balloon_load(QEMUFile *f, void *opaque, size_t size) -{ - return virtio_load(VIRTIO_DEVICE(opaque), f, 1); -} - static int virtio_balloon_load_device(VirtIODevice *vdev, QEMUFile *f, int version_id) { @@ -492,7 +489,15 @@ static void virtio_balloon_instance_init(Object *obj) NULL, s, NULL); } -VMSTATE_VIRTIO_DEVICE(balloon, 1, virtio_balloon_load, virtio_vmstate_save); +static const VMStateDescription vmstate_virtio_balloon = { + .name = "virtio-balloon", + .minimum_version_id = 1, + .version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_VIRTIO_DEVICE, + VMSTATE_END_OF_LIST() + }, +}; static Property virtio_balloon_properties[] = { DEFINE_PROP_BIT("deflate-on-oom", VirtIOBalloon, host_features, From b7de81f697dfb933f4b81d37f35d53f6d1d0332d Mon Sep 17 00:00:00 2001 From: Halil Pasic Date: Thu, 6 Oct 2016 14:55:48 +0200 Subject: [PATCH 626/723] virtio-rng: convert VMSTATE_VIRTIO_DEVICE Use the new VMSTATE_VIRTIO_DEVICE macro. Signed-off-by: Halil Pasic Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-rng.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c index cd8ca10177d..62867d141e6 100644 --- a/hw/virtio/virtio-rng.c +++ b/hw/virtio/virtio-rng.c @@ -9,6 +9,8 @@ * top-level directory. */ +#define VMSTATE_VIRTIO_DEVICE_USE_NEW + #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu/iov.h" @@ -120,15 +122,9 @@ static uint64_t get_features(VirtIODevice *vdev, uint64_t f, Error **errp) return f; } -static int virtio_rng_load(QEMUFile *f, void *opaque, size_t size) +static int virtio_rng_post_load(void *opaque, int version_id) { VirtIORNG *vrng = opaque; - int ret; - - ret = virtio_load(VIRTIO_DEVICE(vrng), f, 1); - if (ret != 0) { - return ret; - } /* We may have an element ready but couldn't process it due to a quota * limit. Make sure to try again after live migration when the quota may @@ -216,7 +212,16 @@ static void virtio_rng_device_unrealize(DeviceState *dev, Error **errp) virtio_cleanup(vdev); } -VMSTATE_VIRTIO_DEVICE(rng, 1, virtio_rng_load, virtio_vmstate_save); +static const VMStateDescription vmstate_virtio_rng = { + .name = "virtio-rng", + .minimum_version_id = 1, + .version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_VIRTIO_DEVICE, + VMSTATE_END_OF_LIST() + }, + .post_load = virtio_rng_post_load, +}; static Property virtio_rng_properties[] = { /* Set a default rate limit of 2^47 bytes per minute or roughly 2TB/s. If From 81cc8a6566d9fdbe0535b26a33f28a2888dceb77 Mon Sep 17 00:00:00 2001 From: Halil Pasic Date: Thu, 6 Oct 2016 14:55:49 +0200 Subject: [PATCH 627/723] vhost-vsock: convert VMSTATE_VIRTIO_DEVICE Use the new VMSTATE_VIRTIO_DEVICE macro. Signed-off-by: Halil Pasic Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost-vsock.c | 44 +++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/hw/virtio/vhost-vsock.c b/hw/virtio/vhost-vsock.c index bde2456621d..99cb216ae1f 100644 --- a/hw/virtio/vhost-vsock.c +++ b/hw/virtio/vhost-vsock.c @@ -11,6 +11,8 @@ * top-level directory. */ +#define VMSTATE_VIRTIO_DEVICE_USE_NEW + #include #include "qemu/osdep.h" #include "standard-headers/linux/virtio_vsock.h" @@ -236,17 +238,6 @@ static void vhost_vsock_send_transport_reset(VHostVSock *vsock) g_free(elem); } -static void vhost_vsock_save(QEMUFile *f, void *opaque, size_t size) -{ - VHostVSock *vsock = opaque; - VirtIODevice *vdev = VIRTIO_DEVICE(vsock); - - /* At this point, backend must be stopped, otherwise - * it might keep writing to memory. */ - assert(!vsock->vhost_dev.started); - virtio_save(vdev, f); -} - static void vhost_vsock_post_load_timer_cleanup(VHostVSock *vsock) { if (!vsock->post_load_timer) { @@ -266,16 +257,19 @@ static void vhost_vsock_post_load_timer_cb(void *opaque) vhost_vsock_send_transport_reset(vsock); } -static int vhost_vsock_load(QEMUFile *f, void *opaque, size_t size) +static void vhost_vsock_pre_save(void *opaque) { VHostVSock *vsock = opaque; - VirtIODevice *vdev = VIRTIO_DEVICE(vsock); - int ret; - ret = virtio_load(vdev, f, VHOST_VSOCK_SAVEVM_VERSION); - if (ret) { - return ret; - } + /* At this point, backend must be stopped, otherwise + * it might keep writing to memory. */ + assert(!vsock->vhost_dev.started); +} + +static int vhost_vsock_post_load(void *opaque, int version_id) +{ + VHostVSock *vsock = opaque; + VirtIODevice *vdev = VIRTIO_DEVICE(vsock); if (virtio_queue_get_addr(vdev, 2)) { /* Defer transport reset event to a vm clock timer so that virtqueue @@ -288,12 +282,20 @@ static int vhost_vsock_load(QEMUFile *f, void *opaque, size_t size) vsock); timer_mod(vsock->post_load_timer, 1); } - return 0; } -VMSTATE_VIRTIO_DEVICE(vhost_vsock, VHOST_VSOCK_SAVEVM_VERSION, - vhost_vsock_load, vhost_vsock_save); +static const VMStateDescription vmstate_virtio_vhost_vsock = { + .name = "virtio-vhost_vsock", + .minimum_version_id = VHOST_VSOCK_SAVEVM_VERSION, + .version_id = VHOST_VSOCK_SAVEVM_VERSION, + .fields = (VMStateField[]) { + VMSTATE_VIRTIO_DEVICE, + VMSTATE_END_OF_LIST() + }, + .pre_save = vhost_vsock_pre_save, + .post_load = vhost_vsock_post_load, +}; static void vhost_vsock_device_realize(DeviceState *dev, Error **errp) { From 5705653ff8666ffb247971361904f902aa033351 Mon Sep 17 00:00:00 2001 From: Halil Pasic Date: Thu, 6 Oct 2016 14:55:50 +0200 Subject: [PATCH 628/723] virtio: cleanup VMSTATE_VIRTIO_DEVICE Now all the usages of the old version of VMSTATE_VIRTIO_DEVICE are gone, so we can get rid of the conditionals, and the old macro. Signed-off-by: Halil Pasic Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/9pfs/virtio-9p-device.c | 2 -- hw/block/virtio-blk.c | 2 -- hw/char/virtio-serial-bus.c | 2 -- hw/display/virtio-gpu.c | 2 -- hw/input/virtio-input.c | 2 -- hw/net/virtio-net.c | 2 -- hw/scsi/virtio-scsi.c | 2 -- hw/virtio/vhost-vsock.c | 2 -- hw/virtio/virtio-balloon.c | 2 -- hw/virtio/virtio-rng.c | 2 -- hw/virtio/virtio.c | 6 ------ include/hw/virtio/virtio.h | 27 --------------------------- 12 files changed, 53 deletions(-) diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c index 526ec7d08f7..e98dd0c4c0a 100644 --- a/hw/9pfs/virtio-9p-device.c +++ b/hw/9pfs/virtio-9p-device.c @@ -11,8 +11,6 @@ * */ -#define VMSTATE_VIRTIO_DEVICE_USE_NEW - #include "qemu/osdep.h" #include "hw/virtio/virtio.h" #include "qemu/sockets.h" diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index 10c5794063f..37fe72bdcd8 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -11,8 +11,6 @@ * */ -#define VMSTATE_VIRTIO_DEVICE_USE_NEW - #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu-common.h" diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c index c9b0fc83253..7975c2cda1f 100644 --- a/hw/char/virtio-serial-bus.c +++ b/hw/char/virtio-serial-bus.c @@ -18,8 +18,6 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#define VMSTATE_VIRTIO_DEVICE_USE_NEW - #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu/iov.h" diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 4fcd63cdb66..fa6fd0e53f2 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -11,8 +11,6 @@ * See the COPYING file in the top-level directory. */ -#define VMSTATE_VIRTIO_DEVICE_USE_NEW - #include "qemu/osdep.h" #include "qemu-common.h" #include "qemu/iov.h" diff --git a/hw/input/virtio-input.c b/hw/input/virtio-input.c index 5e31033c4dd..b678ee9f204 100644 --- a/hw/input/virtio-input.c +++ b/hw/input/virtio-input.c @@ -4,8 +4,6 @@ * top-level directory. */ -#define VMSTATE_VIRTIO_DEVICE_USE_NEW - #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu/iov.h" diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index b2198a550ef..06bfe4bcc93 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -11,8 +11,6 @@ * */ -#define VMSTATE_VIRTIO_DEVICE_USE_NEW - #include "qemu/osdep.h" #include "qemu/iov.h" #include "hw/virtio/virtio.h" diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 9473e1099f6..4762f05274c 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -13,8 +13,6 @@ * */ -#define VMSTATE_VIRTIO_DEVICE_USE_NEW - #include "qemu/osdep.h" #include "qapi/error.h" #include "standard-headers/linux/virtio_ids.h" diff --git a/hw/virtio/vhost-vsock.c b/hw/virtio/vhost-vsock.c index 99cb216ae1f..b4815629e18 100644 --- a/hw/virtio/vhost-vsock.c +++ b/hw/virtio/vhost-vsock.c @@ -11,8 +11,6 @@ * top-level directory. */ -#define VMSTATE_VIRTIO_DEVICE_USE_NEW - #include #include "qemu/osdep.h" #include "standard-headers/linux/virtio_vsock.h" diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index 2c68d3dc5ff..1d770282363 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -13,8 +13,6 @@ * */ -#define VMSTATE_VIRTIO_DEVICE_USE_NEW - #include "qemu/osdep.h" #include "qemu/iov.h" #include "qemu/timer.h" diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c index 62867d141e6..9639f4e89bd 100644 --- a/hw/virtio/virtio-rng.c +++ b/hw/virtio/virtio-rng.c @@ -9,8 +9,6 @@ * top-level directory. */ -#define VMSTATE_VIRTIO_DEVICE_USE_NEW - #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu/iov.h" diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 62b9c002ffb..d48d1a98a70 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -1639,12 +1639,6 @@ void virtio_save(VirtIODevice *vdev, QEMUFile *f) vmstate_save_state(f, &vmstate_virtio, vdev, NULL); } -/* A wrapper for use as a VMState .put function */ -void virtio_vmstate_save(QEMUFile *f, void *opaque, size_t size) -{ - virtio_save(VIRTIO_DEVICE(opaque), f); -} - /* A wrapper for use as a VMState .put function */ static void virtio_device_put(QEMUFile *f, void *opaque, size_t size) { diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index 929fa92c32a..b913aac4558 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -177,12 +177,9 @@ bool virtio_should_notify(VirtIODevice *vdev, VirtQueue *vq); void virtio_notify(VirtIODevice *vdev, VirtQueue *vq); void virtio_save(VirtIODevice *vdev, QEMUFile *f); -void virtio_vmstate_save(QEMUFile *f, void *opaque, size_t size); extern const VMStateInfo virtio_vmstate_info; -#ifdef VMSTATE_VIRTIO_DEVICE_USE_NEW - #define VMSTATE_VIRTIO_DEVICE \ { \ .name = "virtio", \ @@ -190,30 +187,6 @@ extern const VMStateInfo virtio_vmstate_info; .flags = VMS_SINGLE, \ } -#else -/* TODO remove conditional as soon as all users are converted */ - -#define VMSTATE_VIRTIO_DEVICE(devname, v, getf, putf) \ - static const VMStateDescription vmstate_virtio_ ## devname = { \ - .name = "virtio-" #devname , \ - .minimum_version_id = v, \ - .version_id = v, \ - .fields = (VMStateField[]) { \ - { \ - .name = "virtio", \ - .info = &(const VMStateInfo) {\ - .name = "virtio", \ - .get = getf, \ - .put = putf, \ - }, \ - .flags = VMS_SINGLE, \ - }, \ - VMSTATE_END_OF_LIST() \ - } \ - } - -#endif - int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id); void virtio_notify_config(VirtIODevice *vdev); From dea651a95af6dad0997b840241a0bf6059d9a776 Mon Sep 17 00:00:00 2001 From: Feng Wu Date: Thu, 22 Sep 2016 00:12:17 +0800 Subject: [PATCH 629/723] intel-iommu: Check IOAPIC's Trigger Mode against the one in IRTE The Trigger Mode field of IOAPIC must match the Trigger Mode in the IRTE according to VT-d Spec 5.1.5.1. Signed-off-by: Feng Wu Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Peter Xu --- hw/i386/intel_iommu.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 9f4e64af1ad..2efd69bbd7f 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -27,6 +27,7 @@ #include "hw/pci/pci.h" #include "hw/pci/pci_bus.h" #include "hw/i386/pc.h" +#include "hw/i386/apic-msidef.h" #include "hw/boards.h" #include "hw/i386/x86-iommu.h" #include "hw/pci-host/q35.h" @@ -2209,6 +2210,8 @@ static int vtd_interrupt_remap_msi(IntelIOMMUState *iommu, } } else { uint8_t vector = origin->data & 0xff; + uint8_t trigger_mode = (origin->data >> MSI_DATA_TRIGGER_SHIFT) & 0x1; + VTD_DPRINTF(IR, "received IOAPIC interrupt"); /* IOAPIC entry vector should be aligned with IRTE vector * (see vt-d spec 5.1.5.1). */ @@ -2217,6 +2220,15 @@ static int vtd_interrupt_remap_msi(IntelIOMMUState *iommu, "entry: %d, IRTE: %d, index: %d", vector, irq.vector, index); } + + /* The Trigger Mode field must match the Trigger Mode in the IRTE. + * (see vt-d spec 5.1.5.1). */ + if (trigger_mode != irq.trigger_mode) { + VTD_DPRINTF(GENERAL, "IOAPIC trigger mode inconsistent: " + "entry: %u, IRTE: %u, index: %d", + trigger_mode, irq.trigger_mode, index); + } + } /* From 6b39b06339ee59559b31f860d4af635b046322df Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Tue, 11 Oct 2016 10:46:23 -0500 Subject: [PATCH 630/723] build: Work around SIZE_MAX bug in OSX headers C99 requires SIZE_MAX to be declared with the same type as the integral promotion of size_t, but OSX mistakenly defines it as an 'unsigned long long' expression even though size_t is only 'unsigned long'. Rather than futzing around with whether size_t is 32- or 64-bits wide (which would be needed if we cared about using SIZE_T in a #if expression), just hard-code it with a cast. This is not a strict C99-compliant definition, because it doesn't work in the preprocessor, but if we later need that, the build will break on Mac to inform us to improve our replacement at that time. See also https://patchwork.ozlabs.org/patch/542327/ for an instance where the wrong type trips us up if we don't fix it for good in osdep.h. Some versions of glibc make a similar mistake with SSIZE_MAX; the goal is that the approach of this patch could be copied to work around that problem if it ever becomes important to us. Signed-off-by: Eric Blake Reviewed-by: Markus Armbruster Message-id: 1476200784-17210-1-git-send-email-eblake@redhat.com Reviewed-by: John Arbuckle Tested-by: Peter Maydell Signed-off-by: Peter Maydell --- configure | 16 ++++++++++++++++ include/qemu/osdep.h | 8 ++++++++ 2 files changed, 24 insertions(+) diff --git a/configure b/configure index 5751d8ecaa5..dd9e6792bbe 100755 --- a/configure +++ b/configure @@ -1725,6 +1725,19 @@ if test "$cocoa" = "yes"; then sdl=no fi +# Some versions of Mac OS X incorrectly define SIZE_MAX +cat > $TMPC << EOF +#include +#include +int main(int argc, char *argv[]) { + return printf("%zu", SIZE_MAX); +} +EOF +have_broken_size_max=no +if ! compile_object -Werror ; then + have_broken_size_max=yes +fi + ########################################## # L2TPV3 probe @@ -5245,6 +5258,9 @@ fi if test "$have_ifaddrs_h" = "yes" ; then echo "HAVE_IFADDRS_H=y" >> $config_host_mak fi +if test "$have_broken_size_max" = "yes" ; then + echo "HAVE_BROKEN_SIZE_MAX=y" >> $config_host_mak +fi # Work around a system header bug with some kernel/XFS header # versions where they both try to define 'struct fsxattr': diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index 384bfe245f2..0e3c330e6bf 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -141,6 +141,14 @@ extern int daemon(int, int); # error Unknown pointer size #endif +/* Mac OSX has a bug that incorrectly defines SIZE_MAX with + * the wrong type. Our replacement isn't usable in preprocessor + * expressions, but it is sufficient for our needs. */ +#if defined(HAVE_BROKEN_SIZE_MAX) && HAVE_BROKEN_SIZE_MAX +#undef SIZE_MAX +#define SIZE_MAX ((size_t)-1) +#endif + #ifndef MIN #define MIN(a, b) (((a) < (b)) ? (a) : (b)) #endif From 170f75ad80115c509d3bedfcbbf4a8237ff6f771 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Tue, 4 Oct 2016 14:35:40 +0100 Subject: [PATCH 631/723] trace: move colo trace events to net/ sub-directory The colo patch series added various trace events to the top level trace-events file, despite the files using them being in a sub-dir. commit 30656b097e9dd7978d3fe9416cb9f5a421a9e63e Author: Zhang Chen Date: Tue Sep 27 10:22:34 2016 +0800 filter-rewriter: rewrite tcp packet to keep secondary connection commit f4b618360e5a81b097e2e35d52011bec3c63af68 Author: Zhang Chen Date: Tue Sep 27 10:22:31 2016 +0800 colo-compare: add TCP, UDP, ICMP packet comparison We add TCP,UDP,ICMP packet comparison to replace IP packet comparison. This can increase the accuracy of the package comparison. Less checkpoint more efficiency. Signed-off-by: Zhang Chen Signed-off-by: Li Zhijian Signed-off-by: Wen Congyang Signed-off-by: Jason Wang commit 0682e15b19b2f41c0568142b42518b9471168597 Author: Zhang Chen Date: Tue Sep 27 10:22:30 2016 +0800 colo-compare: introduce packet comparison thread commit 59509ec16b7ee92b3f8261c554023aa1d3169317 Author: Zhang Chen Date: Tue Sep 27 10:22:27 2016 +0800 net/colo.c: add colo.c to define and handle packet This moves all events into net/trace-events where they were supposed to live. Reviewed-by: Stefan Hajnoczi Signed-off-by: Daniel P. Berrange Message-id: 1475588159-30598-2-git-send-email-berrange@redhat.com Signed-off-by: Stefan Hajnoczi --- net/trace-events | 16 ++++++++++++++++ trace-events | 16 ---------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/net/trace-events b/net/trace-events index 65c46a48fb5..d67f048825b 100644 --- a/net/trace-events +++ b/net/trace-events @@ -2,3 +2,19 @@ # net/vhost-user.c vhost_user_event(const char *chr, int event) "chr: %s got event: %d" + +# net/colo.c +colo_proxy_main(const char *chr) ": %s" + +# net/colo-compare.c +colo_compare_main(const char *chr) ": %s" +colo_compare_udp_miscompare(const char *sta, int size) ": %s = %d" +colo_compare_icmp_miscompare(const char *sta, int size) ": %s = %d" +colo_compare_ip_info(int psize, const char *sta, const char *stb, int ssize, const char *stc, const char *std) "ppkt size = %d, ip_src = %s, ip_dst = %s, spkt size = %d, ip_src = %s, ip_dst = %s" +colo_old_packet_check_found(int64_t old_time) "%" PRId64 +colo_compare_miscompare(void) "" + +# net/filter-rewriter.c +colo_filter_rewriter_debug(void) "" +colo_filter_rewriter_pkt_info(const char *func, const char *src, const char *dst, uint32_t seq, uint32_t ack, uint32_t flag) "%s: src/dst: %s/%s p: seq/ack=%u/%u flags=%x\n" +colo_filter_rewriter_conn_offset(uint32_t offset) ": offset=%u\n" diff --git a/trace-events b/trace-events index 1a4e092418d..bd2199af32a 100644 --- a/trace-events +++ b/trace-events @@ -122,22 +122,6 @@ memory_region_subpage_write(int cpu_index, void *mr, uint64_t offset, uint64_t v memory_region_tb_read(int cpu_index, uint64_t addr, uint64_t value, unsigned size) "cpu %d addr %#"PRIx64" value %#"PRIx64" size %u" memory_region_tb_write(int cpu_index, uint64_t addr, uint64_t value, unsigned size) "cpu %d addr %#"PRIx64" value %#"PRIx64" size %u" -# net/colo.c -colo_proxy_main(const char *chr) ": %s" - -# net/colo-compare.c -colo_compare_main(const char *chr) ": %s" -colo_compare_udp_miscompare(const char *sta, int size) ": %s = %d" -colo_compare_icmp_miscompare(const char *sta, int size) ": %s = %d" -colo_compare_ip_info(int psize, const char *sta, const char *stb, int ssize, const char *stc, const char *std) "ppkt size = %d, ip_src = %s, ip_dst = %s, spkt size = %d, ip_src = %s, ip_dst = %s" -colo_old_packet_check_found(int64_t old_time) "%" PRId64 -colo_compare_miscompare(void) "" - -# net/filter-rewriter.c -colo_filter_rewriter_debug(void) "" -colo_filter_rewriter_pkt_info(const char *func, const char *src, const char *dst, uint32_t seq, uint32_t ack, uint32_t flag) "%s: src/dst: %s/%s p: seq/ack=%u/%u flags=%x\n" -colo_filter_rewriter_conn_offset(uint32_t offset) ": offset=%u\n" - ### Guest events, keep at bottom From 6a1b0f3aea09142cb8989ccffb3b74bb8808a00f Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Tue, 4 Oct 2016 14:35:42 +0100 Subject: [PATCH 632/723] trace: add trace event iterator APIs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently methods which want to iterate over trace events, do so using the trace_event_count() and trace_event_id() methods. This leaks the concept of a single ID enum to the callers. There is an alternative trace_event_pattern() method which can be used in an iteration context, but its design is stateless, so is not easy to expand it in the future. This defines a formal iterator API will provide a future- proof way of iterating over events. The iterator is also able to apply a pattern match filter to events, further removing the need for the pattern Reviewed-by: Stefan Hajnoczi Reviewed-by: Lluís Vilanova Signed-off-by: Daniel P. Berrange Message-id: 1475588159-30598-4-git-send-email-berrange@redhat.com Signed-off-by: Stefan Hajnoczi --- trace/control.c | 21 +++++++++++++++++++++ trace/control.h | 27 +++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/trace/control.c b/trace/control.c index 10b3e9babad..5a9bb5a8c75 100644 --- a/trace/control.c +++ b/trace/control.c @@ -125,6 +125,27 @@ TraceEvent *trace_event_pattern(const char *pat, TraceEvent *ev) return NULL; } +void trace_event_iter_init(TraceEventIter *iter, const char *pattern) +{ + iter->event = 0; + iter->pattern = pattern; +} + +TraceEvent *trace_event_iter_next(TraceEventIter *iter) +{ + while (iter->event < TRACE_EVENT_COUNT) { + TraceEvent *ev = &(trace_events[iter->event]); + iter->event++; + if (!iter->pattern || + pattern_glob(iter->pattern, + trace_event_get_name(ev))) { + return ev; + } + } + + return NULL; +} + void trace_list_events(void) { int i; diff --git a/trace/control.h b/trace/control.h index a22d11242e0..36d7cd23edd 100644 --- a/trace/control.h +++ b/trace/control.h @@ -13,6 +13,10 @@ #include "qemu-common.h" #include "trace/generated-events.h" +typedef struct TraceEventIter { + size_t event; + const char *pattern; +} TraceEventIter; /** * TraceEventID: @@ -25,6 +29,29 @@ */ enum TraceEventID; + +/** + * trace_event_iter_init: + * @iter: the event iterator struct + * @pattern: optional pattern to filter events on name + * + * Initialize the event iterator struct @iter, + * optionally using @pattern to filter out events + * with non-matching names. + */ +void trace_event_iter_init(TraceEventIter *iter, const char *pattern); + +/** + * trace_event_iter_next: + * @iter: the event iterator struct + * + * Get the next event, if any. When this returns NULL, + * the iterator should no longer be used. + * + * Returns: the next event, or NULL if no more events exist + */ +TraceEvent *trace_event_iter_next(TraceEventIter *iter); + /** * trace_event_id: * @id: Event identifier. From 0d4e995c7368f8bdc8845beb499b650386a38819 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Tue, 4 Oct 2016 14:35:43 +0100 Subject: [PATCH 633/723] trace: convert code to use event iterators MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This converts the HMP/QMP monitor API implementations and some internal trace control methods to use the new trace event iterator APIs. Reviewed-by: Stefan Hajnoczi Signed-off-by: Daniel P. Berrange Reviewed-by: Lluís Vilanova Message-id: 1475588159-30598-5-git-send-email-berrange@redhat.com Signed-off-by: Stefan Hajnoczi --- monitor.c | 26 +++++++------- trace/control-target.c | 8 ++--- trace/control.c | 77 ++++++++++++++++++++++-------------------- trace/qmp.c | 16 +++++---- 4 files changed, 69 insertions(+), 58 deletions(-) diff --git a/monitor.c b/monitor.c index b07f2546984..8728dd9fa5f 100644 --- a/monitor.c +++ b/monitor.c @@ -3330,13 +3330,14 @@ void info_trace_events_completion(ReadLineState *rs, int nb_args, const char *st len = strlen(str); readline_set_completion_index(rs, len); if (nb_args == 2) { - TraceEventID id; - for (id = 0; id < trace_event_count(); id++) { - const char *event_name = trace_event_get_name(trace_event_id(id)); - if (!strncmp(str, event_name, len)) { - readline_add_completion(rs, event_name); - } + TraceEventIter iter; + TraceEvent *ev; + char *pattern = g_strdup_printf("%s*", str); + trace_event_iter_init(&iter, pattern); + while ((ev = trace_event_iter_next(&iter)) != NULL) { + readline_add_completion(rs, trace_event_get_name(ev)); } + g_free(pattern); } } @@ -3347,13 +3348,14 @@ void trace_event_completion(ReadLineState *rs, int nb_args, const char *str) len = strlen(str); readline_set_completion_index(rs, len); if (nb_args == 2) { - TraceEventID id; - for (id = 0; id < trace_event_count(); id++) { - const char *event_name = trace_event_get_name(trace_event_id(id)); - if (!strncmp(str, event_name, len)) { - readline_add_completion(rs, event_name); - } + TraceEventIter iter; + TraceEvent *ev; + char *pattern = g_strdup_printf("%s*", str); + trace_event_iter_init(&iter, pattern); + while ((ev = trace_event_iter_next(&iter)) != NULL) { + readline_add_completion(rs, trace_event_get_name(ev)); } + g_free(pattern); } else if (nb_args == 3) { add_completion_option(rs, str, "on"); add_completion_option(rs, str, "off"); diff --git a/trace/control-target.c b/trace/control-target.c index 52fcce5a005..50bac4fb7d2 100644 --- a/trace/control-target.c +++ b/trace/control-target.c @@ -98,9 +98,10 @@ static bool adding_first_cpu(void) void trace_init_vcpu(CPUState *vcpu) { - TraceEvent *ev = NULL; - - while ((ev = trace_event_pattern("*", ev)) != NULL) { + TraceEventIter iter; + TraceEvent *ev; + trace_event_iter_init(&iter, NULL); + while ((ev = trace_event_iter_next(&iter)) != NULL) { if (trace_event_is_vcpu(ev) && trace_event_get_state_static(ev) && trace_event_get_state_dynamic(ev)) { @@ -118,6 +119,5 @@ void trace_init_vcpu(CPUState *vcpu) } } } - trace_guest_cpu_enter(vcpu); } diff --git a/trace/control.c b/trace/control.c index 5a9bb5a8c75..a107cc370f4 100644 --- a/trace/control.c +++ b/trace/control.c @@ -60,9 +60,10 @@ TraceEvent *trace_event_name(const char *name) { assert(name != NULL); - TraceEventID i; - for (i = 0; i < trace_event_count(); i++) { - TraceEvent *ev = trace_event_id(i); + TraceEventIter iter; + TraceEvent *ev; + trace_event_iter_init(&iter, NULL); + while ((ev = trace_event_iter_next(&iter)) != NULL) { if (strcmp(trace_event_get_name(ev), name) == 0) { return ev; } @@ -105,21 +106,18 @@ TraceEvent *trace_event_pattern(const char *pat, TraceEvent *ev) { assert(pat != NULL); - TraceEventID i; - - if (ev == NULL) { - i = -1; - } else { - i = trace_event_get_id(ev); - } - i++; - - while (i < trace_event_count()) { - TraceEvent *res = trace_event_id(i); - if (pattern_glob(pat, trace_event_get_name(res))) { - return res; + bool matched = ev ? false : true; + TraceEventIter iter; + TraceEvent *thisev; + trace_event_iter_init(&iter, pat); + while ((thisev = trace_event_iter_next(&iter)) != NULL) { + if (matched) { + return thisev; + } else { + if (ev == thisev) { + matched = true; + } } - i++; } return NULL; @@ -148,10 +146,11 @@ TraceEvent *trace_event_iter_next(TraceEventIter *iter) void trace_list_events(void) { - int i; - for (i = 0; i < trace_event_count(); i++) { - TraceEvent *res = trace_event_id(i); - fprintf(stderr, "%s\n", trace_event_get_name(res)); + TraceEventIter iter; + TraceEvent *ev; + trace_event_iter_init(&iter, NULL); + while ((ev = trace_event_iter_next(&iter)) != NULL) { + fprintf(stderr, "%s\n", trace_event_get_name(ev)); } } @@ -159,26 +158,32 @@ static void do_trace_enable_events(const char *line_buf) { const bool enable = ('-' != line_buf[0]); const char *line_ptr = enable ? line_buf : line_buf + 1; + TraceEventIter iter; + TraceEvent *ev; + bool is_pattern = trace_event_is_pattern(line_ptr); - if (trace_event_is_pattern(line_ptr)) { - TraceEvent *ev = NULL; - while ((ev = trace_event_pattern(line_ptr, ev)) != NULL) { - if (trace_event_get_state_static(ev)) { - trace_event_set_state_dynamic_init(ev, enable); + trace_event_iter_init(&iter, line_ptr); + while ((ev = trace_event_iter_next(&iter)) != NULL) { + if (!trace_event_get_state_static(ev)) { + if (!is_pattern) { + error_report("WARNING: trace event '%s' is not traceable", + line_ptr); + return; } + continue; } - } else { - TraceEvent *ev = trace_event_name(line_ptr); - if (ev == NULL) { - error_report("WARNING: trace event '%s' does not exist", - line_ptr); - } else if (!trace_event_get_state_static(ev)) { - error_report("WARNING: trace event '%s' is not traceable", - line_ptr); - } else { - trace_event_set_state_dynamic_init(ev, enable); + + /* start tracing */ + trace_event_set_state_dynamic(ev, enable); + if (!is_pattern) { + return; } } + + if (!is_pattern) { + error_report("WARNING: trace event '%s' does not exist", + line_ptr); + } } void trace_enable_events(const char *line_buf) diff --git a/trace/qmp.c b/trace/qmp.c index 11d2564e7b5..ac777d154f4 100644 --- a/trace/qmp.c +++ b/trace/qmp.c @@ -52,8 +52,10 @@ static bool check_events(bool has_vcpu, bool ignore_unavailable, bool is_pattern return true; } else { /* error for unavailable events */ - TraceEvent *ev = NULL; - while ((ev = trace_event_pattern(name, ev)) != NULL) { + TraceEventIter iter; + TraceEvent *ev; + trace_event_iter_init(&iter, name); + while ((ev = trace_event_iter_next(&iter)) != NULL) { if (!ignore_unavailable && !trace_event_get_state_static(ev)) { error_setg(errp, "event \"%s\" is disabled", trace_event_get_name(ev)); return false; @@ -69,6 +71,7 @@ TraceEventInfoList *qmp_trace_event_get_state(const char *name, { Error *err = NULL; TraceEventInfoList *events = NULL; + TraceEventIter iter; TraceEvent *ev; bool is_pattern = trace_event_is_pattern(name); CPUState *cpu; @@ -86,8 +89,8 @@ TraceEventInfoList *qmp_trace_event_get_state(const char *name, } /* Get states (all errors checked above) */ - ev = NULL; - while ((ev = trace_event_pattern(name, ev)) != NULL) { + trace_event_iter_init(&iter, name); + while ((ev = trace_event_iter_next(&iter)) != NULL) { TraceEventInfoList *elem; bool is_vcpu = trace_event_is_vcpu(ev); if (has_vcpu && !is_vcpu) { @@ -132,6 +135,7 @@ void qmp_trace_event_set_state(const char *name, bool enable, Error **errp) { Error *err = NULL; + TraceEventIter iter; TraceEvent *ev; bool is_pattern = trace_event_is_pattern(name); CPUState *cpu; @@ -150,8 +154,8 @@ void qmp_trace_event_set_state(const char *name, bool enable, } /* Apply changes (all errors checked above) */ - ev = NULL; - while ((ev = trace_event_pattern(name, ev)) != NULL) { + trace_event_iter_init(&iter, name); + while ((ev = trace_event_iter_next(&iter)) != NULL) { if (!trace_event_get_state_static(ev) || (has_vcpu && !trace_event_is_vcpu(ev))) { continue; From 599ab2f241ee6693ea0a2700210718327b346f7f Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Tue, 4 Oct 2016 14:35:44 +0100 Subject: [PATCH 634/723] trace: remove some now unused functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The trace_event_count, trace_event_id and trace_event_pattern methods are no longer required now that everything is using the iterator APIs The trace_event_set_state and trace_event_set_vcpu_state macros were also unused. Reviewed-by: Stefan Hajnoczi Reviewed-by: Lluís Vilanova Signed-off-by: Daniel P. Berrange Message-id: 1475588159-30598-6-git-send-email-berrange@redhat.com Signed-off-by: Stefan Hajnoczi --- trace/control-internal.h | 11 -------- trace/control.c | 20 -------------- trace/control.h | 59 ---------------------------------------- 3 files changed, 90 deletions(-) diff --git a/trace/control-internal.h b/trace/control-internal.h index a4e5f4aa06b..7f31e39059a 100644 --- a/trace/control-internal.h +++ b/trace/control-internal.h @@ -20,17 +20,6 @@ extern uint16_t trace_events_dstate[]; extern int trace_events_enabled_count; -static inline TraceEventID trace_event_count(void) -{ - return TRACE_EVENT_COUNT; -} - -static inline TraceEvent *trace_event_id(TraceEventID id) -{ - assert(id < trace_event_count()); - return &trace_events[id]; -} - static inline bool trace_event_is_pattern(const char *str) { assert(str != NULL); diff --git a/trace/control.c b/trace/control.c index a107cc370f4..a423f32eb09 100644 --- a/trace/control.c +++ b/trace/control.c @@ -102,26 +102,6 @@ static bool pattern_glob(const char *pat, const char *ev) } } -TraceEvent *trace_event_pattern(const char *pat, TraceEvent *ev) -{ - assert(pat != NULL); - - bool matched = ev ? false : true; - TraceEventIter iter; - TraceEvent *thisev; - trace_event_iter_init(&iter, pat); - while ((thisev = trace_event_iter_next(&iter)) != NULL) { - if (matched) { - return thisev; - } else { - if (ev == thisev) { - matched = true; - } - } - } - - return NULL; -} void trace_event_iter_init(TraceEventIter *iter, const char *pattern) { diff --git a/trace/control.h b/trace/control.h index 36d7cd23edd..10d4aba78cd 100644 --- a/trace/control.h +++ b/trace/control.h @@ -52,21 +52,6 @@ void trace_event_iter_init(TraceEventIter *iter, const char *pattern); */ TraceEvent *trace_event_iter_next(TraceEventIter *iter); -/** - * trace_event_id: - * @id: Event identifier. - * - * Get an event by its identifier. - * - * This routine has a constant cost, as opposed to trace_event_name and - * trace_event_pattern. - * - * Pre-conditions: The identifier is valid. - * - * Returns: pointer to #TraceEvent. - * - */ -static TraceEvent *trace_event_id(TraceEventID id); /** * trace_event_name: @@ -78,17 +63,6 @@ static TraceEvent *trace_event_id(TraceEventID id); */ TraceEvent *trace_event_name(const char *name); -/** - * trace_event_pattern: - * @pat: Event name pattern. - * @ev: Event to start searching from (not included). - * - * Get all events with a given name pattern. - * - * Returns: pointer to #TraceEvent or NULL if not found. - */ -TraceEvent *trace_event_pattern(const char *pat, TraceEvent *ev); - /** * trace_event_is_pattern: * @@ -96,14 +70,6 @@ TraceEvent *trace_event_pattern(const char *pat, TraceEvent *ev); */ static bool trace_event_is_pattern(const char *str); -/** - * trace_event_count: - * - * Return the number of events. - */ -static TraceEventID trace_event_count(void); - - /** * trace_event_get_id: @@ -194,31 +160,6 @@ static bool trace_event_get_state_dynamic(TraceEvent *ev); */ static bool trace_event_get_vcpu_state_dynamic(CPUState *vcpu, TraceEvent *ev); -/** - * trace_event_set_state: - * - * Set the tracing state of an event (only if possible). - */ -#define trace_event_set_state(id, state) \ - do { \ - if ((id ##_ENABLED)) { \ - TraceEvent *_e = trace_event_id(id); \ - trace_event_set_state_dynamic(_e, state); \ - } \ - } while (0) - -/** - * trace_event_set_vcpu_state: - * - * Set the tracing state of an event for the given vCPU (only if not disabled). - */ -#define trace_event_set_vcpu_state(vcpu, id, state) \ - do { \ - if ((id ##_ENABLED)) { \ - TraceEvent *_e = trace_event_id(id); \ - trace_event_set_vcpu_state_dynamic(vcpu, _e, state); \ - } \ - } while (0) /** * trace_event_set_state_dynamic: From 93977402441405055500ff0389b49f6bbac9d50b Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Tue, 4 Oct 2016 14:35:45 +0100 Subject: [PATCH 635/723] trace: remove global 'uint16 dstate[]' array MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of having a global dstate array, declare a single 'uint16 TRACE_${EVENT_NAME}_DSTATE' variable for each trace event. Record a pointer to this variable in the TraceEvent struct too. By turning trace_event_get_state_dynamic_by_id into a macro, this still hits the fast path, and cache affinity is ensured by declaring all the uint16 vars adjacent to each other. Reviewed-by: Stefan Hajnoczi Reviewed-by: Lluís Vilanova Signed-off-by: Daniel P. Berrange Message-id: 1475588159-30598-7-git-send-email-berrange@redhat.com Signed-off-by: Stefan Hajnoczi --- scripts/tracetool/__init__.py | 3 ++- scripts/tracetool/format/events_c.py | 9 +++++++-- scripts/tracetool/format/events_h.py | 3 +++ stubs/trace-control.c | 9 ++++----- trace/control-internal.h | 14 ++++---------- trace/control-target.c | 25 ++++++++++--------------- trace/control.c | 6 ------ trace/event-internal.h | 7 +++++++ 8 files changed, 37 insertions(+), 39 deletions(-) diff --git a/scripts/tracetool/__init__.py b/scripts/tracetool/__init__.py index be24039c5ea..a11f36b5d4a 100644 --- a/scripts/tracetool/__init__.py +++ b/scripts/tracetool/__init__.py @@ -265,11 +265,12 @@ def formats(self): QEMU_TRACE = "trace_%(name)s" QEMU_TRACE_TCG = QEMU_TRACE + "_tcg" + QEMU_DSTATE = "_TRACE_%(NAME)s_DSTATE" def api(self, fmt=None): if fmt is None: fmt = Event.QEMU_TRACE - return fmt % {"name": self.name} + return fmt % {"name": self.name, "NAME": self.name.upper()} def transform(self, *trans): """Return a new Event with transformed Arguments.""" diff --git a/scripts/tracetool/format/events_c.py b/scripts/tracetool/format/events_c.py index 40120632836..ef873fa137c 100644 --- a/scripts/tracetool/format/events_c.py +++ b/scripts/tracetool/format/events_c.py @@ -25,6 +25,9 @@ def generate(events, backend): '#include "trace/control.h"', '') + for e in events: + out('uint16_t %s;' % e.api(e.QEMU_DSTATE)) + out('TraceEvent trace_events[TRACE_EVENT_COUNT] = {') for e in events: @@ -34,11 +37,13 @@ def generate(events, backend): vcpu_id = "TRACE_VCPU_EVENT_COUNT" out(' { .id = %(id)s, .vcpu_id = %(vcpu_id)s,' ' .name = \"%(name)s\",' - ' .sstate = %(sstate)s },', + ' .sstate = %(sstate)s,', + ' .dstate = &%(dstate)s, }, ', id = "TRACE_" + e.name.upper(), vcpu_id = vcpu_id, name = e.name, - sstate = "TRACE_%s_ENABLED" % e.name.upper()) + sstate = "TRACE_%s_ENABLED" % e.name.upper(), + dstate = e.api(e.QEMU_DSTATE)) out('};', '') diff --git a/scripts/tracetool/format/events_h.py b/scripts/tracetool/format/events_h.py index a9da60b7fa7..03417de0ec7 100644 --- a/scripts/tracetool/format/events_h.py +++ b/scripts/tracetool/format/events_h.py @@ -32,6 +32,9 @@ def generate(events, backend): out(' TRACE_EVENT_COUNT', '} TraceEventID;') + for e in events: + out('extern uint16_t %s;' % e.api(e.QEMU_DSTATE)) + # per-vCPU event identifiers out('typedef enum {') diff --git a/stubs/trace-control.c b/stubs/trace-control.c index f765a020188..7f856e5c24e 100644 --- a/stubs/trace-control.c +++ b/stubs/trace-control.c @@ -18,22 +18,21 @@ void trace_event_set_state_dynamic_init(TraceEvent *ev, bool state) void trace_event_set_state_dynamic(TraceEvent *ev, bool state) { - TraceEventID id; bool state_pre; assert(trace_event_get_state_static(ev)); - id = trace_event_get_id(ev); + /* * We ignore the "vcpu" property here, since there's no target code. Then * dstate can only be 1 or 0. */ - state_pre = trace_events_dstate[id]; + state_pre = *(ev->dstate); if (state_pre != state) { if (state) { trace_events_enabled_count++; - trace_events_dstate[id] = 1; + *(ev->dstate) = 1; } else { trace_events_enabled_count--; - trace_events_dstate[id] = 0; + *(ev->dstate) = 0; } } } diff --git a/trace/control-internal.h b/trace/control-internal.h index 7f31e39059a..a6d8d2e7c9b 100644 --- a/trace/control-internal.h +++ b/trace/control-internal.h @@ -16,7 +16,6 @@ extern TraceEvent trace_events[]; -extern uint16_t trace_events_dstate[]; extern int trace_events_enabled_count; @@ -54,18 +53,13 @@ static inline bool trace_event_get_state_static(TraceEvent *ev) return ev->sstate; } -static inline bool trace_event_get_state_dynamic_by_id(TraceEventID id) -{ - /* it's on fast path, avoid consistency checks (asserts) */ - return unlikely(trace_events_enabled_count) && trace_events_dstate[id]; -} +/* it's on fast path, avoid consistency checks (asserts) */ +#define trace_event_get_state_dynamic_by_id(id) \ + (unlikely(trace_events_enabled_count) && _ ## id ## _DSTATE) static inline bool trace_event_get_state_dynamic(TraceEvent *ev) { - TraceEventID id; - assert(trace_event_get_state_static(ev)); - id = trace_event_get_id(ev); - return trace_event_get_state_dynamic_by_id(id); + return unlikely(trace_events_enabled_count) && *ev->dstate; } static inline bool trace_event_get_vcpu_state_dynamic_by_vcpu_id(CPUState *vcpu, diff --git a/trace/control-target.c b/trace/control-target.c index 50bac4fb7d2..3b559414145 100644 --- a/trace/control-target.c +++ b/trace/control-target.c @@ -16,21 +16,20 @@ void trace_event_set_state_dynamic_init(TraceEvent *ev, bool state) { - TraceEventID id = trace_event_get_id(ev); bool state_pre; assert(trace_event_get_state_static(ev)); /* * We ignore the "vcpu" property here, since no vCPUs have been created * yet. Then dstate can only be 1 or 0. */ - state_pre = trace_events_dstate[id]; + state_pre = *ev->dstate; if (state_pre != state) { if (state) { trace_events_enabled_count++; - trace_events_dstate[id] = 1; + *ev->dstate = 1; } else { trace_events_enabled_count--; - trace_events_dstate[id] = 0; + *ev->dstate = 0; } } } @@ -45,15 +44,14 @@ void trace_event_set_state_dynamic(TraceEvent *ev, bool state) } } else { /* Without the "vcpu" property, dstate can only be 1 or 0 */ - TraceEventID id = trace_event_get_id(ev); - bool state_pre = trace_events_dstate[id]; + bool state_pre = *ev->dstate; if (state_pre != state) { if (state) { trace_events_enabled_count++; - trace_events_dstate[id] = 1; + *ev->dstate = 1; } else { trace_events_enabled_count--; - trace_events_dstate[id] = 0; + *ev->dstate = 0; } } } @@ -62,23 +60,21 @@ void trace_event_set_state_dynamic(TraceEvent *ev, bool state) void trace_event_set_vcpu_state_dynamic(CPUState *vcpu, TraceEvent *ev, bool state) { - TraceEventID id; TraceEventVCPUID vcpu_id; bool state_pre; assert(trace_event_get_state_static(ev)); assert(trace_event_is_vcpu(ev)); - id = trace_event_get_id(ev); vcpu_id = trace_event_get_vcpu_id(ev); state_pre = test_bit(vcpu_id, vcpu->trace_dstate); if (state_pre != state) { if (state) { trace_events_enabled_count++; set_bit(vcpu_id, vcpu->trace_dstate); - trace_events_dstate[id]++; + (*ev->dstate)++; } else { trace_events_enabled_count--; clear_bit(vcpu_id, vcpu->trace_dstate); - trace_events_dstate[id]--; + (*ev->dstate)--; } } } @@ -105,12 +101,11 @@ void trace_init_vcpu(CPUState *vcpu) if (trace_event_is_vcpu(ev) && trace_event_get_state_static(ev) && trace_event_get_state_dynamic(ev)) { - TraceEventID id = trace_event_get_id(ev); if (adding_first_cpu()) { /* check preconditions */ - assert(trace_events_dstate[id] == 1); + assert(*ev->dstate == 1); /* disable early-init state ... */ - trace_events_dstate[id] = 0; + *ev->dstate = 0; trace_events_enabled_count--; /* ... and properly re-enable */ trace_event_set_vcpu_state_dynamic(vcpu, ev, true); diff --git a/trace/control.c b/trace/control.c index a423f32eb09..e57f2d3f05b 100644 --- a/trace/control.c +++ b/trace/control.c @@ -28,12 +28,6 @@ #include "monitor/monitor.h" int trace_events_enabled_count; -/* - * Interpretation depends on wether the event has the 'vcpu' property: - * - false: Boolean value indicating whether the event is active. - * - true : Integral counting the number of vCPUs that have this event enabled. - */ -uint16_t trace_events_dstate[TRACE_EVENT_COUNT]; QemuOptsList qemu_trace_opts = { .name = "trace", diff --git a/trace/event-internal.h b/trace/event-internal.h index 074faf68624..4a98d09153b 100644 --- a/trace/event-internal.h +++ b/trace/event-internal.h @@ -19,6 +19,12 @@ * @vcpu_id: Unique per-vCPU event identifier. * @name: Event name. * @sstate: Static tracing state. + * @dstate: Dynamic tracing state + * + * Interpretation of @dstate depends on whether the event has the 'vcpu' + * property: + * - false: Boolean value indicating whether the event is active. + * - true : Integral counting the number of vCPUs that have this event enabled. * * Opaque generic description of a tracing event. */ @@ -27,6 +33,7 @@ typedef struct TraceEvent { TraceEventVCPUID vcpu_id; const char * name; const bool sstate; + uint16_t *dstate; } TraceEvent; void trace_event_set_state_dynamic_init(TraceEvent *ev, bool state); From 99672c7167cdee40e7d81e3c8b691b19ae408816 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Tue, 4 Oct 2016 14:35:46 +0100 Subject: [PATCH 636/723] trace: remove duplicate control.h includes in generated-tracers.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The format/h.py file adds an include for control.h to generated-tracers.h. ftrace, log and syslog, then add more duplicate includes for control.h. Reviewed-by: Stefan Hajnoczi Reviewed-by: Lluís Vilanova Signed-off-by: Daniel P. Berrange Message-id: 1475588159-30598-8-git-send-email-berrange@redhat.com Signed-off-by: Stefan Hajnoczi --- scripts/tracetool/backend/ftrace.py | 1 - scripts/tracetool/backend/log.py | 3 +-- scripts/tracetool/backend/syslog.py | 1 - 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/scripts/tracetool/backend/ftrace.py b/scripts/tracetool/backend/ftrace.py index 80dcf30478a..4b83b44f3cd 100644 --- a/scripts/tracetool/backend/ftrace.py +++ b/scripts/tracetool/backend/ftrace.py @@ -21,7 +21,6 @@ def generate_h_begin(events): out('#include "trace/ftrace.h"', - '#include "trace/control.h"', '') diff --git a/scripts/tracetool/backend/log.py b/scripts/tracetool/backend/log.py index b3ff0640118..426bb6e2a25 100644 --- a/scripts/tracetool/backend/log.py +++ b/scripts/tracetool/backend/log.py @@ -20,8 +20,7 @@ def generate_h_begin(events): - out('#include "trace/control.h"', - '#include "qemu/log.h"', + out('#include "qemu/log.h"', '') diff --git a/scripts/tracetool/backend/syslog.py b/scripts/tracetool/backend/syslog.py index 89019bc7592..5f693bdf4df 100644 --- a/scripts/tracetool/backend/syslog.py +++ b/scripts/tracetool/backend/syslog.py @@ -21,7 +21,6 @@ def generate_h_begin(events): out('#include ', - '#include "trace/control.h"', '') From a82417b50bc80310b6294ae2698303c3d67f900c Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Tue, 4 Oct 2016 14:35:47 +0100 Subject: [PATCH 637/723] trace: break circular dependency in event-internal.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently event-internal.h includes generated-events.h, while generated-events.h includes event-internal.h causing a circular dependency. event-internal.h requires that the content of generated-events.h comes first, so that it can see the typedefs for TraceEventID and TraceEventVCPUID. Switching the TraceEvent struct to use uint32_t for the two ID fields removes the dependency on the typedef, allowing events-internal.h to be a self-contained header. This will then let the patch following this move event-internal.h to the top of generated-events.h, so we can expose TraceEvent struct variables in generated-events.h Reviewed-by: Stefan Hajnoczi Reviewed-by: Lluís Vilanova Signed-off-by: Daniel P. Berrange Message-id: 1475588159-30598-9-git-send-email-berrange@redhat.com Signed-off-by: Stefan Hajnoczi --- trace/event-internal.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/trace/event-internal.h b/trace/event-internal.h index 4a98d09153b..58f05517457 100644 --- a/trace/event-internal.h +++ b/trace/event-internal.h @@ -10,9 +10,6 @@ #ifndef TRACE__EVENT_INTERNAL_H #define TRACE__EVENT_INTERNAL_H -#include "trace/generated-events.h" - - /** * TraceEvent: * @id: Unique event identifier. @@ -29,8 +26,8 @@ * Opaque generic description of a tracing event. */ typedef struct TraceEvent { - TraceEventID id; - TraceEventVCPUID vcpu_id; + uint32_t id; + uint32_t vcpu_id; const char * name; const bool sstate; uint16_t *dstate; From 79218be42b835cbc7bd1b0fbd07d115add6e7605 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Tue, 4 Oct 2016 14:35:48 +0100 Subject: [PATCH 638/723] trace: give each trace event a named TraceEvent struct MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we only expose a TraceEvent array, which must be indexed via the TraceEventID enum constants. This changes the generator to expose a named TraceEvent instance for each event, with an _EVENT suffix. Reviewed-by: Lluís Vilanova Reviewed-by: Stefan Hajnoczi Signed-off-by: Daniel P. Berrange Message-id: 1475588159-30598-10-git-send-email-berrange@redhat.com Signed-off-by: Stefan Hajnoczi --- scripts/tracetool/__init__.py | 1 + scripts/tracetool/format/events_c.py | 19 +++++++++++++------ scripts/tracetool/format/events_h.py | 11 ++++++++--- trace/control-internal.h | 2 +- trace/control.c | 2 +- 5 files changed, 24 insertions(+), 11 deletions(-) diff --git a/scripts/tracetool/__init__.py b/scripts/tracetool/__init__.py index a11f36b5d4a..dc93416e9d4 100644 --- a/scripts/tracetool/__init__.py +++ b/scripts/tracetool/__init__.py @@ -266,6 +266,7 @@ def formats(self): QEMU_TRACE = "trace_%(name)s" QEMU_TRACE_TCG = QEMU_TRACE + "_tcg" QEMU_DSTATE = "_TRACE_%(NAME)s_DSTATE" + QEMU_EVENT = "_TRACE_%(NAME)s_EVENT" def api(self, fmt=None): if fmt is None: diff --git a/scripts/tracetool/format/events_c.py b/scripts/tracetool/format/events_c.py index ef873fa137c..a97054fd581 100644 --- a/scripts/tracetool/format/events_c.py +++ b/scripts/tracetool/format/events_c.py @@ -28,22 +28,29 @@ def generate(events, backend): for e in events: out('uint16_t %s;' % e.api(e.QEMU_DSTATE)) - out('TraceEvent trace_events[TRACE_EVENT_COUNT] = {') - for e in events: if "vcpu" in e.properties: vcpu_id = "TRACE_VCPU_" + e.name.upper() else: vcpu_id = "TRACE_VCPU_EVENT_COUNT" - out(' { .id = %(id)s, .vcpu_id = %(vcpu_id)s,' - ' .name = \"%(name)s\",' - ' .sstate = %(sstate)s,', - ' .dstate = &%(dstate)s, }, ', + out('TraceEvent %(event)s = {', + ' .id = %(id)s,', + ' .vcpu_id = %(vcpu_id)s,', + ' .name = \"%(name)s\",', + ' .sstate = %(sstate)s,', + ' .dstate = &%(dstate)s ', + '};', + event = e.api(e.QEMU_EVENT), id = "TRACE_" + e.name.upper(), vcpu_id = vcpu_id, name = e.name, sstate = "TRACE_%s_ENABLED" % e.name.upper(), dstate = e.api(e.QEMU_DSTATE)) + out('TraceEvent *trace_events[TRACE_EVENT_COUNT] = {') + + for e in events: + out(' &%(event)s,', event = e.api(e.QEMU_EVENT)) + out('};', '') diff --git a/scripts/tracetool/format/events_h.py b/scripts/tracetool/format/events_h.py index 03417de0ec7..80a66c57d57 100644 --- a/scripts/tracetool/format/events_h.py +++ b/scripts/tracetool/format/events_h.py @@ -21,7 +21,13 @@ def generate(events, backend): '', '#ifndef TRACE__GENERATED_EVENTS_H', '#define TRACE__GENERATED_EVENTS_H', - '') + '', + '#include "trace/event-internal.h"', + ) + + for e in events: + out('extern TraceEvent %(event)s;', + event = e.api(e.QEMU_EVENT)) # event identifiers out('typedef enum {') @@ -58,6 +64,5 @@ def generate(events, backend): enabled=enabled) out('#define TRACE_%s_ENABLED %d' % (e.name.upper(), enabled)) - out('#include "trace/event-internal.h"', - '', + out('', '#endif /* TRACE__GENERATED_EVENTS_H */') diff --git a/trace/control-internal.h b/trace/control-internal.h index a6d8d2e7c9b..808f85dc06d 100644 --- a/trace/control-internal.h +++ b/trace/control-internal.h @@ -15,7 +15,7 @@ #include "qom/cpu.h" -extern TraceEvent trace_events[]; +extern TraceEvent *trace_events[]; extern int trace_events_enabled_count; diff --git a/trace/control.c b/trace/control.c index e57f2d3f05b..9035846b26f 100644 --- a/trace/control.c +++ b/trace/control.c @@ -106,7 +106,7 @@ void trace_event_iter_init(TraceEventIter *iter, const char *pattern) TraceEvent *trace_event_iter_next(TraceEventIter *iter) { while (iter->event < TRACE_EVENT_COUNT) { - TraceEvent *ev = &(trace_events[iter->event]); + TraceEvent *ev = trace_events[iter->event]; iter->event++; if (!iter->pattern || pattern_glob(iter->pattern, From ef4c9fc8542e06b1d567172c04b0c0377c7ab0c5 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Tue, 4 Oct 2016 14:35:49 +0100 Subject: [PATCH 639/723] trace: remove the TraceEventID and TraceEventVCPUID enums MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The TraceEventID and TraceEventVCPUID enums constants are no longer actually used for anything critical. The TRACE_EVENT_COUNT limit is used to determine the size of the TraceEvents array, and can be removed if we just NULL terminate the array instead. The TRACE_VCPU_EVENT_COUNT limit is used as a magic value for marking non-vCPU events, and also for declaring the size of the trace dstate mask in the CPUState struct. The former usage can be replaced by a dedicated constant TRACE_EVENT_VCPU_NONE, defined as (uint32_t)-1. For the latter usage, we can simply define a constant for the number of VCPUs, avoiding the need for the full enum. The only other usages of the enum values can be replaced by accesing the id/vcpu_id fields via the named TraceEvent structs. Reviewed-by: Lluís Vilanova Reviewed-by: Stefan Hajnoczi Signed-off-by: Daniel P. Berrange Message-id: 1475588159-30598-11-git-send-email-berrange@redhat.com Signed-off-by: Stefan Hajnoczi --- scripts/tracetool/backend/simple.py | 4 ++-- scripts/tracetool/format/events_c.py | 16 +++++++++----- scripts/tracetool/format/events_h.py | 19 ++--------------- scripts/tracetool/format/h.py | 3 +-- trace/control-internal.h | 19 +++++++++-------- trace/control-target.c | 2 +- trace/control.c | 2 +- trace/control.h | 32 ++++++++-------------------- trace/event-internal.h | 6 ++++++ trace/simple.c | 8 +++---- trace/simple.h | 2 +- 11 files changed, 48 insertions(+), 65 deletions(-) diff --git a/scripts/tracetool/backend/simple.py b/scripts/tracetool/backend/simple.py index 1bccada63d8..1114e3550ba 100644 --- a/scripts/tracetool/backend/simple.py +++ b/scripts/tracetool/backend/simple.py @@ -80,11 +80,11 @@ def generate_c(event): ' return;', ' }', '', - ' if (trace_record_start(&rec, %(event_id)s, %(size_str)s)) {', + ' if (trace_record_start(&rec, %(event_obj)s.id, %(size_str)s)) {', ' return; /* Trace Buffer Full, Event Dropped ! */', ' }', cond=cond, - event_id=event_id, + event_obj=event.api(event.QEMU_EVENT), size_str=sizestr) if len(event.args) > 0: diff --git a/scripts/tracetool/format/events_c.py b/scripts/tracetool/format/events_c.py index a97054fd581..40ae39568ec 100644 --- a/scripts/tracetool/format/events_c.py +++ b/scripts/tracetool/format/events_c.py @@ -28,11 +28,16 @@ def generate(events, backend): for e in events: out('uint16_t %s;' % e.api(e.QEMU_DSTATE)) + next_id = 0 + next_vcpu_id = 0 for e in events: + id = next_id + next_id += 1 if "vcpu" in e.properties: - vcpu_id = "TRACE_VCPU_" + e.name.upper() + vcpu_id = next_vcpu_id + next_vcpu_id += 1 else: - vcpu_id = "TRACE_VCPU_EVENT_COUNT" + vcpu_id = "TRACE_VCPU_EVENT_NONE" out('TraceEvent %(event)s = {', ' .id = %(id)s,', ' .vcpu_id = %(vcpu_id)s,', @@ -41,16 +46,17 @@ def generate(events, backend): ' .dstate = &%(dstate)s ', '};', event = e.api(e.QEMU_EVENT), - id = "TRACE_" + e.name.upper(), + id = id, vcpu_id = vcpu_id, name = e.name, sstate = "TRACE_%s_ENABLED" % e.name.upper(), dstate = e.api(e.QEMU_DSTATE)) - out('TraceEvent *trace_events[TRACE_EVENT_COUNT] = {') + out('TraceEvent *trace_events[] = {') for e in events: out(' &%(event)s,', event = e.api(e.QEMU_EVENT)) - out('};', + out(' NULL,', + '};', '') diff --git a/scripts/tracetool/format/events_h.py b/scripts/tracetool/format/events_h.py index 80a66c57d57..ca6d7305197 100644 --- a/scripts/tracetool/format/events_h.py +++ b/scripts/tracetool/format/events_h.py @@ -29,27 +29,12 @@ def generate(events, backend): out('extern TraceEvent %(event)s;', event = e.api(e.QEMU_EVENT)) - # event identifiers - out('typedef enum {') - - for e in events: - out(' TRACE_%s,' % e.name.upper()) - - out(' TRACE_EVENT_COUNT', - '} TraceEventID;') - for e in events: out('extern uint16_t %s;' % e.api(e.QEMU_DSTATE)) - # per-vCPU event identifiers - out('typedef enum {') - - for e in events: - if "vcpu" in e.properties: - out(' TRACE_VCPU_%s,' % e.name.upper()) + numvcpu = len([e for e in events if "vcpu" in e.properties]) - out(' TRACE_VCPU_EVENT_COUNT', - '} TraceEventVCPUID;') + out("#define TRACE_VCPU_EVENT_COUNT %d" % numvcpu) # static state for e in events: diff --git a/scripts/tracetool/format/h.py b/scripts/tracetool/format/h.py index 3763e9aecbc..64a6680fdce 100644 --- a/scripts/tracetool/format/h.py +++ b/scripts/tracetool/format/h.py @@ -32,8 +32,7 @@ def generate(events, backend): if "vcpu" in e.properties: trace_cpu = next(iter(e.args))[1] cond = "trace_event_get_vcpu_state(%(cpu)s,"\ - " TRACE_%(id)s,"\ - " TRACE_VCPU_%(id)s)"\ + " TRACE_%(id)s)"\ % dict( cpu=trace_cpu, id=e.name.upper()) diff --git a/trace/control-internal.h b/trace/control-internal.h index 808f85dc06d..9abbc96bcb4 100644 --- a/trace/control-internal.h +++ b/trace/control-internal.h @@ -25,20 +25,20 @@ static inline bool trace_event_is_pattern(const char *str) return strchr(str, '*') != NULL; } -static inline TraceEventID trace_event_get_id(TraceEvent *ev) +static inline uint32_t trace_event_get_id(TraceEvent *ev) { assert(ev != NULL); return ev->id; } -static inline TraceEventVCPUID trace_event_get_vcpu_id(TraceEvent *ev) +static inline uint32_t trace_event_get_vcpu_id(TraceEvent *ev) { return ev->vcpu_id; } static inline bool trace_event_is_vcpu(TraceEvent *ev) { - return ev->vcpu_id != TRACE_VCPU_EVENT_COUNT; + return ev->vcpu_id != TRACE_VCPU_EVENT_NONE; } static inline const char * trace_event_get_name(TraceEvent *ev) @@ -62,12 +62,13 @@ static inline bool trace_event_get_state_dynamic(TraceEvent *ev) return unlikely(trace_events_enabled_count) && *ev->dstate; } -static inline bool trace_event_get_vcpu_state_dynamic_by_vcpu_id(CPUState *vcpu, - TraceEventVCPUID id) +static inline bool +trace_event_get_vcpu_state_dynamic_by_vcpu_id(CPUState *vcpu, + uint32_t vcpu_id) { /* it's on fast path, avoid consistency checks (asserts) */ if (unlikely(trace_events_enabled_count)) { - return test_bit(id, vcpu->trace_dstate); + return test_bit(vcpu_id, vcpu->trace_dstate); } else { return false; } @@ -76,10 +77,10 @@ static inline bool trace_event_get_vcpu_state_dynamic_by_vcpu_id(CPUState *vcpu, static inline bool trace_event_get_vcpu_state_dynamic(CPUState *vcpu, TraceEvent *ev) { - TraceEventVCPUID id; + uint32_t vcpu_id; assert(trace_event_is_vcpu(ev)); - id = trace_event_get_vcpu_id(ev); - return trace_event_get_vcpu_state_dynamic_by_vcpu_id(vcpu, id); + vcpu_id = trace_event_get_vcpu_id(ev); + return trace_event_get_vcpu_state_dynamic_by_vcpu_id(vcpu, vcpu_id); } #endif /* TRACE__CONTROL_INTERNAL_H */ diff --git a/trace/control-target.c b/trace/control-target.c index 3b559414145..7ebf6e0bcb9 100644 --- a/trace/control-target.c +++ b/trace/control-target.c @@ -60,7 +60,7 @@ void trace_event_set_state_dynamic(TraceEvent *ev, bool state) void trace_event_set_vcpu_state_dynamic(CPUState *vcpu, TraceEvent *ev, bool state) { - TraceEventVCPUID vcpu_id; + uint32_t vcpu_id; bool state_pre; assert(trace_event_get_state_static(ev)); assert(trace_event_is_vcpu(ev)); diff --git a/trace/control.c b/trace/control.c index 9035846b26f..6b32511d60a 100644 --- a/trace/control.c +++ b/trace/control.c @@ -105,7 +105,7 @@ void trace_event_iter_init(TraceEventIter *iter, const char *pattern) TraceEvent *trace_event_iter_next(TraceEventIter *iter) { - while (iter->event < TRACE_EVENT_COUNT) { + while (trace_events[iter->event] != NULL) { TraceEvent *ev = trace_events[iter->event]; iter->event++; if (!iter->pattern || diff --git a/trace/control.h b/trace/control.h index 10d4aba78cd..cccd2a295eb 100644 --- a/trace/control.h +++ b/trace/control.h @@ -18,17 +18,6 @@ typedef struct TraceEventIter { const char *pattern; } TraceEventIter; -/** - * TraceEventID: - * - * Unique tracing event identifier. - * - * These are named as 'TRACE_${EVENT_NAME}'. - * - * See also: "trace/generated-events.h" - */ -enum TraceEventID; - /** * trace_event_iter_init: @@ -76,17 +65,17 @@ static bool trace_event_is_pattern(const char *str); * * Get the identifier of an event. */ -static TraceEventID trace_event_get_id(TraceEvent *ev); +static uint32_t trace_event_get_id(TraceEvent *ev); /** * trace_event_get_vcpu_id: * * Get the per-vCPU identifier of an event. * - * Special value #TRACE_VCPU_EVENT_COUNT means the event is not vCPU-specific + * Special value #TRACE_VCPU_EVENT_NONE means the event is not vCPU-specific * (does not have the "vcpu" property). */ -static TraceEventVCPUID trace_event_get_vcpu_id(TraceEvent *ev); +static uint32_t trace_event_get_vcpu_id(TraceEvent *ev); /** * trace_event_is_vcpu: @@ -104,14 +93,12 @@ static const char * trace_event_get_name(TraceEvent *ev); /** * trace_event_get_state: - * @id: Event identifier. + * @id: Event identifier name. * * Get the tracing state of an event (both static and dynamic). * * If the event has the disabled property, the check will have no performance * impact. - * - * As a down side, you must always use an immediate #TraceEventID value. */ #define trace_event_get_state(id) \ ((id ##_ENABLED) && trace_event_get_state_dynamic_by_id(id)) @@ -119,19 +106,18 @@ static const char * trace_event_get_name(TraceEvent *ev); /** * trace_event_get_vcpu_state: * @vcpu: Target vCPU. - * @id: Event identifier (TraceEventID). - * @vcpu_id: Per-vCPU event identifier (TraceEventVCPUID). + * @id: Event identifier name. * * Get the tracing state of an event (both static and dynamic) for the given * vCPU. * * If the event has the disabled property, the check will have no performance * impact. - * - * As a down side, you must always use an immediate #TraceEventID value. */ -#define trace_event_get_vcpu_state(vcpu, id, vcpu_id) \ - ((id ##_ENABLED) && trace_event_get_vcpu_state_dynamic_by_vcpu_id(vcpu, vcpu_id)) +#define trace_event_get_vcpu_state(vcpu, id) \ + ((id ##_ENABLED) && \ + trace_event_get_vcpu_state_dynamic_by_vcpu_id( \ + vcpu, _ ## id ## _EVENT.vcpu_id)) /** * trace_event_get_state_static: diff --git a/trace/event-internal.h b/trace/event-internal.h index 58f05517457..f63500b37e6 100644 --- a/trace/event-internal.h +++ b/trace/event-internal.h @@ -10,6 +10,12 @@ #ifndef TRACE__EVENT_INTERNAL_H #define TRACE__EVENT_INTERNAL_H +/* + * Special value for TraceEvent.vcpu_id field to indicate + * that the event is not VCPU specific + */ +#define TRACE_VCPU_EVENT_NONE ((uint32_t)-1) + /** * TraceEvent: * @id: Unique event identifier. diff --git a/trace/simple.c b/trace/simple.c index 2f09dafcbc2..2ec32e159c7 100644 --- a/trace/simple.c +++ b/trace/simple.c @@ -17,8 +17,8 @@ #include "trace/control.h" #include "trace/simple.h" -/** Trace file header event ID */ -#define HEADER_EVENT_ID (~(uint64_t)0) /* avoids conflicting with TraceEventIDs */ +/** Trace file header event ID, picked to avoid conflict with real event IDs */ +#define HEADER_EVENT_ID (~(uint64_t)0) /** Trace file magic number */ #define HEADER_MAGIC 0xf2b177cb0aa429b4ULL @@ -58,7 +58,7 @@ static char *trace_file_name; /* * Trace buffer entry */ typedef struct { - uint64_t event; /* TraceEventID */ + uint64_t event; /* event ID value */ uint64_t timestamp_ns; uint32_t length; /* in bytes */ uint32_t pid; @@ -202,7 +202,7 @@ void trace_record_write_str(TraceBufferRecord *rec, const char *s, uint32_t slen rec->rec_off = write_to_buffer(rec->rec_off, (void*)s, slen); } -int trace_record_start(TraceBufferRecord *rec, TraceEventID event, size_t datasize) +int trace_record_start(TraceBufferRecord *rec, uint32_t event, size_t datasize) { unsigned int idx, rec_off, old_idx, new_idx; uint32_t rec_len = sizeof(TraceRecord) + datasize; diff --git a/trace/simple.h b/trace/simple.h index 1e7de455758..17ce47260f5 100644 --- a/trace/simple.h +++ b/trace/simple.h @@ -33,7 +33,7 @@ typedef struct { * * @arglen number of bytes required for arguments */ -int trace_record_start(TraceBufferRecord *rec, TraceEventID id, size_t arglen); +int trace_record_start(TraceBufferRecord *rec, uint32_t id, size_t arglen); /** * Append a 64-bit argument to a trace record From 7f1b588f20d027730676e627713ae3bbf6baab04 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Tue, 4 Oct 2016 14:35:50 +0100 Subject: [PATCH 640/723] trace: emit name <-> ID mapping in simpletrace header Currently simpletrace assumes that events are given IDs starting from 0, based on the order in which they appear in the trace-events file, with no gaps. When the trace-events file is split up, this assumption becomes problematic. To deal with this, extend the simpletrace format so that it outputs a table of event name <-> ID mappings. That will allow QEMU to assign arbitrary IDs to events without breaking simpletrace parsing. The v3 simple trace format was FILE HEADER EVENT TRACE RECORD 0 EVENT TRACE RECORD 1 ... EVENT TRACE RECORD N The v4 simple trace format is now FILE HEADER EVENT MAPPING RECORD 0 EVENT MAPPING RECORD 1 ... EVENT MAPPING RECORD M EVENT TRACE RECORD RECORD 0 EVENT TRACE RECORD RECORD 1 ... EVENT TRACE RECORD N Although this shows all the mapping records being emitted upfront, this is not required by the format. While the main simpletrace backend will emit all mappings at startup, the systemtap simpletrace.stp script will emit the mappings at first use. eg FILE HEADER ... EVENT MAPPING RECORD 0 EVENT TRACE RECORD RECORD 0 EVENT TRACE RECORD RECORD 1 EVENT MAPPING RECORD 1 EVENT TRACE RECORD RECORD 2 ... EVENT TRACE RECORD N This is more space efficient given that most trace records only include a subset of events. In modifying the systemtap simpletrace code, a 'begin' probe was added to emit the trace event header, so you no longer need to add '--no-header' when running simpletrace.py for systemtap generated trace files. Signed-off-by: Daniel P. Berrange Message-id: 1475588159-30598-12-git-send-email-berrange@redhat.com Signed-off-by: Stefan Hajnoczi --- scripts/simpletrace.py | 50 ++++++++++++++------ scripts/tracetool/format/simpletrace_stap.py | 24 +++++++++- trace/simple.c | 33 ++++++++++++- 3 files changed, 89 insertions(+), 18 deletions(-) diff --git a/scripts/simpletrace.py b/scripts/simpletrace.py index 3916c6d14ae..f40467a7946 100755 --- a/scripts/simpletrace.py +++ b/scripts/simpletrace.py @@ -19,6 +19,9 @@ header_magic = 0xf2b177cb0aa429b4 dropped_event_id = 0xfffffffffffffffe +record_type_mapping = 0 +record_type_event = 1 + log_header_fmt = '=QQQ' rec_header_fmt = '=QQII' @@ -30,14 +33,16 @@ def read_header(fobj, hfmt): return None return struct.unpack(hfmt, hdr) -def get_record(edict, rechdr, fobj): - """Deserialize a trace record from a file into a tuple (event_num, timestamp, pid, arg1, ..., arg6).""" +def get_record(edict, idtoname, rechdr, fobj): + """Deserialize a trace record from a file into a tuple + (name, timestamp, pid, arg1, ..., arg6).""" if rechdr is None: return None - rec = (rechdr[0], rechdr[1], rechdr[3]) if rechdr[0] != dropped_event_id: event_id = rechdr[0] - event = edict[event_id] + name = idtoname[event_id] + rec = (name, rechdr[1], rechdr[3]) + event = edict[name] for type, name in event.args: if is_string(type): l = fobj.read(4) @@ -48,15 +53,22 @@ def get_record(edict, rechdr, fobj): (value,) = struct.unpack('=Q', fobj.read(8)) rec = rec + (value,) else: + rec = ("dropped", rechdr[1], rechdr[3]) (value,) = struct.unpack('=Q', fobj.read(8)) rec = rec + (value,) return rec +def get_mapping(fobj): + (event_id, ) = struct.unpack('=Q', fobj.read(8)) + (len, ) = struct.unpack('=L', fobj.read(4)) + name = fobj.read(len) + + return (event_id, name) -def read_record(edict, fobj): +def read_record(edict, idtoname, fobj): """Deserialize a trace record from a file into a tuple (event_num, timestamp, pid, arg1, ..., arg6).""" rechdr = read_header(fobj, rec_header_fmt) - return get_record(edict, rechdr, fobj) # return tuple of record elements + return get_record(edict, idtoname, rechdr, fobj) def read_trace_header(fobj): """Read and verify trace file header""" @@ -67,20 +79,30 @@ def read_trace_header(fobj): raise ValueError('Not a valid trace file!') log_version = header[2] - if log_version not in [0, 2, 3]: + if log_version not in [0, 2, 3, 4]: raise ValueError('Unknown version of tracelog format!') - if log_version != 3: + if log_version != 4: raise ValueError('Log format %d not supported with this QEMU release!' % log_version) def read_trace_records(edict, fobj): """Deserialize trace records from a file, yielding record tuples (event_num, timestamp, pid, arg1, ..., arg6).""" + idtoname = { + dropped_event_id: "dropped" + } while True: - rec = read_record(edict, fobj) - if rec is None: + t = fobj.read(8) + if len(t) == 0: break - yield rec + (rectype, ) = struct.unpack('=Q', t) + if rectype == record_type_mapping: + event_id, name = get_mapping(fobj) + idtoname[event_id] = name + else: + rec = read_record(edict, idtoname, fobj) + + yield rec class Analyzer(object): """A trace file analyzer which processes trace records. @@ -115,10 +137,10 @@ def process(events, log, analyzer, read_header=True): read_trace_header(log) dropped_event = Event.build("Dropped_Event(uint64_t num_events_dropped)") - edict = {dropped_event_id: dropped_event} + edict = {"dropped": dropped_event} - for num, event in enumerate(events): - edict[num] = event + for event in events: + edict[event.name] = event def build_fn(analyzer, event): if isinstance(event, str): diff --git a/scripts/tracetool/format/simpletrace_stap.py b/scripts/tracetool/format/simpletrace_stap.py index 7e44bc18113..ac3580fbcce 100644 --- a/scripts/tracetool/format/simpletrace_stap.py +++ b/scripts/tracetool/format/simpletrace_stap.py @@ -21,6 +21,25 @@ def generate(events, backend): out('/* This file is autogenerated by tracetool, do not edit. */', + '', + 'global event_name_to_id_map', + 'global event_next_id', + 'function simple_trace_map_event(name)', + '', + '{', + ' if (!([name] in event_name_to_id_map)) {', + ' event_name_to_id_map[name] = event_next_id', + ' name_len = strlen(name)', + ' printf("%%8b%%8b%%4b%%.*s", 0, ', + ' event_next_id, name_len, name_len, name)', + ' event_next_id = event_next_id + 1', + ' }', + ' return event_name_to_id_map[name]', + '}', + 'probe begin', + '{', + ' printf("%%8b%%8b%%8b", 0xffffffffffffffff, 0xf2b177cb0aa429b4, 4)', + '}', '') for event_id, e in enumerate(events): @@ -29,6 +48,7 @@ def generate(events, backend): out('probe %(probeprefix)s.simpletrace.%(name)s = %(probeprefix)s.%(name)s ?', '{', + ' id = simple_trace_map_event("%(name)s")', probeprefix=probeprefix(), name=e.name) @@ -48,7 +68,7 @@ def generate(events, backend): sizestr = ' + '.join(sizes) # Generate format string and value pairs for record header and arguments - fields = [('8b', str(event_id)), + fields = [('8b', 'id'), ('8b', 'gettimeofday_ns()'), ('4b', sizestr), ('4b', 'pid()')] @@ -63,7 +83,7 @@ def generate(events, backend): # Emit the entire record in a single SystemTap printf() fmt_str = '%'.join(fmt for fmt, _ in fields) arg_str = ', '.join(arg for _, arg in fields) - out(' printf("%%%(fmt_str)s", %(arg_str)s)', + out(' printf("%%8b%%%(fmt_str)s", 1, %(arg_str)s)', fmt_str=fmt_str, arg_str=arg_str) out('}') diff --git a/trace/simple.c b/trace/simple.c index 2ec32e159c7..b263622fa94 100644 --- a/trace/simple.c +++ b/trace/simple.c @@ -24,7 +24,7 @@ #define HEADER_MAGIC 0xf2b177cb0aa429b4ULL /** Trace file version number, bump if format changes */ -#define HEADER_VERSION 3 +#define HEADER_VERSION 4 /** Records were dropped event ID */ #define DROPPED_EVENT_ID (~(uint64_t)0 - 1) @@ -56,6 +56,9 @@ static uint32_t trace_pid; static FILE *trace_fp; static char *trace_file_name; +#define TRACE_RECORD_TYPE_MAPPING 0 +#define TRACE_RECORD_TYPE_EVENT 1 + /* * Trace buffer entry */ typedef struct { uint64_t event; /* event ID value */ @@ -160,6 +163,7 @@ static gpointer writeout_thread(gpointer opaque) unsigned int idx = 0; int dropped_count; size_t unused __attribute__ ((unused)); + uint64_t type = TRACE_RECORD_TYPE_EVENT; for (;;) { wait_for_trace_records_available(); @@ -174,10 +178,12 @@ static gpointer writeout_thread(gpointer opaque) } while (!g_atomic_int_compare_and_exchange(&dropped_events, dropped_count, 0)); dropped.rec.arguments[0] = dropped_count; + unused = fwrite(&type, sizeof(type), 1, trace_fp); unused = fwrite(&dropped.rec, dropped.rec.length, 1, trace_fp); } while (get_trace_record(idx, &recordptr)) { + unused = fwrite(&type, sizeof(type), 1, trace_fp); unused = fwrite(recordptr, recordptr->length, 1, trace_fp); writeout_idx += recordptr->length; free(recordptr); /* don't use g_free, can deadlock when traced */ @@ -273,6 +279,28 @@ void trace_record_finish(TraceBufferRecord *rec) } } +static int st_write_event_mapping(void) +{ + uint64_t type = TRACE_RECORD_TYPE_MAPPING; + TraceEventIter iter; + TraceEvent *ev; + + trace_event_iter_init(&iter, NULL); + while ((ev = trace_event_iter_next(&iter)) != NULL) { + uint64_t id = trace_event_get_id(ev); + const char *name = trace_event_get_name(ev); + uint32_t len = strlen(name); + if (fwrite(&type, sizeof(type), 1, trace_fp) != 1 || + fwrite(&id, sizeof(id), 1, trace_fp) != 1 || + fwrite(&len, sizeof(len), 1, trace_fp) != 1 || + fwrite(name, len, 1, trace_fp) != 1) { + return -1; + } + } + + return 0; +} + void st_set_trace_file_enabled(bool enable) { if (enable == !!trace_fp) { @@ -297,7 +325,8 @@ void st_set_trace_file_enabled(bool enable) return; } - if (fwrite(&header, sizeof header, 1, trace_fp) != 1) { + if (fwrite(&header, sizeof header, 1, trace_fp) != 1 || + st_write_event_mapping() < 0) { fclose(trace_fp); trace_fp = NULL; return; From 8ed5372874377af4a84a330eeaff1d9d663ca930 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Tue, 4 Oct 2016 14:35:51 +0100 Subject: [PATCH 641/723] trace: don't abort qemu if ftrace can't be initialized If the ftrace backend is compiled into QEMU, any attempt to start QEMU while non-root will fail due to the inability to open /sys/kernel/debug/tracing/tracing_on. Add a fallback into the code so that it connects up the trace_marker_fd variable to /dev/null when getting EACCES on the 'trace_on' file. This allows QEMU to run, with ftrace turned into a no-op. [Fixed s/setting/getting/ and s/EACCESS/EACCES/ errors pointed out by Eric Blake . --Stefan] Signed-off-by: Daniel P. Berrange Message-id: 1475588159-30598-13-git-send-email-berrange@redhat.com Signed-off-by: Stefan Hajnoczi --- trace/ftrace.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/trace/ftrace.c b/trace/ftrace.c index e953922f5bd..3588bb0eb4f 100644 --- a/trace/ftrace.c +++ b/trace/ftrace.c @@ -51,6 +51,12 @@ bool ftrace_init(void) snprintf(path, PATH_MAX, "%s/tracing/tracing_on", debugfs); trace_fd = open(path, O_WRONLY); if (trace_fd < 0) { + if (errno == EACCES) { + trace_marker_fd = open("/dev/null", O_WRONLY); + if (trace_marker_fd != -1) { + return true; + } + } perror("Could not open ftrace 'tracing_on' file"); return false; } else { From fe4db84d49545e669806d0cce12b3aa384e04ac3 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Tue, 4 Oct 2016 14:35:52 +0100 Subject: [PATCH 642/723] trace: provide mechanism for registering trace events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the notion of there being a single global array of trace events, by introducing a method for registering groups of events. The module_call_init() needs to be invoked at the start of any program that wants to make use of the trace support. Currently this covers system emulators qemu-nbd, qemu-img and qemu-io. [Squashed the following fix from Daniel P. Berrange : linux-user/bsd-user: initialize trace events subsystem The bsd-user/linux-user programs make use of the CPU emulation code and this now requires that the trace events subsystem is enabled, otherwise it'll crash trying to allocate an empty trace events bitmap for the CPU object. --Stefan] Reviewed-by: Stefan Hajnoczi Reviewed-by: Lluís Vilanova Signed-off-by: Daniel P. Berrange Message-id: 1475588159-30598-14-git-send-email-berrange@redhat.com Signed-off-by: Stefan Hajnoczi --- bsd-user/main.c | 1 + include/qemu/module.h | 2 ++ linux-user/main.c | 1 + qemu-img.c | 1 + qemu-io.c | 1 + qemu-nbd.c | 1 + scripts/tracetool/format/events_c.py | 6 ++++++ trace/control-internal.h | 4 +++- trace/control.c | 25 +++++++++++++++++++++++-- trace/control.h | 1 + vl.c | 2 ++ 11 files changed, 42 insertions(+), 3 deletions(-) diff --git a/bsd-user/main.c b/bsd-user/main.c index d8367bda467..4fd7b6396df 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -740,6 +740,7 @@ int main(int argc, char **argv) if (argc <= 1) usage(); + module_call_init(MODULE_INIT_TRACE); qemu_init_cpu_list(); module_call_init(MODULE_INIT_QOM); diff --git a/include/qemu/module.h b/include/qemu/module.h index dc2c9d4c4ee..877cca7d7b6 100644 --- a/include/qemu/module.h +++ b/include/qemu/module.h @@ -44,6 +44,7 @@ typedef enum { MODULE_INIT_OPTS, MODULE_INIT_QAPI, MODULE_INIT_QOM, + MODULE_INIT_TRACE, MODULE_INIT_MAX } module_init_type; @@ -51,6 +52,7 @@ typedef enum { #define opts_init(function) module_init(function, MODULE_INIT_OPTS) #define qapi_init(function) module_init(function, MODULE_INIT_QAPI) #define type_init(function) module_init(function, MODULE_INIT_QOM) +#define trace_init(function) module_init(function, MODULE_INIT_TRACE) #define block_module_load_one(lib) module_load_one("block-", lib) diff --git a/linux-user/main.c b/linux-user/main.c index 9e4b430d66f..0e31dad6846 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -4158,6 +4158,7 @@ int main(int argc, char **argv, char **envp) int ret; int execfd; + module_call_init(MODULE_INIT_TRACE); qemu_init_cpu_list(); module_call_init(MODULE_INIT_QOM); diff --git a/qemu-img.c b/qemu-img.c index ceffefeacb6..02c07b913dd 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -4165,6 +4165,7 @@ int main(int argc, char **argv) signal(SIGPIPE, SIG_IGN); #endif + module_call_init(MODULE_INIT_TRACE); error_set_progname(argv[0]); qemu_init_exec_dir(argv[0]); diff --git a/qemu-io.c b/qemu-io.c index db129eac5ff..23a229f880b 100644 --- a/qemu-io.c +++ b/qemu-io.c @@ -467,6 +467,7 @@ int main(int argc, char **argv) signal(SIGPIPE, SIG_IGN); #endif + module_call_init(MODULE_INIT_TRACE); progname = basename(argv[0]); qemu_init_exec_dir(argv[0]); diff --git a/qemu-nbd.c b/qemu-nbd.c index 705b95ec293..cca4a983b77 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -533,6 +533,7 @@ int main(int argc, char **argv) sa_sigterm.sa_handler = termsig_handler; sigaction(SIGTERM, &sa_sigterm, NULL); + module_call_init(MODULE_INIT_TRACE); qcrypto_init(&error_fatal); module_call_init(MODULE_INIT_QOM); diff --git a/scripts/tracetool/format/events_c.py b/scripts/tracetool/format/events_c.py index 40ae39568ec..88175559dea 100644 --- a/scripts/tracetool/format/events_c.py +++ b/scripts/tracetool/format/events_c.py @@ -60,3 +60,9 @@ def generate(events, backend): out(' NULL,', '};', '') + + out('static void trace_register_events(void)', + '{', + ' trace_event_register_group(trace_events);', + '}', + 'trace_init(trace_register_events)') diff --git a/trace/control-internal.h b/trace/control-internal.h index 9abbc96bcb4..a9d395a5870 100644 --- a/trace/control-internal.h +++ b/trace/control-internal.h @@ -15,7 +15,6 @@ #include "qom/cpu.h" -extern TraceEvent *trace_events[]; extern int trace_events_enabled_count; @@ -83,4 +82,7 @@ static inline bool trace_event_get_vcpu_state_dynamic(CPUState *vcpu, return trace_event_get_vcpu_state_dynamic_by_vcpu_id(vcpu, vcpu_id); } + +void trace_event_register_group(TraceEvent **events); + #endif /* TRACE__CONTROL_INTERNAL_H */ diff --git a/trace/control.c b/trace/control.c index 6b32511d60a..a2313273d88 100644 --- a/trace/control.c +++ b/trace/control.c @@ -29,6 +29,13 @@ int trace_events_enabled_count; +typedef struct TraceEventGroup { + TraceEvent **events; +} TraceEventGroup; + +static TraceEventGroup *event_groups; +static size_t nevent_groups; + QemuOptsList qemu_trace_opts = { .name = "trace", .implied_opt_name = "enable", @@ -50,6 +57,14 @@ QemuOptsList qemu_trace_opts = { }; +void trace_event_register_group(TraceEvent **events) +{ + event_groups = g_renew(TraceEventGroup, event_groups, nevent_groups + 1); + event_groups[nevent_groups].events = events; + nevent_groups++; +} + + TraceEvent *trace_event_name(const char *name) { assert(name != NULL); @@ -100,14 +115,20 @@ static bool pattern_glob(const char *pat, const char *ev) void trace_event_iter_init(TraceEventIter *iter, const char *pattern) { iter->event = 0; + iter->group = 0; iter->pattern = pattern; } TraceEvent *trace_event_iter_next(TraceEventIter *iter) { - while (trace_events[iter->event] != NULL) { - TraceEvent *ev = trace_events[iter->event]; + while (iter->group < nevent_groups && + event_groups[iter->group].events[iter->event] != NULL) { + TraceEvent *ev = event_groups[iter->group].events[iter->event]; iter->event++; + if (event_groups[iter->group].events[iter->event] == NULL) { + iter->event = 0; + iter->group++; + } if (!iter->pattern || pattern_glob(iter->pattern, trace_event_get_name(ev))) { diff --git a/trace/control.h b/trace/control.h index cccd2a295eb..3f30a0c2b77 100644 --- a/trace/control.h +++ b/trace/control.h @@ -15,6 +15,7 @@ typedef struct TraceEventIter { size_t event; + size_t group; const char *pattern; } TraceEventIter; diff --git a/vl.c b/vl.c index eb3c5ee3484..c657acdd3c7 100644 --- a/vl.c +++ b/vl.c @@ -3024,6 +3024,8 @@ int main(int argc, char **argv, char **envp) Error *err = NULL; bool list_data_dirs = false; + module_call_init(MODULE_INIT_TRACE); + qemu_init_cpu_list(); qemu_init_cpu_loop(); qemu_mutex_lock_iothread(); From b7d48952c375842bd669460fd8384d90cc12286c Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Tue, 4 Oct 2016 14:35:53 +0100 Subject: [PATCH 643/723] trace: dynamically allocate trace_dstate in CPUState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CPUState struct has a bitmap tracking which VCPU events are currently active. This is indexed based on the event ID values, and sized according the maximum TraceEventVCPUID enum value. When we start dynamically assigning IDs at runtime, we can't statically declare a bitmap without making an assumption about the max event count. This problem can be solved by dynamically allocating the per-CPU dstate bitmap. Reviewed-by: Stefan Hajnoczi Reviewed-by: Lluís Vilanova Signed-off-by: Daniel P. Berrange Message-id: 1475588159-30598-15-git-send-email-berrange@redhat.com Signed-off-by: Stefan Hajnoczi --- include/qom/cpu.h | 9 ++++++--- qom/cpu.c | 7 +++++-- trace/control.c | 5 +++++ trace/control.h | 7 +++++++ 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/include/qom/cpu.h b/include/qom/cpu.h index 22b54d6d937..6d481a1dc05 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -27,7 +27,6 @@ #include "qemu/bitmap.h" #include "qemu/queue.h" #include "qemu/thread.h" -#include "trace/generated-events.h" typedef int (*WriteCoreDumpFunction)(const void *buf, size_t size, void *opaque); @@ -345,8 +344,12 @@ struct CPUState { struct KVMState *kvm_state; struct kvm_run *kvm_run; - /* Used for events with 'vcpu' and *without* the 'disabled' properties */ - DECLARE_BITMAP(trace_dstate, TRACE_VCPU_EVENT_COUNT); + /* + * Used for events with 'vcpu' and *without* the 'disabled' properties. + * Dynamically allocated based on bitmap requried to hold up to + * trace_get_vcpu_event_count() entries. + */ + unsigned long *trace_dstate; /* TODO Move common fields from CPUArchState here. */ int cpu_index; /* used by alpha TCG */ diff --git a/qom/cpu.c b/qom/cpu.c index e765bc0caf2..c40f774a0ca 100644 --- a/qom/cpu.c +++ b/qom/cpu.c @@ -360,12 +360,15 @@ static void cpu_common_initfn(Object *obj) qemu_mutex_init(&cpu->work_mutex); QTAILQ_INIT(&cpu->breakpoints); QTAILQ_INIT(&cpu->watchpoints); - bitmap_zero(cpu->trace_dstate, TRACE_VCPU_EVENT_COUNT); + + cpu->trace_dstate = bitmap_new(trace_get_vcpu_event_count()); } static void cpu_common_finalize(Object *obj) { - cpu_exec_exit(CPU(obj)); + CPUState *cpu = CPU(obj); + cpu_exec_exit(cpu); + g_free(cpu->trace_dstate); } static int64_t cpu_common_get_arch_id(CPUState *cpu) diff --git a/trace/control.c b/trace/control.c index a2313273d88..5f10e2d96e8 100644 --- a/trace/control.c +++ b/trace/control.c @@ -290,3 +290,8 @@ char *trace_opt_parse(const char *optarg) return trace_file; } + +uint32_t trace_get_vcpu_event_count(void) +{ + return TRACE_VCPU_EVENT_COUNT; +} diff --git a/trace/control.h b/trace/control.h index 3f30a0c2b77..69635bfb8b9 100644 --- a/trace/control.h +++ b/trace/control.h @@ -232,6 +232,13 @@ extern QemuOptsList qemu_trace_opts; */ char *trace_opt_parse(const char *optarg); +/** + * trace_get_vcpu_event_count: + * + * Return the number of known vcpu-specific events + */ +uint32_t trace_get_vcpu_event_count(void); + #include "trace/control-internal.h" From ca3fa0e88f3a8e22f774751bcb10cc205772c2fc Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Tue, 4 Oct 2016 14:35:54 +0100 Subject: [PATCH 644/723] trace: dynamically allocate event IDs at runtime MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of having the code generator assign event IDs and event VCPU IDs, assign them when the events are registered at runtime. This will allow code to be generated from individual trace-events without having to figure out globally unique numbering at build time. Reviewed-by: Stefan Hajnoczi Reviewed-by: Lluís Vilanova Signed-off-by: Daniel P. Berrange Message-id: 1475588159-30598-16-git-send-email-berrange@redhat.com Signed-off-by: Stefan Hajnoczi --- scripts/tracetool/format/events_c.py | 10 ++-------- scripts/tracetool/format/events_h.py | 4 ---- trace/control.c | 11 ++++++++++- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/scripts/tracetool/format/events_c.py b/scripts/tracetool/format/events_c.py index 88175559dea..a976c22c8b7 100644 --- a/scripts/tracetool/format/events_c.py +++ b/scripts/tracetool/format/events_c.py @@ -28,25 +28,19 @@ def generate(events, backend): for e in events: out('uint16_t %s;' % e.api(e.QEMU_DSTATE)) - next_id = 0 - next_vcpu_id = 0 for e in events: - id = next_id - next_id += 1 if "vcpu" in e.properties: - vcpu_id = next_vcpu_id - next_vcpu_id += 1 + vcpu_id = 0 else: vcpu_id = "TRACE_VCPU_EVENT_NONE" out('TraceEvent %(event)s = {', - ' .id = %(id)s,', + ' .id = 0,', ' .vcpu_id = %(vcpu_id)s,', ' .name = \"%(name)s\",', ' .sstate = %(sstate)s,', ' .dstate = &%(dstate)s ', '};', event = e.api(e.QEMU_EVENT), - id = id, vcpu_id = vcpu_id, name = e.name, sstate = "TRACE_%s_ENABLED" % e.name.upper(), diff --git a/scripts/tracetool/format/events_h.py b/scripts/tracetool/format/events_h.py index ca6d7305197..1cb332befc0 100644 --- a/scripts/tracetool/format/events_h.py +++ b/scripts/tracetool/format/events_h.py @@ -32,10 +32,6 @@ def generate(events, backend): for e in events: out('extern uint16_t %s;' % e.api(e.QEMU_DSTATE)) - numvcpu = len([e for e in events if "vcpu" in e.properties]) - - out("#define TRACE_VCPU_EVENT_COUNT %d" % numvcpu) - # static state for e in events: if 'disable' in e.properties: diff --git a/trace/control.c b/trace/control.c index 5f10e2d96e8..1a7bee6ddcb 100644 --- a/trace/control.c +++ b/trace/control.c @@ -35,6 +35,8 @@ typedef struct TraceEventGroup { static TraceEventGroup *event_groups; static size_t nevent_groups; +static uint32_t next_id; +static uint32_t next_vcpu_id; QemuOptsList qemu_trace_opts = { .name = "trace", @@ -59,6 +61,13 @@ QemuOptsList qemu_trace_opts = { void trace_event_register_group(TraceEvent **events) { + size_t i; + for (i = 0; events[i] != NULL; i++) { + events[i]->id = next_id++; + if (events[i]->vcpu_id != TRACE_VCPU_EVENT_NONE) { + events[i]->vcpu_id = next_vcpu_id++; + } + } event_groups = g_renew(TraceEventGroup, event_groups, nevent_groups + 1); event_groups[nevent_groups].events = events; nevent_groups++; @@ -293,5 +302,5 @@ char *trace_opt_parse(const char *optarg) uint32_t trace_get_vcpu_event_count(void) { - return TRACE_VCPU_EVENT_COUNT; + return next_vcpu_id; } From 347701879ceaa9a03093364bc519042b248b4967 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Tue, 4 Oct 2016 14:35:55 +0100 Subject: [PATCH 645/723] trace: get rid of generated-events.h/generated-events.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently the generated-events.[ch] files contain the event dstates, constants and TraceEvent structs, while the generated-tracers.[ch] files contain the actual trace probe logic. With the removal of usage of the event enums from the API there is no longer any compelling reason for the separation between these files. The generated-events.h content is only ever needed from the generated-tracers.[ch] files. The enums/constants/structs from generated-events.[ch] are thus moved into the generated-tracers.[ch], so that there is one less file to be generated. Reviewed-by: Stefan Hajnoczi Reviewed-by: Lluís Vilanova Signed-off-by: Daniel P. Berrange Message-id: 1475588159-30598-17-git-send-email-berrange@redhat.com Signed-off-by: Stefan Hajnoczi --- Makefile | 3 -- include/trace-tcg.h | 1 - include/trace.h | 1 - scripts/tracetool/format/c.py | 50 +++++++++++++++++++--- scripts/tracetool/format/events_c.py | 62 ---------------------------- scripts/tracetool/format/events_h.py | 49 ---------------------- scripts/tracetool/format/h.py | 20 +++++++++ trace/Makefile.objs | 28 ++----------- trace/control.h | 2 +- trace/simple.h | 4 -- 10 files changed, 70 insertions(+), 150 deletions(-) delete mode 100644 scripts/tracetool/format/events_c.py delete mode 100644 scripts/tracetool/format/events_h.py diff --git a/Makefile b/Makefile index 5f6acaed3bc..3bcb0565b60 100644 --- a/Makefile +++ b/Makefile @@ -56,9 +56,6 @@ GENERATED_SOURCES += qmp-marshal.c qapi-types.c qapi-visit.c qapi-event.c GENERATED_HEADERS += qmp-introspect.h GENERATED_SOURCES += qmp-introspect.c -GENERATED_HEADERS += trace/generated-events.h -GENERATED_SOURCES += trace/generated-events.c - GENERATED_HEADERS += trace/generated-tracers.h ifeq ($(findstring dtrace,$(TRACE_BACKENDS)),dtrace) GENERATED_HEADERS += trace/generated-tracers-dtrace.h diff --git a/include/trace-tcg.h b/include/trace-tcg.h index edab4b159c0..da68608c856 100644 --- a/include/trace-tcg.h +++ b/include/trace-tcg.h @@ -2,6 +2,5 @@ #define TRACE_TCG_H #include "trace/generated-tcg-tracers.h" -#include "trace/generated-events.h" #endif /* TRACE_TCG_H */ diff --git a/include/trace.h b/include/trace.h index 9a01e4454bd..ac9ff3dddd5 100644 --- a/include/trace.h +++ b/include/trace.h @@ -2,6 +2,5 @@ #define TRACE_H #include "trace/generated-tracers.h" -#include "trace/generated-events.h" #endif /* TRACE_H */ diff --git a/scripts/tracetool/format/c.py b/scripts/tracetool/format/c.py index 699598fb020..7ac6d4c5081 100644 --- a/scripts/tracetool/format/c.py +++ b/scripts/tracetool/format/c.py @@ -17,12 +17,52 @@ def generate(events, backend): - events = [e for e in events - if "disable" not in e.properties] + active_events = [e for e in events + if "disable" not in e.properties] out('/* This file is autogenerated by tracetool, do not edit. */', + '', + '#include "qemu/osdep.h"', + '#include "trace.h"', '') - backend.generate_begin(events) - for event in events: + + for e in events: + out('uint16_t %s;' % e.api(e.QEMU_DSTATE)) + + for e in events: + if "vcpu" in e.properties: + vcpu_id = 0 + else: + vcpu_id = "TRACE_VCPU_EVENT_NONE" + out('TraceEvent %(event)s = {', + ' .id = 0,', + ' .vcpu_id = %(vcpu_id)s,', + ' .name = \"%(name)s\",', + ' .sstate = %(sstate)s,', + ' .dstate = &%(dstate)s ', + '};', + event = e.api(e.QEMU_EVENT), + vcpu_id = vcpu_id, + name = e.name, + sstate = "TRACE_%s_ENABLED" % e.name.upper(), + dstate = e.api(e.QEMU_DSTATE)) + + out('TraceEvent *trace_events[] = {') + + for e in events: + out(' &%(event)s,', event = e.api(e.QEMU_EVENT)) + + out(' NULL,', + '};', + '') + + out('static void trace_register_events(void)', + '{', + ' trace_event_register_group(trace_events);', + '}', + 'trace_init(trace_register_events)') + + backend.generate_begin(active_events) + for event in active_events: backend.generate(event) - backend.generate_end(events) + backend.generate_end(active_events) diff --git a/scripts/tracetool/format/events_c.py b/scripts/tracetool/format/events_c.py deleted file mode 100644 index a976c22c8b7..00000000000 --- a/scripts/tracetool/format/events_c.py +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" -trace/generated-events.c -""" - -__author__ = "Lluís Vilanova " -__copyright__ = "Copyright 2012-2016, Lluís Vilanova " -__license__ = "GPL version 2 or (at your option) any later version" - -__maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@linux.vnet.ibm.com" - - -from tracetool import out - - -def generate(events, backend): - out('/* This file is autogenerated by tracetool, do not edit. */', - '', - '#include "qemu/osdep.h"', - '#include "trace.h"', - '#include "trace/generated-events.h"', - '#include "trace/control.h"', - '') - - for e in events: - out('uint16_t %s;' % e.api(e.QEMU_DSTATE)) - - for e in events: - if "vcpu" in e.properties: - vcpu_id = 0 - else: - vcpu_id = "TRACE_VCPU_EVENT_NONE" - out('TraceEvent %(event)s = {', - ' .id = 0,', - ' .vcpu_id = %(vcpu_id)s,', - ' .name = \"%(name)s\",', - ' .sstate = %(sstate)s,', - ' .dstate = &%(dstate)s ', - '};', - event = e.api(e.QEMU_EVENT), - vcpu_id = vcpu_id, - name = e.name, - sstate = "TRACE_%s_ENABLED" % e.name.upper(), - dstate = e.api(e.QEMU_DSTATE)) - - out('TraceEvent *trace_events[] = {') - - for e in events: - out(' &%(event)s,', event = e.api(e.QEMU_EVENT)) - - out(' NULL,', - '};', - '') - - out('static void trace_register_events(void)', - '{', - ' trace_event_register_group(trace_events);', - '}', - 'trace_init(trace_register_events)') diff --git a/scripts/tracetool/format/events_h.py b/scripts/tracetool/format/events_h.py deleted file mode 100644 index 1cb332befc0..00000000000 --- a/scripts/tracetool/format/events_h.py +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" -trace/generated-events.h -""" - -__author__ = "Lluís Vilanova " -__copyright__ = "Copyright 2012-2016, Lluís Vilanova " -__license__ = "GPL version 2 or (at your option) any later version" - -__maintainer__ = "Stefan Hajnoczi" -__email__ = "stefanha@linux.vnet.ibm.com" - - -from tracetool import out - - -def generate(events, backend): - out('/* This file is autogenerated by tracetool, do not edit. */', - '', - '#ifndef TRACE__GENERATED_EVENTS_H', - '#define TRACE__GENERATED_EVENTS_H', - '', - '#include "trace/event-internal.h"', - ) - - for e in events: - out('extern TraceEvent %(event)s;', - event = e.api(e.QEMU_EVENT)) - - for e in events: - out('extern uint16_t %s;' % e.api(e.QEMU_DSTATE)) - - # static state - for e in events: - if 'disable' in e.properties: - enabled = 0 - else: - enabled = 1 - if "tcg-exec" in e.properties: - # a single define for the two "sub-events" - out('#define TRACE_%(name)s_ENABLED %(enabled)d', - name=e.original.name.upper(), - enabled=enabled) - out('#define TRACE_%s_ENABLED %d' % (e.name.upper(), enabled)) - - out('', - '#endif /* TRACE__GENERATED_EVENTS_H */') diff --git a/scripts/tracetool/format/h.py b/scripts/tracetool/format/h.py index 64a6680fdce..f4748c301f4 100644 --- a/scripts/tracetool/format/h.py +++ b/scripts/tracetool/format/h.py @@ -26,6 +26,26 @@ def generate(events, backend): '#include "trace/control.h"', '') + for e in events: + out('extern TraceEvent %(event)s;', + event = e.api(e.QEMU_EVENT)) + + for e in events: + out('extern uint16_t %s;' % e.api(e.QEMU_DSTATE)) + + # static state + for e in events: + if 'disable' in e.properties: + enabled = 0 + else: + enabled = 1 + if "tcg-exec" in e.properties: + # a single define for the two "sub-events" + out('#define TRACE_%(name)s_ENABLED %(enabled)d', + name=e.original.name.upper(), + enabled=enabled) + out('#define TRACE_%s_ENABLED %d' % (e.name.upper(), enabled)) + backend.generate_begin(events) for e in events: diff --git a/trace/Makefile.objs b/trace/Makefile.objs index 24d3b3758c4..abac3330947 100644 --- a/trace/Makefile.objs +++ b/trace/Makefile.objs @@ -32,32 +32,11 @@ $(obj)/generated-ust.c-timestamp: $(BUILD_DIR)/trace-events-all $(tracetool-y) --backends=$(TRACE_BACKENDS) \ < $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") -$(obj)/generated-events.h: $(obj)/generated-ust-provider.h -$(obj)/generated-events.c: $(obj)/generated-ust.c +$(obj)/generated-tracers.h: $(obj)/generated-ust-provider.h +$(obj)/generated-tracers.c: $(obj)/generated-ust.c endif -###################################################################### -# Auto-generated event descriptions - -$(obj)/generated-events.h: $(obj)/generated-events.h-timestamp - @cmp $< $@ >/dev/null 2>&1 || cp $< $@ -$(obj)/generated-events.h-timestamp: $(BUILD_DIR)/trace-events-all $(tracetool-y) - $(call quiet-command,$(TRACETOOL) \ - --format=events-h \ - --backends=$(TRACE_BACKENDS) \ - < $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") - -$(obj)/generated-events.c: $(obj)/generated-events.c-timestamp $(BUILD_DIR)/config-host.mak - @cmp $< $@ >/dev/null 2>&1 || cp $< $@ -$(obj)/generated-events.c-timestamp: $(BUILD_DIR)/trace-events-all $(tracetool-y) - $(call quiet-command,$(TRACETOOL) \ - --format=events-c \ - --backends=$(TRACE_BACKENDS) \ - < $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") - -util-obj-y += generated-events.o - ###################################################################### # Auto-generated tracing routines @@ -154,7 +133,8 @@ $(obj)/generated-tcg-tracers.h-timestamp: $(BUILD_DIR)/trace-events-all $(BUILD_ ###################################################################### # Backend code -util-obj-$(CONFIG_TRACE_SIMPLE) += simple.o generated-tracers.o +util-obj-y += generated-tracers.o +util-obj-$(CONFIG_TRACE_SIMPLE) += simple.o util-obj-$(CONFIG_TRACE_FTRACE) += ftrace.o util-obj-$(CONFIG_TRACE_UST) += generated-ust.o util-obj-y += control.o diff --git a/trace/control.h b/trace/control.h index 69635bfb8b9..ccaeac8552d 100644 --- a/trace/control.h +++ b/trace/control.h @@ -11,7 +11,7 @@ #define TRACE__CONTROL_H #include "qemu-common.h" -#include "trace/generated-events.h" +#include "event-internal.h" typedef struct TraceEventIter { size_t event; diff --git a/trace/simple.h b/trace/simple.h index 17ce47260f5..9931808c053 100644 --- a/trace/simple.h +++ b/trace/simple.h @@ -11,10 +11,6 @@ #ifndef TRACE_SIMPLE_H #define TRACE_SIMPLE_H - -#include "trace/generated-events.h" - - void st_print_trace_file_status(FILE *stream, fprintf_function stream_printf); void st_set_trace_file_enabled(bool enable); void st_set_trace_file(const char *file); From d1b97bcea3586bad572879f22437f44c690874cb Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Tue, 4 Oct 2016 14:35:56 +0100 Subject: [PATCH 646/723] trace: rename _read_events to read_events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The _read_events method is used by callers outside of its module, so should be a public method, not private. Reviewed-by: Stefan Hajnoczi Reviewed-by: Lluís Vilanova Signed-off-by: Daniel P. Berrange Message-id: 1475588159-30598-18-git-send-email-berrange@redhat.com Signed-off-by: Stefan Hajnoczi --- scripts/simpletrace.py | 6 +++--- scripts/tracetool/__init__.py | 14 ++++++++++++-- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/scripts/simpletrace.py b/scripts/simpletrace.py index f40467a7946..4ca903dc0cf 100755 --- a/scripts/simpletrace.py +++ b/scripts/simpletrace.py @@ -12,7 +12,7 @@ import struct import re import inspect -from tracetool import _read_events, Event +from tracetool import read_events, Event from tracetool.backend.simple import is_string header_event_id = 0xffffffffffffffff @@ -129,7 +129,7 @@ def end(self): def process(events, log, analyzer, read_header=True): """Invoke an analyzer on each event in a log.""" if isinstance(events, str): - events = _read_events(open(events, 'r')) + events = read_events(open(events, 'r')) if isinstance(log, str): log = open(log, 'rb') @@ -188,7 +188,7 @@ def run(analyzer): '\n' % sys.argv[0]) sys.exit(1) - events = _read_events(open(sys.argv[1], 'r')) + events = read_events(open(sys.argv[1], 'r')) process(events, sys.argv[2], analyzer, read_header=read_header) if __name__ == '__main__': diff --git a/scripts/tracetool/__init__.py b/scripts/tracetool/__init__.py index dc93416e9d4..bf01e9341eb 100644 --- a/scripts/tracetool/__init__.py +++ b/scripts/tracetool/__init__.py @@ -282,7 +282,17 @@ def transform(self, *trans): self) -def _read_events(fobj): +def read_events(fobj): + """Generate the output for the given (format, backends) pair. + + Parameters + ---------- + fobj : file + Event description file. + + Returns a list of Event objects + """ + events = [] for line in fobj: if not line.strip(): @@ -391,6 +401,6 @@ def generate(fevents, format, backends, tracetool.backend.dtrace.BINARY = binary tracetool.backend.dtrace.PROBEPREFIX = probe_prefix - events = _read_events(fevents) + events = read_events(fevents) tracetool.format.generate(events, format, backend) From 9096b78a38a22963ca59bb16d54a772aa86d5159 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Tue, 4 Oct 2016 14:35:57 +0100 Subject: [PATCH 647/723] trace: push reading of events up a level to tracetool main MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the reading of events out of the 'tracetool.generate' method and into tracetool.main, so that the latter is not tied to generating from a single source of events. Reviewed-by: Stefan Hajnoczi Reviewed-by: Lluís Vilanova Signed-off-by: Daniel P. Berrange Message-id: 1475588159-30598-19-git-send-email-berrange@redhat.com Signed-off-by: Stefan Hajnoczi --- scripts/tracetool.py | 4 +++- scripts/tracetool/__init__.py | 8 +++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/tracetool.py b/scripts/tracetool.py index 7b82959e84a..6accbbff69c 100755 --- a/scripts/tracetool.py +++ b/scripts/tracetool.py @@ -129,8 +129,10 @@ def main(args): if probe_prefix is None: probe_prefix = ".".join(["qemu", target_type, target_name]) + events = tracetool.read_events(sys.stdin) + try: - tracetool.generate(sys.stdin, arg_format, arg_backends, + tracetool.generate(events, arg_format, arg_backends, binary=binary, probe_prefix=probe_prefix) except tracetool.TracetoolError as e: error_opt(str(e)) diff --git a/scripts/tracetool/__init__.py b/scripts/tracetool/__init__.py index bf01e9341eb..ac2cb8fa98b 100644 --- a/scripts/tracetool/__init__.py +++ b/scripts/tracetool/__init__.py @@ -364,14 +364,14 @@ def try_import(mod_name, attr_name=None, attr_default=None): return False, None -def generate(fevents, format, backends, +def generate(events, format, backends, binary=None, probe_prefix=None): """Generate the output for the given (format, backends) pair. Parameters ---------- - fevents : file - Event description file. + events : list + list of Event objects to generate for format : str Output format name. backends : list @@ -401,6 +401,4 @@ def generate(fevents, format, backends, tracetool.backend.dtrace.BINARY = binary tracetool.backend.dtrace.PROBEPREFIX = probe_prefix - events = read_events(fevents) - tracetool.format.generate(events, format, backend) From 0bc6484d58bd7f43fbf6fc87c7974910b698489c Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Tue, 4 Oct 2016 14:35:58 +0100 Subject: [PATCH 648/723] trace: pass trace-events to tracetool as a positional param MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of reading the contents of 'trace-events' from stdin, accept the filename as a positional parameter. This also allows for reading from multiple files, though this facility is not used at this time. Reviewed-by: Stefan Hajnoczi Reviewed-by: Lluís Vilanova Signed-off-by: Daniel P. Berrange Message-id: 1475588159-30598-20-git-send-email-berrange@redhat.com Signed-off-by: Stefan Hajnoczi --- Makefile.target | 6 +++--- scripts/tracetool.py | 5 ++++- trace/Makefile.objs | 18 +++++++++--------- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/Makefile.target b/Makefile.target index 9968871d6ee..2c460912258 100644 --- a/Makefile.target +++ b/Makefile.target @@ -55,7 +55,7 @@ $(QEMU_PROG).stp-installed: $(BUILD_DIR)/trace-events-all --binary=$(bindir)/$(QEMU_PROG) \ --target-name=$(TARGET_NAME) \ --target-type=$(TARGET_TYPE) \ - < $< > $@,"GEN","$(TARGET_DIR)$(QEMU_PROG).stp-installed") + $< > $@,"GEN","$(TARGET_DIR)$(QEMU_PROG).stp-installed") $(QEMU_PROG).stp: $(BUILD_DIR)/trace-events-all $(call quiet-command,$(TRACETOOL) \ @@ -64,14 +64,14 @@ $(QEMU_PROG).stp: $(BUILD_DIR)/trace-events-all --binary=$(realpath .)/$(QEMU_PROG) \ --target-name=$(TARGET_NAME) \ --target-type=$(TARGET_TYPE) \ - < $< > $@,"GEN","$(TARGET_DIR)$(QEMU_PROG).stp") + $< > $@,"GEN","$(TARGET_DIR)$(QEMU_PROG).stp") $(QEMU_PROG)-simpletrace.stp: $(BUILD_DIR)/trace-events-all $(call quiet-command,$(TRACETOOL) \ --format=simpletrace-stap \ --backends=$(TRACE_BACKENDS) \ --probe-prefix=qemu.$(TARGET_TYPE).$(TARGET_NAME) \ - < $< > $@,"GEN","$(TARGET_DIR)$(QEMU_PROG)-simpletrace.stp") + $< > $@,"GEN","$(TARGET_DIR)$(QEMU_PROG)-simpletrace.stp") else stap: diff --git a/scripts/tracetool.py b/scripts/tracetool.py index 6accbbff69c..f66e7672715 100755 --- a/scripts/tracetool.py +++ b/scripts/tracetool.py @@ -129,7 +129,10 @@ def main(args): if probe_prefix is None: probe_prefix = ".".join(["qemu", target_type, target_name]) - events = tracetool.read_events(sys.stdin) + if len(args) != 1: + error_opt("missing trace-events filepath") + with open(args[0], "r") as fh: + events = tracetool.read_events(fh) try: tracetool.generate(events, arg_format, arg_backends, diff --git a/trace/Makefile.objs b/trace/Makefile.objs index abac3330947..1e1ce7479d0 100644 --- a/trace/Makefile.objs +++ b/trace/Makefile.objs @@ -22,7 +22,7 @@ $(obj)/generated-ust-provider.h-timestamp: $(BUILD_DIR)/trace-events-all $(trace $(call quiet-command,$(TRACETOOL) \ --format=ust-events-h \ --backends=$(TRACE_BACKENDS) \ - < $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") + $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") $(obj)/generated-ust.c: $(obj)/generated-ust.c-timestamp $(BUILD_DIR)/config-host.mak @cmp $< $@ >/dev/null 2>&1 || cp $< $@ @@ -30,7 +30,7 @@ $(obj)/generated-ust.c-timestamp: $(BUILD_DIR)/trace-events-all $(tracetool-y) $(call quiet-command,$(TRACETOOL) \ --format=ust-events-c \ --backends=$(TRACE_BACKENDS) \ - < $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") + $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") $(obj)/generated-tracers.h: $(obj)/generated-ust-provider.h $(obj)/generated-tracers.c: $(obj)/generated-ust.c @@ -50,7 +50,7 @@ $(obj)/generated-tracers.h-timestamp: $(BUILD_DIR)/trace-events-all $(BUILD_DIR) $(call quiet-command,$(TRACETOOL) \ --format=h \ --backends=$(TRACE_BACKENDS) \ - < $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") + $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") ############################## # non-DTrace @@ -61,7 +61,7 @@ $(obj)/generated-tracers.c-timestamp: $(BUILD_DIR)/trace-events-all $(BUILD_DIR) $(call quiet-command,$(TRACETOOL) \ --format=c \ --backends=$(TRACE_BACKENDS) \ - < $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") + $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") $(obj)/generated-tracers.o: $(obj)/generated-tracers.c $(obj)/generated-tracers.h @@ -79,7 +79,7 @@ $(obj)/generated-tracers-dtrace.dtrace-timestamp: $(BUILD_DIR)/trace-events-all $(call quiet-command,$(TRACETOOL) \ --format=d \ --backends=$(TRACE_BACKENDS) \ - < $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") + $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") $(obj)/generated-tracers-dtrace.h: $(obj)/generated-tracers-dtrace.dtrace $(call quiet-command,dtrace -o $@ -h -s $<,"GEN","$@") @@ -98,7 +98,7 @@ $(obj)/generated-helpers-wrappers.h-timestamp: $(BUILD_DIR)/trace-events-all $(B $(call quiet-command,$(TRACETOOL) \ --format=tcg-helper-wrapper-h \ --backend=$(TRACE_BACKENDS) \ - < $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") + $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") $(obj)/generated-helpers.h: $(obj)/generated-helpers.h-timestamp @cmp $< $@ >/dev/null 2>&1 || cp $< $@ @@ -106,7 +106,7 @@ $(obj)/generated-helpers.h-timestamp: $(BUILD_DIR)/trace-events-all $(BUILD_DIR) $(call quiet-command,$(TRACETOOL) \ --format=tcg-helper-h \ --backend=$(TRACE_BACKENDS) \ - < $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") + $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") $(obj)/generated-helpers.c: $(obj)/generated-helpers.c-timestamp @cmp $< $@ >/dev/null 2>&1 || cp $< $@ @@ -114,7 +114,7 @@ $(obj)/generated-helpers.c-timestamp: $(BUILD_DIR)/trace-events-all $(BUILD_DIR) $(call quiet-command,$(TRACETOOL) \ --format=tcg-helper-c \ --backend=$(TRACE_BACKENDS) \ - < $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") + $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") $(obj)/generated-helpers.o: $(obj)/generated-helpers.c @@ -127,7 +127,7 @@ $(obj)/generated-tcg-tracers.h-timestamp: $(BUILD_DIR)/trace-events-all $(BUILD_ $(call quiet-command,$(TRACETOOL) \ --format=tcg-h \ --backend=$(TRACE_BACKENDS) \ - < $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") + $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") ###################################################################### From 80dd5c4918aba98f025ca60c838dd68b6e33ff0e Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Tue, 4 Oct 2016 14:35:59 +0100 Subject: [PATCH 649/723] trace: introduce a formal group name for trace events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The declarations in the generated-tracers.h file are assuming there's only ever going to be one instance of this header, as they are not namespaced. When we have one header per event group, if a single source file needs to include multiple sets of trace events, the symbols will all clash. This change thus introduces a '--group NAME' arg to the 'tracetool' program. This will cause all the symbols in the generated header files to be given a unique namespace. If no group is given, the group name 'common' is used, which is suitable for the current usage where there is only one global trace-events file used for code generation. Reviewed-by: Stefan Hajnoczi Signed-off-by: Daniel P. Berrange Reviewed-by: Lluís Vilanova Message-id: 1475588159-30598-21-git-send-email-berrange@redhat.com Signed-off-by: Stefan Hajnoczi --- scripts/tracetool.py | 15 ++++++++++++++- scripts/tracetool/__init__.py | 6 ++++-- scripts/tracetool/backend/__init__.py | 12 ++++++------ scripts/tracetool/backend/dtrace.py | 4 ++-- scripts/tracetool/backend/ftrace.py | 4 ++-- scripts/tracetool/backend/log.py | 4 ++-- scripts/tracetool/backend/simple.py | 8 ++++---- scripts/tracetool/backend/syslog.py | 4 ++-- scripts/tracetool/backend/ust.py | 4 ++-- scripts/tracetool/format/__init__.py | 4 ++-- scripts/tracetool/format/c.py | 18 ++++++++++-------- scripts/tracetool/format/d.py | 2 +- scripts/tracetool/format/h.py | 14 +++++++------- scripts/tracetool/format/simpletrace_stap.py | 2 +- scripts/tracetool/format/stap.py | 2 +- scripts/tracetool/format/tcg_h.py | 8 ++++---- scripts/tracetool/format/tcg_helper_c.py | 2 +- scripts/tracetool/format/tcg_helper_h.py | 2 +- .../tracetool/format/tcg_helper_wrapper_h.py | 2 +- scripts/tracetool/format/ust_events_c.py | 2 +- scripts/tracetool/format/ust_events_h.py | 9 +++++---- 21 files changed, 73 insertions(+), 55 deletions(-) diff --git a/scripts/tracetool.py b/scripts/tracetool.py index f66e7672715..629b2593c84 100755 --- a/scripts/tracetool.py +++ b/scripts/tracetool.py @@ -15,6 +15,8 @@ import sys import getopt +import os.path +import re from tracetool import error_write, out import tracetool.backend @@ -60,6 +62,15 @@ def error_opt(msg = None): else: sys.exit(1) +def make_group_name(filename): + dirname = os.path.realpath(os.path.dirname(filename)) + basedir = os.path.join(os.path.dirname(__file__), os.pardir) + basedir = os.path.realpath(os.path.abspath(basedir)) + dirname = dirname[len(basedir) + 1:] + + if dirname == "": + return "common" + return re.sub(r"/|-", "_", dirname) def main(args): global _SCRIPT @@ -134,8 +145,10 @@ def main(args): with open(args[0], "r") as fh: events = tracetool.read_events(fh) + group = make_group_name(args[0]) + try: - tracetool.generate(events, arg_format, arg_backends, + tracetool.generate(events, group, arg_format, arg_backends, binary=binary, probe_prefix=probe_prefix) except tracetool.TracetoolError as e: error_opt(str(e)) diff --git a/scripts/tracetool/__init__.py b/scripts/tracetool/__init__.py index ac2cb8fa98b..365446fa533 100644 --- a/scripts/tracetool/__init__.py +++ b/scripts/tracetool/__init__.py @@ -364,7 +364,7 @@ def try_import(mod_name, attr_name=None, attr_default=None): return False, None -def generate(events, format, backends, +def generate(events, group, format, backends, binary=None, probe_prefix=None): """Generate the output for the given (format, backends) pair. @@ -372,6 +372,8 @@ def generate(events, format, backends, ---------- events : list list of Event objects to generate for + group: str + Name of the tracing group format : str Output format name. backends : list @@ -401,4 +403,4 @@ def generate(events, format, backends, tracetool.backend.dtrace.BINARY = binary tracetool.backend.dtrace.PROBEPREFIX = probe_prefix - tracetool.format.generate(events, format, backend) + tracetool.format.generate(events, format, backend, group) diff --git a/scripts/tracetool/backend/__init__.py b/scripts/tracetool/backend/__init__.py index d4b6dab9ca2..f735a259c09 100644 --- a/scripts/tracetool/backend/__init__.py +++ b/scripts/tracetool/backend/__init__.py @@ -113,11 +113,11 @@ def _run_function(self, name, *args, **kwargs): if func is not None: func(*args, **kwargs) - def generate_begin(self, events): - self._run_function("generate_%s_begin", events) + def generate_begin(self, events, group): + self._run_function("generate_%s_begin", events, group) - def generate(self, event): - self._run_function("generate_%s", event) + def generate(self, event, group): + self._run_function("generate_%s", event, group) - def generate_end(self, events): - self._run_function("generate_%s_end", events) + def generate_end(self, events, group): + self._run_function("generate_%s_end", events, group) diff --git a/scripts/tracetool/backend/dtrace.py b/scripts/tracetool/backend/dtrace.py index ab9ecfab301..79505c6b1ab 100644 --- a/scripts/tracetool/backend/dtrace.py +++ b/scripts/tracetool/backend/dtrace.py @@ -35,12 +35,12 @@ def binary(): return BINARY -def generate_h_begin(events): +def generate_h_begin(events, group): out('#include "trace/generated-tracers-dtrace.h"', '') -def generate_h(event): +def generate_h(event, group): out(' QEMU_%(uppername)s(%(argnames)s);', uppername=event.name.upper(), argnames=", ".join(event.args.names())) diff --git a/scripts/tracetool/backend/ftrace.py b/scripts/tracetool/backend/ftrace.py index 4b83b44f3cd..db9fe7ad576 100644 --- a/scripts/tracetool/backend/ftrace.py +++ b/scripts/tracetool/backend/ftrace.py @@ -19,12 +19,12 @@ PUBLIC = True -def generate_h_begin(events): +def generate_h_begin(events, group): out('#include "trace/ftrace.h"', '') -def generate_h(event): +def generate_h(event, group): argnames = ", ".join(event.args.names()) if len(event.args) > 0: argnames = ", " + argnames diff --git a/scripts/tracetool/backend/log.py b/scripts/tracetool/backend/log.py index 426bb6e2a25..4f4a4d38b19 100644 --- a/scripts/tracetool/backend/log.py +++ b/scripts/tracetool/backend/log.py @@ -19,12 +19,12 @@ PUBLIC = True -def generate_h_begin(events): +def generate_h_begin(events, group): out('#include "qemu/log.h"', '') -def generate_h(event): +def generate_h(event, group): argnames = ", ".join(event.args.names()) if len(event.args) > 0: argnames = ", " + argnames diff --git a/scripts/tracetool/backend/simple.py b/scripts/tracetool/backend/simple.py index 1114e3550ba..9885e83cd40 100644 --- a/scripts/tracetool/backend/simple.py +++ b/scripts/tracetool/backend/simple.py @@ -27,7 +27,7 @@ def is_string(arg): return False -def generate_h_begin(events): +def generate_h_begin(events, group): for event in events: out('void _simple_%(api)s(%(args)s);', api=event.api(), @@ -35,13 +35,13 @@ def generate_h_begin(events): out('') -def generate_h(event): +def generate_h(event, group): out(' _simple_%(api)s(%(args)s);', api=event.api(), args=", ".join(event.args.names())) -def generate_c_begin(events): +def generate_c_begin(events, group): out('#include "qemu/osdep.h"', '#include "trace.h"', '#include "trace/control.h"', @@ -49,7 +49,7 @@ def generate_c_begin(events): '') -def generate_c(event): +def generate_c(event, group): out('void _simple_%(api)s(%(args)s)', '{', ' TraceBufferRecord rec;', diff --git a/scripts/tracetool/backend/syslog.py b/scripts/tracetool/backend/syslog.py index 5f693bdf4df..b8ff2790c4a 100644 --- a/scripts/tracetool/backend/syslog.py +++ b/scripts/tracetool/backend/syslog.py @@ -19,12 +19,12 @@ PUBLIC = True -def generate_h_begin(events): +def generate_h_begin(events, group): out('#include ', '') -def generate_h(event): +def generate_h(event, group): argnames = ", ".join(event.args.names()) if len(event.args) > 0: argnames = ", " + argnames diff --git a/scripts/tracetool/backend/ust.py b/scripts/tracetool/backend/ust.py index ed4c227f693..4594db61283 100644 --- a/scripts/tracetool/backend/ust.py +++ b/scripts/tracetool/backend/ust.py @@ -19,13 +19,13 @@ PUBLIC = True -def generate_h_begin(events): +def generate_h_begin(events, group): out('#include ', '#include "trace/generated-ust-provider.h"', '') -def generate_h(event): +def generate_h(event, group): argnames = ", ".join(event.args.names()) if len(event.args) > 0: argnames = ", " + argnames diff --git a/scripts/tracetool/format/__init__.py b/scripts/tracetool/format/__init__.py index 812570ff6f7..cf6e0e2da50 100644 --- a/scripts/tracetool/format/__init__.py +++ b/scripts/tracetool/format/__init__.py @@ -74,7 +74,7 @@ def exists(name): return tracetool.try_import("tracetool.format." + name)[1] -def generate(events, format, backend): +def generate(events, format, backend, group): if not exists(format): raise ValueError("unknown format: %s" % format) format = format.replace("-", "_") @@ -82,4 +82,4 @@ def generate(events, format, backend): "generate")[1] if func is None: raise AttributeError("format has no 'generate': %s" % format) - func(events, backend) + func(events, backend, group) diff --git a/scripts/tracetool/format/c.py b/scripts/tracetool/format/c.py index 7ac6d4c5081..47115ed8af7 100644 --- a/scripts/tracetool/format/c.py +++ b/scripts/tracetool/format/c.py @@ -16,7 +16,7 @@ from tracetool import out -def generate(events, backend): +def generate(events, backend, group): active_events = [e for e in events if "disable" not in e.properties] @@ -47,7 +47,8 @@ def generate(events, backend): sstate = "TRACE_%s_ENABLED" % e.name.upper(), dstate = e.api(e.QEMU_DSTATE)) - out('TraceEvent *trace_events[] = {') + out('TraceEvent *%(group)s_trace_events[] = {', + group = group.lower()) for e in events: out(' &%(event)s,', event = e.api(e.QEMU_EVENT)) @@ -56,13 +57,14 @@ def generate(events, backend): '};', '') - out('static void trace_register_events(void)', + out('static void trace_%(group)s_register_events(void)', '{', - ' trace_event_register_group(trace_events);', + ' trace_event_register_group(%(group)s_trace_events);', '}', - 'trace_init(trace_register_events)') + 'trace_init(trace_%(group)s_register_events)', + group = group.lower()) - backend.generate_begin(active_events) + backend.generate_begin(active_events, group) for event in active_events: - backend.generate(event) - backend.generate_end(active_events) + backend.generate(event, group) + backend.generate_end(active_events, group) diff --git a/scripts/tracetool/format/d.py b/scripts/tracetool/format/d.py index c77d5b7ab0b..78397c24d23 100644 --- a/scripts/tracetool/format/d.py +++ b/scripts/tracetool/format/d.py @@ -29,7 +29,7 @@ ) -def generate(events, backend): +def generate(events, backend, group): events = [e for e in events if "disable" not in e.properties] diff --git a/scripts/tracetool/format/h.py b/scripts/tracetool/format/h.py index f4748c301f4..3682f4e6a8f 100644 --- a/scripts/tracetool/format/h.py +++ b/scripts/tracetool/format/h.py @@ -16,11 +16,11 @@ from tracetool import out -def generate(events, backend): +def generate(events, backend, group): out('/* This file is autogenerated by tracetool, do not edit. */', '', - '#ifndef TRACE__GENERATED_TRACERS_H', - '#define TRACE__GENERATED_TRACERS_H', + '#ifndef TRACE_%s_GENERATED_TRACERS_H' % group.upper(), + '#define TRACE_%s_GENERATED_TRACERS_H' % group.upper(), '', '#include "qemu-common.h"', '#include "trace/control.h"', @@ -46,7 +46,7 @@ def generate(events, backend): enabled=enabled) out('#define TRACE_%s_ENABLED %d' % (e.name.upper(), enabled)) - backend.generate_begin(events) + backend.generate_begin(events, group) for e in events: if "vcpu" in e.properties: @@ -68,11 +68,11 @@ def generate(events, backend): cond=cond) if "disable" not in e.properties: - backend.generate(e) + backend.generate(e, group) out(' }', '}') - backend.generate_end(events) + backend.generate_end(events, group) - out('#endif /* TRACE__GENERATED_TRACERS_H */') + out('#endif /* TRACE_%s_GENERATED_TRACERS_H */' % group.upper()) diff --git a/scripts/tracetool/format/simpletrace_stap.py b/scripts/tracetool/format/simpletrace_stap.py index ac3580fbcce..c35e662e004 100644 --- a/scripts/tracetool/format/simpletrace_stap.py +++ b/scripts/tracetool/format/simpletrace_stap.py @@ -19,7 +19,7 @@ from tracetool.format.stap import stap_escape -def generate(events, backend): +def generate(events, backend, group): out('/* This file is autogenerated by tracetool, do not edit. */', '', 'global event_name_to_id_map', diff --git a/scripts/tracetool/format/stap.py b/scripts/tracetool/format/stap.py index 9e780f1b065..e8ef3e762d7 100644 --- a/scripts/tracetool/format/stap.py +++ b/scripts/tracetool/format/stap.py @@ -34,7 +34,7 @@ def stap_escape(identifier): return identifier -def generate(events, backend): +def generate(events, backend, group): events = [e for e in events if "disable" not in e.properties] diff --git a/scripts/tracetool/format/tcg_h.py b/scripts/tracetool/format/tcg_h.py index e2331f251de..5f213f6cba9 100644 --- a/scripts/tracetool/format/tcg_h.py +++ b/scripts/tracetool/format/tcg_h.py @@ -27,12 +27,12 @@ def vcpu_transform_args(args): ]) -def generate(events, backend): +def generate(events, backend, group): out('/* This file is autogenerated by tracetool, do not edit. */', '/* You must include this file after the inclusion of helper.h */', '', - '#ifndef TRACE__GENERATED_TCG_TRACERS_H', - '#define TRACE__GENERATED_TCG_TRACERS_H', + '#ifndef TRACE_%s_GENERATED_TCG_TRACERS_H' % group.upper(), + '#define TRACE_%s_GENERATED_TCG_TRACERS_H' % group.upper(), '', '#include "trace.h"', '#include "exec/helper-proto.h"', @@ -63,4 +63,4 @@ def generate(events, backend): out('}') out('', - '#endif /* TRACE__GENERATED_TCG_TRACERS_H */') + '#endif /* TRACE_%s_GENERATED_TCG_TRACERS_H */' % group.upper()) diff --git a/scripts/tracetool/format/tcg_helper_c.py b/scripts/tracetool/format/tcg_helper_c.py index e3485b7f923..cc26e03008f 100644 --- a/scripts/tracetool/format/tcg_helper_c.py +++ b/scripts/tracetool/format/tcg_helper_c.py @@ -40,7 +40,7 @@ def vcpu_transform_args(args, mode): assert False -def generate(events, backend): +def generate(events, backend, group): events = [e for e in events if "disable" not in e.properties] diff --git a/scripts/tracetool/format/tcg_helper_h.py b/scripts/tracetool/format/tcg_helper_h.py index dc76c15ebc5..6b184b641b5 100644 --- a/scripts/tracetool/format/tcg_helper_h.py +++ b/scripts/tracetool/format/tcg_helper_h.py @@ -18,7 +18,7 @@ import tracetool.vcpu -def generate(events, backend): +def generate(events, backend, group): events = [e for e in events if "disable" not in e.properties] diff --git a/scripts/tracetool/format/tcg_helper_wrapper_h.py b/scripts/tracetool/format/tcg_helper_wrapper_h.py index 020f4422a97..ff534475120 100644 --- a/scripts/tracetool/format/tcg_helper_wrapper_h.py +++ b/scripts/tracetool/format/tcg_helper_wrapper_h.py @@ -18,7 +18,7 @@ import tracetool.vcpu -def generate(events, backend): +def generate(events, backend, group): events = [e for e in events if "disable" not in e.properties] diff --git a/scripts/tracetool/format/ust_events_c.py b/scripts/tracetool/format/ust_events_c.py index 9967c7a82e0..cd87d8ab8f4 100644 --- a/scripts/tracetool/format/ust_events_c.py +++ b/scripts/tracetool/format/ust_events_c.py @@ -16,7 +16,7 @@ from tracetool import out -def generate(events, backend): +def generate(events, backend, group): events = [e for e in events if "disabled" not in e.properties] diff --git a/scripts/tracetool/format/ust_events_h.py b/scripts/tracetool/format/ust_events_h.py index 3e8a7cdf19a..d853155d21f 100644 --- a/scripts/tracetool/format/ust_events_h.py +++ b/scripts/tracetool/format/ust_events_h.py @@ -16,7 +16,7 @@ from tracetool import out -def generate(events, backend): +def generate(events, backend, group): events = [e for e in events if "disabled" not in e.properties] @@ -28,8 +28,9 @@ def generate(events, backend): '#undef TRACEPOINT_INCLUDE_FILE', '#define TRACEPOINT_INCLUDE_FILE ./generated-ust-provider.h', '', - '#if !defined (TRACE__GENERATED_UST_H) || defined(TRACEPOINT_HEADER_MULTI_READ)', - '#define TRACE__GENERATED_UST_H', + '#if !defined (TRACE_%s_GENERATED_UST_H) || \\' % group.upper(), + ' defined(TRACEPOINT_HEADER_MULTI_READ)', + '#define TRACE_%s_GENERATED_UST_H' % group.upper(), '', '#include "qemu-common.h"', '#include ', @@ -94,7 +95,7 @@ def generate(events, backend): '', name=e.name) - out('#endif /* TRACE__GENERATED_UST_H */', + out('#endif /* TRACE_%s_GENERATED_UST_H */' % group.upper(), '', '/* This part must be outside ifdef protection */', '#include ') From f5e2b3be82ec7e2ec8fed37da3fb2da469ae7d4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Vilanova?= Date: Wed, 5 Oct 2016 14:03:29 +0200 Subject: [PATCH 650/723] trace: Add missing execution mode of guest events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add missing execution mode documentation for the 'guest_cpu_enter' and 'guest_cpu_reset' events. Signed-off-by: Lluís Vilanova Message-id: 147566900921.7708.656450813307396468.stgit@fimbulvetr.bsc.es Signed-off-by: Stefan Hajnoczi --- trace-events | 2 ++ 1 file changed, 2 insertions(+) diff --git a/trace-events b/trace-events index bd2199af32a..8ecded51506 100644 --- a/trace-events +++ b/trace-events @@ -129,11 +129,13 @@ memory_region_tb_write(int cpu_index, uint64_t addr, uint64_t value, unsigned si # Hot-plug a new virtual (guest) CPU # +# Mode: user, softmmu # Targets: all vcpu guest_cpu_enter(void) # Reset the state of a virtual (guest) CPU # +# Mode: user, softmmu # Targets: all vcpu guest_cpu_reset(void) From 05f43d44e4bc26611ce25fd7d726e483f73363ce Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 10 Oct 2016 12:46:22 +0200 Subject: [PATCH 651/723] xhci: limit the number of link trbs we are willing to process Needed to avoid we run in circles forever in case the guest builds an endless loop with link trbs. Reported-by: Li Qiang Tested-by: P J P Signed-off-by: Gerd Hoffmann Message-id: 1476096382-7981-1-git-send-email-kraxel@redhat.com --- hw/usb/hcd-xhci.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index 726435c4620..ee4fa484d6b 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -54,6 +54,8 @@ * to the specs when it gets them */ #define ER_FULL_HACK +#define TRB_LINK_LIMIT 4 + #define LEN_CAP 0x40 #define LEN_OPER (0x400 + 0x10 * MAXPORTS) #define LEN_RUNTIME ((MAXINTRS + 1) * 0x20) @@ -1000,6 +1002,7 @@ static TRBType xhci_ring_fetch(XHCIState *xhci, XHCIRing *ring, XHCITRB *trb, dma_addr_t *addr) { PCIDevice *pci_dev = PCI_DEVICE(xhci); + uint32_t link_cnt = 0; while (1) { TRBType type; @@ -1026,6 +1029,9 @@ static TRBType xhci_ring_fetch(XHCIState *xhci, XHCIRing *ring, XHCITRB *trb, ring->dequeue += TRB_SIZE; return type; } else { + if (++link_cnt > TRB_LINK_LIMIT) { + return 0; + } ring->dequeue = xhci_mask64(trb->parameter); if (trb->control & TRB_LK_TC) { ring->ccs = !ring->ccs; @@ -1043,6 +1049,7 @@ static int xhci_ring_chain_length(XHCIState *xhci, const XHCIRing *ring) bool ccs = ring->ccs; /* hack to bundle together the two/three TDs that make a setup transfer */ bool control_td_set = 0; + uint32_t link_cnt = 0; while (1) { TRBType type; @@ -1058,6 +1065,9 @@ static int xhci_ring_chain_length(XHCIState *xhci, const XHCIRing *ring) type = TRB_TYPE(trb); if (type == TR_LINK) { + if (++link_cnt > TRB_LINK_LIMIT) { + return -length; + } dequeue = xhci_mask64(trb.parameter); if (trb.control & TRB_LK_TC) { ccs = !ccs; From 1fe163feeb31cbd20e2ace071f34141892c8e06b Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 27 Sep 2016 10:32:46 +0200 Subject: [PATCH 652/723] xhci: decouple EV_QUEUE from TD_QUEUE EV_QUEUE must not change because an array of that size is part of live migration data. Hard-code current value there, so we can touch TD_QUEUE without breaking live migration. Signed-off-by: Gerd Hoffmann Message-id: 1474965172-30321-3-git-send-email-kraxel@redhat.com --- hw/usb/hcd-xhci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index ee4fa484d6b..d9ac1b4be3c 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -49,7 +49,7 @@ #define TD_QUEUE 24 /* Very pessimistic, let's hope it's enough for all cases */ -#define EV_QUEUE (((3*TD_QUEUE)+16)*MAXSLOTS) +#define EV_QUEUE (((3 * 24) + 16) * MAXSLOTS) /* Do not deliver ER Full events. NEC's driver does some things not bound * to the specs when it gets them */ #define ER_FULL_HACK From 7512b13dd7f77c3e93a5b856eddf78378bddcc7f Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 27 Sep 2016 10:32:47 +0200 Subject: [PATCH 653/723] xhci: drop unused comp_xfer field Signed-off-by: Gerd Hoffmann Message-id: 1474965172-30321-4-git-send-email-kraxel@redhat.com --- hw/usb/hcd-xhci.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index d9ac1b4be3c..3a035c81770 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -386,7 +386,6 @@ struct XHCIEPContext { XHCIRing ring; unsigned int next_xfer; - unsigned int comp_xfer; XHCITransfer transfers[TD_QUEUE]; XHCITransfer *retry; EPType type; From 94b037f2a451b3dc855f9f2c346e5049a361bd55 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 27 Sep 2016 10:32:48 +0200 Subject: [PATCH 654/723] xhci: use linked list for transfers xhci has a fixed number of 24 (TD_QUEUE) XHCITransfer structs per endpoint, which turns out to be a problem for usb3 devices with 32 (or more) bulk streams. xhci re-checks the trb rings on every finished transfer to make sure it'll pick up any pending work. But that scheme breaks in case the first transfer of a ring can't be started because we ran out of XHCITransfer structs already. So remove static XHCITransfer array from XHCIEPContext. Use a linked list instead, and allocate/free XHCITransfer as needed. Add helper functions to allocate & initialize and to cleanup & release XHCITransfer structs. That also simplifies trb management, we never have to realloc XHCITransfer->trbs because we don't reuse XHCITransfer structs any more. New dynamic limit for in-flight xhci transfers per endpoint is number-of-streams + 16. Signed-off-by: Gerd Hoffmann Message-id: 1474965172-30321-5-git-send-email-kraxel@redhat.com --- hw/usb/hcd-xhci.c | 122 ++++++++++++++++++++++++++-------------------- 1 file changed, 68 insertions(+), 54 deletions(-) diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index 3a035c81770..e14c2a81643 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -21,6 +21,7 @@ #include "qemu/osdep.h" #include "hw/hw.h" #include "qemu/timer.h" +#include "qemu/queue.h" #include "hw/usb.h" #include "hw/pci/pci.h" #include "hw/pci/msi.h" @@ -46,8 +47,6 @@ #define MAXSLOTS 64 #define MAXINTRS 16 -#define TD_QUEUE 24 - /* Very pessimistic, let's hope it's enough for all cases */ #define EV_QUEUE (((3 * 24) + 16) * MAXSLOTS) /* Do not deliver ER Full events. NEC's driver does some things not bound @@ -346,6 +345,7 @@ typedef struct XHCIPort { typedef struct XHCITransfer { XHCIState *xhci; + XHCIEPContext *epctx; USBPacket packet; QEMUSGList sgl; bool running_async; @@ -361,7 +361,6 @@ typedef struct XHCITransfer { bool timed_xfer; unsigned int trb_count; - unsigned int trb_alloced; XHCITRB *trbs; TRBCCode status; @@ -371,6 +370,8 @@ typedef struct XHCITransfer { unsigned int cur_pkt; uint64_t mfindex_kick; + + QTAILQ_ENTRY(XHCITransfer) next; } XHCITransfer; struct XHCIStreamContext { @@ -385,8 +386,8 @@ struct XHCIEPContext { unsigned int epid; XHCIRing ring; - unsigned int next_xfer; - XHCITransfer transfers[TD_QUEUE]; + uint32_t xfer_count; + QTAILQ_HEAD(, XHCITransfer) transfers; XHCITransfer *retry; EPType type; dma_addr_t pctx; @@ -1370,19 +1371,13 @@ static XHCIEPContext *xhci_alloc_epctx(XHCIState *xhci, unsigned int epid) { XHCIEPContext *epctx; - int i; epctx = g_new0(XHCIEPContext, 1); epctx->xhci = xhci; epctx->slotid = slotid; epctx->epid = epid; - for (i = 0; i < ARRAY_SIZE(epctx->transfers); i++) { - epctx->transfers[i].xhci = xhci; - epctx->transfers[i].slotid = slotid; - epctx->transfers[i].epid = epid; - usb_packet_init(&epctx->transfers[i].packet); - } + QTAILQ_INIT(&epctx->transfers); epctx->kick_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, xhci_ep_kick_timer, epctx); return epctx; @@ -1443,6 +1438,41 @@ static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid, return CC_SUCCESS; } +static XHCITransfer *xhci_ep_alloc_xfer(XHCIEPContext *epctx, + uint32_t length) +{ + uint32_t limit = epctx->nr_pstreams + 16; + XHCITransfer *xfer; + + if (epctx->xfer_count >= limit) { + return NULL; + } + + xfer = g_new0(XHCITransfer, 1); + xfer->xhci = epctx->xhci; + xfer->epctx = epctx; + xfer->slotid = epctx->slotid; + xfer->epid = epctx->epid; + xfer->trbs = g_new(XHCITRB, length); + xfer->trb_count = length; + usb_packet_init(&xfer->packet); + + QTAILQ_INSERT_TAIL(&epctx->transfers, xfer, next); + epctx->xfer_count++; + + return xfer; +} + +static void xhci_ep_free_xfer(XHCITransfer *xfer) +{ + QTAILQ_REMOVE(&xfer->epctx->transfers, xfer, next); + xfer->epctx->xfer_count--; + + usb_packet_cleanup(&xfer->packet); + g_free(xfer->trbs); + g_free(xfer); +} + static int xhci_ep_nuke_one_xfer(XHCITransfer *t, TRBCCode report) { int killed = 0; @@ -1469,7 +1499,7 @@ static int xhci_ep_nuke_one_xfer(XHCITransfer *t, TRBCCode report) g_free(t->trbs); t->trbs = NULL; - t->trb_count = t->trb_alloced = 0; + t->trb_count = 0; return killed; } @@ -1479,7 +1509,8 @@ static int xhci_ep_nuke_xfers(XHCIState *xhci, unsigned int slotid, { XHCISlot *slot; XHCIEPContext *epctx; - int i, xferi, killed = 0; + XHCITransfer *xfer; + int killed = 0; USBEndpoint *ep = NULL; assert(slotid >= 1 && slotid <= xhci->numslots); assert(epid >= 1 && epid <= 31); @@ -1494,14 +1525,16 @@ static int xhci_ep_nuke_xfers(XHCIState *xhci, unsigned int slotid, epctx = slot->eps[epid-1]; - xferi = epctx->next_xfer; - for (i = 0; i < TD_QUEUE; i++) { - killed += xhci_ep_nuke_one_xfer(&epctx->transfers[xferi], report); + for (;;) { + xfer = QTAILQ_FIRST(&epctx->transfers); + if (xfer == NULL) { + break; + } + killed += xhci_ep_nuke_one_xfer(xfer, report); if (killed) { report = 0; /* Only report once */ } - epctx->transfers[xferi].packet.ep = NULL; - xferi = (xferi + 1) % TD_QUEUE; + xhci_ep_free_xfer(xfer); } ep = xhci_epid_to_usbep(xhci, slotid, epid); @@ -1516,7 +1549,6 @@ static TRBCCode xhci_disable_ep(XHCIState *xhci, unsigned int slotid, { XHCISlot *slot; XHCIEPContext *epctx; - int i; trace_usb_xhci_ep_disable(slotid, epid); assert(slotid >= 1 && slotid <= xhci->numslots); @@ -1537,10 +1569,6 @@ static TRBCCode xhci_disable_ep(XHCIState *xhci, unsigned int slotid, xhci_free_streams(epctx); } - for (i = 0; i < ARRAY_SIZE(epctx->transfers); i++) { - usb_packet_cleanup(&epctx->transfers[i].packet); - } - /* only touch guest RAM if we're not resetting the HC */ if (xhci->dcbaap_low || xhci->dcbaap_high) { xhci_set_ep_state(xhci, epctx, NULL, EP_DISABLED); @@ -2104,6 +2132,7 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, { XHCIStreamContext *stctx; XHCIEPContext *epctx; + XHCITransfer *xfer; XHCIRing *ring; USBEndpoint *ep = NULL; uint64_t mfindex; @@ -2168,6 +2197,7 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, xhci_complete_packet(xfer); } assert(!xfer->running_retry); + xhci_ep_free_xfer(epctx->retry); epctx->retry = NULL; } @@ -2193,27 +2223,14 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, assert(ring->dequeue != 0); while (1) { - XHCITransfer *xfer = &epctx->transfers[epctx->next_xfer]; - if (xfer->running_async || xfer->running_retry) { - break; - } length = xhci_ring_chain_length(xhci, ring); - if (length < 0) { + if (length <= 0) { break; - } else if (length == 0) { - break; - } - if (xfer->trbs && xfer->trb_alloced < length) { - xfer->trb_count = 0; - xfer->trb_alloced = 0; - g_free(xfer->trbs); - xfer->trbs = NULL; } - if (!xfer->trbs) { - xfer->trbs = g_new(XHCITRB, length); - xfer->trb_alloced = length; + xfer = xhci_ep_alloc_xfer(epctx, length); + if (xfer == NULL) { + break; } - xfer->trb_count = length; for (i = 0; i < length; i++) { TRBType type; @@ -2223,25 +2240,19 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, xfer->streamid = streamid; if (epid == 1) { - if (xhci_fire_ctl_transfer(xhci, xfer) >= 0) { - epctx->next_xfer = (epctx->next_xfer + 1) % TD_QUEUE; - } else { - DPRINTF("xhci: error firing CTL transfer\n"); - } + xhci_fire_ctl_transfer(xhci, xfer); } else { - if (xhci_fire_transfer(xhci, xfer, epctx) >= 0) { - epctx->next_xfer = (epctx->next_xfer + 1) % TD_QUEUE; - } else { - if (!xfer->timed_xfer) { - DPRINTF("xhci: error firing data transfer\n"); - } - } + xhci_fire_transfer(xhci, xfer, epctx); + } + if (xfer->complete) { + xhci_ep_free_xfer(xfer); + xfer = NULL; } if (epctx->state == EP_HALTED) { break; } - if (xfer->running_retry) { + if (xfer != NULL && xfer->running_retry) { DPRINTF("xhci: xfer nacked, stopping schedule\n"); epctx->retry = xfer; break; @@ -3480,6 +3491,9 @@ static void xhci_complete(USBPort *port, USBPacket *packet) } xhci_complete_packet(xfer); xhci_kick_ep(xfer->xhci, xfer->slotid, xfer->epid, xfer->streamid); + if (xfer->complete) { + xhci_ep_free_xfer(xfer); + } } static void xhci_child_detach(USBPort *uport, USBDevice *child) From 5612564ea9cf5b9636438a1b58ae9a2ab6ca16ae Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 27 Sep 2016 10:32:49 +0200 Subject: [PATCH 655/723] xhci: drop XHCITransfer->xhci Use XHCITransfer->epctx->xhci instead. Signed-off-by: Gerd Hoffmann Message-id: 1474965172-30321-6-git-send-email-kraxel@redhat.com --- hw/usb/hcd-xhci.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index e14c2a81643..20f46c44965 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -344,7 +344,6 @@ typedef struct XHCIPort { } XHCIPort; typedef struct XHCITransfer { - XHCIState *xhci; XHCIEPContext *epctx; USBPacket packet; QEMUSGList sgl; @@ -1449,7 +1448,6 @@ static XHCITransfer *xhci_ep_alloc_xfer(XHCIEPContext *epctx, } xfer = g_new0(XHCITransfer, 1); - xfer->xhci = epctx->xhci; xfer->epctx = epctx; xfer->slotid = epctx->slotid; xfer->epid = epctx->epid; @@ -1488,10 +1486,9 @@ static int xhci_ep_nuke_one_xfer(XHCITransfer *t, TRBCCode report) killed = 1; } if (t->running_retry) { - XHCIEPContext *epctx = t->xhci->slots[t->slotid-1].eps[t->epid-1]; - if (epctx) { - epctx->retry = NULL; - timer_del(epctx->kick_timer); + if (t->epctx) { + t->epctx->retry = NULL; + timer_del(t->epctx->kick_timer); } t->running_retry = 0; killed = 1; @@ -1721,7 +1718,7 @@ static TRBCCode xhci_set_ep_dequeue(XHCIState *xhci, unsigned int slotid, static int xhci_xfer_create_sgl(XHCITransfer *xfer, int in_xfer) { - XHCIState *xhci = xfer->xhci; + XHCIState *xhci = xfer->epctx->xhci; int i; xfer->int_req = false; @@ -1780,7 +1777,7 @@ static void xhci_xfer_report(XHCITransfer *xfer) bool reported = 0; bool shortpkt = 0; XHCIEvent event = {ER_TRANSFER, CC_SUCCESS}; - XHCIState *xhci = xfer->xhci; + XHCIState *xhci = xfer->epctx->xhci; int i; left = xfer->packet.actual_length; @@ -1854,9 +1851,8 @@ static void xhci_xfer_report(XHCITransfer *xfer) static void xhci_stall_ep(XHCITransfer *xfer) { - XHCIState *xhci = xfer->xhci; - XHCISlot *slot = &xhci->slots[xfer->slotid-1]; - XHCIEPContext *epctx = slot->eps[xfer->epid-1]; + XHCIEPContext *epctx = xfer->epctx; + XHCIState *xhci = epctx->xhci; uint32_t err; XHCIStreamContext *sctx; @@ -1880,7 +1876,7 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, static int xhci_setup_packet(XHCITransfer *xfer) { - XHCIState *xhci = xfer->xhci; + XHCIState *xhci = xfer->epctx->xhci; USBEndpoint *ep; int dir; @@ -3490,7 +3486,7 @@ static void xhci_complete(USBPort *port, USBPacket *packet) return; } xhci_complete_packet(xfer); - xhci_kick_ep(xfer->xhci, xfer->slotid, xfer->epid, xfer->streamid); + xhci_kick_ep(xfer->epctx->xhci, xfer->slotid, xfer->epid, xfer->streamid); if (xfer->complete) { xhci_ep_free_xfer(xfer); } From 3a533ee8fda6457ddc85d3c5dfeff037a808fcb3 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 27 Sep 2016 10:32:50 +0200 Subject: [PATCH 656/723] xhci: add & use xhci_kick_epctx() xhci_kick_epctx is a xhci_kick_ep variant which takes an XHCIEPContext as input instead of slotid and epid. So in case we have a XHCIEPContext at hand at the callsite we can just pass it directly. Signed-off-by: Gerd Hoffmann Message-id: 1474965172-30321-7-git-send-email-kraxel@redhat.com --- hw/usb/hcd-xhci.c | 43 ++++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index 20f46c44965..c82fe091d1a 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -509,6 +509,7 @@ enum xhci_flags { static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid, unsigned int streamid); +static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid); static TRBCCode xhci_disable_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid); static void xhci_xfer_report(XHCITransfer *xfer); @@ -1362,7 +1363,7 @@ static void xhci_set_ep_state(XHCIState *xhci, XHCIEPContext *epctx, static void xhci_ep_kick_timer(void *opaque) { XHCIEPContext *epctx = opaque; - xhci_kick_ep(epctx->xhci, epctx->slotid, epctx->epid, 0); + xhci_kick_epctx(epctx, 0); } static XHCIEPContext *xhci_alloc_epctx(XHCIState *xhci, @@ -2008,7 +2009,7 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) xhci_complete_packet(xfer); if (!xfer->running_async && !xfer->running_retry) { - xhci_kick_ep(xhci, xfer->slotid, xfer->epid, 0); + xhci_kick_epctx(xfer->epctx, 0); } return 0; } @@ -2112,7 +2113,7 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx xhci_complete_packet(xfer); if (!xfer->running_async && !xfer->running_retry) { - xhci_kick_ep(xhci, xfer->slotid, xfer->epid, xfer->streamid); + xhci_kick_epctx(xfer->epctx, xfer->streamid); } return 0; } @@ -2126,16 +2127,8 @@ static int xhci_fire_transfer(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid, unsigned int streamid) { - XHCIStreamContext *stctx; XHCIEPContext *epctx; - XHCITransfer *xfer; - XHCIRing *ring; - USBEndpoint *ep = NULL; - uint64_t mfindex; - int length; - int i; - trace_usb_xhci_ep_kick(slotid, epid, streamid); assert(slotid >= 1 && slotid <= xhci->numslots); assert(epid >= 1 && epid <= 31); @@ -2150,11 +2143,27 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, return; } + xhci_kick_epctx(epctx, streamid); +} + +static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid) +{ + XHCIState *xhci = epctx->xhci; + XHCIStreamContext *stctx; + XHCITransfer *xfer; + XHCIRing *ring; + USBEndpoint *ep = NULL; + uint64_t mfindex; + int length; + int i; + + trace_usb_xhci_ep_kick(epctx->slotid, epctx->epid, streamid); + /* If the device has been detached, but the guest has not noticed this yet the 2 above checks will succeed, but we must NOT continue */ - if (!xhci->slots[slotid - 1].uport || - !xhci->slots[slotid - 1].uport->dev || - !xhci->slots[slotid - 1].uport->dev->attached) { + if (!xhci->slots[epctx->slotid - 1].uport || + !xhci->slots[epctx->slotid - 1].uport->dev || + !xhci->slots[epctx->slotid - 1].uport->dev->attached) { return; } @@ -2235,7 +2244,7 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, } xfer->streamid = streamid; - if (epid == 1) { + if (epctx->epid == 1) { xhci_fire_ctl_transfer(xhci, xfer); } else { xhci_fire_transfer(xhci, xfer, epctx); @@ -2255,7 +2264,7 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, } } - ep = xhci_epid_to_usbep(xhci, slotid, epid); + ep = xhci_epid_to_usbep(xhci, epctx->slotid, epctx->epid); if (ep) { usb_device_flush_ep_queue(ep->dev, ep); } @@ -3486,7 +3495,7 @@ static void xhci_complete(USBPort *port, USBPacket *packet) return; } xhci_complete_packet(xfer); - xhci_kick_ep(xfer->epctx->xhci, xfer->slotid, xfer->epid, xfer->streamid); + xhci_kick_epctx(xfer->epctx, xfer->streamid); if (xfer->complete) { xhci_ep_free_xfer(xfer); } From d6fcb2936f9bacf3ad696e957e229ee2aadc0d0d Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 27 Sep 2016 10:32:51 +0200 Subject: [PATCH 657/723] xhci: drop XHCITransfer->{slotid,epid} We can use XHCITransfer->epctx->{slotid,epid} instead. Signed-off-by: Gerd Hoffmann Message-id: 1474965172-30321-8-git-send-email-kraxel@redhat.com --- hw/usb/hcd-xhci.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index c82fe091d1a..80840d3e207 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -352,8 +352,6 @@ typedef struct XHCITransfer { bool complete; bool int_req; unsigned int iso_pkts; - unsigned int slotid; - unsigned int epid; unsigned int streamid; bool in_xfer; bool iso_xfer; @@ -1450,8 +1448,6 @@ static XHCITransfer *xhci_ep_alloc_xfer(XHCIEPContext *epctx, xfer = g_new0(XHCITransfer, 1); xfer->epctx = epctx; - xfer->slotid = epctx->slotid; - xfer->epid = epctx->epid; xfer->trbs = g_new(XHCITRB, length); xfer->trb_count = length; usb_packet_init(&xfer->packet); @@ -1816,8 +1812,8 @@ static void xhci_xfer_report(XHCITransfer *xfer) if (!reported && ((trb->control & TRB_TR_IOC) || (shortpkt && (trb->control & TRB_TR_ISP)) || (xfer->status != CC_SUCCESS && left == 0))) { - event.slotid = xfer->slotid; - event.epid = xfer->epid; + event.slotid = xfer->epctx->slotid; + event.epid = xfer->epctx->epid; event.length = (trb->status & 0x1ffff) - chunk; event.flags = 0; event.ptr = trb->addr; @@ -1886,7 +1882,7 @@ static int xhci_setup_packet(XHCITransfer *xfer) if (xfer->packet.ep) { ep = xfer->packet.ep; } else { - ep = xhci_epid_to_usbep(xhci, xfer->slotid, xfer->epid); + ep = xhci_epid_to_usbep(xhci, xfer->epctx->slotid, xfer->epctx->epid); if (!ep) { DPRINTF("xhci: slot %d has no device\n", xfer->slotid); @@ -1966,7 +1962,8 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) trb_setup = &xfer->trbs[0]; trb_status = &xfer->trbs[xfer->trb_count-1]; - trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid, xfer->streamid); + trace_usb_xhci_xfer_start(xfer, xfer->epctx->slotid, + xfer->epctx->epid, xfer->streamid); /* at most one Event Data TRB allowed after STATUS */ if (TRB_TYPE(*trb_status) == TR_EVDATA && xfer->trb_count > 2) { @@ -2120,7 +2117,8 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx static int xhci_fire_transfer(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx) { - trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid, xfer->streamid); + trace_usb_xhci_xfer_start(xfer, xfer->epctx->slotid, + xfer->epctx->epid, xfer->streamid); return xhci_submit(xhci, xfer, epctx); } From 070eeef9e0821fbaeda7002de4ee61b5b4015fa6 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 27 Sep 2016 10:32:52 +0200 Subject: [PATCH 658/723] xhci: make xhci_epid_to_usbep accept XHCIEPContext All callsites have a XHCIEPContext pointer anyway, so we can just pass it directly instead of fiddeling with slotid and epid. Signed-off-by: Gerd Hoffmann Message-id: 1474965172-30321-9-git-send-email-kraxel@redhat.com --- hw/usb/hcd-xhci.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index 80840d3e207..4acf0c6dd8c 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -513,8 +513,7 @@ static TRBCCode xhci_disable_ep(XHCIState *xhci, unsigned int slotid, static void xhci_xfer_report(XHCITransfer *xfer); static void xhci_event(XHCIState *xhci, XHCIEvent *event, int v); static void xhci_write_event(XHCIState *xhci, XHCIEvent *event, int v); -static USBEndpoint *xhci_epid_to_usbep(XHCIState *xhci, - unsigned int slotid, unsigned int epid); +static USBEndpoint *xhci_epid_to_usbep(XHCIEPContext *epctx); static const char *TRBType_names[] = { [TRB_RESERVED] = "TRB_RESERVED", @@ -1200,7 +1199,7 @@ static int xhci_epmask_to_eps_with_streams(XHCIState *xhci, } epctx = slot->eps[i - 1]; - ep = xhci_epid_to_usbep(xhci, slotid, i); + ep = xhci_epid_to_usbep(epctx); if (!epctx || !epctx->nr_pstreams || !ep) { continue; } @@ -1531,7 +1530,7 @@ static int xhci_ep_nuke_xfers(XHCIState *xhci, unsigned int slotid, xhci_ep_free_xfer(xfer); } - ep = xhci_epid_to_usbep(xhci, slotid, epid); + ep = xhci_epid_to_usbep(epctx); if (ep) { usb_device_ep_stopped(ep->dev, ep); } @@ -1873,7 +1872,6 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, static int xhci_setup_packet(XHCITransfer *xfer) { - XHCIState *xhci = xfer->epctx->xhci; USBEndpoint *ep; int dir; @@ -1882,7 +1880,7 @@ static int xhci_setup_packet(XHCITransfer *xfer) if (xfer->packet.ep) { ep = xfer->packet.ep; } else { - ep = xhci_epid_to_usbep(xhci, xfer->epctx->slotid, xfer->epctx->epid); + ep = xhci_epid_to_usbep(xfer->epctx); if (!ep) { DPRINTF("xhci: slot %d has no device\n", xfer->slotid); @@ -2262,7 +2260,7 @@ static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid) } } - ep = xhci_epid_to_usbep(xhci, epctx->slotid, epctx->epid); + ep = xhci_epid_to_usbep(epctx); if (ep) { usb_device_flush_ep_queue(ep->dev, ep); } @@ -3527,17 +3525,20 @@ static int xhci_find_epid(USBEndpoint *ep) } } -static USBEndpoint *xhci_epid_to_usbep(XHCIState *xhci, - unsigned int slotid, unsigned int epid) +static USBEndpoint *xhci_epid_to_usbep(XHCIEPContext *epctx) { - assert(slotid >= 1 && slotid <= xhci->numslots); + USBPort *uport; + uint32_t token; - if (!xhci->slots[slotid - 1].uport) { + if (!epctx) { return NULL; } - - return usb_ep_get(xhci->slots[slotid - 1].uport->dev, - (epid & 1) ? USB_TOKEN_IN : USB_TOKEN_OUT, epid >> 1); + uport = epctx->xhci->slots[epctx->slotid - 1].uport; + token = (epctx->epid & 1) ? USB_TOKEN_IN : USB_TOKEN_OUT; + if (!uport) { + return NULL; + } + return usb_ep_get(uport->dev, token, epctx->epid >> 1); } static void xhci_wakeup_endpoint(USBBus *bus, USBEndpoint *ep, From 0136464d10f1fd9393a8125f2c552ef24f3e592c Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 5 Oct 2016 11:33:18 +0200 Subject: [PATCH 659/723] usb: fix serial generator snprintf return value is *not* the number of chars written into the buffer, but the number of chars needed. So in case the buffer is too small you can go alloc a bigger one and try again. But that also means you can't simply use the return value for the next snprintf call without checking beforehand that things did actually fit. Problem is that usb_desc_create_serial didn't perform that check, so a loooong path string (can happen with deep pci-bridge nesting) results in the third snprintf call smashing the stack. Fix this by throwing out all the snpintf calls and use g_strdup_printf instead. https://bugzilla.redhat.com/show_bug.cgi?id=1381630 Reported-by: Thomas Huth Signed-off-by: Gerd Hoffmann Reviewed-by: Thomas Huth Reviewed-by: Eric Blake Message-id: 1475659998-22045-1-git-send-email-kraxel@redhat.com --- hw/usb/desc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hw/usb/desc.c b/hw/usb/desc.c index 5e0e1d157e3..7828e52c6f2 100644 --- a/hw/usb/desc.c +++ b/hw/usb/desc.c @@ -556,9 +556,7 @@ void usb_desc_create_serial(USBDevice *dev) DeviceState *hcd = dev->qdev.parent_bus->parent; const USBDesc *desc = usb_device_get_usb_desc(dev); int index = desc->id.iSerialNumber; - char serial[64]; - char *path; - int dst; + char *path, *serial; if (dev->serial) { /* 'serial' usb bus property has priority if present */ @@ -567,14 +565,16 @@ void usb_desc_create_serial(USBDevice *dev) } assert(index != 0 && desc->str[index] != NULL); - dst = snprintf(serial, sizeof(serial), "%s", desc->str[index]); path = qdev_get_dev_path(hcd); if (path) { - dst += snprintf(serial+dst, sizeof(serial)-dst, "-%s", path); + serial = g_strdup_printf("%s-%s-%s", desc->str[index], + path, dev->port->path); + } else { + serial = g_strdup_printf("%s-%s", desc->str[index], dev->port->path); } - dst += snprintf(serial+dst, sizeof(serial)-dst, "-%s", dev->port->path); usb_desc_set_string(dev, index, serial); g_free(path); + g_free(serial); } const char *usb_desc_get_string(USBDevice *dev, uint8_t index) From 6998b6c7c77e22d386fb8792365e668351d22f91 Mon Sep 17 00:00:00 2001 From: Vijay Kumar B Date: Wed, 28 Sep 2016 16:39:18 +0530 Subject: [PATCH 660/723] usb: Fix incorrect default DMA offset. The default DMA offset is set to 3. When the property is not set by the consumer, the default causes DMA access to be shifted by 3 bytes. In PXA, this results in incorrect DMA access, leading to error notification in the USB controller driver. A better default would be 0, so that there is no offset, when the consumer does not specify one. Signed-off-by: Vijay Kumar B. Reviewed-by: Deepak S. Message-id: 1475060958-7760-1-git-send-email-vijaykumar@zilogic.com Signed-off-by: Gerd Hoffmann --- hw/usb/hcd-ohci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c index fa5703832ce..c82a92fff73 100644 --- a/hw/usb/hcd-ohci.c +++ b/hw/usb/hcd-ohci.c @@ -2139,7 +2139,7 @@ static const TypeInfo ohci_pci_info = { static Property ohci_sysbus_properties[] = { DEFINE_PROP_UINT32("num-ports", OHCISysBusState, num_ports, 3), - DEFINE_PROP_DMAADDR("dma-offset", OHCISysBusState, dma_offset, 3), + DEFINE_PROP_DMAADDR("dma-offset", OHCISysBusState, dma_offset, 0), DEFINE_PROP_END_OF_LIST(), }; From d5c42857d6b0c35028897df8dfc3749eba6f6de3 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 10 Oct 2016 12:45:13 +0200 Subject: [PATCH 661/723] usb-redir: allocate buffers before waking up the host adapter Needed to make sure usb redirection is prepared to actually handle the callback from the usb host adapter. Without this interrupt endpoints don't work on xhci. Note: On ehci the usb_wakeup() call only schedules a BH for the actual work, which hides this bug because the allocation happens before ehci calls back even without this patch. Signed-off-by: Hans de Goede Message-id: 1476096313-7730-1-git-send-email-kraxel@redhat.com Signed-off-by: Gerd Hoffmann --- hw/usb/redirect.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index 444672a000c..d4ca026f00a 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -2036,18 +2036,22 @@ static void usbredir_interrupt_packet(void *priv, uint64_t id, } if (ep & USB_DIR_IN) { + bool q_was_empty; + if (dev->endpoint[EP2I(ep)].interrupt_started == 0) { DPRINTF("received int packet while not started ep %02X\n", ep); free(data); return; } - if (QTAILQ_EMPTY(&dev->endpoint[EP2I(ep)].bufpq)) { - usb_wakeup(usb_ep_get(&dev->dev, USB_TOKEN_IN, ep & 0x0f), 0); - } + q_was_empty = QTAILQ_EMPTY(&dev->endpoint[EP2I(ep)].bufpq); /* bufp_alloc also adds the packet to the ep queue */ bufp_alloc(dev, data, data_len, interrupt_packet->status, ep, data); + + if (q_was_empty) { + usb_wakeup(usb_ep_get(&dev->dev, USB_TOKEN_IN, ep & 0x0f), 0); + } } else { /* * We report output interrupt packets as completed directly upon From 6ff3ab0d6b44fde29a6d936512e2afea213f83b5 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Mon, 15 Aug 2016 17:37:44 +0200 Subject: [PATCH 662/723] linux-headers: update Update headers against 4.8-rc2. Signed-off-by: Cornelia Huck --- .../linux/input-event-codes.h | 32 +++++++ include/standard-headers/linux/input.h | 1 + .../standard-headers/linux/virtio_config.h | 10 +- include/standard-headers/linux/virtio_ids.h | 1 + include/standard-headers/linux/virtio_net.h | 3 + include/standard-headers/linux/virtio_vsock.h | 94 +++++++++++++++++++ linux-headers/asm-arm/kvm.h | 4 +- linux-headers/asm-arm64/kvm.h | 2 + linux-headers/asm-s390/kvm.h | 41 ++++++++ linux-headers/asm-x86/unistd_x32.h | 4 +- linux-headers/linux/kvm.h | 18 +++- linux-headers/linux/vhost.h | 33 +++++++ 12 files changed, 236 insertions(+), 7 deletions(-) create mode 100644 include/standard-headers/linux/virtio_vsock.h diff --git a/include/standard-headers/linux/input-event-codes.h b/include/standard-headers/linux/input-event-codes.h index 354f0decf1e..5c10f7e25d0 100644 --- a/include/standard-headers/linux/input-event-codes.h +++ b/include/standard-headers/linux/input-event-codes.h @@ -611,6 +611,37 @@ #define KEY_KBDINPUTASSIST_ACCEPT 0x264 #define KEY_KBDINPUTASSIST_CANCEL 0x265 +/* Diagonal movement keys */ +#define KEY_RIGHT_UP 0x266 +#define KEY_RIGHT_DOWN 0x267 +#define KEY_LEFT_UP 0x268 +#define KEY_LEFT_DOWN 0x269 + +#define KEY_ROOT_MENU 0x26a /* Show Device's Root Menu */ +/* Show Top Menu of the Media (e.g. DVD) */ +#define KEY_MEDIA_TOP_MENU 0x26b +#define KEY_NUMERIC_11 0x26c +#define KEY_NUMERIC_12 0x26d +/* + * Toggle Audio Description: refers to an audio service that helps blind and + * visually impaired consumers understand the action in a program. Note: in + * some countries this is referred to as "Video Description". + */ +#define KEY_AUDIO_DESC 0x26e +#define KEY_3D_MODE 0x26f +#define KEY_NEXT_FAVORITE 0x270 +#define KEY_STOP_RECORD 0x271 +#define KEY_PAUSE_RECORD 0x272 +#define KEY_VOD 0x273 /* Video on Demand */ +#define KEY_UNMUTE 0x274 +#define KEY_FASTREVERSE 0x275 +#define KEY_SLOWREVERSE 0x276 +/* + * Control a data application associated with the currently viewed channel, + * e.g. teletext or data broadcast application (MHEG, MHP, HbbTV, etc.) + */ +#define KEY_DATA 0x275 + #define BTN_TRIGGER_HAPPY 0x2c0 #define BTN_TRIGGER_HAPPY1 0x2c0 #define BTN_TRIGGER_HAPPY2 0x2c1 @@ -749,6 +780,7 @@ #define SW_ROTATE_LOCK 0x0c /* set = rotate locked/disabled */ #define SW_LINEIN_INSERT 0x0d /* set = inserted */ #define SW_MUTE_DEVICE 0x0e /* set = device disabled */ +#define SW_PEN_INSERTED 0x0f /* set = pen inserted */ #define SW_MAX_ 0x0f #define SW_CNT (SW_MAX_+1) diff --git a/include/standard-headers/linux/input.h b/include/standard-headers/linux/input.h index a52b2025ba9..7361a16b50e 100644 --- a/include/standard-headers/linux/input.h +++ b/include/standard-headers/linux/input.h @@ -244,6 +244,7 @@ struct input_mask { #define BUS_ATARI 0x1B #define BUS_SPI 0x1C #define BUS_RMI 0x1D +#define BUS_CEC 0x1E /* * MT_TOOL types diff --git a/include/standard-headers/linux/virtio_config.h b/include/standard-headers/linux/virtio_config.h index b30d0cb0c12..b7770696995 100644 --- a/include/standard-headers/linux/virtio_config.h +++ b/include/standard-headers/linux/virtio_config.h @@ -49,7 +49,7 @@ * transport being used (eg. virtio_ring), the rest are per-device feature * bits. */ #define VIRTIO_TRANSPORT_F_START 28 -#define VIRTIO_TRANSPORT_F_END 33 +#define VIRTIO_TRANSPORT_F_END 34 #ifndef VIRTIO_CONFIG_NO_LEGACY /* Do we get callbacks when the ring is completely used, even if we've @@ -63,4 +63,12 @@ /* v1.0 compliant. */ #define VIRTIO_F_VERSION_1 32 +/* + * If clear - device has the IOMMU bypass quirk feature. + * If set - use platform tools to detect the IOMMU. + * + * Note the reverse polarity (compared to most other features), + * this is for compatibility with legacy systems. + */ +#define VIRTIO_F_IOMMU_PLATFORM 33 #endif /* _LINUX_VIRTIO_CONFIG_H */ diff --git a/include/standard-headers/linux/virtio_ids.h b/include/standard-headers/linux/virtio_ids.h index 77925f587b1..3228d582234 100644 --- a/include/standard-headers/linux/virtio_ids.h +++ b/include/standard-headers/linux/virtio_ids.h @@ -41,5 +41,6 @@ #define VIRTIO_ID_CAIF 12 /* Virtio caif */ #define VIRTIO_ID_GPU 16 /* virtio GPU */ #define VIRTIO_ID_INPUT 18 /* virtio input */ +#define VIRTIO_ID_VSOCK 19 /* virtio vsock transport */ #endif /* _LINUX_VIRTIO_IDS_H */ diff --git a/include/standard-headers/linux/virtio_net.h b/include/standard-headers/linux/virtio_net.h index a78f33e775e..30ff24940df 100644 --- a/include/standard-headers/linux/virtio_net.h +++ b/include/standard-headers/linux/virtio_net.h @@ -35,6 +35,7 @@ #define VIRTIO_NET_F_CSUM 0 /* Host handles pkts w/ partial csum */ #define VIRTIO_NET_F_GUEST_CSUM 1 /* Guest handles pkts w/ partial csum */ #define VIRTIO_NET_F_CTRL_GUEST_OFFLOADS 2 /* Dynamic offload configuration. */ +#define VIRTIO_NET_F_MTU 3 /* Initial MTU advice */ #define VIRTIO_NET_F_MAC 5 /* Host has given MAC address. */ #define VIRTIO_NET_F_GUEST_TSO4 7 /* Guest can handle TSOv4 in. */ #define VIRTIO_NET_F_GUEST_TSO6 8 /* Guest can handle TSOv6 in. */ @@ -73,6 +74,8 @@ struct virtio_net_config { * Legal values are between 1 and 0x8000 */ uint16_t max_virtqueue_pairs; + /* Default maximum transmit unit advice */ + uint16_t mtu; } QEMU_PACKED; /* diff --git a/include/standard-headers/linux/virtio_vsock.h b/include/standard-headers/linux/virtio_vsock.h new file mode 100644 index 00000000000..be443211ce9 --- /dev/null +++ b/include/standard-headers/linux/virtio_vsock.h @@ -0,0 +1,94 @@ +/* + * This header, excluding the #ifdef __KERNEL__ part, is BSD licensed so + * anyone can use the definitions to implement compatible drivers/servers: + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of IBM nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Copyright (C) Red Hat, Inc., 2013-2015 + * Copyright (C) Asias He , 2013 + * Copyright (C) Stefan Hajnoczi , 2015 + */ + +#ifndef _LINUX_VIRTIO_VSOCK_H +#define _LINUX_VIRTIO_VSOCK_H + +#include "standard-headers/linux/types.h" +#include "standard-headers/linux/virtio_ids.h" +#include "standard-headers/linux/virtio_config.h" + +struct virtio_vsock_config { + uint64_t guest_cid; +} QEMU_PACKED; + +enum virtio_vsock_event_id { + VIRTIO_VSOCK_EVENT_TRANSPORT_RESET = 0, +}; + +struct virtio_vsock_event { + uint32_t id; +} QEMU_PACKED; + +struct virtio_vsock_hdr { + uint64_t src_cid; + uint64_t dst_cid; + uint32_t src_port; + uint32_t dst_port; + uint32_t len; + uint16_t type; /* enum virtio_vsock_type */ + uint16_t op; /* enum virtio_vsock_op */ + uint32_t flags; + uint32_t buf_alloc; + uint32_t fwd_cnt; +} QEMU_PACKED; + +enum virtio_vsock_type { + VIRTIO_VSOCK_TYPE_STREAM = 1, +}; + +enum virtio_vsock_op { + VIRTIO_VSOCK_OP_INVALID = 0, + + /* Connect operations */ + VIRTIO_VSOCK_OP_REQUEST = 1, + VIRTIO_VSOCK_OP_RESPONSE = 2, + VIRTIO_VSOCK_OP_RST = 3, + VIRTIO_VSOCK_OP_SHUTDOWN = 4, + + /* To send payload */ + VIRTIO_VSOCK_OP_RW = 5, + + /* Tell the peer our credit info */ + VIRTIO_VSOCK_OP_CREDIT_UPDATE = 6, + /* Request the peer to send the credit info to us */ + VIRTIO_VSOCK_OP_CREDIT_REQUEST = 7, +}; + +/* VIRTIO_VSOCK_OP_SHUTDOWN flags values */ +enum virtio_vsock_shutdown { + VIRTIO_VSOCK_SHUTDOWN_RCV = 1, + VIRTIO_VSOCK_SHUTDOWN_SEND = 2, +}; + +#endif /* _LINUX_VIRTIO_VSOCK_H */ diff --git a/linux-headers/asm-arm/kvm.h b/linux-headers/asm-arm/kvm.h index c98e4dc4606..541268c946f 100644 --- a/linux-headers/asm-arm/kvm.h +++ b/linux-headers/asm-arm/kvm.h @@ -139,8 +139,8 @@ struct kvm_arch_memory_slot { #define ARM_CP15_REG64(...) __ARM_CP15_REG64(__VA_ARGS__) #define KVM_REG_ARM_TIMER_CTL ARM_CP15_REG32(0, 14, 3, 1) -#define KVM_REG_ARM_TIMER_CNT ARM_CP15_REG64(1, 14) -#define KVM_REG_ARM_TIMER_CVAL ARM_CP15_REG64(3, 14) +#define KVM_REG_ARM_TIMER_CNT ARM_CP15_REG64(1, 14) +#define KVM_REG_ARM_TIMER_CVAL ARM_CP15_REG64(3, 14) /* Normal registers are mapped as coprocessor 16. */ #define KVM_REG_ARM_CORE (0x0010 << KVM_REG_ARM_COPROC_SHIFT) diff --git a/linux-headers/asm-arm64/kvm.h b/linux-headers/asm-arm64/kvm.h index 7d82d1f9d50..fd5a2761a5b 100644 --- a/linux-headers/asm-arm64/kvm.h +++ b/linux-headers/asm-arm64/kvm.h @@ -87,9 +87,11 @@ struct kvm_regs { /* Supported VGICv3 address types */ #define KVM_VGIC_V3_ADDR_TYPE_DIST 2 #define KVM_VGIC_V3_ADDR_TYPE_REDIST 3 +#define KVM_VGIC_ITS_ADDR_TYPE 4 #define KVM_VGIC_V3_DIST_SIZE SZ_64K #define KVM_VGIC_V3_REDIST_SIZE (2 * SZ_64K) +#define KVM_VGIC_V3_ITS_SIZE (2 * SZ_64K) #define KVM_ARM_VCPU_POWER_OFF 0 /* CPU is started in OFF state */ #define KVM_ARM_VCPU_EL1_32BIT 1 /* CPU running a 32bit VM */ diff --git a/linux-headers/asm-s390/kvm.h b/linux-headers/asm-s390/kvm.h index 09ae5dc2e90..ac63ca630b3 100644 --- a/linux-headers/asm-s390/kvm.h +++ b/linux-headers/asm-s390/kvm.h @@ -93,6 +93,47 @@ struct kvm_s390_vm_cpu_machine { __u64 fac_list[256]; }; +#define KVM_S390_VM_CPU_PROCESSOR_FEAT 2 +#define KVM_S390_VM_CPU_MACHINE_FEAT 3 + +#define KVM_S390_VM_CPU_FEAT_NR_BITS 1024 +#define KVM_S390_VM_CPU_FEAT_ESOP 0 +#define KVM_S390_VM_CPU_FEAT_SIEF2 1 +#define KVM_S390_VM_CPU_FEAT_64BSCAO 2 +#define KVM_S390_VM_CPU_FEAT_SIIF 3 +#define KVM_S390_VM_CPU_FEAT_GPERE 4 +#define KVM_S390_VM_CPU_FEAT_GSLS 5 +#define KVM_S390_VM_CPU_FEAT_IB 6 +#define KVM_S390_VM_CPU_FEAT_CEI 7 +#define KVM_S390_VM_CPU_FEAT_IBS 8 +#define KVM_S390_VM_CPU_FEAT_SKEY 9 +#define KVM_S390_VM_CPU_FEAT_CMMA 10 +#define KVM_S390_VM_CPU_FEAT_PFMFI 11 +#define KVM_S390_VM_CPU_FEAT_SIGPIF 12 +struct kvm_s390_vm_cpu_feat { + __u64 feat[16]; +}; + +#define KVM_S390_VM_CPU_PROCESSOR_SUBFUNC 4 +#define KVM_S390_VM_CPU_MACHINE_SUBFUNC 5 +/* for "test bit" instructions MSB 0 bit ordering, for "query" raw blocks */ +struct kvm_s390_vm_cpu_subfunc { + __u8 plo[32]; /* always */ + __u8 ptff[16]; /* with TOD-clock steering */ + __u8 kmac[16]; /* with MSA */ + __u8 kmc[16]; /* with MSA */ + __u8 km[16]; /* with MSA */ + __u8 kimd[16]; /* with MSA */ + __u8 klmd[16]; /* with MSA */ + __u8 pckmo[16]; /* with MSA3 */ + __u8 kmctr[16]; /* with MSA4 */ + __u8 kmf[16]; /* with MSA4 */ + __u8 kmo[16]; /* with MSA4 */ + __u8 pcc[16]; /* with MSA4 */ + __u8 ppno[16]; /* with MSA5 */ + __u8 reserved[1824]; +}; + /* kvm attributes for crypto */ #define KVM_S390_VM_CRYPTO_ENABLE_AES_KW 0 #define KVM_S390_VM_CRYPTO_ENABLE_DEA_KW 1 diff --git a/linux-headers/asm-x86/unistd_x32.h b/linux-headers/asm-x86/unistd_x32.h index 0230779a84d..e5aea761f84 100644 --- a/linux-headers/asm-x86/unistd_x32.h +++ b/linux-headers/asm-x86/unistd_x32.h @@ -306,9 +306,7 @@ #define __NR_vmsplice (__X32_SYSCALL_BIT + 532) #define __NR_move_pages (__X32_SYSCALL_BIT + 533) #define __NR_preadv (__X32_SYSCALL_BIT + 534) -#define __NR_preadv2 (__X32_SYSCALL_BIT + 534) #define __NR_pwritev (__X32_SYSCALL_BIT + 535) -#define __NR_pwritev2 (__X32_SYSCALL_BIT + 535) #define __NR_rt_tgsigqueueinfo (__X32_SYSCALL_BIT + 536) #define __NR_recvmmsg (__X32_SYSCALL_BIT + 537) #define __NR_sendmmsg (__X32_SYSCALL_BIT + 538) @@ -319,5 +317,7 @@ #define __NR_io_setup (__X32_SYSCALL_BIT + 543) #define __NR_io_submit (__X32_SYSCALL_BIT + 544) #define __NR_execveat (__X32_SYSCALL_BIT + 545) +#define __NR_preadv2 (__X32_SYSCALL_BIT + 546) +#define __NR_pwritev2 (__X32_SYSCALL_BIT + 547) #endif /* _ASM_X86_UNISTD_X32_H */ diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index e60e21ba227..4806e069e74 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -866,6 +866,10 @@ struct kvm_ppc_smmu_info { #define KVM_CAP_ARM_PMU_V3 126 #define KVM_CAP_VCPU_ATTRIBUTES 127 #define KVM_CAP_MAX_VCPU_ID 128 +#define KVM_CAP_X2APIC_API 129 +#define KVM_CAP_S390_USER_INSTR0 130 +#define KVM_CAP_MSI_DEVID 131 +#define KVM_CAP_PPC_HTM 132 #ifdef KVM_CAP_IRQ_ROUTING @@ -878,7 +882,10 @@ struct kvm_irq_routing_msi { __u32 address_lo; __u32 address_hi; __u32 data; - __u32 pad; + union { + __u32 pad; + __u32 devid; + }; }; struct kvm_irq_routing_s390_adapter { @@ -1024,12 +1031,14 @@ struct kvm_one_reg { __u64 addr; }; +#define KVM_MSI_VALID_DEVID (1U << 0) struct kvm_msi { __u32 address_lo; __u32 address_hi; __u32 data; __u32 flags; - __u8 pad[16]; + __u32 devid; + __u8 pad[12]; }; struct kvm_arm_device_addr { @@ -1074,6 +1083,8 @@ enum kvm_device_type { #define KVM_DEV_TYPE_FLIC KVM_DEV_TYPE_FLIC KVM_DEV_TYPE_ARM_VGIC_V3, #define KVM_DEV_TYPE_ARM_VGIC_V3 KVM_DEV_TYPE_ARM_VGIC_V3 + KVM_DEV_TYPE_ARM_VGIC_ITS, +#define KVM_DEV_TYPE_ARM_VGIC_ITS KVM_DEV_TYPE_ARM_VGIC_ITS KVM_DEV_TYPE_MAX, }; @@ -1313,4 +1324,7 @@ struct kvm_assigned_msix_entry { __u16 padding[3]; }; +#define KVM_X2APIC_API_USE_32BIT_IDS (1ULL << 0) +#define KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK (1ULL << 1) + #endif /* __LINUX_KVM_H */ diff --git a/linux-headers/linux/vhost.h b/linux-headers/linux/vhost.h index 571294cea0e..ac7a1f136a6 100644 --- a/linux-headers/linux/vhost.h +++ b/linux-headers/linux/vhost.h @@ -47,6 +47,32 @@ struct vhost_vring_addr { __u64 log_guest_addr; }; +/* no alignment requirement */ +struct vhost_iotlb_msg { + __u64 iova; + __u64 size; + __u64 uaddr; +#define VHOST_ACCESS_RO 0x1 +#define VHOST_ACCESS_WO 0x2 +#define VHOST_ACCESS_RW 0x3 + __u8 perm; +#define VHOST_IOTLB_MISS 1 +#define VHOST_IOTLB_UPDATE 2 +#define VHOST_IOTLB_INVALIDATE 3 +#define VHOST_IOTLB_ACCESS_FAIL 4 + __u8 type; +}; + +#define VHOST_IOTLB_MSG 0x1 + +struct vhost_msg { + int type; + union { + struct vhost_iotlb_msg iotlb; + __u8 padding[64]; + }; +}; + struct vhost_memory_region { __u64 guest_phys_addr; __u64 memory_size; /* bytes */ @@ -146,6 +172,8 @@ struct vhost_memory { #define VHOST_F_LOG_ALL 26 /* vhost-net should add virtio_net_hdr for RX, and strip for TX packets. */ #define VHOST_NET_F_VIRTIO_NET_HDR 27 +/* Vhost have device IOTLB */ +#define VHOST_F_DEVICE_IOTLB 63 /* VHOST_SCSI specific definitions */ @@ -175,4 +203,9 @@ struct vhost_scsi_target { #define VHOST_SCSI_SET_EVENTS_MISSED _IOW(VHOST_VIRTIO, 0x43, __u32) #define VHOST_SCSI_GET_EVENTS_MISSED _IOW(VHOST_VIRTIO, 0x44, __u32) +/* VHOST_VSOCK specific defines */ + +#define VHOST_VSOCK_SET_GUEST_CID _IOW(VHOST_VIRTIO, 0x60, __u64) +#define VHOST_VSOCK_SET_RUNNING _IOW(VHOST_VIRTIO, 0x61, int) + #endif From 5c179666057a7568306062e2cd030042a25eb57a Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 28 Sep 2016 13:16:28 +0200 Subject: [PATCH 663/723] hw/ppc/spapr: Move code related to "ibm,pa-features" to a separate function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function spapr_populate_cpu_dt() has become quite big already, and since we likely have to extend the pa-features property for every new processor generation, it is nicer if we put the related code into a separate function. Signed-off-by: Thomas Huth Reviewed-by: Cédric Le Goater Signed-off-by: David Gibson (cherry picked from commit 230bf719d3a3b144a4ffa441e5d6170ef0ad8999) --- hw/ppc/spapr.c | 66 +++++++++++++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 30d6800ab37..36d90778536 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -594,6 +594,41 @@ static int spapr_populate_memory(sPAPRMachineState *spapr, void *fdt) return 0; } +/* Populate the "ibm,pa-features" property */ +static void spapr_populate_pa_features(CPUPPCState *env, void *fdt, int offset) +{ + uint8_t pa_features_206[] = { 6, 0, + 0xf6, 0x1f, 0xc7, 0x00, 0x80, 0xc0 }; + uint8_t pa_features_207[] = { 24, 0, + 0xf6, 0x1f, 0xc7, 0xc0, 0x80, 0xf0, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00 }; + uint8_t *pa_features; + size_t pa_size; + + if (env->mmu_model == POWERPC_MMU_2_06) { + pa_features = pa_features_206; + pa_size = sizeof(pa_features_206); + } else { /* env->mmu_model == POWERPC_MMU_2_07 */ + pa_features = pa_features_207; + pa_size = sizeof(pa_features_207); + } + + if (env->ci_large_pages) { + /* + * Note: we keep CI large pages off by default because a 64K capable + * guest provisioned with large pages might otherwise try to map a qemu + * framebuffer (or other kind of memory mapped PCI BAR) using 64K pages + * even if that qemu runs on a 4k host. + * We dd this bit back here if we are confident this is not an issue + */ + pa_features[3] |= 0x20; + } + + _FDT((fdt_setprop(fdt, offset, "ibm,pa-features", pa_features, pa_size))); +} + static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset, sPAPRMachineState *spapr) { @@ -621,24 +656,6 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset, _FDT((fdt_setprop_cell(fdt, offset, "ibm,my-drc-index", drc_index))); } - /* Note: we keep CI large pages off for now because a 64K capable guest - * provisioned with large pages might otherwise try to map a qemu - * framebuffer (or other kind of memory mapped PCI BAR) using 64K pages - * even if that qemu runs on a 4k host. - * - * We can later add this bit back when we are confident this is not - * an issue (!HV KVM or 64K host) - */ - uint8_t pa_features_206[] = { 6, 0, - 0xf6, 0x1f, 0xc7, 0x00, 0x80, 0xc0 }; - uint8_t pa_features_207[] = { 24, 0, - 0xf6, 0x1f, 0xc7, 0xc0, 0x80, 0xf0, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, - 0x80, 0x00, 0x80, 0x00, 0x80, 0x00 }; - uint8_t *pa_features; - size_t pa_size; - _FDT((fdt_setprop_cell(fdt, offset, "reg", index))); _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu"))); @@ -705,18 +722,7 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset, page_sizes_prop, page_sizes_prop_size))); } - /* Do the ibm,pa-features property, adjust it for ci-large-pages */ - if (env->mmu_model == POWERPC_MMU_2_06) { - pa_features = pa_features_206; - pa_size = sizeof(pa_features_206); - } else /* env->mmu_model == POWERPC_MMU_2_07 */ { - pa_features = pa_features_207; - pa_size = sizeof(pa_features_207); - } - if (env->ci_large_pages) { - pa_features[3] |= 0x20; - } - _FDT((fdt_setprop(fdt, offset, "ibm,pa-features", pa_features, pa_size))); + spapr_populate_pa_features(env, fdt, offset); _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id", cs->cpu_index / vcpus_per_socket))); From 45a4f18e2ec40b96893c780c28ab18c246906355 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 28 Sep 2016 13:16:29 +0200 Subject: [PATCH 664/723] hw/ppc/spapr: Fix the selection of the processor features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current code uses pa_features_206 for POWERPC_MMU_2_06, and for everything else, it uses pa_features_207. This is bad in some cases because there is also a "degraded" MMU version of ISA 2.06, called POWERPC_MMU_2_06a, which should of course use the flags for 2.06 instead. And there is also the possibility that the user runs the pseries machine with a POWER5+ or even 970 processor. In that case we certainly do not want to set the flags for 2.07, and rather simply skip the setting of the pa-features property instead. Signed-off-by: Thomas Huth Reviewed-by: Cédric Le Goater Signed-off-by: David Gibson (cherry picked from commit 4cbec30d769a73853b60dc7f275e6e7da9ab5162) --- hw/ppc/spapr.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 36d90778536..9f0d99b438a 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -607,12 +607,19 @@ static void spapr_populate_pa_features(CPUPPCState *env, void *fdt, int offset) uint8_t *pa_features; size_t pa_size; - if (env->mmu_model == POWERPC_MMU_2_06) { + switch (env->mmu_model) { + case POWERPC_MMU_2_06: + case POWERPC_MMU_2_06a: pa_features = pa_features_206; pa_size = sizeof(pa_features_206); - } else { /* env->mmu_model == POWERPC_MMU_2_07 */ + break; + case POWERPC_MMU_2_07: + case POWERPC_MMU_2_07a: pa_features = pa_features_207; pa_size = sizeof(pa_features_207); + break; + default: + return; } if (env->ci_large_pages) { From 2e68f28854f0120c9a938a61b64aaf1eaecb162b Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 28 Sep 2016 13:16:30 +0200 Subject: [PATCH 665/723] ppc: Check the availability of transactional memory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit KVM-PR currently does not support transactional memory, and the implementation in TCG is just a fake. We should not announce TM support in the ibm,pa-features property when running on such a system, so disable it by default and only enable it if the KVM implementation supports it (i.e. recent versions of KVM-HV). These changes are based on some earlier work from Anton Blanchard (thanks!). Signed-off-by: Thomas Huth Reviewed-by: Cédric Le Goater Signed-off-by: David Gibson (cherry picked from commit bac3bf287ab60e264b636f5f00c116a19b655762) --- hw/ppc/spapr.c | 5 ++++- target-ppc/kvm.c | 7 +++++++ target-ppc/kvm_ppc.h | 6 ++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 9f0d99b438a..82723d16cb6 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -603,7 +603,7 @@ static void spapr_populate_pa_features(CPUPPCState *env, void *fdt, int offset) 0xf6, 0x1f, 0xc7, 0xc0, 0x80, 0xf0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, - 0x80, 0x00, 0x80, 0x00, 0x80, 0x00 }; + 0x80, 0x00, 0x80, 0x00, 0x00, 0x00 }; uint8_t *pa_features; size_t pa_size; @@ -632,6 +632,9 @@ static void spapr_populate_pa_features(CPUPPCState *env, void *fdt, int offset) */ pa_features[3] |= 0x20; } + if (kvmppc_has_cap_htm() && pa_size > 24) { + pa_features[24] |= 0x80; /* Transactional memory support */ + } _FDT((fdt_setprop(fdt, offset, "ibm,pa-features", pa_features, pa_size))); } diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index dcb68b90812..f26a141d059 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -79,6 +79,7 @@ static int cap_ppc_watchdog; static int cap_papr; static int cap_htab_fd; static int cap_fixup_hcalls; +static int cap_htm; /* Hardware transactional memory support */ static uint32_t debug_inst_opcode; @@ -121,6 +122,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s) * only activated after this by kvmppc_set_papr() */ cap_htab_fd = kvm_check_extension(s, KVM_CAP_PPC_HTAB_FD); cap_fixup_hcalls = kvm_check_extension(s, KVM_CAP_PPC_FIXUP_HCALL); + cap_htm = kvm_vm_check_extension(s, KVM_CAP_PPC_HTM); if (!cap_interrupt_level) { fprintf(stderr, "KVM: Couldn't find level irq capability. Expect the " @@ -2339,6 +2341,11 @@ bool kvmppc_has_cap_fixup_hcalls(void) return cap_fixup_hcalls; } +bool kvmppc_has_cap_htm(void) +{ + return cap_htm; +} + static PowerPCCPUClass *ppc_cpu_get_family_class(PowerPCCPUClass *pcc) { ObjectClass *oc = OBJECT_CLASS(pcc); diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index 5461d1082c1..e45c81513f0 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -54,6 +54,7 @@ void kvmppc_hash64_free_pteg(uint64_t token); void kvmppc_hash64_write_pte(CPUPPCState *env, target_ulong pte_index, target_ulong pte0, target_ulong pte1); bool kvmppc_has_cap_fixup_hcalls(void); +bool kvmppc_has_cap_htm(void); int kvmppc_enable_hwrng(void); int kvmppc_put_books_sregs(PowerPCCPU *cpu); PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void); @@ -244,6 +245,11 @@ static inline bool kvmppc_has_cap_fixup_hcalls(void) abort(); } +static inline bool kvmppc_has_cap_htm(void) +{ + return false; +} + static inline int kvmppc_enable_hwrng(void) { return -1; From ecccaea2f5769bb909c7a3510dc3ff9dbd736249 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Thu, 29 Sep 2016 16:45:32 +0100 Subject: [PATCH 666/723] ui: remove misleading comment from vnc_init_state The last line in vnc_init_state() says /* vs might be free()ed here */ This was added in commit 198a0039c5fca224a77e9761e2350dd9cc102ad0 Author: Gerd Hoffmann Date: Tue Jun 16 14:19:48 2009 +0200 vnc: rework VncState release workflow. because the preceeding 'vnc_update_client()' could indeed release the VncState instance. The call to vnc_update_client() was removed not long after though in commit 1fc624122fb923c7fc4c1f426541d953e7df13c9 Author: Stefano Stabellini Date: Mon Aug 3 10:54:32 2009 +0100 single vnc server surface and so the comment has been wrong ever since Signed-off-by: Daniel P. Berrange Message-id: 1475163940-26094-2-git-send-email-berrange@redhat.com Signed-off-by: Gerd Hoffmann --- ui/vnc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/ui/vnc.c b/ui/vnc.c index 76a3273e0be..5faf79bc4d6 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -3092,8 +3092,6 @@ void vnc_init_state(VncState *vs) vs->mouse_mode_notifier.notify = check_pointer_type_change; qemu_add_mouse_mode_change_notifier(&vs->mouse_mode_notifier); - - /* vs might be free()ed here */ } static gboolean vnc_listen_io(QIOChannel *ioc, From 12b2806761a2dd4b88bdbe6f3bee4bcd998a9918 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Thu, 29 Sep 2016 16:45:33 +0100 Subject: [PATCH 667/723] ui: remove 'enabled' and 'ws_enabled' fields from VncState The 'ws_enabled' field is never used outside of the vnc_display_open method, so can be a local variable. The 'enabled' field is easily replaced by a check for whether 'lsock' is non-NULL. Signed-off-by: Daniel P. Berrange Message-id: 1475163940-26094-3-git-send-email-berrange@redhat.com Signed-off-by: Gerd Hoffmann --- ui/vnc.c | 23 ++++++++++------------- ui/vnc.h | 2 -- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/ui/vnc.c b/ui/vnc.c index 5faf79bc4d6..45a23d30f4f 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -371,7 +371,7 @@ VncInfo *qmp_query_vnc(Error **errp) VncDisplay *vd = vnc_display_find(NULL); SocketAddress *addr = NULL; - if (vd == NULL || !vd->enabled) { + if (vd == NULL || !vd->lsock) { info->enabled = false; } else { info->enabled = true; @@ -3169,7 +3169,6 @@ static void vnc_display_close(VncDisplay *vs) { if (!vs) return; - vs->enabled = false; vs->is_unix = false; if (vs->lsock != NULL) { if (vs->lsock_tag) { @@ -3178,7 +3177,6 @@ static void vnc_display_close(VncDisplay *vs) object_unref(OBJECT(vs->lsock)); vs->lsock = NULL; } - vs->ws_enabled = false; if (vs->lwebsock != NULL) { if (vs->lwebsock_tag) { g_source_remove(vs->lwebsock_tag); @@ -3538,6 +3536,7 @@ void vnc_display_open(const char *id, Error **errp) int acl = 0; int lock_key_sync = 1; int key_delay_ms; + bool ws_enabled = false; if (!vs) { error_setg(errp, "VNC display not active"); @@ -3573,7 +3572,7 @@ void vnc_display_open(const char *id, Error **errp) } wsaddr = g_new0(SocketAddress, 1); - vs->ws_enabled = true; + ws_enabled = true; } if (strncmp(vnc, "unix:", 5) == 0) { @@ -3581,7 +3580,7 @@ void vnc_display_open(const char *id, Error **errp) saddr->u.q_unix.data = g_new0(UnixSocketAddress, 1); saddr->u.q_unix.data->path = g_strdup(vnc + 5); - if (vs->ws_enabled) { + if (ws_enabled) { error_setg(errp, "UNIX sockets not supported with websock"); goto fail; } @@ -3617,7 +3616,7 @@ void vnc_display_open(const char *id, Error **errp) inet->ipv6 = ipv6; inet->has_ipv6 = has_ipv6; - if (vs->ws_enabled) { + if (ws_enabled) { wsaddr->type = SOCKET_ADDRESS_KIND_INET; inet = wsaddr->u.inet.data = g_new0(InetSocketAddress, 1); inet->host = g_strdup(saddr->u.inet.data->host); @@ -3777,7 +3776,7 @@ void vnc_display_open(const char *id, Error **errp) } #endif - if (vnc_display_setup_auth(vs, password, sasl, vs->ws_enabled, errp) < 0) { + if (vnc_display_setup_auth(vs, password, sasl, ws_enabled, errp) < 0) { goto fail; } @@ -3816,7 +3815,7 @@ void vnc_display_open(const char *id, Error **errp) QIOChannelSocket *sioc = NULL; vs->lsock = NULL; vs->lwebsock = NULL; - if (vs->ws_enabled) { + if (ws_enabled) { error_setg(errp, "Cannot use websockets in reverse mode"); goto fail; } @@ -3833,9 +3832,8 @@ void vnc_display_open(const char *id, Error **errp) goto fail; } vs->is_unix = saddr->type == SOCKET_ADDRESS_KIND_UNIX; - vs->enabled = true; - if (vs->ws_enabled) { + if (ws_enabled) { vs->lwebsock = qio_channel_socket_new(); if (qio_channel_socket_listen_sync(vs->lwebsock, wsaddr, errp) < 0) { @@ -3848,7 +3846,7 @@ void vnc_display_open(const char *id, Error **errp) vs->lsock_tag = qio_channel_add_watch( QIO_CHANNEL(vs->lsock), G_IO_IN, vnc_listen_io, vs, NULL); - if (vs->ws_enabled) { + if (ws_enabled) { vs->lwebsock_tag = qio_channel_add_watch( QIO_CHANNEL(vs->lwebsock), G_IO_IN, vnc_listen_io, vs, NULL); @@ -3866,8 +3864,7 @@ void vnc_display_open(const char *id, Error **errp) fail: qapi_free_SocketAddress(saddr); qapi_free_SocketAddress(wsaddr); - vs->enabled = false; - vs->ws_enabled = false; + ws_enabled = false; } void vnc_display_add_client(const char *id, int csock, bool skipauth) diff --git a/ui/vnc.h b/ui/vnc.h index ab5f244116a..a0519cc9d6f 100644 --- a/ui/vnc.h +++ b/ui/vnc.h @@ -150,7 +150,6 @@ struct VncDisplay guint lsock_tag; QIOChannelSocket *lwebsock; guint lwebsock_tag; - bool ws_enabled; DisplaySurface *ds; DisplayChangeListener dcl; kbd_layout_t *kbd_layout; @@ -167,7 +166,6 @@ struct VncDisplay const char *id; QTAILQ_ENTRY(VncDisplay) next; - bool enabled; bool is_unix; char *password; time_t expires; From 38e5756a614e9a492d1bb181166cd031bc87e159 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Thu, 29 Sep 2016 16:45:34 +0100 Subject: [PATCH 668/723] ui: remove 'ws_tls' field from VncState The 'ws_tls' field in VncState is only ever representing the result of 'tlscreds != NULL' and is thus pointless. Replace use of 'ws_tls' with a direct check against 'tlscreds' Signed-off-by: Daniel P. Berrange Message-id: 1475163940-26094-4-git-send-email-berrange@redhat.com Signed-off-by: Gerd Hoffmann --- ui/vnc.c | 11 +---------- ui/vnc.h | 1 - 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/ui/vnc.c b/ui/vnc.c index 45a23d30f4f..83a608b3cba 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -3029,7 +3029,7 @@ static void vnc_connect(VncDisplay *vd, QIOChannelSocket *sioc, qio_channel_set_blocking(vs->ioc, false, NULL); if (websocket) { vs->websocket = 1; - if (vd->ws_tls) { + if (vd->tlscreds) { vs->ioc_tag = qio_channel_add_watch( vs->ioc, G_IO_IN, vncws_tls_handshake_io, vs, NULL); } else { @@ -3379,9 +3379,6 @@ vnc_display_setup_auth(VncDisplay *vs, if (password) { if (vs->tlscreds) { vs->auth = VNC_AUTH_VENCRYPT; - if (websocket) { - vs->ws_tls = true; - } if (object_dynamic_cast(OBJECT(vs->tlscreds), TYPE_QCRYPTO_TLS_CREDS_X509)) { VNC_DEBUG("Initializing VNC server with x509 password auth\n"); @@ -3409,9 +3406,6 @@ vnc_display_setup_auth(VncDisplay *vs, } else if (sasl) { if (vs->tlscreds) { vs->auth = VNC_AUTH_VENCRYPT; - if (websocket) { - vs->ws_tls = true; - } if (object_dynamic_cast(OBJECT(vs->tlscreds), TYPE_QCRYPTO_TLS_CREDS_X509)) { VNC_DEBUG("Initializing VNC server with x509 SASL auth\n"); @@ -3439,9 +3433,6 @@ vnc_display_setup_auth(VncDisplay *vs, } else { if (vs->tlscreds) { vs->auth = VNC_AUTH_VENCRYPT; - if (websocket) { - vs->ws_tls = true; - } if (object_dynamic_cast(OBJECT(vs->tlscreds), TYPE_QCRYPTO_TLS_CREDS_X509)) { VNC_DEBUG("Initializing VNC server with x509 no auth\n"); diff --git a/ui/vnc.h b/ui/vnc.h index a0519cc9d6f..223af385154 100644 --- a/ui/vnc.h +++ b/ui/vnc.h @@ -172,7 +172,6 @@ struct VncDisplay int auth; int subauth; /* Used by VeNCrypt */ int ws_auth; /* Used by websockets */ - bool ws_tls; /* Used by websockets */ bool lossy; bool non_adaptive; QCryptoTLSCreds *tlscreds; From bf01c1794e870b6da83ccc57bb363e704ad9aa9e Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Thu, 29 Sep 2016 16:45:35 +0100 Subject: [PATCH 669/723] ui: rename misleading 'VncDisplay' variables Normally code declares 'VncDisplay *vd' or 'VncState *vs' but there are a bunch of places which misleadingly declare 'VncDisplay *vs'. Signed-off-by: Daniel P. Berrange Message-id: 1475163940-26094-5-git-send-email-berrange@redhat.com Signed-off-by: Gerd Hoffmann --- ui/vnc.c | 274 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 138 insertions(+), 136 deletions(-) diff --git a/ui/vnc.c b/ui/vnc.c index 83a608b3cba..1104697e640 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -3098,17 +3098,17 @@ static gboolean vnc_listen_io(QIOChannel *ioc, GIOCondition condition, void *opaque) { - VncDisplay *vs = opaque; + VncDisplay *vd = opaque; QIOChannelSocket *sioc = NULL; Error *err = NULL; /* Catch-up */ - graphic_hw_update(vs->dcl.con); + graphic_hw_update(vd->dcl.con); sioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc), &err); if (sioc != NULL) { qio_channel_set_delay(QIO_CHANNEL(sioc), false); - vnc_connect(vs, sioc, false, - ioc != QIO_CHANNEL(vs->lsock)); + vnc_connect(vd, sioc, false, + ioc != QIO_CHANNEL(vd->lsock)); object_unref(OBJECT(sioc)); } else { /* client probably closed connection before we got there */ @@ -3131,106 +3131,108 @@ static const DisplayChangeListenerOps dcl_ops = { void vnc_display_init(const char *id) { - VncDisplay *vs; + VncDisplay *vd; if (vnc_display_find(id) != NULL) { return; } - vs = g_malloc0(sizeof(*vs)); + vd = g_malloc0(sizeof(*vd)); - vs->id = strdup(id); - QTAILQ_INSERT_TAIL(&vnc_displays, vs, next); + vd->id = strdup(id); + QTAILQ_INSERT_TAIL(&vnc_displays, vd, next); - QTAILQ_INIT(&vs->clients); - vs->expires = TIME_MAX; + QTAILQ_INIT(&vd->clients); + vd->expires = TIME_MAX; if (keyboard_layout) { trace_vnc_key_map_init(keyboard_layout); - vs->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout); + vd->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout); } else { - vs->kbd_layout = init_keyboard_layout(name2keysym, "en-us"); + vd->kbd_layout = init_keyboard_layout(name2keysym, "en-us"); } - if (!vs->kbd_layout) + if (!vd->kbd_layout) { exit(1); + } - vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE; - vs->connections_limit = 32; + vd->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE; + vd->connections_limit = 32; - qemu_mutex_init(&vs->mutex); + qemu_mutex_init(&vd->mutex); vnc_start_worker_thread(); - vs->dcl.ops = &dcl_ops; - register_displaychangelistener(&vs->dcl); + vd->dcl.ops = &dcl_ops; + register_displaychangelistener(&vd->dcl); } -static void vnc_display_close(VncDisplay *vs) +static void vnc_display_close(VncDisplay *vd) { - if (!vs) + if (!vd) { return; - vs->is_unix = false; - if (vs->lsock != NULL) { - if (vs->lsock_tag) { - g_source_remove(vs->lsock_tag); + } + vd->is_unix = false; + if (vd->lsock != NULL) { + if (vd->lsock_tag) { + g_source_remove(vd->lsock_tag); } - object_unref(OBJECT(vs->lsock)); - vs->lsock = NULL; + object_unref(OBJECT(vd->lsock)); + vd->lsock = NULL; } - if (vs->lwebsock != NULL) { - if (vs->lwebsock_tag) { - g_source_remove(vs->lwebsock_tag); + if (vd->lwebsock != NULL) { + if (vd->lwebsock_tag) { + g_source_remove(vd->lwebsock_tag); } - object_unref(OBJECT(vs->lwebsock)); - vs->lwebsock = NULL; + object_unref(OBJECT(vd->lwebsock)); + vd->lwebsock = NULL; } - vs->auth = VNC_AUTH_INVALID; - vs->subauth = VNC_AUTH_INVALID; - if (vs->tlscreds) { - object_unparent(OBJECT(vs->tlscreds)); - vs->tlscreds = NULL; + vd->auth = VNC_AUTH_INVALID; + vd->subauth = VNC_AUTH_INVALID; + if (vd->tlscreds) { + object_unparent(OBJECT(vd->tlscreds)); + vd->tlscreds = NULL; } - g_free(vs->tlsaclname); - vs->tlsaclname = NULL; + g_free(vd->tlsaclname); + vd->tlsaclname = NULL; } int vnc_display_password(const char *id, const char *password) { - VncDisplay *vs = vnc_display_find(id); + VncDisplay *vd = vnc_display_find(id); - if (!vs) { + if (!vd) { return -EINVAL; } - if (vs->auth == VNC_AUTH_NONE) { + if (vd->auth == VNC_AUTH_NONE) { error_printf_unless_qmp("If you want use passwords please enable " "password auth using '-vnc ${dpy},password'.\n"); return -EINVAL; } - g_free(vs->password); - vs->password = g_strdup(password); + g_free(vd->password); + vd->password = g_strdup(password); return 0; } int vnc_display_pw_expire(const char *id, time_t expires) { - VncDisplay *vs = vnc_display_find(id); + VncDisplay *vd = vnc_display_find(id); - if (!vs) { + if (!vd) { return -EINVAL; } - vs->expires = expires; + vd->expires = expires; return 0; } -static void vnc_display_print_local_addr(VncDisplay *vs) +static void vnc_display_print_local_addr(VncDisplay *vd) { SocketAddress *addr; Error *err = NULL; - addr = qio_channel_socket_get_local_address(vs->lsock, &err); + addr = qio_channel_socket_get_local_address(vd->lsock, &err); if (!addr) { return; } @@ -3323,7 +3325,7 @@ static QemuOptsList qemu_vnc_opts = { static int -vnc_display_setup_auth(VncDisplay *vs, +vnc_display_setup_auth(VncDisplay *vd, bool password, bool sasl, bool websocket, @@ -3377,85 +3379,85 @@ vnc_display_setup_auth(VncDisplay *vs, * result has the same security characteristics. */ if (password) { - if (vs->tlscreds) { - vs->auth = VNC_AUTH_VENCRYPT; - if (object_dynamic_cast(OBJECT(vs->tlscreds), + if (vd->tlscreds) { + vd->auth = VNC_AUTH_VENCRYPT; + if (object_dynamic_cast(OBJECT(vd->tlscreds), TYPE_QCRYPTO_TLS_CREDS_X509)) { VNC_DEBUG("Initializing VNC server with x509 password auth\n"); - vs->subauth = VNC_AUTH_VENCRYPT_X509VNC; - } else if (object_dynamic_cast(OBJECT(vs->tlscreds), + vd->subauth = VNC_AUTH_VENCRYPT_X509VNC; + } else if (object_dynamic_cast(OBJECT(vd->tlscreds), TYPE_QCRYPTO_TLS_CREDS_ANON)) { VNC_DEBUG("Initializing VNC server with TLS password auth\n"); - vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC; + vd->subauth = VNC_AUTH_VENCRYPT_TLSVNC; } else { error_setg(errp, "Unsupported TLS cred type %s", - object_get_typename(OBJECT(vs->tlscreds))); + object_get_typename(OBJECT(vd->tlscreds))); return -1; } } else { VNC_DEBUG("Initializing VNC server with password auth\n"); - vs->auth = VNC_AUTH_VNC; - vs->subauth = VNC_AUTH_INVALID; + vd->auth = VNC_AUTH_VNC; + vd->subauth = VNC_AUTH_INVALID; } if (websocket) { - vs->ws_auth = VNC_AUTH_VNC; + vd->ws_auth = VNC_AUTH_VNC; } else { - vs->ws_auth = VNC_AUTH_INVALID; + vd->ws_auth = VNC_AUTH_INVALID; } } else if (sasl) { - if (vs->tlscreds) { - vs->auth = VNC_AUTH_VENCRYPT; - if (object_dynamic_cast(OBJECT(vs->tlscreds), + if (vd->tlscreds) { + vd->auth = VNC_AUTH_VENCRYPT; + if (object_dynamic_cast(OBJECT(vd->tlscreds), TYPE_QCRYPTO_TLS_CREDS_X509)) { VNC_DEBUG("Initializing VNC server with x509 SASL auth\n"); - vs->subauth = VNC_AUTH_VENCRYPT_X509SASL; - } else if (object_dynamic_cast(OBJECT(vs->tlscreds), + vd->subauth = VNC_AUTH_VENCRYPT_X509SASL; + } else if (object_dynamic_cast(OBJECT(vd->tlscreds), TYPE_QCRYPTO_TLS_CREDS_ANON)) { VNC_DEBUG("Initializing VNC server with TLS SASL auth\n"); - vs->subauth = VNC_AUTH_VENCRYPT_TLSSASL; + vd->subauth = VNC_AUTH_VENCRYPT_TLSSASL; } else { error_setg(errp, "Unsupported TLS cred type %s", - object_get_typename(OBJECT(vs->tlscreds))); + object_get_typename(OBJECT(vd->tlscreds))); return -1; } } else { VNC_DEBUG("Initializing VNC server with SASL auth\n"); - vs->auth = VNC_AUTH_SASL; - vs->subauth = VNC_AUTH_INVALID; + vd->auth = VNC_AUTH_SASL; + vd->subauth = VNC_AUTH_INVALID; } if (websocket) { - vs->ws_auth = VNC_AUTH_SASL; + vd->ws_auth = VNC_AUTH_SASL; } else { - vs->ws_auth = VNC_AUTH_INVALID; + vd->ws_auth = VNC_AUTH_INVALID; } } else { - if (vs->tlscreds) { - vs->auth = VNC_AUTH_VENCRYPT; - if (object_dynamic_cast(OBJECT(vs->tlscreds), + if (vd->tlscreds) { + vd->auth = VNC_AUTH_VENCRYPT; + if (object_dynamic_cast(OBJECT(vd->tlscreds), TYPE_QCRYPTO_TLS_CREDS_X509)) { VNC_DEBUG("Initializing VNC server with x509 no auth\n"); - vs->subauth = VNC_AUTH_VENCRYPT_X509NONE; - } else if (object_dynamic_cast(OBJECT(vs->tlscreds), + vd->subauth = VNC_AUTH_VENCRYPT_X509NONE; + } else if (object_dynamic_cast(OBJECT(vd->tlscreds), TYPE_QCRYPTO_TLS_CREDS_ANON)) { VNC_DEBUG("Initializing VNC server with TLS no auth\n"); - vs->subauth = VNC_AUTH_VENCRYPT_TLSNONE; + vd->subauth = VNC_AUTH_VENCRYPT_TLSNONE; } else { error_setg(errp, "Unsupported TLS cred type %s", - object_get_typename(OBJECT(vs->tlscreds))); + object_get_typename(OBJECT(vd->tlscreds))); return -1; } } else { VNC_DEBUG("Initializing VNC server with no auth\n"); - vs->auth = VNC_AUTH_NONE; - vs->subauth = VNC_AUTH_INVALID; + vd->auth = VNC_AUTH_NONE; + vd->subauth = VNC_AUTH_INVALID; } if (websocket) { - vs->ws_auth = VNC_AUTH_NONE; + vd->ws_auth = VNC_AUTH_NONE; } else { - vs->ws_auth = VNC_AUTH_INVALID; + vd->ws_auth = VNC_AUTH_INVALID; } } return 0; @@ -3509,7 +3511,7 @@ vnc_display_create_creds(bool x509, void vnc_display_open(const char *id, Error **errp) { - VncDisplay *vs = vnc_display_find(id); + VncDisplay *vd = vnc_display_find(id); QemuOpts *opts = qemu_opts_find(&qemu_vnc_opts, id); SocketAddress *saddr = NULL, *wsaddr = NULL; const char *share, *device_id; @@ -3529,11 +3531,11 @@ void vnc_display_open(const char *id, Error **errp) int key_delay_ms; bool ws_enabled = false; - if (!vs) { + if (!vd) { error_setg(errp, "VNC display not active"); return; } - vnc_display_close(vs); + vnc_display_close(vd); if (!opts) { return; @@ -3674,17 +3676,17 @@ void vnc_display_open(const char *id, Error **errp) credid); goto fail; } - vs->tlscreds = (QCryptoTLSCreds *) + vd->tlscreds = (QCryptoTLSCreds *) object_dynamic_cast(creds, TYPE_QCRYPTO_TLS_CREDS); - if (!vs->tlscreds) { + if (!vd->tlscreds) { error_setg(errp, "Object with id '%s' is not TLS credentials", credid); goto fail; } - object_ref(OBJECT(vs->tlscreds)); + object_ref(OBJECT(vd->tlscreds)); - if (vs->tlscreds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) { + if (vd->tlscreds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) { error_setg(errp, "Expecting TLS credentials with a server endpoint"); goto fail; @@ -3705,12 +3707,12 @@ void vnc_display_open(const char *id, Error **errp) x509verify = true; } } - vs->tlscreds = vnc_display_create_creds(x509, + vd->tlscreds = vnc_display_create_creds(x509, x509verify, path, - vs->id, + vd->id, errp); - if (!vs->tlscreds) { + if (!vd->tlscreds) { goto fail; } } @@ -3720,54 +3722,54 @@ void vnc_display_open(const char *id, Error **errp) share = qemu_opt_get(opts, "share"); if (share) { if (strcmp(share, "ignore") == 0) { - vs->share_policy = VNC_SHARE_POLICY_IGNORE; + vd->share_policy = VNC_SHARE_POLICY_IGNORE; } else if (strcmp(share, "allow-exclusive") == 0) { - vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE; + vd->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE; } else if (strcmp(share, "force-shared") == 0) { - vs->share_policy = VNC_SHARE_POLICY_FORCE_SHARED; + vd->share_policy = VNC_SHARE_POLICY_FORCE_SHARED; } else { error_setg(errp, "unknown vnc share= option"); goto fail; } } else { - vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE; + vd->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE; } - vs->connections_limit = qemu_opt_get_number(opts, "connections", 32); + vd->connections_limit = qemu_opt_get_number(opts, "connections", 32); #ifdef CONFIG_VNC_JPEG - vs->lossy = qemu_opt_get_bool(opts, "lossy", false); + vd->lossy = qemu_opt_get_bool(opts, "lossy", false); #endif - vs->non_adaptive = qemu_opt_get_bool(opts, "non-adaptive", false); + vd->non_adaptive = qemu_opt_get_bool(opts, "non-adaptive", false); /* adaptive updates are only used with tight encoding and * if lossy updates are enabled so we can disable all the * calculations otherwise */ - if (!vs->lossy) { - vs->non_adaptive = true; + if (!vd->lossy) { + vd->non_adaptive = true; } if (acl) { - if (strcmp(vs->id, "default") == 0) { - vs->tlsaclname = g_strdup("vnc.x509dname"); + if (strcmp(vd->id, "default") == 0) { + vd->tlsaclname = g_strdup("vnc.x509dname"); } else { - vs->tlsaclname = g_strdup_printf("vnc.%s.x509dname", vs->id); + vd->tlsaclname = g_strdup_printf("vnc.%s.x509dname", vd->id); } - qemu_acl_init(vs->tlsaclname); + qemu_acl_init(vd->tlsaclname); } #ifdef CONFIG_VNC_SASL if (acl && sasl) { char *aclname; - if (strcmp(vs->id, "default") == 0) { + if (strcmp(vd->id, "default") == 0) { aclname = g_strdup("vnc.username"); } else { - aclname = g_strdup_printf("vnc.%s.username", vs->id); + aclname = g_strdup_printf("vnc.%s.username", vd->id); } - vs->sasl.acl = qemu_acl_init(aclname); + vd->sasl.acl = qemu_acl_init(aclname); g_free(aclname); } #endif - if (vnc_display_setup_auth(vs, password, sasl, ws_enabled, errp) < 0) { + if (vnc_display_setup_auth(vd, password, sasl, ws_enabled, errp) < 0) { goto fail; } @@ -3778,8 +3780,8 @@ void vnc_display_open(const char *id, Error **errp) goto fail; } #endif - vs->lock_key_sync = lock_key_sync; - vs->key_delay_ms = key_delay_ms; + vd->lock_key_sync = lock_key_sync; + vd->key_delay_ms = key_delay_ms; device_id = qemu_opt_get(opts, "display"); if (device_id) { @@ -3795,57 +3797,57 @@ void vnc_display_open(const char *id, Error **errp) con = NULL; } - if (con != vs->dcl.con) { - unregister_displaychangelistener(&vs->dcl); - vs->dcl.con = con; - register_displaychangelistener(&vs->dcl); + if (con != vd->dcl.con) { + unregister_displaychangelistener(&vd->dcl); + vd->dcl.con = con; + register_displaychangelistener(&vd->dcl); } if (reverse) { /* connect to viewer */ QIOChannelSocket *sioc = NULL; - vs->lsock = NULL; - vs->lwebsock = NULL; + vd->lsock = NULL; + vd->lwebsock = NULL; if (ws_enabled) { error_setg(errp, "Cannot use websockets in reverse mode"); goto fail; } - vs->is_unix = saddr->type == SOCKET_ADDRESS_KIND_UNIX; + vd->is_unix = saddr->type == SOCKET_ADDRESS_KIND_UNIX; sioc = qio_channel_socket_new(); if (qio_channel_socket_connect_sync(sioc, saddr, errp) < 0) { goto fail; } - vnc_connect(vs, sioc, false, false); + vnc_connect(vd, sioc, false, false); object_unref(OBJECT(sioc)); } else { - vs->lsock = qio_channel_socket_new(); - if (qio_channel_socket_listen_sync(vs->lsock, saddr, errp) < 0) { + vd->lsock = qio_channel_socket_new(); + if (qio_channel_socket_listen_sync(vd->lsock, saddr, errp) < 0) { goto fail; } - vs->is_unix = saddr->type == SOCKET_ADDRESS_KIND_UNIX; + vd->is_unix = saddr->type == SOCKET_ADDRESS_KIND_UNIX; if (ws_enabled) { - vs->lwebsock = qio_channel_socket_new(); - if (qio_channel_socket_listen_sync(vs->lwebsock, + vd->lwebsock = qio_channel_socket_new(); + if (qio_channel_socket_listen_sync(vd->lwebsock, wsaddr, errp) < 0) { - object_unref(OBJECT(vs->lsock)); - vs->lsock = NULL; + object_unref(OBJECT(vd->lsock)); + vd->lsock = NULL; goto fail; } } - vs->lsock_tag = qio_channel_add_watch( - QIO_CHANNEL(vs->lsock), - G_IO_IN, vnc_listen_io, vs, NULL); + vd->lsock_tag = qio_channel_add_watch( + QIO_CHANNEL(vd->lsock), + G_IO_IN, vnc_listen_io, vd, NULL); if (ws_enabled) { - vs->lwebsock_tag = qio_channel_add_watch( - QIO_CHANNEL(vs->lwebsock), - G_IO_IN, vnc_listen_io, vs, NULL); + vd->lwebsock_tag = qio_channel_add_watch( + QIO_CHANNEL(vd->lwebsock), + G_IO_IN, vnc_listen_io, vd, NULL); } } if (show_vnc_port) { - vnc_display_print_local_addr(vs); + vnc_display_print_local_addr(vd); } qapi_free_SocketAddress(saddr); @@ -3860,16 +3862,16 @@ void vnc_display_open(const char *id, Error **errp) void vnc_display_add_client(const char *id, int csock, bool skipauth) { - VncDisplay *vs = vnc_display_find(id); + VncDisplay *vd = vnc_display_find(id); QIOChannelSocket *sioc; - if (!vs) { + if (!vd) { return; } sioc = qio_channel_socket_new_fd(csock, NULL); if (sioc) { - vnc_connect(vs, sioc, skipauth, false); + vnc_connect(vd, sioc, skipauth, false); object_unref(OBJECT(sioc)); } } From eda24e188637e2f86db31c3edb76d457212fdcb1 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Thu, 29 Sep 2016 16:45:36 +0100 Subject: [PATCH 670/723] ui: refactor method for setting up VncDisplay auth types There is a lot of repeated code in the auth type setup method, particularly around checking TLS credential types. Refactor it to reduce duplication and instead of having one method do both plain and websockets at once, call it separately for each. Signed-off-by: Daniel P. Berrange Message-id: 1475163940-26094-6-git-send-email-berrange@redhat.com Signed-off-by: Gerd Hoffmann --- ui/vnc.c | 124 +++++++++++++++++++++++-------------------------------- ui/vnc.h | 1 + 2 files changed, 53 insertions(+), 72 deletions(-) diff --git a/ui/vnc.c b/ui/vnc.c index 1104697e640..2f3ebdcd37a 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -3325,7 +3325,9 @@ static QemuOptsList qemu_vnc_opts = { static int -vnc_display_setup_auth(VncDisplay *vd, +vnc_display_setup_auth(int *auth, + int *subauth, + QCryptoTLSCreds *tlscreds, bool password, bool sasl, bool websocket, @@ -3378,86 +3380,56 @@ vnc_display_setup_auth(VncDisplay *vd, * VNC auth mechs for plain VNC vs websockets VNC, the end * result has the same security characteristics. */ - if (password) { - if (vd->tlscreds) { - vd->auth = VNC_AUTH_VENCRYPT; - if (object_dynamic_cast(OBJECT(vd->tlscreds), - TYPE_QCRYPTO_TLS_CREDS_X509)) { - VNC_DEBUG("Initializing VNC server with x509 password auth\n"); - vd->subauth = VNC_AUTH_VENCRYPT_X509VNC; - } else if (object_dynamic_cast(OBJECT(vd->tlscreds), - TYPE_QCRYPTO_TLS_CREDS_ANON)) { - VNC_DEBUG("Initializing VNC server with TLS password auth\n"); - vd->subauth = VNC_AUTH_VENCRYPT_TLSVNC; - } else { - error_setg(errp, - "Unsupported TLS cred type %s", - object_get_typename(OBJECT(vd->tlscreds))); - return -1; - } - } else { + if (websocket || !tlscreds) { + if (password) { VNC_DEBUG("Initializing VNC server with password auth\n"); - vd->auth = VNC_AUTH_VNC; - vd->subauth = VNC_AUTH_INVALID; - } - if (websocket) { - vd->ws_auth = VNC_AUTH_VNC; + *auth = VNC_AUTH_VNC; + } else if (sasl) { + VNC_DEBUG("Initializing VNC server with SASL auth\n"); + *auth = VNC_AUTH_SASL; } else { - vd->ws_auth = VNC_AUTH_INVALID; + VNC_DEBUG("Initializing VNC server with no auth\n"); + *auth = VNC_AUTH_NONE; } - } else if (sasl) { - if (vd->tlscreds) { - vd->auth = VNC_AUTH_VENCRYPT; - if (object_dynamic_cast(OBJECT(vd->tlscreds), - TYPE_QCRYPTO_TLS_CREDS_X509)) { + *subauth = VNC_AUTH_INVALID; + } else { + bool is_x509 = object_dynamic_cast(OBJECT(tlscreds), + TYPE_QCRYPTO_TLS_CREDS_X509) != NULL; + bool is_anon = object_dynamic_cast(OBJECT(tlscreds), + TYPE_QCRYPTO_TLS_CREDS_ANON) != NULL; + + if (!is_x509 && !is_anon) { + error_setg(errp, + "Unsupported TLS cred type %s", + object_get_typename(OBJECT(tlscreds))); + return -1; + } + *auth = VNC_AUTH_VENCRYPT; + if (password) { + if (is_x509) { + VNC_DEBUG("Initializing VNC server with x509 password auth\n"); + *subauth = VNC_AUTH_VENCRYPT_X509VNC; + } else { + VNC_DEBUG("Initializing VNC server with TLS password auth\n"); + *subauth = VNC_AUTH_VENCRYPT_TLSVNC; + } + + } else if (sasl) { + if (is_x509) { VNC_DEBUG("Initializing VNC server with x509 SASL auth\n"); - vd->subauth = VNC_AUTH_VENCRYPT_X509SASL; - } else if (object_dynamic_cast(OBJECT(vd->tlscreds), - TYPE_QCRYPTO_TLS_CREDS_ANON)) { - VNC_DEBUG("Initializing VNC server with TLS SASL auth\n"); - vd->subauth = VNC_AUTH_VENCRYPT_TLSSASL; + *subauth = VNC_AUTH_VENCRYPT_X509SASL; } else { - error_setg(errp, - "Unsupported TLS cred type %s", - object_get_typename(OBJECT(vd->tlscreds))); - return -1; + VNC_DEBUG("Initializing VNC server with TLS SASL auth\n"); + *subauth = VNC_AUTH_VENCRYPT_TLSSASL; } } else { - VNC_DEBUG("Initializing VNC server with SASL auth\n"); - vd->auth = VNC_AUTH_SASL; - vd->subauth = VNC_AUTH_INVALID; - } - if (websocket) { - vd->ws_auth = VNC_AUTH_SASL; - } else { - vd->ws_auth = VNC_AUTH_INVALID; - } - } else { - if (vd->tlscreds) { - vd->auth = VNC_AUTH_VENCRYPT; - if (object_dynamic_cast(OBJECT(vd->tlscreds), - TYPE_QCRYPTO_TLS_CREDS_X509)) { + if (is_x509) { VNC_DEBUG("Initializing VNC server with x509 no auth\n"); - vd->subauth = VNC_AUTH_VENCRYPT_X509NONE; - } else if (object_dynamic_cast(OBJECT(vd->tlscreds), - TYPE_QCRYPTO_TLS_CREDS_ANON)) { - VNC_DEBUG("Initializing VNC server with TLS no auth\n"); - vd->subauth = VNC_AUTH_VENCRYPT_TLSNONE; + *subauth = VNC_AUTH_VENCRYPT_X509NONE; } else { - error_setg(errp, - "Unsupported TLS cred type %s", - object_get_typename(OBJECT(vd->tlscreds))); - return -1; + VNC_DEBUG("Initializing VNC server with TLS no auth\n"); + *subauth = VNC_AUTH_VENCRYPT_TLSNONE; } - } else { - VNC_DEBUG("Initializing VNC server with no auth\n"); - vd->auth = VNC_AUTH_NONE; - vd->subauth = VNC_AUTH_INVALID; - } - if (websocket) { - vd->ws_auth = VNC_AUTH_NONE; - } else { - vd->ws_auth = VNC_AUTH_INVALID; } } return 0; @@ -3769,7 +3741,15 @@ void vnc_display_open(const char *id, Error **errp) } #endif - if (vnc_display_setup_auth(vd, password, sasl, ws_enabled, errp) < 0) { + if (vnc_display_setup_auth(&vd->auth, &vd->subauth, + vd->tlscreds, password, + sasl, false, errp) < 0) { + goto fail; + } + + if (vnc_display_setup_auth(&vd->ws_auth, &vd->ws_subauth, + vd->tlscreds, password, + sasl, true, errp) < 0) { goto fail; } diff --git a/ui/vnc.h b/ui/vnc.h index 223af385154..d191d88356f 100644 --- a/ui/vnc.h +++ b/ui/vnc.h @@ -172,6 +172,7 @@ struct VncDisplay int auth; int subauth; /* Used by VeNCrypt */ int ws_auth; /* Used by websockets */ + int ws_subauth; /* Used by websockets */ bool lossy; bool non_adaptive; QCryptoTLSCreds *tlscreds; From f54195ddf7460df077bec42a2475fd2d30a3f3f1 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Thu, 29 Sep 2016 16:45:37 +0100 Subject: [PATCH 671/723] ui: remove bogus call to graphic_hw_update() in vnc_listen_io Just before accepting a new client connection the vnc_listen_io method calls graphic_hw_update(). This is bogus because there is a call to this method already in vnc_state_init() and the client doesn't need up2date graphics console before reaching that. Signed-off-by: Daniel P. Berrange Message-id: 1475163940-26094-7-git-send-email-berrange@redhat.com Signed-off-by: Gerd Hoffmann --- ui/vnc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/ui/vnc.c b/ui/vnc.c index 2f3ebdcd37a..d1f33d3e360 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -3102,8 +3102,6 @@ static gboolean vnc_listen_io(QIOChannel *ioc, QIOChannelSocket *sioc = NULL; Error *err = NULL; - /* Catch-up */ - graphic_hw_update(vd->dcl.con); sioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc), &err); if (sioc != NULL) { qio_channel_set_delay(QIO_CHANNEL(sioc), false); From 2df2041036ee63ff9116631c6214e3ffb5f4bf45 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Thu, 29 Sep 2016 16:45:38 +0100 Subject: [PATCH 672/723] ui: remove bogus call to reset_keys() in vnc_init_state The vnc_init_state method calls reset_keys() to reset the modifier key state. This was originally added in commit 53762ddb277c690e486d0e17b10591774248c8cf Author: malc Date: Mon Dec 1 20:57:52 2008 +0000 Reset the key modifiers upon client connect This was valid at this time because there was only the single VncState object which was persistent across client connections and so needed resetting. The persistent data was later split off into VncDisplay and VncState was allocated at time of client connection: commit 753b4053311ff1437d99726970b1e7e6bf38249b Author: aliguori Date: Mon Feb 16 14:59:30 2009 +0000 Support multiple VNC clients (Brian Kress) at which point the modifier state is always 0 due to use of g_new0. As such the reset_keys() call has been a no-op ever since. Signed-off-by: Daniel P. Berrange Message-id: 1475163940-26094-8-git-send-email-berrange@redhat.com Signed-off-by: Gerd Hoffmann --- ui/vnc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/ui/vnc.c b/ui/vnc.c index d1f33d3e360..7c8f07d5582 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -3086,7 +3086,6 @@ void vnc_init_state(VncState *vs) vnc_write(vs, "RFB 003.008\n", 12); vnc_flush(vs); vnc_read_when(vs, protocol_version, 12); - reset_keys(vs); if (vs->vd->lock_key_sync) vs->led = qemu_add_led_event_handler(kbd_leds, vs); From 90cd03a30ee96779ee9ae36a84b387452e256358 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Thu, 29 Sep 2016 16:45:39 +0100 Subject: [PATCH 673/723] ui: move some initialization out of vnc_init_state Most of the fields in VncState are initialized in the vnc_connect() method, but some are done in vnc_init_state() instead. The purpose of having vnc_init_state() is to delay starting of the VNC wire protocol until after the websockets handshake has completed. As such the vnc_init_state() method only needs to be used for initialization that is dependant on the wire protocol running. This also lets us get rid of the initialized boolean flag from the VncState struct. Signed-off-by: Daniel P. Berrange Message-id: 1475163940-26094-9-git-send-email-berrange@redhat.com Signed-off-by: Gerd Hoffmann --- ui/vnc.c | 49 +++++++++++++++++++++++-------------------------- ui/vnc.h | 1 - 2 files changed, 23 insertions(+), 27 deletions(-) diff --git a/ui/vnc.c b/ui/vnc.c index 7c8f07d5582..c10a003b88a 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -1222,13 +1222,13 @@ void vnc_disconnect_finish(VncState *vs) audio_del(vs); vnc_release_modifiers(vs); - if (vs->initialized) { - QTAILQ_REMOVE(&vs->vd->clients, vs, next); + if (vs->mouse_mode_notifier.notify != NULL) { qemu_remove_mouse_mode_change_notifier(&vs->mouse_mode_notifier); - if (QTAILQ_EMPTY(&vs->vd->clients)) { - /* last client gone */ - vnc_update_server_surface(vs->vd); - } + } + QTAILQ_REMOVE(&vs->vd->clients, vs, next); + if (QTAILQ_EMPTY(&vs->vd->clients)) { + /* last client gone */ + vnc_update_server_surface(vs->vd); } if (vs->vd->lock_key_sync) @@ -2978,6 +2978,7 @@ static void vnc_connect(VncDisplay *vd, QIOChannelSocket *sioc, bool skipauth, bool websocket) { VncState *vs = g_new0(VncState, 1); + bool first_client = QTAILQ_EMPTY(&vd->clients); int i; vs->sioc = sioc; @@ -3045,26 +3046,6 @@ static void vnc_connect(VncDisplay *vd, QIOChannelSocket *sioc, vnc_qmp_event(vs, QAPI_EVENT_VNC_CONNECTED); vnc_set_share_mode(vs, VNC_SHARE_MODE_CONNECTING); - if (!vs->websocket) { - vnc_init_state(vs); - } - - if (vd->num_connecting > vd->connections_limit) { - QTAILQ_FOREACH(vs, &vd->clients, next) { - if (vs->share_mode == VNC_SHARE_MODE_CONNECTING) { - vnc_disconnect_start(vs); - return; - } - } - } -} - -void vnc_init_state(VncState *vs) -{ - vs->initialized = true; - VncDisplay *vd = vs->vd; - bool first_client = QTAILQ_EMPTY(&vd->clients); - vs->last_x = -1; vs->last_y = -1; @@ -3083,6 +3064,22 @@ void vnc_init_state(VncState *vs) graphic_hw_update(vd->dcl.con); + if (!vs->websocket) { + vnc_init_state(vs); + } + + if (vd->num_connecting > vd->connections_limit) { + QTAILQ_FOREACH(vs, &vd->clients, next) { + if (vs->share_mode == VNC_SHARE_MODE_CONNECTING) { + vnc_disconnect_start(vs); + return; + } + } + } +} + +void vnc_init_state(VncState *vs) +{ vnc_write(vs, "RFB 003.008\n", 12); vnc_flush(vs); vnc_read_when(vs, protocol_version, 12); diff --git a/ui/vnc.h b/ui/vnc.h index d191d88356f..e48e155ce4e 100644 --- a/ui/vnc.h +++ b/ui/vnc.h @@ -307,7 +307,6 @@ struct VncState QEMUPutLEDEntry *led; bool abort; - bool initialized; QemuMutex output_mutex; QEMUBH *bh; Buffer jobs_buffer; From dbee9897d5c35643ab2932a86bdf27bee673a7b8 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Thu, 29 Sep 2016 16:45:40 +0100 Subject: [PATCH 674/723] ui: rename vnc_init_state to vnc_start_protocol Rename the vnc_init_state method to reflect what its actual purpose is, to discourage future devs from using it for more general state initialization. Signed-off-by: Daniel P. Berrange Message-id: 1475163940-26094-10-git-send-email-berrange@redhat.com Signed-off-by: Gerd Hoffmann --- ui/vnc-ws.c | 2 +- ui/vnc.c | 4 ++-- ui/vnc.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ui/vnc-ws.c b/ui/vnc-ws.c index 3bac46e7741..42a8e7be5c6 100644 --- a/ui/vnc-ws.c +++ b/ui/vnc-ws.c @@ -92,7 +92,7 @@ static void vncws_handshake_done(Object *source, vnc_client_error(vs); } else { VNC_DEBUG("Websock handshake complete, starting VNC protocol\n"); - vnc_init_state(vs); + vnc_start_protocol(vs); vs->ioc_tag = qio_channel_add_watch( vs->ioc, G_IO_IN, vnc_client_io, vs, NULL); } diff --git a/ui/vnc.c b/ui/vnc.c index c10a003b88a..c1e98fb6bfb 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -3065,7 +3065,7 @@ static void vnc_connect(VncDisplay *vd, QIOChannelSocket *sioc, graphic_hw_update(vd->dcl.con); if (!vs->websocket) { - vnc_init_state(vs); + vnc_start_protocol(vs); } if (vd->num_connecting > vd->connections_limit) { @@ -3078,7 +3078,7 @@ static void vnc_connect(VncDisplay *vd, QIOChannelSocket *sioc, } } -void vnc_init_state(VncState *vs) +void vnc_start_protocol(VncState *vs) { vnc_write(vs, "RFB 003.008\n", 12); vnc_flush(vs); diff --git a/ui/vnc.h b/ui/vnc.h index e48e155ce4e..d20b154a775 100644 --- a/ui/vnc.h +++ b/ui/vnc.h @@ -515,7 +515,7 @@ void vnc_write_u8(VncState *vs, uint8_t value); void vnc_flush(VncState *vs); void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting); void vnc_disconnect_finish(VncState *vs); -void vnc_init_state(VncState *vs); +void vnc_start_protocol(VncState *vs); /* Buffer I/O functions */ From 2a57c55f26f7ba6dcea6d01ef74bae7069150f6f Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 12 Oct 2016 15:03:04 +0200 Subject: [PATCH 675/723] input-linux: initialize key state Query input device keys, initialize state accordingly, so the correct state is reflected in case any key is pressed at initialization time. There is a high chance for this to actually happen for the 'enter' key in case you start qemu with a terminal command (directly or virsh). When finding any pressed keys the input grab is delayed until all keys are lifted, to avoid confusing guest and host with appearently stuck keys. Reported-by: Muted Bytes Signed-off-by: Gerd Hoffmann Message-id: 1476277384-30365-1-git-send-email-kraxel@redhat.com --- ui/input-linux.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/ui/input-linux.c b/ui/input-linux.c index 0e230ce6991..f3453177948 100644 --- a/ui/input-linux.c +++ b/ui/input-linux.c @@ -347,7 +347,8 @@ static void input_linux_event(void *opaque) static void input_linux_complete(UserCreatable *uc, Error **errp) { InputLinux *il = INPUT_LINUX(uc); - uint8_t evtmap, relmap, absmap, keymap[KEY_CNT / 8]; + uint8_t evtmap, relmap, absmap; + uint8_t keymap[KEY_CNT / 8], keystate[KEY_CNT / 8]; unsigned int i; int rc, ver; @@ -394,6 +395,7 @@ static void input_linux_complete(UserCreatable *uc, Error **errp) if (evtmap & (1 << EV_KEY)) { memset(keymap, 0, sizeof(keymap)); rc = ioctl(il->fd, EVIOCGBIT(EV_KEY, sizeof(keymap)), keymap); + rc = ioctl(il->fd, EVIOCGKEY(sizeof(keystate)), keystate); for (i = 0; i < KEY_CNT; i++) { if (keymap[i / 8] & (1 << (i % 8))) { if (linux_is_button(i)) { @@ -401,12 +403,21 @@ static void input_linux_complete(UserCreatable *uc, Error **errp) } else { il->num_keys++; } + if (keystate[i / 8] & (1 << (i % 8))) { + il->keydown[i] = true; + il->keycount++; + } } } } qemu_set_fd_handler(il->fd, input_linux_event, NULL, il); - input_linux_toggle_grab(il); + if (il->keycount) { + /* delay grab until all keys are released */ + il->grab_request = true; + } else { + input_linux_toggle_grab(il); + } QTAILQ_INSERT_TAIL(&inputs, il, next); il->initialized = true; return; From 692d88b4085559f1254d0e04d64a849ce8ab5932 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Thu, 13 Oct 2016 15:14:41 +0400 Subject: [PATCH 676/723] Revert "char: use a fixed idx for child muxed chr" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit That commit mis-used mux char: the frontend are multiplexed, not the backend. Fix the regression preventing "c-a c" to switch the focus. The following patches will fix the crash (when leaving or removing frontend) by tracking frontends with handler tags. This reverts commit 949055a2549afc4cde06b7972072c7288bb43722. Signed-off-by: Marc-André Lureau Signed-off-by: Peter Maydell --- include/sysemu/char.h | 1 - qemu-char.c | 22 +++++++--------------- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/include/sysemu/char.h b/include/sysemu/char.h index 0d121756efd..19dad3fb9c7 100644 --- a/include/sysemu/char.h +++ b/include/sysemu/char.h @@ -107,7 +107,6 @@ struct CharDriverState { int explicit_be_open; int avail_connections; int is_mux; - int mux_idx; guint fd_in_tag; bool replay; DECLARE_BITMAP(features, QEMU_CHAR_FEATURE_LAST); diff --git a/qemu-char.c b/qemu-char.c index 721ce21ea2a..d83a89618e1 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -165,7 +165,6 @@ CharDriverState *qemu_chr_alloc(ChardevCommon *backend, Error **errp) CharDriverState *chr = g_malloc0(sizeof(CharDriverState)); qemu_mutex_init(&chr->chr_write_lock); - chr->mux_idx = -1; if (backend->has_logfile) { int flags = O_WRONLY | O_CREAT; if (backend->has_logappend && @@ -739,25 +738,17 @@ static void mux_chr_update_read_handler(CharDriverState *chr, GMainContext *context) { MuxDriver *d = chr->opaque; - int idx; if (d->mux_cnt >= MAX_MUX) { fprintf(stderr, "Cannot add I/O handlers, MUX array is full\n"); return; } - - if (chr->mux_idx == -1) { - chr->mux_idx = d->mux_cnt++; - } - - idx = chr->mux_idx; - d->ext_opaque[idx] = chr->handler_opaque; - d->chr_can_read[idx] = chr->chr_can_read; - d->chr_read[idx] = chr->chr_read; - d->chr_event[idx] = chr->chr_event; - + d->ext_opaque[d->mux_cnt] = chr->handler_opaque; + d->chr_can_read[d->mux_cnt] = chr->chr_can_read; + d->chr_read[d->mux_cnt] = chr->chr_read; + d->chr_event[d->mux_cnt] = chr->chr_event; /* Fix up the real driver with mux routines */ - if (d->mux_cnt == 1) { + if (d->mux_cnt == 0) { qemu_chr_add_handlers_full(d->drv, mux_chr_can_read, mux_chr_read, mux_chr_event, @@ -766,7 +757,8 @@ static void mux_chr_update_read_handler(CharDriverState *chr, if (d->focus != -1) { mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_OUT); } - d->focus = idx; + d->focus = d->mux_cnt; + d->mux_cnt++; mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_IN); } From a1771070e7b892a0bdea81b4a1ec7fcca0af21f5 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Tue, 27 Sep 2016 19:56:04 +0100 Subject: [PATCH 677/723] migration: report an error giving the failed field When a field fails to load (typically due to a limit check, or a call to a get/put) report the device and field to give an indication of the cause. Signed-off-by: Dr. David Alan Gilbert Reviewed-by: John Snow Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- migration/vmstate.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/migration/vmstate.c b/migration/vmstate.c index fc29acf74d7..1d637b20dac 100644 --- a/migration/vmstate.c +++ b/migration/vmstate.c @@ -130,6 +130,8 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd, } if (ret < 0) { qemu_file_set_error(f, ret); + error_report("Failed to load %s:%s", vmsd->name, + field->name); trace_vmstate_load_field_error(field->name, ret); return ret; } From 49228e17edc3f9a7cef6061daffdcc3a33d8023d Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Tue, 27 Sep 2016 19:56:05 +0100 Subject: [PATCH 678/723] migration: Report values for comparisons Report the values when a comparison fails; together with the previous patch that prints the device and field names this should give a good idea of why loading the migration failed. Signed-off-by: Dr. David Alan Gilbert Reviewed-by: John Snow Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- migration/vmstate.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/migration/vmstate.c b/migration/vmstate.c index 1d637b20dac..0bc9f35ef81 100644 --- a/migration/vmstate.c +++ b/migration/vmstate.c @@ -557,6 +557,7 @@ static int get_int32_equal(QEMUFile *f, void *pv, size_t size) if (*v == v2) { return 0; } + error_report("%" PRIx32 " != %" PRIx32, *v, v2); return -EINVAL; } @@ -580,6 +581,9 @@ static int get_int32_le(QEMUFile *f, void *pv, size_t size) *cur = loaded; return 0; } + error_report("Invalid value %" PRId32 + " expecting positive value <= %" PRId32, + loaded, *cur); return -EINVAL; } @@ -685,6 +689,7 @@ static int get_uint32_equal(QEMUFile *f, void *pv, size_t size) if (*v == v2) { return 0; } + error_report("%" PRIx32 " != %" PRIx32, *v, v2); return -EINVAL; } @@ -727,6 +732,7 @@ static int get_uint64_equal(QEMUFile *f, void *pv, size_t size) if (*v == v2) { return 0; } + error_report("%" PRIx64 " != %" PRIx64, *v, v2); return -EINVAL; } @@ -748,6 +754,7 @@ static int get_uint8_equal(QEMUFile *f, void *pv, size_t size) if (*v == v2) { return 0; } + error_report("%x != %x", *v, v2); return -EINVAL; } @@ -769,6 +776,7 @@ static int get_uint16_equal(QEMUFile *f, void *pv, size_t size) if (*v == v2) { return 0; } + error_report("%x != %x", *v, v2); return -EINVAL; } From 12c67ffb1fe34ff72a55fa440243c0dfcf22f89b Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Fri, 23 Sep 2016 20:14:02 +0100 Subject: [PATCH 679/723] migration/rdma: Pass qemu_file errors across link If we fail for some reason (e.g. a mismatched RAMBlock) and it's set the qemu_file error flag, pass that error back to the peer so it can clean up rather than waiting for some higher level progress. Signed-off-by: Dr. David Alan Gilbert Reviewed-by: Michael R. Hines Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- migration/rdma.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/migration/rdma.c b/migration/rdma.c index 88bdb64457c..7271292db07 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -2804,6 +2804,9 @@ static int qio_channel_rdma_close(QIOChannel *ioc, QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(ioc); trace_qemu_rdma_close(); if (rioc->rdma) { + if (!rioc->rdma->error_state) { + rioc->rdma->error_state = qemu_file_get_error(rioc->file); + } qemu_rdma_cleanup(rioc->rdma); g_free(rioc->rdma); rioc->rdma = NULL; From ccb783c3124b66fed6b11aa7a1cd1939a2268287 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Fri, 23 Sep 2016 20:14:03 +0100 Subject: [PATCH 680/723] migration: Make failed migration load set file error If an error occurs in a section load, set the file error flag so that the transport can get notified to do a cleanup. Signed-off-by: Dr. David Alan Gilbert Reviewed-by: Michael R. Hines Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- migration/savevm.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/migration/savevm.c b/migration/savevm.c index 33a2911ec25..a831ec2d677 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -1828,40 +1828,45 @@ qemu_loadvm_section_part_end(QEMUFile *f, MigrationIncomingState *mis) static int qemu_loadvm_state_main(QEMUFile *f, MigrationIncomingState *mis) { uint8_t section_type; - int ret; + int ret = 0; while ((section_type = qemu_get_byte(f)) != QEMU_VM_EOF) { - + ret = 0; trace_qemu_loadvm_state_section(section_type); switch (section_type) { case QEMU_VM_SECTION_START: case QEMU_VM_SECTION_FULL: ret = qemu_loadvm_section_start_full(f, mis); if (ret < 0) { - return ret; + goto out; } break; case QEMU_VM_SECTION_PART: case QEMU_VM_SECTION_END: ret = qemu_loadvm_section_part_end(f, mis); if (ret < 0) { - return ret; + goto out; } break; case QEMU_VM_COMMAND: ret = loadvm_process_command(f); trace_qemu_loadvm_state_section_command(ret); if ((ret < 0) || (ret & LOADVM_QUIT)) { - return ret; + goto out; } break; default: error_report("Unknown savevm section type %d", section_type); - return -EINVAL; + ret = -EINVAL; + goto out; } } - return 0; +out: + if (ret < 0) { + qemu_file_set_error(f, ret); + } + return ret; } int qemu_loadvm_state(QEMUFile *f) From cd5ea070645682893312d67dba6d4dd0b1a80739 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Fri, 23 Sep 2016 20:14:04 +0100 Subject: [PATCH 681/723] migration/rdma: Don't flag an error when we've been told about one If the other side tells us there's been an error and we fail the migration, we don't need to signal that failure to the other side because it already knew. Signed-off-by: Dr. David Alan Gilbert Reviewed-by: Michael R. Hines Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- migration/rdma.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/migration/rdma.c b/migration/rdma.c index 7271292db07..674ccab12e1 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -350,6 +350,7 @@ typedef struct RDMAContext { */ int error_state; int error_reported; + int received_error; /* * Description of ram blocks used throughout the code. @@ -1676,6 +1677,9 @@ static int qemu_rdma_exchange_get_response(RDMAContext *rdma, ", but got: %s (%d), length: %d", control_desc[expecting], expecting, control_desc[head->type], head->type, head->len); + if (head->type == RDMA_CONTROL_ERROR) { + rdma->received_error = true; + } return -EIO; } if (head->len > RDMA_CONTROL_MAX_BUFFER - sizeof(*head)) { @@ -2202,7 +2206,7 @@ static void qemu_rdma_cleanup(RDMAContext *rdma) int ret, idx; if (rdma->cm_id && rdma->connected) { - if (rdma->error_state) { + if (rdma->error_state && !rdma->received_error) { RDMAControlHeader head = { .len = 0, .type = RDMA_CONTROL_ERROR, .repeat = 1, From bb2b777cf9a2862fe31a40256659ff49ae3d2006 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Thu, 8 Sep 2016 22:14:14 -0500 Subject: [PATCH 682/723] migrate: Fix cpu-throttle-increment regression in HMP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 69ef1f3 accidentally broke migrate_set_parameter's ability to set the cpu-throttle-increment to anything other than the default, because it forgot to parse the user's string into an integer. CC: qemu-stable@nongnu.org Signed-off-by: Eric Blake Reviewed-by: Marc-André Lureau Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- hmp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hmp.c b/hmp.c index 42bef84ed5c..9509596e1b2 100644 --- a/hmp.c +++ b/hmp.c @@ -1351,6 +1351,7 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict) break; case MIGRATION_PARAMETER_CPU_THROTTLE_INCREMENT: has_cpu_throttle_increment = true; + use_int_value = true; break; case MIGRATION_PARAMETER_TLS_CREDS: has_tls_creds = true; From de63ab61241b44598cdfd30060ef23d46d368f9d Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Thu, 8 Sep 2016 22:14:15 -0500 Subject: [PATCH 683/723] migrate: Share common MigrationParameters struct MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is rather verbose, and slightly error-prone, to repeat the same set of parameters for input (migrate-set-parameters) as for output (query-migrate-parameters), where the only difference is whether the members are optional. We can just document that the optional members will always be present on output, and then share a common struct between both commands. The next patch can then reduce the amount of code needed on input. Also, we made a mistake in qemu 2.7 of returning an empty string during 'query-migrate-parameters' when there is no TLS, rather than omitting TLS details entirely. Technically, this change risks breaking any 2.7 client that is hard-coded to expect the parameter's existence; on the other hand, clients that are portable to 2.6 already must be prepared for those members to not be present. And this gets rid of yet one more place where the QMP output visitor is silently converting a NULL string into "" (which is a hack I ultimately want to kill off). Signed-off-by: Eric Blake Reviewed-by: Marc-André Lureau Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- hmp.c | 9 ++++- migration/migration.c | 7 ++++ qapi-schema.json | 85 ++++++++++++++----------------------------- 3 files changed, 41 insertions(+), 60 deletions(-) diff --git a/hmp.c b/hmp.c index 9509596e1b2..c405d3ea0cc 100644 --- a/hmp.c +++ b/hmp.c @@ -284,27 +284,32 @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict) if (params) { monitor_printf(mon, "parameters:"); + assert(params->has_compress_level); monitor_printf(mon, " %s: %" PRId64, MigrationParameter_lookup[MIGRATION_PARAMETER_COMPRESS_LEVEL], params->compress_level); + assert(params->has_compress_threads); monitor_printf(mon, " %s: %" PRId64, MigrationParameter_lookup[MIGRATION_PARAMETER_COMPRESS_THREADS], params->compress_threads); + assert(params->has_decompress_threads); monitor_printf(mon, " %s: %" PRId64, MigrationParameter_lookup[MIGRATION_PARAMETER_DECOMPRESS_THREADS], params->decompress_threads); + assert(params->has_cpu_throttle_initial); monitor_printf(mon, " %s: %" PRId64, MigrationParameter_lookup[MIGRATION_PARAMETER_CPU_THROTTLE_INITIAL], params->cpu_throttle_initial); + assert(params->has_cpu_throttle_increment); monitor_printf(mon, " %s: %" PRId64, MigrationParameter_lookup[MIGRATION_PARAMETER_CPU_THROTTLE_INCREMENT], params->cpu_throttle_increment); monitor_printf(mon, " %s: '%s'", MigrationParameter_lookup[MIGRATION_PARAMETER_TLS_CREDS], - params->tls_creds ? : ""); + params->has_tls_creds ? params->tls_creds : ""); monitor_printf(mon, " %s: '%s'", MigrationParameter_lookup[MIGRATION_PARAMETER_TLS_HOSTNAME], - params->tls_hostname ? : ""); + params->has_tls_hostname ? params->tls_hostname : ""); monitor_printf(mon, "\n"); } diff --git a/migration/migration.c b/migration/migration.c index 955d5ee38cb..1a8f26b3e9d 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -559,12 +559,19 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp) MigrationState *s = migrate_get_current(); params = g_malloc0(sizeof(*params)); + params->has_compress_level = true; params->compress_level = s->parameters.compress_level; + params->has_compress_threads = true; params->compress_threads = s->parameters.compress_threads; + params->has_decompress_threads = true; params->decompress_threads = s->parameters.decompress_threads; + params->has_cpu_throttle_initial = true; params->cpu_throttle_initial = s->parameters.cpu_throttle_initial; + params->has_cpu_throttle_increment = true; params->cpu_throttle_increment = s->parameters.cpu_throttle_increment; + params->has_tls_creds = !!s->parameters.tls_creds; params->tls_creds = g_strdup(s->parameters.tls_creds); + params->has_tls_hostname = !!s->parameters.tls_hostname; params->tls_hostname = g_strdup(s->parameters.tls_hostname); return params; diff --git a/qapi-schema.json b/qapi-schema.json index 9e47b47cc78..e16e8895055 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -668,75 +668,45 @@ # # @migrate-set-parameters # -# Set the following migration parameters -# -# @compress-level: compression level -# -# @compress-threads: compression thread count -# -# @decompress-threads: decompression thread count -# -# @cpu-throttle-initial: Initial percentage of time guest cpus are throttled -# when migration auto-converge is activated. The -# default value is 20. (Since 2.7) -# -# @cpu-throttle-increment: throttle percentage increase each time -# auto-converge detects that migration is not making -# progress. The default value is 10. (Since 2.7) -# -# @tls-creds: ID of the 'tls-creds' object that provides credentials for -# establishing a TLS connection over the migration data channel. -# On the outgoing side of the migration, the credentials must -# be for a 'client' endpoint, while for the incoming side the -# credentials must be for a 'server' endpoint. Setting this -# will enable TLS for all migrations. The default is unset, -# resulting in unsecured migration at the QEMU level. (Since 2.7) -# -# @tls-hostname: hostname of the target host for the migration. This is -# required when using x509 based TLS credentials and the -# migration URI does not already include a hostname. For -# example if using fd: or exec: based migration, the -# hostname must be provided so that the server's x509 -# certificate identity can be validated. (Since 2.7) +# Set various migration parameters. See MigrationParameters for details. # # Since: 2.4 ## { 'command': 'migrate-set-parameters', - 'data': { '*compress-level': 'int', - '*compress-threads': 'int', - '*decompress-threads': 'int', - '*cpu-throttle-initial': 'int', - '*cpu-throttle-increment': 'int', - '*tls-creds': 'str', - '*tls-hostname': 'str'} } + 'data': 'MigrationParameters' } # # @MigrationParameters # -# @compress-level: compression level +# Optional members can be omitted on input ('migrate-set-parameters') +# but most members will always be present on output +# ('query-migrate-parameters'), with the exception of tls-creds and +# tls-hostname. # -# @compress-threads: compression thread count +# @compress-level: #optional compression level # -# @decompress-threads: decompression thread count +# @compress-threads: #optional compression thread count # -# @cpu-throttle-initial: Initial percentage of time guest cpus are throttled -# when migration auto-converge is activated. The -# default value is 20. (Since 2.7) +# @decompress-threads: #optional decompression thread count # -# @cpu-throttle-increment: throttle percentage increase each time +# @cpu-throttle-initial: #optional Initial percentage of time guest cpus are +# throttledwhen migration auto-converge is activated. +# The default value is 20. (Since 2.7) +# +# @cpu-throttle-increment: #optional throttle percentage increase each time # auto-converge detects that migration is not making # progress. The default value is 10. (Since 2.7) # -# @tls-creds: ID of the 'tls-creds' object that provides credentials for -# establishing a TLS connection over the migration data channel. -# On the outgoing side of the migration, the credentials must -# be for a 'client' endpoint, while for the incoming side the +# @tls-creds: #optional ID of the 'tls-creds' object that provides credentials +# for establishing a TLS connection over the migration data +# channel. On the outgoing side of the migration, the credentials +# must be for a 'client' endpoint, while for the incoming side the # credentials must be for a 'server' endpoint. Setting this # will enable TLS for all migrations. The default is unset, # resulting in unsecured migration at the QEMU level. (Since 2.7) # -# @tls-hostname: hostname of the target host for the migration. This is -# required when using x509 based TLS credentials and the +# @tls-hostname: #optional hostname of the target host for the migration. This +# is required when using x509 based TLS credentials and the # migration URI does not already include a hostname. For # example if using fd: or exec: based migration, the # hostname must be provided so that the server's x509 @@ -745,14 +715,13 @@ # Since: 2.4 ## { 'struct': 'MigrationParameters', - 'data': { 'compress-level': 'int', - 'compress-threads': 'int', - 'decompress-threads': 'int', - 'cpu-throttle-initial': 'int', - 'cpu-throttle-increment': 'int', - 'tls-creds': 'str', - 'tls-hostname': 'str'} } - + 'data': { '*compress-level': 'int', + '*compress-threads': 'int', + '*decompress-threads': 'int', + '*cpu-throttle-initial': 'int', + '*cpu-throttle-increment': 'int', + '*tls-creds': 'str', + '*tls-hostname': 'str'} } ## # @query-migrate-parameters # From 7f375e0446bb3ce1cbb93b3e145452ec42bb2041 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Thu, 8 Sep 2016 22:14:16 -0500 Subject: [PATCH 684/723] migrate: Use boxed qapi for migrate-set-parameters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that QAPI makes it easy to pass a struct around, we don't have to declare as many parameters or local variables. Signed-off-by: Eric Blake Reviewed-by: Marc-André Lureau Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- hmp.c | 40 ++++++++++++-------------- migration/migration.c | 65 ++++++++++++++++++------------------------- qapi-schema.json | 2 +- 3 files changed, 46 insertions(+), 61 deletions(-) diff --git a/hmp.c b/hmp.c index c405d3ea0cc..4c0f60049fe 100644 --- a/hmp.c +++ b/hmp.c @@ -1325,44 +1325,40 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict) const char *valuestr = qdict_get_str(qdict, "value"); long valueint = 0; Error *err = NULL; - bool has_compress_level = false; - bool has_compress_threads = false; - bool has_decompress_threads = false; - bool has_cpu_throttle_initial = false; - bool has_cpu_throttle_increment = false; - bool has_tls_creds = false; - bool has_tls_hostname = false; bool use_int_value = false; int i; for (i = 0; i < MIGRATION_PARAMETER__MAX; i++) { if (strcmp(param, MigrationParameter_lookup[i]) == 0) { + MigrationParameters p = { 0 }; switch (i) { case MIGRATION_PARAMETER_COMPRESS_LEVEL: - has_compress_level = true; + p.has_compress_level = true; use_int_value = true; break; case MIGRATION_PARAMETER_COMPRESS_THREADS: - has_compress_threads = true; + p.has_compress_threads = true; use_int_value = true; break; case MIGRATION_PARAMETER_DECOMPRESS_THREADS: - has_decompress_threads = true; + p.has_decompress_threads = true; use_int_value = true; break; case MIGRATION_PARAMETER_CPU_THROTTLE_INITIAL: - has_cpu_throttle_initial = true; + p.has_cpu_throttle_initial = true; use_int_value = true; break; case MIGRATION_PARAMETER_CPU_THROTTLE_INCREMENT: - has_cpu_throttle_increment = true; + p.has_cpu_throttle_increment = true; use_int_value = true; break; case MIGRATION_PARAMETER_TLS_CREDS: - has_tls_creds = true; + p.has_tls_creds = true; + p.tls_creds = (char *) valuestr; break; case MIGRATION_PARAMETER_TLS_HOSTNAME: - has_tls_hostname = true; + p.has_tls_hostname = true; + p.tls_hostname = (char *) valuestr; break; } @@ -1372,16 +1368,16 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict) valuestr); goto cleanup; } + /* Set all integers; only one has_FOO will be set, and + * the code ignores the remaining values */ + p.compress_level = valueint; + p.compress_threads = valueint; + p.decompress_threads = valueint; + p.cpu_throttle_initial = valueint; + p.cpu_throttle_increment = valueint; } - qmp_migrate_set_parameters(has_compress_level, valueint, - has_compress_threads, valueint, - has_decompress_threads, valueint, - has_cpu_throttle_initial, valueint, - has_cpu_throttle_increment, valueint, - has_tls_creds, valuestr, - has_tls_hostname, valuestr, - &err); + qmp_migrate_set_parameters(&p, &err); break; } } diff --git a/migration/migration.c b/migration/migration.c index 1a8f26b3e9d..42336e3bfdb 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -766,78 +766,67 @@ void qmp_migrate_set_capabilities(MigrationCapabilityStatusList *params, } } -void qmp_migrate_set_parameters(bool has_compress_level, - int64_t compress_level, - bool has_compress_threads, - int64_t compress_threads, - bool has_decompress_threads, - int64_t decompress_threads, - bool has_cpu_throttle_initial, - int64_t cpu_throttle_initial, - bool has_cpu_throttle_increment, - int64_t cpu_throttle_increment, - bool has_tls_creds, - const char *tls_creds, - bool has_tls_hostname, - const char *tls_hostname, - Error **errp) +void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp) { MigrationState *s = migrate_get_current(); - if (has_compress_level && (compress_level < 0 || compress_level > 9)) { + if (params->has_compress_level && + (params->compress_level < 0 || params->compress_level > 9)) { error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "compress_level", "is invalid, it should be in the range of 0 to 9"); return; } - if (has_compress_threads && - (compress_threads < 1 || compress_threads > 255)) { + if (params->has_compress_threads && + (params->compress_threads < 1 || params->compress_threads > 255)) { error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "compress_threads", "is invalid, it should be in the range of 1 to 255"); return; } - if (has_decompress_threads && - (decompress_threads < 1 || decompress_threads > 255)) { + if (params->has_decompress_threads && + (params->decompress_threads < 1 || params->decompress_threads > 255)) { error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "decompress_threads", "is invalid, it should be in the range of 1 to 255"); return; } - if (has_cpu_throttle_initial && - (cpu_throttle_initial < 1 || cpu_throttle_initial > 99)) { + if (params->has_cpu_throttle_initial && + (params->cpu_throttle_initial < 1 || + params->cpu_throttle_initial > 99)) { error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "cpu_throttle_initial", "an integer in the range of 1 to 99"); } - if (has_cpu_throttle_increment && - (cpu_throttle_increment < 1 || cpu_throttle_increment > 99)) { + if (params->has_cpu_throttle_increment && + (params->cpu_throttle_increment < 1 || + params->cpu_throttle_increment > 99)) { error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "cpu_throttle_increment", "an integer in the range of 1 to 99"); } - if (has_compress_level) { - s->parameters.compress_level = compress_level; + if (params->has_compress_level) { + s->parameters.compress_level = params->compress_level; } - if (has_compress_threads) { - s->parameters.compress_threads = compress_threads; + if (params->has_compress_threads) { + s->parameters.compress_threads = params->compress_threads; } - if (has_decompress_threads) { - s->parameters.decompress_threads = decompress_threads; + if (params->has_decompress_threads) { + s->parameters.decompress_threads = params->decompress_threads; } - if (has_cpu_throttle_initial) { - s->parameters.cpu_throttle_initial = cpu_throttle_initial; + if (params->has_cpu_throttle_initial) { + s->parameters.cpu_throttle_initial = params->cpu_throttle_initial; } - if (has_cpu_throttle_increment) { - s->parameters.cpu_throttle_increment = cpu_throttle_increment; + if (params->has_cpu_throttle_increment) { + s->parameters.cpu_throttle_increment = params->cpu_throttle_increment; } - if (has_tls_creds) { + if (params->has_tls_creds) { g_free(s->parameters.tls_creds); - s->parameters.tls_creds = g_strdup(tls_creds); + s->parameters.tls_creds = g_strdup(params->tls_creds); } - if (has_tls_hostname) { + if (params->has_tls_hostname) { g_free(s->parameters.tls_hostname); - s->parameters.tls_hostname = g_strdup(tls_hostname); + s->parameters.tls_hostname = g_strdup(params->tls_hostname); } } diff --git a/qapi-schema.json b/qapi-schema.json index e16e8895055..58bed718375 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -672,7 +672,7 @@ # # Since: 2.4 ## -{ 'command': 'migrate-set-parameters', +{ 'command': 'migrate-set-parameters', 'boxed': true, 'data': 'MigrationParameters' } # From 091ecc8b69bd735383e171828d4e8ed5e34c2a3b Mon Sep 17 00:00:00 2001 From: Ashijeet Acharya Date: Sat, 10 Sep 2016 02:43:17 +0530 Subject: [PATCH 685/723] migrate: Fix bounds check for migration parameters in migration.c This patch fixes the out-of-bounds check of migration parameters in qmp_migrate_set_parameters() for cpu-throttle-initial and cpu-throttle-increment by adding a return statement for both as they were broken since their introduction in 2.5 via commit 1626fee. Due to the missing return statements, parameters were getting set to out-of-bounds values despite the error. Signed-off-by: Ashijeet Acharya Reviewed-by: Eric Blake Reviewed-by: Amit Shah Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- migration/migration.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/migration/migration.c b/migration/migration.c index 42336e3bfdb..04b706f69ec 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -796,6 +796,7 @@ void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp) error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "cpu_throttle_initial", "an integer in the range of 1 to 99"); + return; } if (params->has_cpu_throttle_increment && (params->cpu_throttle_increment < 1 || @@ -803,6 +804,7 @@ void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp) error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "cpu_throttle_increment", "an integer in the range of 1 to 99"); + return; } if (params->has_compress_level) { From 2ebeaec012b4e5695612774c44f14c61ab46c72c Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Wed, 24 Aug 2016 18:15:46 +0100 Subject: [PATCH 686/723] Postcopy vs xbzrle: Don't send xbzrle pages once in postcopy [for 2.8] xbzrle relies on reading pages that have already been sent to the destination and then applying the modifications; we can't do that in postcopy because the destination may well have modified the page already or the page has been discarded. I already didn't allow reception of xbzrle pages, but I forgot to add the test to stop them being sent. Enabling both xbzrle and postcopy can make some sense; if you think that your migration might finish if you have xbzrle, then when it doesn't complete you flick over to postcopy and stop xbzrle'ing. This corresponds to RH bug: https://bugzilla.redhat.com/show_bug.cgi?id=1368422 Symptom is: Unknown combination of migration flags: 0x60 (postcopy mode) (either 0x60 or 0x40) Signed-off-by: Dr. David Alan Gilbert Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- migration/ram.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/migration/ram.c b/migration/ram.c index c8ec9f268fd..bc6154fe344 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -771,7 +771,9 @@ static int ram_save_page(QEMUFile *f, PageSearchStatus *pss, * page would be stale */ xbzrle_cache_zero_page(current_addr); - } else if (!ram_bulk_stage && migrate_use_xbzrle()) { + } else if (!ram_bulk_stage && + !migration_in_postcopy(migrate_get_current()) && + migrate_use_xbzrle()) { pages = save_xbzrle_page(f, &p, current_addr, block, offset, last_stage, bytes_transferred); if (!last_stage) { From 863e9621c51a7544f1a2ae78387749145adaf450 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Thu, 29 Sep 2016 20:09:37 +0100 Subject: [PATCH 687/723] RAMBlocks: Store page size Store the page size in each RAMBlock, we need it later. Signed-off-by: Dr. David Alan Gilbert Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- exec.c | 19 ++++++++++++------- include/exec/cpu-common.h | 1 + include/exec/ram_addr.h | 1 + 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/exec.c b/exec.c index 374c364dff6..e63c5a1bd4d 100644 --- a/exec.c +++ b/exec.c @@ -1199,7 +1199,6 @@ static void *file_ram_alloc(RAMBlock *block, char *c; void *area = MAP_FAILED; int fd = -1; - int64_t page_size; if (kvm_enabled() && !kvm_has_sync_mmu()) { error_setg(errp, @@ -1254,17 +1253,17 @@ static void *file_ram_alloc(RAMBlock *block, */ } - page_size = qemu_fd_getpagesize(fd); - block->mr->align = MAX(page_size, QEMU_VMALLOC_ALIGN); + block->page_size = qemu_fd_getpagesize(fd); + block->mr->align = MAX(block->page_size, QEMU_VMALLOC_ALIGN); - if (memory < page_size) { + if (memory < block->page_size) { error_setg(errp, "memory size 0x" RAM_ADDR_FMT " must be equal to " - "or larger than page size 0x%" PRIx64, - memory, page_size); + "or larger than page size 0x%zx", + memory, block->page_size); goto error; } - memory = ROUND_UP(memory, page_size); + memory = ROUND_UP(memory, block->page_size); /* * ftruncate is not supported by hugetlbfs in older @@ -1419,6 +1418,11 @@ void qemu_ram_unset_idstr(RAMBlock *block) } } +size_t qemu_ram_pagesize(RAMBlock *rb) +{ + return rb->page_size; +} + static int memory_try_enable_merging(void *addr, size_t len) { if (!machine_mem_merge(current_machine)) { @@ -1658,6 +1662,7 @@ RAMBlock *qemu_ram_alloc_internal(ram_addr_t size, ram_addr_t max_size, new_block->max_length = max_size; assert(max_size >= size); new_block->fd = -1; + new_block->page_size = getpagesize(); new_block->host = host; if (host) { new_block->flags |= RAM_PREALLOC; diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h index 869ba41b0c8..cffdc130e6a 100644 --- a/include/exec/cpu-common.h +++ b/include/exec/cpu-common.h @@ -63,6 +63,7 @@ RAMBlock *qemu_ram_block_from_host(void *ptr, bool round_offset, void qemu_ram_set_idstr(RAMBlock *block, const char *name, DeviceState *dev); void qemu_ram_unset_idstr(RAMBlock *block); const char *qemu_ram_get_idstr(RAMBlock *rb); +size_t qemu_ram_pagesize(RAMBlock *block); void cpu_physical_memory_rw(hwaddr addr, uint8_t *buf, int len, int is_write); diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h index 2a9465da11b..54d7108a9ef 100644 --- a/include/exec/ram_addr.h +++ b/include/exec/ram_addr.h @@ -36,6 +36,7 @@ struct RAMBlock { /* RCU-enabled, writes protected by the ramlist lock */ QLIST_ENTRY(RAMBlock) next; int fd; + size_t page_size; }; static inline bool offset_in_ramblock(RAMBlock *b, ram_addr_t offset) From 5cf0f48d2aa860877c992030854540ba82dfe8fa Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Thu, 29 Sep 2016 20:09:38 +0100 Subject: [PATCH 688/723] migration/postcopy: Explicitly disallow huge pages At the moment postcopy will fail as soon as qemu tries to register userfault on the RAMBlock pages that are backed by hugepages. However, the kernel is going to get userfault support for hugepage at some point, and we've not got the rest of the QEMU code to support it yet, so fail neatly with an error like: Postcopy doesn't support hugetlbfs yet (/objects/mem1) Signed-off-by: Dr. David Alan Gilbert Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- migration/postcopy-ram.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c index 9b0477835ff..a40dddbaf67 100644 --- a/migration/postcopy-ram.c +++ b/migration/postcopy-ram.c @@ -84,6 +84,24 @@ static bool ufd_version_check(int ufd) return true; } +/* + * Check for things that postcopy won't support; returns 0 if the block + * is fine. + */ +static int check_range(const char *block_name, void *host_addr, + ram_addr_t offset, ram_addr_t length, void *opaque) +{ + RAMBlock *rb = qemu_ram_block_by_name(block_name); + + if (qemu_ram_pagesize(rb) > getpagesize()) { + error_report("Postcopy doesn't support large page sizes yet (%s)", + block_name); + return -E2BIG; + } + + return 0; +} + /* * Note: This has the side effect of munlock'ing all of RAM, that's * normally fine since if the postcopy succeeds it gets turned back on at the @@ -104,6 +122,12 @@ bool postcopy_ram_supported_by_host(void) goto out; } + /* Check for anything about the RAMBlocks we don't support */ + if (qemu_ram_foreach_block(check_range, NULL)) { + /* check_range will have printed its own error */ + goto out; + } + ufd = syscall(__NR_userfaultfd, O_CLOEXEC); if (ufd == -1) { error_report("%s: userfaultfd not available: %s", __func__, From 9308ae54858a86f2955e0b45f74d6e1f9c38820b Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Tue, 13 Sep 2016 10:08:41 +0100 Subject: [PATCH 689/723] migration: Fix seg with missing port The command : migrate tcp:localhost: currently segs; fix it so it now says: error parsing address 'localhost:' and the same for -incoming. Signed-off-by: Dr. David Alan Gilbert Reviewed-by: Daniel P. Berrange Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- migration/socket.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/migration/socket.c b/migration/socket.c index 00de1fe127d..a21c0c5c359 100644 --- a/migration/socket.c +++ b/migration/socket.c @@ -112,8 +112,12 @@ void tcp_start_outgoing_migration(MigrationState *s, const char *host_port, Error **errp) { - SocketAddress *saddr = tcp_build_address(host_port, errp); - socket_start_outgoing_migration(s, saddr, errp); + Error *err = NULL; + SocketAddress *saddr = tcp_build_address(host_port, &err); + if (!err) { + socket_start_outgoing_migration(s, saddr, &err); + } + error_propagate(errp, err); } void unix_start_outgoing_migration(MigrationState *s, @@ -174,8 +178,12 @@ static void socket_start_incoming_migration(SocketAddress *saddr, void tcp_start_incoming_migration(const char *host_port, Error **errp) { - SocketAddress *saddr = tcp_build_address(host_port, errp); - socket_start_incoming_migration(saddr, errp); + Error *err = NULL; + SocketAddress *saddr = tcp_build_address(host_port, &err); + if (!err) { + socket_start_incoming_migration(saddr, &err); + } + error_propagate(errp, err); } void unix_start_incoming_migration(const char *path, Error **errp) From 2ff30257974e19ebe2a97baad32ac29c06da5fb9 Mon Sep 17 00:00:00 2001 From: Ashijeet Acharya Date: Thu, 15 Sep 2016 21:50:28 +0530 Subject: [PATCH 690/723] migrate: move max-bandwidth and downtime-limit to migrate_set_parameter Mark the old commands 'migrate_set_speed' and 'migrate_set_downtime' as deprecated. Move max-bandwidth and downtime-limit into migrate-set-parameters for setting maximum migration speed and expected downtime limit parameters respectively. Change downtime units to milliseconds (only for new-command) and set its upper bound limit to 2000 seconds. Update the query part in both hmp and qmp qemu control interfaces. Signed-off-by: Ashijeet Acharya Reviewed-by: Eric Blake Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- docs/qmp-commands.txt | 13 ++++-- hmp.c | 27 ++++++++++++ include/migration/migration.h | 1 - migration/migration.c | 83 +++++++++++++++++++++-------------- qapi-schema.json | 23 ++++++++-- 5 files changed, 107 insertions(+), 40 deletions(-) diff --git a/docs/qmp-commands.txt b/docs/qmp-commands.txt index 7f652e01e5b..3220fb1075d 100644 --- a/docs/qmp-commands.txt +++ b/docs/qmp-commands.txt @@ -2910,7 +2910,9 @@ Set migration parameters throttled for auto-converge (json-int) - "cpu-throttle-increment": set throttle increasing percentage for auto-converge (json-int) - +- "max-bandwidth": set maximum speed for migrations (in bytes/sec) (json-int) +- "downtime-limit": set maximum tolerated downtime (in milliseconds) for + migrations (json-int) Arguments: Example: @@ -2931,7 +2933,10 @@ Query current migration parameters throttled (json-int) - "cpu-throttle-increment" : throttle increasing percentage for auto-converge (json-int) - + - "max-bandwidth" : maximium migration speed in bytes per second + (json-int) + - "downtime-limit" : maximum tolerated downtime of migration in + milliseconds (json-int) Arguments: Example: @@ -2943,7 +2948,9 @@ Example: "cpu-throttle-increment": 10, "compress-threads": 8, "compress-level": 1, - "cpu-throttle-initial": 20 + "cpu-throttle-initial": 20, + "max-bandwidth": 33554432, + "downtime-limit": 300 } } diff --git a/hmp.c b/hmp.c index 4c0f60049fe..80f7f1fefb1 100644 --- a/hmp.c +++ b/hmp.c @@ -310,6 +310,14 @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict) monitor_printf(mon, " %s: '%s'", MigrationParameter_lookup[MIGRATION_PARAMETER_TLS_HOSTNAME], params->has_tls_hostname ? params->tls_hostname : ""); + assert(params->has_max_bandwidth); + monitor_printf(mon, " %s: %" PRId64 " bytes/second", + MigrationParameter_lookup[MIGRATION_PARAMETER_MAX_BANDWIDTH], + params->max_bandwidth); + assert(params->has_downtime_limit); + monitor_printf(mon, " %s: %" PRId64 " milliseconds", + MigrationParameter_lookup[MIGRATION_PARAMETER_DOWNTIME_LIMIT], + params->downtime_limit); monitor_printf(mon, "\n"); } @@ -1265,6 +1273,7 @@ void hmp_migrate_incoming(Monitor *mon, const QDict *qdict) hmp_handle_error(mon, &err); } +/* Kept for backwards compatibility */ void hmp_migrate_set_downtime(Monitor *mon, const QDict *qdict) { double value = qdict_get_double(qdict, "value"); @@ -1283,6 +1292,7 @@ void hmp_migrate_set_cache_size(Monitor *mon, const QDict *qdict) } } +/* Kept for backwards compatibility */ void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict) { int64_t value = qdict_get_int(qdict, "value"); @@ -1323,7 +1333,9 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict) { const char *param = qdict_get_str(qdict, "parameter"); const char *valuestr = qdict_get_str(qdict, "value"); + int64_t valuebw = 0; long valueint = 0; + char *endp; Error *err = NULL; bool use_int_value = false; int i; @@ -1360,6 +1372,20 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict) p.has_tls_hostname = true; p.tls_hostname = (char *) valuestr; break; + case MIGRATION_PARAMETER_MAX_BANDWIDTH: + p.has_max_bandwidth = true; + valuebw = qemu_strtosz(valuestr, &endp); + if (valuebw < 0 || (size_t)valuebw != valuebw + || *endp != '\0') { + error_setg(&err, "Invalid size %s", valuestr); + goto cleanup; + } + p.max_bandwidth = valuebw; + break; + case MIGRATION_PARAMETER_DOWNTIME_LIMIT: + p.has_downtime_limit = true; + use_int_value = true; + break; } if (use_int_value) { @@ -1375,6 +1401,7 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict) p.decompress_threads = valueint; p.cpu_throttle_initial = valueint; p.cpu_throttle_increment = valueint; + p.downtime_limit = valueint; } qmp_migrate_set_parameters(&p, &err); diff --git a/include/migration/migration.h b/include/migration/migration.h index d4acc72b85d..2791b90c00b 100644 --- a/include/migration/migration.h +++ b/include/migration/migration.h @@ -129,7 +129,6 @@ struct MigrationSrcPageRequest { struct MigrationState { - int64_t bandwidth_limit; size_t bytes_xfer; size_t xfer_limit; QemuThread thread; diff --git a/migration/migration.c b/migration/migration.c index 04b706f69ec..4d417b76cf8 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -44,6 +44,10 @@ #define BUFFER_DELAY 100 #define XFER_LIMIT_RATIO (1000 / BUFFER_DELAY) +/* Time in milliseconds we are allowed to stop the source, + * for sending the last part */ +#define DEFAULT_MIGRATE_SET_DOWNTIME 300 + /* Default compression thread count */ #define DEFAULT_MIGRATE_COMPRESS_THREAD_COUNT 8 /* Default decompression thread count, usually decompression is at @@ -80,7 +84,6 @@ MigrationState *migrate_get_current(void) static bool once; static MigrationState current_migration = { .state = MIGRATION_STATUS_NONE, - .bandwidth_limit = MAX_THROTTLE, .xbzrle_cache_size = DEFAULT_MIGRATE_CACHE_SIZE, .mbps = -1, .parameters = { @@ -89,6 +92,8 @@ MigrationState *migrate_get_current(void) .decompress_threads = DEFAULT_MIGRATE_DECOMPRESS_THREAD_COUNT, .cpu_throttle_initial = DEFAULT_MIGRATE_CPU_THROTTLE_INITIAL, .cpu_throttle_increment = DEFAULT_MIGRATE_CPU_THROTTLE_INCREMENT, + .max_bandwidth = MAX_THROTTLE, + .downtime_limit = DEFAULT_MIGRATE_SET_DOWNTIME, }, }; @@ -517,17 +522,6 @@ void migrate_send_rp_pong(MigrationIncomingState *mis, migrate_send_rp_message(mis, MIG_RP_MSG_PONG, sizeof(buf), &buf); } -/* amount of nanoseconds we are willing to wait for migration to be down. - * the choice of nanoseconds is because it is the maximum resolution that - * get_clock() can achieve. It is an internal measure. All user-visible - * units must be in seconds */ -static uint64_t max_downtime = 300000000; - -uint64_t migrate_max_downtime(void) -{ - return max_downtime; -} - MigrationCapabilityStatusList *qmp_query_migrate_capabilities(Error **errp) { MigrationCapabilityStatusList *head = NULL; @@ -573,6 +567,10 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp) params->tls_creds = g_strdup(s->parameters.tls_creds); params->has_tls_hostname = !!s->parameters.tls_hostname; params->tls_hostname = g_strdup(s->parameters.tls_hostname); + params->has_max_bandwidth = true; + params->max_bandwidth = s->parameters.max_bandwidth; + params->has_downtime_limit = true; + params->downtime_limit = s->parameters.downtime_limit; return params; } @@ -806,6 +804,19 @@ void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp) "an integer in the range of 1 to 99"); return; } + if (params->has_max_bandwidth && + (params->max_bandwidth < 0 || params->max_bandwidth > SIZE_MAX)) { + error_setg(errp, "Parameter 'max_bandwidth' expects an integer in the" + " range of 0 to %zu bytes/second", SIZE_MAX); + return; + } + if (params->has_downtime_limit && + (params->downtime_limit < 0 || params->downtime_limit > 2000000)) { + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, + "downtime_limit", + "an integer in the range of 0 to 2000000 milliseconds"); + return; + } if (params->has_compress_level) { s->parameters.compress_level = params->compress_level; @@ -830,6 +841,16 @@ void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp) g_free(s->parameters.tls_hostname); s->parameters.tls_hostname = g_strdup(params->tls_hostname); } + if (params->has_max_bandwidth) { + s->parameters.max_bandwidth = params->max_bandwidth; + if (s->to_dst_file) { + qemu_file_set_rate_limit(s->to_dst_file, + s->parameters.max_bandwidth / XFER_LIMIT_RATIO); + } + } + if (params->has_downtime_limit) { + s->parameters.downtime_limit = params->downtime_limit; + } } @@ -1163,28 +1184,25 @@ int64_t qmp_query_migrate_cache_size(Error **errp) void qmp_migrate_set_speed(int64_t value, Error **errp) { - MigrationState *s; - - if (value < 0) { - value = 0; - } - if (value > SIZE_MAX) { - value = SIZE_MAX; - } + MigrationParameters p = { + .has_max_bandwidth = true, + .max_bandwidth = value, + }; - s = migrate_get_current(); - s->bandwidth_limit = value; - if (s->to_dst_file) { - qemu_file_set_rate_limit(s->to_dst_file, - s->bandwidth_limit / XFER_LIMIT_RATIO); - } + qmp_migrate_set_parameters(&p, errp); } void qmp_migrate_set_downtime(double value, Error **errp) { - value *= 1e9; - value = MAX(0, MIN(UINT64_MAX, value)); - max_downtime = (uint64_t)value; + value *= 1000; /* Convert to milliseconds */ + value = MAX(0, MIN(INT64_MAX, value)); + + MigrationParameters p = { + .has_downtime_limit = true, + .downtime_limit = value, + }; + + qmp_migrate_set_parameters(&p, errp); } bool migrate_postcopy_ram(void) @@ -1791,7 +1809,7 @@ static void *migration_thread(void *opaque) initial_bytes; uint64_t time_spent = current_time - initial_time; double bandwidth = (double)transferred_bytes / time_spent; - max_size = bandwidth * migrate_max_downtime() / 1000000; + max_size = bandwidth * s->parameters.downtime_limit; s->mbps = (((double) transferred_bytes * 8.0) / ((double) time_spent / 1000.0)) / 1000.0 / 1000.0; @@ -1850,13 +1868,12 @@ static void *migration_thread(void *opaque) void migrate_fd_connect(MigrationState *s) { - /* This is a best 1st approximation. ns to ms */ - s->expected_downtime = max_downtime/1000000; + s->expected_downtime = s->parameters.downtime_limit; s->cleanup_bh = qemu_bh_new(migrate_fd_cleanup, s); qemu_file_set_blocking(s->to_dst_file, true); qemu_file_set_rate_limit(s->to_dst_file, - s->bandwidth_limit / XFER_LIMIT_RATIO); + s->parameters.max_bandwidth / XFER_LIMIT_RATIO); /* Notify before starting migration thread */ notifier_list_notify(&migration_state_notifiers, s); diff --git a/qapi-schema.json b/qapi-schema.json index 58bed718375..ded1179f065 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -658,12 +658,19 @@ # hostname must be provided so that the server's x509 # certificate identity can be validated. (Since 2.7) # +# @max-bandwidth: to set maximum speed for migration. maximum speed in +# bytes per second. (Since 2.8) +# +# @downtime-limit: set maximum tolerated downtime for migration. maximum +# downtime in milliseconds (Since 2.8) +# # Since: 2.4 ## { 'enum': 'MigrationParameter', 'data': ['compress-level', 'compress-threads', 'decompress-threads', 'cpu-throttle-initial', 'cpu-throttle-increment', - 'tls-creds', 'tls-hostname'] } + 'tls-creds', 'tls-hostname', 'max-bandwidth', + 'downtime-limit'] } # # @migrate-set-parameters @@ -712,6 +719,12 @@ # hostname must be provided so that the server's x509 # certificate identity can be validated. (Since 2.7) # +# @max-bandwidth: to set maximum speed for migration. maximum speed in +# bytes per second. (Since 2.8) +# +# @downtime-limit: set maximum tolerated downtime for migration. maximum +# downtime in milliseconds (Since 2.8) +# # Since: 2.4 ## { 'struct': 'MigrationParameters', @@ -721,7 +734,9 @@ '*cpu-throttle-initial': 'int', '*cpu-throttle-increment': 'int', '*tls-creds': 'str', - '*tls-hostname': 'str'} } + '*tls-hostname': 'str', + '*max-bandwidth': 'int', + '*downtime-limit': 'int'} } ## # @query-migrate-parameters # @@ -1803,6 +1818,8 @@ # # Returns: nothing on success # +# Notes: This command is deprecated in favor of 'migrate-set-parameters' +# # Since: 0.14.0 ## { 'command': 'migrate_set_downtime', 'data': {'value': 'number'} } @@ -1816,7 +1833,7 @@ # # Returns: nothing on success # -# Notes: A value lesser than zero will be automatically round up to zero. +# Notes: This command is deprecated in favor of 'migrate-set-parameters' # # Since: 0.14.0 ## From 7c2b0f65cc2b6b14ad797549b8bde13aa97f6ba2 Mon Sep 17 00:00:00 2001 From: Cao jin Date: Thu, 8 Sep 2016 19:13:58 +0800 Subject: [PATCH 691/723] docs/xbzrle: correction 1. Default cache size is 64MB. 2. Semantics correction. Signed-off-by: Cao jin Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- docs/xbzrle.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/xbzrle.txt b/docs/xbzrle.txt index 52c8511a4c7..c0a7dfd44cd 100644 --- a/docs/xbzrle.txt +++ b/docs/xbzrle.txt @@ -42,7 +42,7 @@ nzrun = length byte... length = uleb128 encoded integer On the sender side XBZRLE is used as a compact delta encoding of page updates, -retrieving the old page content from the cache (default size of 512 MB). The +retrieving the old page content from the cache (default size of 64MB). The receiving side uses the existing page's content and XBZRLE to decode the new page's content. @@ -73,7 +73,7 @@ e9 07 0f 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 03 01 67 01 01 69 Cache update strategy ===================== -Keeping the hot pages in the cache is effective for decreased cache +Keeping the hot pages in the cache is effective for decreasing cache misses. XBZRLE uses a counter as the age of each page. The counter will increase after each ram dirty bitmap sync. When a cache conflict is detected, XBZRLE will only evict pages in the cache that are older than From 44a3dd9b8718a7f0a94053c57782886748a43d7a Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 6 Oct 2016 16:50:48 +0200 Subject: [PATCH 692/723] tests: minor cleanups in usb-hcd-uhci-test Two minor cleanups: - exit gracefully in case on unsupported target, - put machine command line in a constant to avoid to duplicate it. Signed-off-by: Laurent Vivier Reviewed-by: Gerd Hoffmann Signed-off-by: David Gibson --- tests/usb-hcd-uhci-test.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/tests/usb-hcd-uhci-test.c b/tests/usb-hcd-uhci-test.c index 4b951ce4922..e956b9ccb7a 100644 --- a/tests/usb-hcd-uhci-test.c +++ b/tests/usb-hcd-uhci-test.c @@ -77,6 +77,9 @@ static void test_usb_storage_hotplug(void) int main(int argc, char **argv) { const char *arch = qtest_get_arch(); + const char *cmd = "-device piix3-usb-uhci,id=uhci,addr=1d.0" + " -drive id=drive0,if=none,file=/dev/null,format=raw" + " -device usb-tablet,bus=uhci.0,port=1"; int ret; g_test_init(&argc, &argv, NULL); @@ -87,13 +90,13 @@ int main(int argc, char **argv) qtest_add_func("/uhci/pci/hotplug/usb-storage", test_usb_storage_hotplug); if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { - qs = qtest_pc_boot("-device piix3-usb-uhci,id=uhci,addr=1d.0" - " -drive id=drive0,if=none,file=/dev/null,format=raw" - " -device usb-tablet,bus=uhci.0,port=1"); + qs = qtest_pc_boot(cmd); } else if (strcmp(arch, "ppc64") == 0) { - qs = qtest_spapr_boot("-device piix3-usb-uhci,id=uhci,addr=1d.0" - " -drive id=drive0,if=none,file=/dev/null,format=raw" - " -device usb-tablet,bus=uhci.0,port=1"); + qs = qtest_spapr_boot(cmd); + } else { + g_printerr("usb-hcd-uhci-test tests are only " + "available on x86 or ppc64\n"); + exit(EXIT_FAILURE); } ret = g_test_run(); qtest_shutdown(qs); From 54ce6f22e86977b6e94692d90e13fce6fc9aa641 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Fri, 7 Oct 2016 12:14:27 +0200 Subject: [PATCH 693/723] qtest: ask endianness of the target in qtest_init() The target endianness is not deduced anymore from the architecture name but asked directly to the guest, using a new qtest command: "endianness". As it can't change (this is the value of TARGET_WORDS_BIGENDIAN), we store it to not have to ask every time we want to know if we have to byte-swap a value. Signed-off-by: Laurent Vivier CC: Greg Kurz CC: David Gibson CC: Peter Maydell Signed-off-by: David Gibson --- qtest.c | 7 ++++ tests/libqos/virtio-pci.c | 2 +- tests/libqtest.c | 68 +++++++++++++-------------------------- tests/libqtest.h | 16 +++++++-- tests/virtio-blk-test.c | 2 +- 5 files changed, 45 insertions(+), 50 deletions(-) diff --git a/qtest.c b/qtest.c index 22482cc3592..b53b39c9d75 100644 --- a/qtest.c +++ b/qtest.c @@ -537,6 +537,13 @@ static void qtest_process_command(CharDriverState *chr, gchar **words) qtest_send_prefix(chr); qtest_send(chr, "OK\n"); + } else if (strcmp(words[0], "endianness") == 0) { + qtest_send_prefix(chr); +#if defined(TARGET_WORDS_BIGENDIAN) + qtest_sendf(chr, "OK big\n"); +#else + qtest_sendf(chr, "OK little\n"); +#endif #ifdef TARGET_PPC64 } else if (strcmp(words[0], "rtas") == 0) { uint64_t res, args, ret; diff --git a/tests/libqos/virtio-pci.c b/tests/libqos/virtio-pci.c index 18b92b95dc3..6e005c18350 100644 --- a/tests/libqos/virtio-pci.c +++ b/tests/libqos/virtio-pci.c @@ -86,7 +86,7 @@ static uint64_t qvirtio_pci_config_readq(QVirtioDevice *d, uint64_t addr) int i; uint64_t u64 = 0; - if (qtest_big_endian()) { + if (target_big_endian()) { for (i = 0; i < 8; ++i) { u64 |= (uint64_t)qpci_io_readb(dev->pdev, (void *)(uintptr_t)addr + i) << (7 - i) * 8; diff --git a/tests/libqtest.c b/tests/libqtest.c index 6f6bdf142fb..d4e6bff121e 100644 --- a/tests/libqtest.c +++ b/tests/libqtest.c @@ -37,6 +37,7 @@ struct QTestState bool irq_level[MAX_IRQ]; GString *rx; pid_t qemu_pid; /* our child QEMU process */ + bool big_endian; }; static GHookList abrt_hooks; @@ -47,6 +48,8 @@ static struct sigaction sigact_old; g_assert_cmpint(ret, !=, -1); \ } while (0) +static int qtest_query_target_endianness(QTestState *s); + static int init_socket(const char *socket_path) { struct sockaddr_un addr; @@ -209,6 +212,10 @@ QTestState *qtest_init(const char *extra_args) kill(s->qemu_pid, SIGSTOP); } + /* ask endianness of the target */ + + s->big_endian = qtest_query_target_endianness(s); + return s; } @@ -342,6 +349,20 @@ static gchar **qtest_rsp(QTestState *s, int expected_args) return words; } +static int qtest_query_target_endianness(QTestState *s) +{ + gchar **args; + int big_endian; + + qtest_sendf(s, "endianness\n"); + args = qtest_rsp(s, 1); + g_assert(strcmp(args[1], "big") == 0 || strcmp(args[1], "little") == 0); + big_endian = strcmp(args[1], "big") == 0; + g_strfreev(args); + + return big_endian; +} + typedef struct { JSONMessageParser parser; QDict *response; @@ -886,50 +907,7 @@ char *hmp(const char *fmt, ...) return ret; } -bool qtest_big_endian(void) +bool qtest_big_endian(QTestState *s) { - const char *arch = qtest_get_arch(); - int i; - - static const struct { - const char *arch; - bool big_endian; - } endianness[] = { - { "aarch64", false }, - { "alpha", false }, - { "arm", false }, - { "cris", false }, - { "i386", false }, - { "lm32", true }, - { "m68k", true }, - { "microblaze", true }, - { "microblazeel", false }, - { "mips", true }, - { "mips64", true }, - { "mips64el", false }, - { "mipsel", false }, - { "moxie", true }, - { "or32", true }, - { "ppc", true }, - { "ppc64", true }, - { "ppcemb", true }, - { "s390x", true }, - { "sh4", false }, - { "sh4eb", true }, - { "sparc", true }, - { "sparc64", true }, - { "unicore32", false }, - { "x86_64", false }, - { "xtensa", false }, - { "xtensaeb", true }, - {}, - }; - - for (i = 0; endianness[i].arch; i++) { - if (strcmp(endianness[i].arch, arch) == 0) { - return endianness[i].big_endian; - } - } - - return false; + return s->big_endian; } diff --git a/tests/libqtest.h b/tests/libqtest.h index f7402e0cc12..4be1f77877d 100644 --- a/tests/libqtest.h +++ b/tests/libqtest.h @@ -409,6 +409,14 @@ int64_t qtest_clock_step(QTestState *s, int64_t step); */ int64_t qtest_clock_set(QTestState *s, int64_t val); +/** + * qtest_big_endian: + * @s: QTestState instance to operate on. + * + * Returns: True if the architecture under test has a big endian configuration. + */ +bool qtest_big_endian(QTestState *s); + /** * qtest_get_arch: * @@ -874,12 +882,14 @@ static inline int64_t clock_set(int64_t val) } /** - * qtest_big_endian: + * target_big_endian: * * Returns: True if the architecture under test has a big endian configuration. */ -bool qtest_big_endian(void); - +static inline bool target_big_endian(void) +{ + return qtest_big_endian(global_qtest); +} QDict *qmp_fd_receive(int fd); void qmp_fd_sendv(int fd, const char *fmt, va_list ap); diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c index 3c4fecc1f02..05069173413 100644 --- a/tests/virtio-blk-test.c +++ b/tests/virtio-blk-test.c @@ -125,7 +125,7 @@ static inline void virtio_blk_fix_request(QVirtioBlkReq *req) bool host_endian = false; #endif - if (qtest_big_endian() != host_endian) { + if (target_big_endian() != host_endian) { req->type = bswap32(req->type); req->ioprio = bswap32(req->ioprio); req->sector = bswap64(req->sector); From 1ef2ef96296f061c89b60e77c3c50577fd6fe415 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 11 Oct 2016 17:19:35 +0200 Subject: [PATCH 694/723] tests/boot-sector: Use minimum length for the Forth boot script The pxe-test is quite slow on ppc64 with tcg. We can speed it up a little bit by decreasing the size of the file that has to be loaded via TFTP. Signed-off-by: Thomas Huth Reviewed-by: Eric Blake Reviewed-by: Michael S. Tsirkin Signed-off-by: David Gibson --- tests/boot-sector.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/boot-sector.c b/tests/boot-sector.c index e3193c0a128..0168fd02479 100644 --- a/tests/boot-sector.c +++ b/tests/boot-sector.c @@ -72,6 +72,7 @@ static uint8_t boot_sector[0x7e000] = { int boot_sector_init(const char *fname) { FILE *f = fopen(fname, "w"); + size_t len = sizeof boot_sector; if (!f) { fprintf(stderr, "Couldn't open \"%s\": %s", fname, strerror(errno)); @@ -80,13 +81,12 @@ int boot_sector_init(const char *fname) /* For Open Firmware based system, we can use a Forth script instead */ if (strcmp(qtest_get_arch(), "ppc64") == 0) { - memset(boot_sector, ' ', sizeof boot_sector); - sprintf((char *)boot_sector, "\\ Bootscript\n%x %x c! %x %x c!\n", + len = sprintf((char *)boot_sector, "\\ Bootscript\n%x %x c! %x %x c!\n", LOW(SIGNATURE), BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET, HIGH(SIGNATURE), BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET + 1); } - fwrite(boot_sector, 1, sizeof boot_sector, f); + fwrite(boot_sector, 1, len, f); fclose(f); return 0; } From 3e353773721596971db2d0abc7015e7ea3d3af07 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 11 Oct 2016 17:19:36 +0200 Subject: [PATCH 695/723] tests/boot-sector: Use mkstemp() to create a unique file name The pxe-test is run for three different targets now (x86_64, i386 and ppc64), and the bios-tables-test is run for two targets (x86_64 and i386). But each of the tests is using an invariant name for the disk image with the boot sector code - so if the tests are running in parallel, there is a race condition that they destroy the disk image of a parallel test program. Let's use mkstemp() to create unique temporary files here instead - and since mkstemp() is returning an integer file descriptor instead of a FILE pointer, we also switch the fwrite() and fclose() to write() and close() instead. Reported-by: Sascha Silbe Signed-off-by: Thomas Huth Reviewed-by: Michael S. Tsirkin Signed-off-by: David Gibson --- tests/bios-tables-test.c | 2 +- tests/boot-sector.c | 17 ++++++++++++----- tests/boot-sector.h | 4 ++-- tests/pxe-test.c | 2 +- 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c index 6ea2b6d00a7..812f8305397 100644 --- a/tests/bios-tables-test.c +++ b/tests/bios-tables-test.c @@ -112,7 +112,7 @@ typedef struct { g_assert_cmpstr(ACPI_ASSERT_CMP_str, ==, expected); \ } while (0) -static const char *disk = "tests/acpi-test-disk.raw"; +static char disk[] = "tests/acpi-test-disk-XXXXXX"; static const char *data_dir = "tests/acpi-test-data"; #ifdef CONFIG_IASL static const char *iasl = stringify(CONFIG_IASL); diff --git a/tests/boot-sector.c b/tests/boot-sector.c index 0168fd02479..83993143a61 100644 --- a/tests/boot-sector.c +++ b/tests/boot-sector.c @@ -69,12 +69,13 @@ static uint8_t boot_sector[0x7e000] = { }; /* Create boot disk file. */ -int boot_sector_init(const char *fname) +int boot_sector_init(char *fname) { - FILE *f = fopen(fname, "w"); + int fd, ret; size_t len = sizeof boot_sector; - if (!f) { + fd = mkstemp(fname); + if (fd < 0) { fprintf(stderr, "Couldn't open \"%s\": %s", fname, strerror(errno)); return 1; } @@ -86,8 +87,14 @@ int boot_sector_init(const char *fname) HIGH(SIGNATURE), BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET + 1); } - fwrite(boot_sector, 1, len, f); - fclose(f); + ret = write(fd, boot_sector, len); + close(fd); + + if (ret != len) { + fprintf(stderr, "Could not write \"%s\"", fname); + return 1; + } + return 0; } diff --git a/tests/boot-sector.h b/tests/boot-sector.h index f64b477aa33..35d61c7e2bd 100644 --- a/tests/boot-sector.h +++ b/tests/boot-sector.h @@ -14,8 +14,8 @@ #ifndef TEST_BOOT_SECTOR_H #define TEST_BOOT_SECTOR_H -/* Create boot disk file. */ -int boot_sector_init(const char *fname); +/* Create boot disk file. fname must be a suitable string for mkstemp() */ +int boot_sector_init(char *fname); /* Loop until signature in memory is OK. */ void boot_sector_test(void); diff --git a/tests/pxe-test.c b/tests/pxe-test.c index 5d3ddbe5e95..34282d3704d 100644 --- a/tests/pxe-test.c +++ b/tests/pxe-test.c @@ -19,7 +19,7 @@ #define NETNAME "net0" -static const char *disk = "tests/pxe-test-disk.raw"; +static char disk[] = "tests/pxe-test-disk-XXXXXX"; static void test_pxe_one(const char *params, bool ipv6) { From 74cba2b3b23d069d1a3d9b3ef7876123d939d3ba Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 11 Oct 2016 17:19:37 +0200 Subject: [PATCH 696/723] tests/boot-sector: Increase time-out to 90 seconds Since the PXE tester runs rather slow on ppc64 with tcg, there is a chance that we hit the 60 seconds timeout on machines that have a heavy CPU load. So let's increase the timeout to ease the situation. Signed-off-by: Thomas Huth Reviewed-by: Michael S. Tsirkin Signed-off-by: David Gibson --- tests/boot-sector.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/boot-sector.c b/tests/boot-sector.c index 83993143a61..e3880f4455a 100644 --- a/tests/boot-sector.c +++ b/tests/boot-sector.c @@ -106,9 +106,9 @@ void boot_sector_test(void) uint16_t signature; int i; - /* Wait at most 1 minute */ + /* Wait at most 90 seconds */ #define TEST_DELAY (1 * G_USEC_PER_SEC / 10) -#define TEST_CYCLES MAX((60 * G_USEC_PER_SEC / TEST_DELAY), 1) +#define TEST_CYCLES MAX((90 * G_USEC_PER_SEC / TEST_DELAY), 1) /* Poll until code has run and modified memory. Once it has we know BIOS * initialization is done. TODO: check that IP reached the halt From 125a9b2327173f4cd38509276ea74f2133934820 Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Wed, 12 Oct 2016 10:38:51 +0530 Subject: [PATCH 697/723] target-ppc: implement vexts[bh]2w and vexts[bhw]2d Vector Extend Sign Instructions: vextsb2w: Vector Extend Sign Byte To Word vextsh2w: Vector Extend Sign Halfword To Word vextsb2d: Vector Extend Sign Byte To Doubleword vextsh2d: Vector Extend Sign Halfword To Doubleword vextsw2d: Vector Extend Sign Word To Doubleword Signed-off-by: Nikunj A Dadhania Signed-off-by: David Gibson --- target-ppc/helper.h | 5 +++++ target-ppc/int_helper.c | 15 +++++++++++++++ target-ppc/translate/vmx-impl.inc.c | 5 +++++ target-ppc/translate/vmx-ops.inc.c | 5 +++++ 4 files changed, 30 insertions(+) diff --git a/target-ppc/helper.h b/target-ppc/helper.h index 796ad455f8b..04c64217b7f 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -267,6 +267,11 @@ DEF_HELPER_3(vinsertb, void, avr, avr, i32) DEF_HELPER_3(vinserth, void, avr, avr, i32) DEF_HELPER_3(vinsertw, void, avr, avr, i32) DEF_HELPER_3(vinsertd, void, avr, avr, i32) +DEF_HELPER_2(vextsb2w, void, avr, avr) +DEF_HELPER_2(vextsh2w, void, avr, avr) +DEF_HELPER_2(vextsb2d, void, avr, avr) +DEF_HELPER_2(vextsh2d, void, avr, avr) +DEF_HELPER_2(vextsw2d, void, avr, avr) DEF_HELPER_2(vupkhpx, void, avr, avr) DEF_HELPER_2(vupklpx, void, avr, avr) DEF_HELPER_2(vupkhsb, void, avr, avr) diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c index 202854fabdb..5aee0a81c70 100644 --- a/target-ppc/int_helper.c +++ b/target-ppc/int_helper.c @@ -1934,6 +1934,21 @@ VEXTRACT(uw, u32) VEXTRACT(d, u64) #undef VEXTRACT +#define VEXT_SIGNED(name, element, mask, cast, recast) \ +void helper_##name(ppc_avr_t *r, ppc_avr_t *b) \ +{ \ + int i; \ + VECTOR_FOR_INORDER_I(i, element) { \ + r->element[i] = (recast)((cast)(b->element[i] & mask)); \ + } \ +} +VEXT_SIGNED(vextsb2w, s32, UINT8_MAX, int8_t, int32_t) +VEXT_SIGNED(vextsb2d, s64, UINT8_MAX, int8_t, int64_t) +VEXT_SIGNED(vextsh2w, s32, UINT16_MAX, int16_t, int32_t) +VEXT_SIGNED(vextsh2d, s64, UINT16_MAX, int16_t, int64_t) +VEXT_SIGNED(vextsw2d, s64, UINT32_MAX, int32_t, int64_t) +#undef VEXT_SIGNED + #define VSPLTI(suffix, element, splat_type) \ void helper_vspltis##suffix(ppc_avr_t *r, uint32_t splat) \ { \ diff --git a/target-ppc/translate/vmx-impl.inc.c b/target-ppc/translate/vmx-impl.inc.c index 25cd0735acc..c8998f3eab3 100644 --- a/target-ppc/translate/vmx-impl.inc.c +++ b/target-ppc/translate/vmx-impl.inc.c @@ -815,6 +815,11 @@ GEN_VXFORM_NOA(vclzb, 1, 28) GEN_VXFORM_NOA(vclzh, 1, 29) GEN_VXFORM_NOA(vclzw, 1, 30) GEN_VXFORM_NOA(vclzd, 1, 31) +GEN_VXFORM_NOA_2(vextsb2w, 1, 24, 16) +GEN_VXFORM_NOA_2(vextsh2w, 1, 24, 17) +GEN_VXFORM_NOA_2(vextsb2d, 1, 24, 24) +GEN_VXFORM_NOA_2(vextsh2d, 1, 24, 25) +GEN_VXFORM_NOA_2(vextsw2d, 1, 24, 26) GEN_VXFORM_NOA_2(vctzb, 1, 24, 28) GEN_VXFORM_NOA_2(vctzh, 1, 24, 29) GEN_VXFORM_NOA_2(vctzw, 1, 24, 30) diff --git a/target-ppc/translate/vmx-ops.inc.c b/target-ppc/translate/vmx-ops.inc.c index ac1dc9b2b22..68cba3e4745 100644 --- a/target-ppc/translate/vmx-ops.inc.c +++ b/target-ppc/translate/vmx-ops.inc.c @@ -215,6 +215,11 @@ GEN_VXFORM_DUAL_INV(vspltish, vinserth, 6, 13, 0x00000000, 0x100000, GEN_VXFORM_DUAL_INV(vspltisw, vinsertw, 6, 14, 0x00000000, 0x100000, PPC_ALTIVEC), GEN_VXFORM_300_EXT(vinsertd, 6, 15, 0x100000), +GEN_VXFORM_300_EO(vextsb2w, 0x01, 0x18, 0x10), +GEN_VXFORM_300_EO(vextsh2w, 0x01, 0x18, 0x11), +GEN_VXFORM_300_EO(vextsb2d, 0x01, 0x18, 0x18), +GEN_VXFORM_300_EO(vextsh2d, 0x01, 0x18, 0x19), +GEN_VXFORM_300_EO(vextsw2d, 0x01, 0x18, 0x1A), GEN_VXFORM_300_EO(vctzb, 0x01, 0x18, 0x1C), GEN_VXFORM_300_EO(vctzh, 0x01, 0x18, 0x1D), GEN_VXFORM_300_EO(vctzw, 0x01, 0x18, 0x1E), From 672de881e9367f6d1787901c016c6e836d712f21 Mon Sep 17 00:00:00 2001 From: Michael Roth Date: Wed, 12 Oct 2016 18:13:53 -0500 Subject: [PATCH 698/723] spapr: fix inheritance chain for default machine options Rather than machine instances having backward-compatible option defaults that need to be repeatedly re-enabled for every new machine type we introduce, we set the defaults appropriate for newer machine types, then add code to explicitly disable instance options as needed to maintain compatibility with older machine types. Currently pseries-2.5 does not inherit from pseries-2.6 in this fashion, which is okay at the moment since we do not have any instance compatibility options for pseries-2.6+ currently. We will make use of this in future patches though, so fix it here. Signed-off-by: Michael Roth [dwg: Extended to make 2.7 inherit from 2.8 as well] Signed-off-by: David Gibson --- hw/ppc/spapr.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 03e38039e87..fc4c3c98c8e 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -2475,6 +2475,7 @@ DEFINE_SPAPR_MACHINE(2_8, "2.8", true); static void spapr_machine_2_7_instance_options(MachineState *machine) { + spapr_machine_2_8_instance_options(machine); } static void spapr_machine_2_7_class_options(MachineClass *mc) @@ -2501,6 +2502,7 @@ DEFINE_SPAPR_MACHINE(2_7, "2.7", false); static void spapr_machine_2_6_instance_options(MachineState *machine) { + spapr_machine_2_7_instance_options(machine); } static void spapr_machine_2_6_class_options(MachineClass *mc) @@ -2525,6 +2527,7 @@ DEFINE_SPAPR_MACHINE(2_6, "2.6", false); static void spapr_machine_2_5_instance_options(MachineState *machine) { + spapr_machine_2_6_instance_options(machine); } static void spapr_machine_2_5_class_options(MachineClass *mc) From cc706a530518f867c29177a5a337bb08503e617e Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 3 Oct 2016 09:24:46 +0200 Subject: [PATCH 699/723] ppc/xics: Make the ICSState a list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of an array of fixed sized blocks, use a list, as we will need to have sources with variable number of interrupts. SPAPR only uses a single entry. Native will create more. If performance becomes an issue we can add some hashed lookup but for now this will do fine. Signed-off-by: Benjamin Herrenschmidt [ move the initialization of list to xics_common_initfn, restore xirr_owner after migration and move restoring to icp_post_load] Signed-off-by: Nikunj A Dadhania [ clg: removed the icp_post_load() changes from nikunj patchset v3: http://patchwork.ozlabs.org/patch/646008/ ] Signed-off-by: Cédric Le Goater Signed-off-by: David Gibson --- hw/intc/trace-events | 5 ++- hw/intc/xics.c | 83 +++++++++++++++++++++++----------------- hw/intc/xics_kvm.c | 27 +++++++++---- hw/intc/xics_spapr.c | 88 ++++++++++++++++++++++++++++--------------- hw/ppc/spapr_events.c | 2 +- hw/ppc/spapr_pci.c | 5 +-- hw/ppc/spapr_vio.c | 2 +- include/hw/ppc/xics.h | 13 ++++--- 8 files changed, 139 insertions(+), 86 deletions(-) diff --git a/hw/intc/trace-events b/hw/intc/trace-events index f12192c082b..aa342a86fa6 100644 --- a/hw/intc/trace-events +++ b/hw/intc/trace-events @@ -56,10 +56,11 @@ xics_set_irq_lsi(int srcno, int nr) "set_irq_lsi: srcno %d [irq %#x]" xics_ics_write_xive(int nr, int srcno, int server, uint8_t priority) "ics_write_xive: irq %#x [src %d] server %#x prio %#x" xics_ics_reject(int nr, int srcno) "reject irq %#x [src %d]" xics_ics_eoi(int nr) "ics_eoi: irq %#x" -xics_alloc(int src, int irq) "source#%d, irq %d" -xics_alloc_block(int src, int first, int num, bool lsi, int align) "source#%d, first irq %d, %d irqs, lsi=%d, alignnum %d" +xics_alloc(int irq) "irq %d" +xics_alloc_block(int first, int num, bool lsi, int align) "first irq %d, %d irqs, lsi=%d, alignnum %d" xics_ics_free(int src, int irq, int num) "Source#%d, first irq %d, %d irqs" xics_ics_free_warn(int src, int irq) "Source#%d, irq %d is already free" +xics_icp_post_load(uint32_t server_no, uint32_t xirr, uint64_t addr, uint8_t pend) "server_no %d, xirr %#x, xirr_owner 0x%" PRIx64 ", pending %d" # hw/intc/s390_flic_kvm.c flic_create_device(int err) "flic: create device failed %d" diff --git a/hw/intc/xics.c b/hw/intc/xics.c index 69162f0328f..433af93254f 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -96,13 +96,16 @@ void xics_cpu_setup(XICSState *xics, PowerPCCPU *cpu) static void xics_common_reset(DeviceState *d) { XICSState *xics = XICS_COMMON(d); + ICSState *ics; int i; for (i = 0; i < xics->nr_servers; i++) { device_reset(DEVICE(&xics->ss[i])); } - device_reset(DEVICE(xics->ics)); + QLIST_FOREACH(ics, &xics->ics, list) { + device_reset(DEVICE(ics)); + } } static void xics_prop_get_nr_irqs(Object *obj, Visitor *v, const char *name, @@ -134,7 +137,6 @@ static void xics_prop_set_nr_irqs(Object *obj, Visitor *v, const char *name, } assert(info->set_nr_irqs); - assert(xics->ics); info->set_nr_irqs(xics, value, errp); } @@ -174,6 +176,9 @@ static void xics_prop_set_nr_servers(Object *obj, Visitor *v, static void xics_common_initfn(Object *obj) { + XICSState *xics = XICS_COMMON(obj); + + QLIST_INIT(&xics->ics); object_property_add(obj, "nr_irqs", "int", xics_prop_get_nr_irqs, xics_prop_set_nr_irqs, NULL, NULL, NULL); @@ -212,33 +217,35 @@ static void ics_reject(ICSState *ics, int nr); static void ics_resend(ICSState *ics); static void ics_eoi(ICSState *ics, int nr); -static void icp_check_ipi(XICSState *xics, int server) +static void icp_check_ipi(ICPState *ss) { - ICPState *ss = xics->ss + server; - if (XISR(ss) && (ss->pending_priority <= ss->mfrr)) { return; } - trace_xics_icp_check_ipi(server, ss->mfrr); + trace_xics_icp_check_ipi(ss->cs->cpu_index, ss->mfrr); - if (XISR(ss)) { - ics_reject(xics->ics, XISR(ss)); + if (XISR(ss) && ss->xirr_owner) { + ics_reject(ss->xirr_owner, XISR(ss)); } ss->xirr = (ss->xirr & ~XISR_MASK) | XICS_IPI; ss->pending_priority = ss->mfrr; + ss->xirr_owner = NULL; qemu_irq_raise(ss->output); } static void icp_resend(XICSState *xics, int server) { ICPState *ss = xics->ss + server; + ICSState *ics; if (ss->mfrr < CPPR(ss)) { - icp_check_ipi(xics, server); + icp_check_ipi(ss); + } + QLIST_FOREACH(ics, &xics->ics, list) { + ics_resend(ics); } - ics_resend(xics->ics); } void icp_set_cppr(XICSState *xics, int server, uint8_t cppr) @@ -256,7 +263,10 @@ void icp_set_cppr(XICSState *xics, int server, uint8_t cppr) ss->xirr &= ~XISR_MASK; /* Clear XISR */ ss->pending_priority = 0xff; qemu_irq_lower(ss->output); - ics_reject(xics->ics, old_xisr); + if (ss->xirr_owner) { + ics_reject(ss->xirr_owner, old_xisr); + ss->xirr_owner = NULL; + } } } else { if (!XISR(ss)) { @@ -271,7 +281,7 @@ void icp_set_mfrr(XICSState *xics, int server, uint8_t mfrr) ss->mfrr = mfrr; if (mfrr < CPPR(ss)) { - icp_check_ipi(xics, server); + icp_check_ipi(ss); } } @@ -282,6 +292,7 @@ uint32_t icp_accept(ICPState *ss) qemu_irq_lower(ss->output); ss->xirr = ss->pending_priority << 24; ss->pending_priority = 0xff; + ss->xirr_owner = NULL; trace_xics_icp_accept(xirr, ss->xirr); @@ -299,30 +310,40 @@ uint32_t icp_ipoll(ICPState *ss, uint32_t *mfrr) void icp_eoi(XICSState *xics, int server, uint32_t xirr) { ICPState *ss = xics->ss + server; + ICSState *ics; + uint32_t irq; /* Send EOI -> ICS */ ss->xirr = (ss->xirr & ~CPPR_MASK) | (xirr & CPPR_MASK); trace_xics_icp_eoi(server, xirr, ss->xirr); - ics_eoi(xics->ics, xirr & XISR_MASK); + irq = xirr & XISR_MASK; + QLIST_FOREACH(ics, &xics->ics, list) { + if (ics_valid_irq(ics, irq)) { + ics_eoi(ics, irq); + } + } if (!XISR(ss)) { icp_resend(xics, server); } } -static void icp_irq(XICSState *xics, int server, int nr, uint8_t priority) +static void icp_irq(ICSState *ics, int server, int nr, uint8_t priority) { + XICSState *xics = ics->xics; ICPState *ss = xics->ss + server; trace_xics_icp_irq(server, nr, priority); if ((priority >= CPPR(ss)) || (XISR(ss) && (ss->pending_priority <= priority))) { - ics_reject(xics->ics, nr); + ics_reject(ics, nr); } else { - if (XISR(ss)) { - ics_reject(xics->ics, XISR(ss)); + if (XISR(ss) && ss->xirr_owner) { + ics_reject(ss->xirr_owner, XISR(ss)); + ss->xirr_owner = NULL; } ss->xirr = (ss->xirr & ~XISR_MASK) | (nr & XISR_MASK); + ss->xirr_owner = ics; ss->pending_priority = priority; trace_xics_icp_raise(ss->xirr, ss->pending_priority); qemu_irq_raise(ss->output); @@ -405,8 +426,7 @@ static void resend_msi(ICSState *ics, int srcno) if (irq->status & XICS_STATUS_REJECTED) { irq->status &= ~XICS_STATUS_REJECTED; if (irq->priority != 0xff) { - icp_irq(ics->xics, irq->server, srcno + ics->offset, - irq->priority); + icp_irq(ics, irq->server, srcno + ics->offset, irq->priority); } } } @@ -419,7 +439,7 @@ static void resend_lsi(ICSState *ics, int srcno) && (irq->status & XICS_STATUS_ASSERTED) && !(irq->status & XICS_STATUS_SENT)) { irq->status |= XICS_STATUS_SENT; - icp_irq(ics->xics, irq->server, srcno + ics->offset, irq->priority); + icp_irq(ics, irq->server, srcno + ics->offset, irq->priority); } } @@ -434,7 +454,7 @@ static void set_irq_msi(ICSState *ics, int srcno, int val) irq->status |= XICS_STATUS_MASKED_PENDING; trace_xics_masked_pending(); } else { - icp_irq(ics->xics, irq->server, srcno + ics->offset, irq->priority); + icp_irq(ics, irq->server, srcno + ics->offset, irq->priority); } } } @@ -473,7 +493,7 @@ static void write_xive_msi(ICSState *ics, int srcno) } irq->status &= ~XICS_STATUS_MASKED_PENDING; - icp_irq(ics->xics, irq->server, srcno + ics->offset, irq->priority); + icp_irq(ics, irq->server, srcno + ics->offset, irq->priority); } static void write_xive_lsi(ICSState *ics, int srcno) @@ -662,28 +682,23 @@ static const TypeInfo ics_info = { /* * Exported functions */ -int xics_find_source(XICSState *xics, int irq) +ICSState *xics_find_source(XICSState *xics, int irq) { - int sources = 1; - int src; + ICSState *ics; - /* FIXME: implement multiple sources */ - for (src = 0; src < sources; ++src) { - ICSState *ics = &xics->ics[src]; + QLIST_FOREACH(ics, &xics->ics, list) { if (ics_valid_irq(ics, irq)) { - return src; + return ics; } } - - return -1; + return NULL; } qemu_irq xics_get_qirq(XICSState *xics, int irq) { - int src = xics_find_source(xics, irq); + ICSState *ics = xics_find_source(xics, irq); - if (src >= 0) { - ICSState *ics = &xics->ics[src]; + if (ics) { return ics->qirqs[irq - ics->offset]; } diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c index c9caefcf2b0..843905cfbd3 100644 --- a/hw/intc/xics_kvm.c +++ b/hw/intc/xics_kvm.c @@ -361,7 +361,13 @@ static void xics_kvm_cpu_setup(XICSState *xics, PowerPCCPU *cpu) static void xics_kvm_set_nr_irqs(XICSState *xics, uint32_t nr_irqs, Error **errp) { - xics->nr_irqs = xics->ics->nr_irqs = nr_irqs; + ICSState *ics = QLIST_FIRST(&xics->ics); + + /* This needs to be deprecated ... */ + xics->nr_irqs = nr_irqs; + if (ics) { + ics->nr_irqs = nr_irqs; + } } static void xics_kvm_set_nr_servers(XICSState *xics, uint32_t nr_servers, @@ -394,6 +400,7 @@ static void xics_kvm_realize(DeviceState *dev, Error **errp) { KVMXICSState *xicskvm = XICS_SPAPR_KVM(dev); XICSState *xics = XICS_COMMON(dev); + ICSState *ics; int i, rc; Error *error = NULL; struct kvm_create_device xics_create_device = { @@ -445,10 +452,12 @@ static void xics_kvm_realize(DeviceState *dev, Error **errp) xicskvm->kernel_xics_fd = xics_create_device.fd; - object_property_set_bool(OBJECT(xics->ics), true, "realized", &error); - if (error) { - error_propagate(errp, error); - goto fail; + QLIST_FOREACH(ics, &xics->ics, list) { + object_property_set_bool(OBJECT(ics), true, "realized", &error); + if (error) { + error_propagate(errp, error); + goto fail; + } } assert(xics->nr_servers); @@ -477,10 +486,12 @@ static void xics_kvm_realize(DeviceState *dev, Error **errp) static void xics_kvm_initfn(Object *obj) { XICSState *xics = XICS_COMMON(obj); + ICSState *ics; - xics->ics = ICS(object_new(TYPE_KVM_ICS)); - object_property_add_child(obj, "ics", OBJECT(xics->ics), NULL); - xics->ics->xics = xics; + ics = ICS(object_new(TYPE_KVM_ICS)); + object_property_add_child(obj, "ics", OBJECT(ics), NULL); + ics->xics = xics; + QLIST_INSERT_HEAD(&xics->ics, ics, list); } static void xics_kvm_class_init(ObjectClass *oc, void *data) diff --git a/hw/intc/xics_spapr.c b/hw/intc/xics_spapr.c index 618826dacf0..0b0845d6280 100644 --- a/hw/intc/xics_spapr.c +++ b/hw/intc/xics_spapr.c @@ -113,13 +113,17 @@ static void rtas_set_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) { - ICSState *ics = spapr->xics->ics; + ICSState *ics = QLIST_FIRST(&spapr->xics->ics); uint32_t nr, server, priority; if ((nargs != 3) || (nret != 1)) { rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); return; } + if (!ics) { + rtas_st(rets, 0, RTAS_OUT_HW_ERROR); + return; + } nr = rtas_ld(args, 0); server = xics_get_cpu_index_by_dt_id(rtas_ld(args, 1)); @@ -141,13 +145,17 @@ static void rtas_get_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) { - ICSState *ics = spapr->xics->ics; + ICSState *ics = QLIST_FIRST(&spapr->xics->ics); uint32_t nr; if ((nargs != 1) || (nret != 3)) { rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); return; } + if (!ics) { + rtas_st(rets, 0, RTAS_OUT_HW_ERROR); + return; + } nr = rtas_ld(args, 0); @@ -166,13 +174,17 @@ static void rtas_int_off(PowerPCCPU *cpu, sPAPRMachineState *spapr, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) { - ICSState *ics = spapr->xics->ics; + ICSState *ics = QLIST_FIRST(&spapr->xics->ics); uint32_t nr; if ((nargs != 1) || (nret != 1)) { rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); return; } + if (!ics) { + rtas_st(rets, 0, RTAS_OUT_HW_ERROR); + return; + } nr = rtas_ld(args, 0); @@ -192,13 +204,17 @@ static void rtas_int_on(PowerPCCPU *cpu, sPAPRMachineState *spapr, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) { - ICSState *ics = spapr->xics->ics; + ICSState *ics = QLIST_FIRST(&spapr->xics->ics); uint32_t nr; if ((nargs != 1) || (nret != 1)) { rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); return; } + if (!ics) { + rtas_st(rets, 0, RTAS_OUT_HW_ERROR); + return; + } nr = rtas_ld(args, 0); @@ -217,7 +233,13 @@ static void rtas_int_on(PowerPCCPU *cpu, sPAPRMachineState *spapr, static void xics_spapr_set_nr_irqs(XICSState *xics, uint32_t nr_irqs, Error **errp) { - xics->nr_irqs = xics->ics->nr_irqs = nr_irqs; + ICSState *ics = QLIST_FIRST(&xics->ics); + + /* This needs to be deprecated ... */ + xics->nr_irqs = nr_irqs; + if (ics) { + ics->nr_irqs = nr_irqs; + } } static void xics_spapr_set_nr_servers(XICSState *xics, uint32_t nr_servers, @@ -240,6 +262,7 @@ static void xics_spapr_set_nr_servers(XICSState *xics, uint32_t nr_servers, static void xics_spapr_realize(DeviceState *dev, Error **errp) { XICSState *xics = XICS_SPAPR(dev); + ICSState *ics; Error *error = NULL; int i; @@ -261,10 +284,12 @@ static void xics_spapr_realize(DeviceState *dev, Error **errp) spapr_register_hypercall(H_EOI, h_eoi); spapr_register_hypercall(H_IPOLL, h_ipoll); - object_property_set_bool(OBJECT(xics->ics), true, "realized", &error); - if (error) { - error_propagate(errp, error); - return; + QLIST_FOREACH(ics, &xics->ics, list) { + object_property_set_bool(OBJECT(ics), true, "realized", &error); + if (error) { + error_propagate(errp, error); + return; + } } for (i = 0; i < xics->nr_servers; i++) { @@ -280,10 +305,12 @@ static void xics_spapr_realize(DeviceState *dev, Error **errp) static void xics_spapr_initfn(Object *obj) { XICSState *xics = XICS_SPAPR(obj); + ICSState *ics; - xics->ics = ICS(object_new(TYPE_ICS)); - object_property_add_child(obj, "ics", OBJECT(xics->ics), NULL); - xics->ics->xics = xics; + ics = ICS(object_new(TYPE_ICS)); + object_property_add_child(obj, "ics", OBJECT(ics), NULL); + ics->xics = xics; + QLIST_INSERT_HEAD(&xics->ics, ics, list); } static void xics_spapr_class_init(ObjectClass *oc, void *data) @@ -329,14 +356,15 @@ static int ics_find_free_block(ICSState *ics, int num, int alignnum) return -1; } -int xics_spapr_alloc(XICSState *xics, int src, int irq_hint, bool lsi, - Error **errp) +int xics_spapr_alloc(XICSState *xics, int irq_hint, bool lsi, Error **errp) { - ICSState *ics = &xics->ics[src]; + ICSState *ics = QLIST_FIRST(&xics->ics); int irq; + if (!ics) { + return -1; + } if (irq_hint) { - assert(src == xics_find_source(xics, irq_hint)); if (!ICS_IRQ_FREE(ics, irq_hint - ics->offset)) { error_setg(errp, "can't allocate IRQ %d: already in use", irq_hint); return -1; @@ -352,7 +380,7 @@ int xics_spapr_alloc(XICSState *xics, int src, int irq_hint, bool lsi, } ics_set_irq_type(ics, irq - ics->offset, lsi); - trace_xics_alloc(src, irq); + trace_xics_alloc(irq); return irq; } @@ -361,13 +389,16 @@ int xics_spapr_alloc(XICSState *xics, int src, int irq_hint, bool lsi, * Allocate block of consecutive IRQs, and return the number of the first IRQ in * the block. If align==true, aligns the first IRQ number to num. */ -int xics_spapr_alloc_block(XICSState *xics, int src, int num, bool lsi, - bool align, Error **errp) +int xics_spapr_alloc_block(XICSState *xics, int num, bool lsi, bool align, + Error **errp) { + ICSState *ics = QLIST_FIRST(&xics->ics); int i, first = -1; - ICSState *ics = &xics->ics[src]; - assert(src == 0); + if (!ics) { + return -1; + } + /* * MSIMesage::data is used for storing VIRQ so * it has to be aligned to num to support multiple @@ -394,7 +425,7 @@ int xics_spapr_alloc_block(XICSState *xics, int src, int num, bool lsi, } first += ics->offset; - trace_xics_alloc_block(src, first, num, lsi, align); + trace_xics_alloc_block(first, num, lsi, align); return first; } @@ -405,7 +436,7 @@ static void ics_free(ICSState *ics, int srcno, int num) for (i = srcno; i < srcno + num; ++i) { if (ICS_IRQ_FREE(ics, i)) { - trace_xics_ics_free_warn(ics - ics->xics->ics, i + ics->offset); + trace_xics_ics_free_warn(0, i + ics->offset); } memset(&ics->irqs[i], 0, sizeof(ICSIRQState)); } @@ -413,15 +444,10 @@ static void ics_free(ICSState *ics, int srcno, int num) void xics_spapr_free(XICSState *xics, int irq, int num) { - int src = xics_find_source(xics, irq); - - if (src >= 0) { - ICSState *ics = &xics->ics[src]; - - /* FIXME: implement multiple sources */ - assert(src == 0); + ICSState *ics = xics_find_source(xics, irq); - trace_xics_ics_free(ics - xics->ics, irq, num); + if (ics) { + trace_xics_ics_free(0, irq, num); ics_free(ics, irq - ics->offset, num); } } diff --git a/hw/ppc/spapr_events.c b/hw/ppc/spapr_events.c index 4c7b6aeab63..6d3534541c8 100644 --- a/hw/ppc/spapr_events.c +++ b/hw/ppc/spapr_events.c @@ -594,7 +594,7 @@ static void event_scan(PowerPCCPU *cpu, sPAPRMachineState *spapr, void spapr_events_init(sPAPRMachineState *spapr) { QTAILQ_INIT(&spapr->pending_events); - spapr->check_exception_irq = xics_spapr_alloc(spapr->xics, 0, 0, false, + spapr->check_exception_irq = xics_spapr_alloc(spapr->xics, 0, false, &error_fatal); spapr->epow_notifier.notify = spapr_powerdown_req; qemu_register_powerdown_notifier(&spapr->epow_notifier); diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 4f008654d67..a7ca9883879 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -363,7 +363,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr, } /* Allocate MSIs */ - irq = xics_spapr_alloc_block(spapr->xics, 0, req_num, false, + irq = xics_spapr_alloc_block(spapr->xics, req_num, false, ret_intr_type == RTAS_TYPE_MSI, &err); if (err) { error_reportf_err(err, "Can't allocate MSIs for device %x: ", @@ -1445,8 +1445,7 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp) uint32_t irq; Error *local_err = NULL; - irq = xics_spapr_alloc_block(spapr->xics, 0, 1, true, false, - &local_err); + irq = xics_spapr_alloc_block(spapr->xics, 1, true, false, &local_err); if (local_err) { error_propagate(errp, local_err); error_prepend(errp, "can't allocate LSIs: "); diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c index d68dd35679b..3648aa59604 100644 --- a/hw/ppc/spapr_vio.c +++ b/hw/ppc/spapr_vio.c @@ -453,7 +453,7 @@ static void spapr_vio_busdev_realize(DeviceState *qdev, Error **errp) dev->qdev.id = id; } - dev->irq = xics_spapr_alloc(spapr->xics, 0, dev->irq, false, &local_err); + dev->irq = xics_spapr_alloc(spapr->xics, dev->irq, false, &local_err); if (local_err) { error_propagate(errp, local_err); return; diff --git a/include/hw/ppc/xics.h b/include/hw/ppc/xics.h index 5aac67ad89b..e49a2dab934 100644 --- a/include/hw/ppc/xics.h +++ b/include/hw/ppc/xics.h @@ -85,7 +85,7 @@ struct XICSState { uint32_t nr_servers; uint32_t nr_irqs; ICPState *ss; - ICSState *ics; + QLIST_HEAD(, ICSState) ics; }; #define TYPE_ICP "icp" @@ -111,6 +111,7 @@ struct ICPState { DeviceState parent_obj; /*< public >*/ CPUState *cs; + ICSState *xirr_owner; uint32_t xirr; uint8_t pending_priority; uint8_t mfrr; @@ -145,6 +146,7 @@ struct ICSState { qemu_irq *qirqs; ICSIRQState *irqs; XICSState *xics; + QLIST_ENTRY(ICSState) list; }; static inline bool ics_valid_irq(ICSState *ics, uint32_t nr) @@ -172,10 +174,9 @@ struct ICSIRQState { #define XICS_IRQS_SPAPR 1024 qemu_irq xics_get_qirq(XICSState *icp, int irq); -int xics_spapr_alloc(XICSState *icp, int src, int irq_hint, bool lsi, - Error **errp); -int xics_spapr_alloc_block(XICSState *icp, int src, int num, bool lsi, - bool align, Error **errp); +int xics_spapr_alloc(XICSState *icp, int irq_hint, bool lsi, Error **errp); +int xics_spapr_alloc_block(XICSState *icp, int num, bool lsi, bool align, + Error **errp); void xics_spapr_free(XICSState *icp, int irq, int num); void xics_cpu_setup(XICSState *icp, PowerPCCPU *cpu); @@ -195,6 +196,6 @@ void ics_write_xive(ICSState *ics, int nr, int server, void ics_set_irq_type(ICSState *ics, int srcno, bool lsi); -int xics_find_source(XICSState *icp, int irq); +ICSState *xics_find_source(XICSState *icp, int irq); #endif /* XICS_H */ From d4d7a59a7a703220757cdc24d08a498db3e70212 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 3 Oct 2016 09:24:47 +0200 Subject: [PATCH 700/723] ppc/xics: Split ICS into ics-base and ics class MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The existing implementation remains same and ics-base is introduced. The type name "ics" is retained, and all the related functions renamed as ics_simple_* This will allow different implementations for the source controllers such as the MSI support of PHB3 on Power8 which uses in-memory state tables for example. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Nikunj A Dadhania Reviewed-by: David Gibson [ clg: added ICS_BASE_GET_CLASS and related fixes, based on : http://patchwork.ozlabs.org/patch/646010/ ] Signed-off-by: Cédric Le Goater Signed-off-by: David Gibson --- hw/intc/trace-events | 10 +-- hw/intc/xics.c | 150 ++++++++++++++++++++++++++---------------- hw/intc/xics_kvm.c | 12 ++-- hw/intc/xics_spapr.c | 30 +++++---- include/hw/ppc/xics.h | 27 +++++--- 5 files changed, 138 insertions(+), 91 deletions(-) diff --git a/hw/intc/trace-events b/hw/intc/trace-events index aa342a86fa6..a367b46b1c2 100644 --- a/hw/intc/trace-events +++ b/hw/intc/trace-events @@ -50,12 +50,12 @@ xics_icp_accept(uint32_t old_xirr, uint32_t new_xirr) "icp_accept: XIRR %#"PRIx3 xics_icp_eoi(int server, uint32_t xirr, uint32_t new_xirr) "icp_eoi: server %d given XIRR %#"PRIx32" new XIRR %#"PRIx32 xics_icp_irq(int server, int nr, uint8_t priority) "cpu %d trying to deliver irq %#"PRIx32" priority %#x" xics_icp_raise(uint32_t xirr, uint8_t pending_priority) "raising IRQ new XIRR=%#x new pending priority=%#x" -xics_set_irq_msi(int srcno, int nr) "set_irq_msi: srcno %d [irq %#x]" +xics_ics_simple_set_irq_msi(int srcno, int nr) "set_irq_msi: srcno %d [irq %#x]" xics_masked_pending(void) "set_irq_msi: masked pending" -xics_set_irq_lsi(int srcno, int nr) "set_irq_lsi: srcno %d [irq %#x]" -xics_ics_write_xive(int nr, int srcno, int server, uint8_t priority) "ics_write_xive: irq %#x [src %d] server %#x prio %#x" -xics_ics_reject(int nr, int srcno) "reject irq %#x [src %d]" -xics_ics_eoi(int nr) "ics_eoi: irq %#x" +xics_ics_simple_set_irq_lsi(int srcno, int nr) "set_irq_lsi: srcno %d [irq %#x]" +xics_ics_simple_write_xive(int nr, int srcno, int server, uint8_t priority) "ics_write_xive: irq %#x [src %d] server %#x prio %#x" +xics_ics_simple_reject(int nr, int srcno) "reject irq %#x [src %d]" +xics_ics_simple_eoi(int nr) "ics_eoi: irq %#x" xics_alloc(int irq) "irq %d" xics_alloc_block(int first, int num, bool lsi, int align) "first irq %d, %d irqs, lsi=%d, alignnum %d" xics_ics_free(int src, int irq, int num) "Source#%d, first irq %d, %d irqs" diff --git a/hw/intc/xics.c b/hw/intc/xics.c index 433af93254f..f40b00003a4 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -213,9 +213,32 @@ static const TypeInfo xics_common_info = { #define XISR(ss) (((ss)->xirr) & XISR_MASK) #define CPPR(ss) (((ss)->xirr) >> 24) -static void ics_reject(ICSState *ics, int nr); -static void ics_resend(ICSState *ics); -static void ics_eoi(ICSState *ics, int nr); +static void ics_reject(ICSState *ics, uint32_t nr) +{ + ICSStateClass *k = ICS_BASE_GET_CLASS(ics); + + if (k->reject) { + k->reject(ics, nr); + } +} + +static void ics_resend(ICSState *ics) +{ + ICSStateClass *k = ICS_BASE_GET_CLASS(ics); + + if (k->resend) { + k->resend(ics); + } +} + +static void ics_eoi(ICSState *ics, int nr) +{ + ICSStateClass *k = ICS_BASE_GET_CLASS(ics); + + if (k->eoi) { + k->eoi(ics, nr); + } +} static void icp_check_ipi(ICPState *ss) { @@ -418,7 +441,7 @@ static const TypeInfo icp_info = { /* * ICS: Source layer */ -static void resend_msi(ICSState *ics, int srcno) +static void ics_simple_resend_msi(ICSState *ics, int srcno) { ICSIRQState *irq = ics->irqs + srcno; @@ -431,7 +454,7 @@ static void resend_msi(ICSState *ics, int srcno) } } -static void resend_lsi(ICSState *ics, int srcno) +static void ics_simple_resend_lsi(ICSState *ics, int srcno) { ICSIRQState *irq = ics->irqs + srcno; @@ -443,11 +466,11 @@ static void resend_lsi(ICSState *ics, int srcno) } } -static void set_irq_msi(ICSState *ics, int srcno, int val) +static void ics_simple_set_irq_msi(ICSState *ics, int srcno, int val) { ICSIRQState *irq = ics->irqs + srcno; - trace_xics_set_irq_msi(srcno, srcno + ics->offset); + trace_xics_ics_simple_set_irq_msi(srcno, srcno + ics->offset); if (val) { if (irq->priority == 0xff) { @@ -459,31 +482,31 @@ static void set_irq_msi(ICSState *ics, int srcno, int val) } } -static void set_irq_lsi(ICSState *ics, int srcno, int val) +static void ics_simple_set_irq_lsi(ICSState *ics, int srcno, int val) { ICSIRQState *irq = ics->irqs + srcno; - trace_xics_set_irq_lsi(srcno, srcno + ics->offset); + trace_xics_ics_simple_set_irq_lsi(srcno, srcno + ics->offset); if (val) { irq->status |= XICS_STATUS_ASSERTED; } else { irq->status &= ~XICS_STATUS_ASSERTED; } - resend_lsi(ics, srcno); + ics_simple_resend_lsi(ics, srcno); } -static void ics_set_irq(void *opaque, int srcno, int val) +static void ics_simple_set_irq(void *opaque, int srcno, int val) { ICSState *ics = (ICSState *)opaque; if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) { - set_irq_lsi(ics, srcno, val); + ics_simple_set_irq_lsi(ics, srcno, val); } else { - set_irq_msi(ics, srcno, val); + ics_simple_set_irq_msi(ics, srcno, val); } } -static void write_xive_msi(ICSState *ics, int srcno) +static void ics_simple_write_xive_msi(ICSState *ics, int srcno) { ICSIRQState *irq = ics->irqs + srcno; @@ -496,35 +519,35 @@ static void write_xive_msi(ICSState *ics, int srcno) icp_irq(ics, irq->server, srcno + ics->offset, irq->priority); } -static void write_xive_lsi(ICSState *ics, int srcno) +static void ics_simple_write_xive_lsi(ICSState *ics, int srcno) { - resend_lsi(ics, srcno); + ics_simple_resend_lsi(ics, srcno); } -void ics_write_xive(ICSState *ics, int nr, int server, - uint8_t priority, uint8_t saved_priority) +void ics_simple_write_xive(ICSState *ics, int srcno, int server, + uint8_t priority, uint8_t saved_priority) { - int srcno = nr - ics->offset; ICSIRQState *irq = ics->irqs + srcno; irq->server = server; irq->priority = priority; irq->saved_priority = saved_priority; - trace_xics_ics_write_xive(nr, srcno, server, priority); + trace_xics_ics_simple_write_xive(ics->offset + srcno, srcno, server, + priority); if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) { - write_xive_lsi(ics, srcno); + ics_simple_write_xive_lsi(ics, srcno); } else { - write_xive_msi(ics, srcno); + ics_simple_write_xive_msi(ics, srcno); } } -static void ics_reject(ICSState *ics, int nr) +static void ics_simple_reject(ICSState *ics, uint32_t nr) { ICSIRQState *irq = ics->irqs + nr - ics->offset; - trace_xics_ics_reject(nr, nr - ics->offset); + trace_xics_ics_simple_reject(nr, nr - ics->offset); if (irq->flags & XICS_FLAGS_IRQ_MSI) { irq->status |= XICS_STATUS_REJECTED; } else if (irq->flags & XICS_FLAGS_IRQ_LSI) { @@ -532,35 +555,35 @@ static void ics_reject(ICSState *ics, int nr) } } -static void ics_resend(ICSState *ics) +static void ics_simple_resend(ICSState *ics) { int i; for (i = 0; i < ics->nr_irqs; i++) { /* FIXME: filter by server#? */ if (ics->irqs[i].flags & XICS_FLAGS_IRQ_LSI) { - resend_lsi(ics, i); + ics_simple_resend_lsi(ics, i); } else { - resend_msi(ics, i); + ics_simple_resend_msi(ics, i); } } } -static void ics_eoi(ICSState *ics, int nr) +static void ics_simple_eoi(ICSState *ics, uint32_t nr) { int srcno = nr - ics->offset; ICSIRQState *irq = ics->irqs + srcno; - trace_xics_ics_eoi(nr); + trace_xics_ics_simple_eoi(nr); if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) { irq->status &= ~XICS_STATUS_SENT; } } -static void ics_reset(DeviceState *dev) +static void ics_simple_reset(DeviceState *dev) { - ICSState *ics = ICS(dev); + ICSState *ics = ICS_SIMPLE(dev); int i; uint8_t flags[ics->nr_irqs]; @@ -577,7 +600,7 @@ static void ics_reset(DeviceState *dev) } } -static int ics_post_load(ICSState *ics, int version_id) +static int ics_simple_post_load(ICSState *ics, int version_id) { int i; @@ -588,20 +611,20 @@ static int ics_post_load(ICSState *ics, int version_id) return 0; } -static void ics_dispatch_pre_save(void *opaque) +static void ics_simple_dispatch_pre_save(void *opaque) { ICSState *ics = opaque; - ICSStateClass *info = ICS_GET_CLASS(ics); + ICSStateClass *info = ICS_BASE_GET_CLASS(ics); if (info->pre_save) { info->pre_save(ics); } } -static int ics_dispatch_post_load(void *opaque, int version_id) +static int ics_simple_dispatch_post_load(void *opaque, int version_id) { ICSState *ics = opaque; - ICSStateClass *info = ICS_GET_CLASS(ics); + ICSStateClass *info = ICS_BASE_GET_CLASS(ics); if (info->post_load) { return info->post_load(ics, version_id); @@ -610,7 +633,7 @@ static int ics_dispatch_post_load(void *opaque, int version_id) return 0; } -static const VMStateDescription vmstate_ics_irq = { +static const VMStateDescription vmstate_ics_simple_irq = { .name = "ics/irq", .version_id = 2, .minimum_version_id = 1, @@ -624,59 +647,71 @@ static const VMStateDescription vmstate_ics_irq = { }, }; -static const VMStateDescription vmstate_ics = { +static const VMStateDescription vmstate_ics_simple = { .name = "ics", .version_id = 1, .minimum_version_id = 1, - .pre_save = ics_dispatch_pre_save, - .post_load = ics_dispatch_post_load, + .pre_save = ics_simple_dispatch_pre_save, + .post_load = ics_simple_dispatch_post_load, .fields = (VMStateField[]) { /* Sanity check */ VMSTATE_UINT32_EQUAL(nr_irqs, ICSState), VMSTATE_STRUCT_VARRAY_POINTER_UINT32(irqs, ICSState, nr_irqs, - vmstate_ics_irq, ICSIRQState), + vmstate_ics_simple_irq, + ICSIRQState), VMSTATE_END_OF_LIST() }, }; -static void ics_initfn(Object *obj) +static void ics_simple_initfn(Object *obj) { - ICSState *ics = ICS(obj); + ICSState *ics = ICS_SIMPLE(obj); ics->offset = XICS_IRQ_BASE; } -static void ics_realize(DeviceState *dev, Error **errp) +static void ics_simple_realize(DeviceState *dev, Error **errp) { - ICSState *ics = ICS(dev); + ICSState *ics = ICS_SIMPLE(dev); if (!ics->nr_irqs) { error_setg(errp, "Number of interrupts needs to be greater 0"); return; } ics->irqs = g_malloc0(ics->nr_irqs * sizeof(ICSIRQState)); - ics->qirqs = qemu_allocate_irqs(ics_set_irq, ics, ics->nr_irqs); + ics->qirqs = qemu_allocate_irqs(ics_simple_set_irq, ics, ics->nr_irqs); } -static void ics_class_init(ObjectClass *klass, void *data) +static void ics_simple_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - ICSStateClass *isc = ICS_CLASS(klass); + ICSStateClass *isc = ICS_BASE_CLASS(klass); - dc->realize = ics_realize; - dc->vmsd = &vmstate_ics; - dc->reset = ics_reset; - isc->post_load = ics_post_load; + dc->realize = ics_simple_realize; + dc->vmsd = &vmstate_ics_simple; + dc->reset = ics_simple_reset; + isc->post_load = ics_simple_post_load; + isc->reject = ics_simple_reject; + isc->resend = ics_simple_resend; + isc->eoi = ics_simple_eoi; } -static const TypeInfo ics_info = { - .name = TYPE_ICS, +static const TypeInfo ics_simple_info = { + .name = TYPE_ICS_SIMPLE, + .parent = TYPE_ICS_BASE, + .instance_size = sizeof(ICSState), + .class_init = ics_simple_class_init, + .class_size = sizeof(ICSStateClass), + .instance_init = ics_simple_initfn, +}; + +static const TypeInfo ics_base_info = { + .name = TYPE_ICS_BASE, .parent = TYPE_DEVICE, + .abstract = true, .instance_size = sizeof(ICSState), - .class_init = ics_class_init, .class_size = sizeof(ICSStateClass), - .instance_init = ics_initfn, }; /* @@ -716,7 +751,8 @@ void ics_set_irq_type(ICSState *ics, int srcno, bool lsi) static void xics_register_types(void) { type_register_static(&xics_common_info); - type_register_static(&ics_info); + type_register_static(&ics_simple_info); + type_register_static(&ics_base_info); type_register_static(&icp_info); } diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c index 843905cfbd3..9c2f198fd14 100644 --- a/hw/intc/xics_kvm.c +++ b/hw/intc/xics_kvm.c @@ -272,7 +272,7 @@ static void ics_kvm_set_irq(void *opaque, int srcno, int val) static void ics_kvm_reset(DeviceState *dev) { - ICSState *ics = ICS(dev); + ICSState *ics = ICS_SIMPLE(dev); int i; uint8_t flags[ics->nr_irqs]; @@ -293,7 +293,7 @@ static void ics_kvm_reset(DeviceState *dev) static void ics_kvm_realize(DeviceState *dev, Error **errp) { - ICSState *ics = ICS(dev); + ICSState *ics = ICS_SIMPLE(dev); if (!ics->nr_irqs) { error_setg(errp, "Number of interrupts needs to be greater 0"); @@ -306,7 +306,7 @@ static void ics_kvm_realize(DeviceState *dev, Error **errp) static void ics_kvm_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - ICSStateClass *icsc = ICS_CLASS(klass); + ICSStateClass *icsc = ICS_BASE_CLASS(klass); dc->realize = ics_kvm_realize; dc->reset = ics_kvm_reset; @@ -315,8 +315,8 @@ static void ics_kvm_class_init(ObjectClass *klass, void *data) } static const TypeInfo ics_kvm_info = { - .name = TYPE_KVM_ICS, - .parent = TYPE_ICS, + .name = TYPE_ICS_KVM, + .parent = TYPE_ICS_SIMPLE, .instance_size = sizeof(ICSState), .class_init = ics_kvm_class_init, }; @@ -488,7 +488,7 @@ static void xics_kvm_initfn(Object *obj) XICSState *xics = XICS_COMMON(obj); ICSState *ics; - ics = ICS(object_new(TYPE_KVM_ICS)); + ics = ICS_SIMPLE(object_new(TYPE_ICS_KVM)); object_property_add_child(obj, "ics", OBJECT(ics), NULL); ics->xics = xics; QLIST_INSERT_HEAD(&xics->ics, ics, list); diff --git a/hw/intc/xics_spapr.c b/hw/intc/xics_spapr.c index 0b0845d6280..e8d0623c2cb 100644 --- a/hw/intc/xics_spapr.c +++ b/hw/intc/xics_spapr.c @@ -114,7 +114,7 @@ static void rtas_set_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr, uint32_t nret, target_ulong rets) { ICSState *ics = QLIST_FIRST(&spapr->xics->ics); - uint32_t nr, server, priority; + uint32_t nr, srcno, server, priority; if ((nargs != 3) || (nret != 1)) { rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); @@ -135,7 +135,8 @@ static void rtas_set_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr, return; } - ics_write_xive(ics, nr, server, priority, priority); + srcno = nr - ics->offset; + ics_simple_write_xive(ics, srcno, server, priority, priority); rtas_st(rets, 0, RTAS_OUT_SUCCESS); } @@ -146,7 +147,7 @@ static void rtas_get_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr, uint32_t nret, target_ulong rets) { ICSState *ics = QLIST_FIRST(&spapr->xics->ics); - uint32_t nr; + uint32_t nr, srcno; if ((nargs != 1) || (nret != 3)) { rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); @@ -165,8 +166,9 @@ static void rtas_get_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr, } rtas_st(rets, 0, RTAS_OUT_SUCCESS); - rtas_st(rets, 1, ics->irqs[nr - ics->offset].server); - rtas_st(rets, 2, ics->irqs[nr - ics->offset].priority); + srcno = nr - ics->offset; + rtas_st(rets, 1, ics->irqs[srcno].server); + rtas_st(rets, 2, ics->irqs[srcno].priority); } static void rtas_int_off(PowerPCCPU *cpu, sPAPRMachineState *spapr, @@ -175,7 +177,7 @@ static void rtas_int_off(PowerPCCPU *cpu, sPAPRMachineState *spapr, uint32_t nret, target_ulong rets) { ICSState *ics = QLIST_FIRST(&spapr->xics->ics); - uint32_t nr; + uint32_t nr, srcno; if ((nargs != 1) || (nret != 1)) { rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); @@ -193,8 +195,9 @@ static void rtas_int_off(PowerPCCPU *cpu, sPAPRMachineState *spapr, return; } - ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server, 0xff, - ics->irqs[nr - ics->offset].priority); + srcno = nr - ics->offset; + ics_simple_write_xive(ics, srcno, ics->irqs[srcno].server, 0xff, + ics->irqs[srcno].priority); rtas_st(rets, 0, RTAS_OUT_SUCCESS); } @@ -205,7 +208,7 @@ static void rtas_int_on(PowerPCCPU *cpu, sPAPRMachineState *spapr, uint32_t nret, target_ulong rets) { ICSState *ics = QLIST_FIRST(&spapr->xics->ics); - uint32_t nr; + uint32_t nr, srcno; if ((nargs != 1) || (nret != 1)) { rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); @@ -223,9 +226,10 @@ static void rtas_int_on(PowerPCCPU *cpu, sPAPRMachineState *spapr, return; } - ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server, - ics->irqs[nr - ics->offset].saved_priority, - ics->irqs[nr - ics->offset].saved_priority); + srcno = nr - ics->offset; + ics_simple_write_xive(ics, srcno, ics->irqs[srcno].server, + ics->irqs[srcno].saved_priority, + ics->irqs[srcno].saved_priority); rtas_st(rets, 0, RTAS_OUT_SUCCESS); } @@ -307,7 +311,7 @@ static void xics_spapr_initfn(Object *obj) XICSState *xics = XICS_SPAPR(obj); ICSState *ics; - ics = ICS(object_new(TYPE_ICS)); + ics = ICS_SIMPLE(object_new(TYPE_ICS_SIMPLE)); object_property_add_child(obj, "ics", OBJECT(ics), NULL); ics->xics = xics; QLIST_INSERT_HEAD(&xics->ics, ics, list); diff --git a/include/hw/ppc/xics.h b/include/hw/ppc/xics.h index e49a2dab934..66ae55ded38 100644 --- a/include/hw/ppc/xics.h +++ b/include/hw/ppc/xics.h @@ -119,22 +119,29 @@ struct ICPState { bool cap_irq_xics_enabled; }; -#define TYPE_ICS "ics" -#define ICS(obj) OBJECT_CHECK(ICSState, (obj), TYPE_ICS) +#define TYPE_ICS_BASE "ics-base" +#define ICS_BASE(obj) OBJECT_CHECK(ICSState, (obj), TYPE_ICS_BASE) -#define TYPE_KVM_ICS "icskvm" -#define KVM_ICS(obj) OBJECT_CHECK(ICSState, (obj), TYPE_KVM_ICS) +/* Retain ics for sPAPR for migration from existing sPAPR guests */ +#define TYPE_ICS_SIMPLE "ics" +#define ICS_SIMPLE(obj) OBJECT_CHECK(ICSState, (obj), TYPE_ICS_SIMPLE) -#define ICS_CLASS(klass) \ - OBJECT_CLASS_CHECK(ICSStateClass, (klass), TYPE_ICS) -#define ICS_GET_CLASS(obj) \ - OBJECT_GET_CLASS(ICSStateClass, (obj), TYPE_ICS) +#define TYPE_ICS_KVM "icskvm" +#define ICS_KVM(obj) OBJECT_CHECK(ICSState, (obj), TYPE_ICS_KVM) + +#define ICS_BASE_CLASS(klass) \ + OBJECT_CLASS_CHECK(ICSStateClass, (klass), TYPE_ICS_BASE) +#define ICS_BASE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(ICSStateClass, (obj), TYPE_ICS_BASE) struct ICSStateClass { DeviceClass parent_class; void (*pre_save)(ICSState *s); int (*post_load)(ICSState *s, int version_id); + void (*reject)(ICSState *s, uint32_t irq); + void (*resend)(ICSState *s); + void (*eoi)(ICSState *s, uint32_t irq); }; struct ICSState { @@ -191,8 +198,8 @@ uint32_t icp_accept(ICPState *ss); uint32_t icp_ipoll(ICPState *ss, uint32_t *mfrr); void icp_eoi(XICSState *icp, int server, uint32_t xirr); -void ics_write_xive(ICSState *ics, int nr, int server, - uint8_t priority, uint8_t saved_priority); +void ics_simple_write_xive(ICSState *ics, int nr, int server, + uint8_t priority, uint8_t saved_priority); void ics_set_irq_type(ICSState *ics, int srcno, bool lsi); From cd1b354ec05035f84bb05f591cb632770ad36e7c Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 12 Oct 2016 13:30:07 +1100 Subject: [PATCH 701/723] libqos: Isolate knowledge of spapr memory map to qpci_init_spapr() The libqos code for accessing PCI on the spapr machine type uses IOBASE() and MMIOBASE() macros to determine the address in the CPU memory map of the windows to PCI address space. This is a detail of the implementation of PCI in the machine type, it's not specified by the PAPR standard. Real guests would get the addresses of the PCI windows from the device tree. Finding the device tree in libqos would be awkward, but we can at least localize this knowledge of the implementation to the init function, saving it in the QPCIBusSPAPR structure for use by the accessors. That leaves only one place to fix if we alter the location of the PCI windows, as we're planning to do. Signed-off-by: David Gibson Reviewed-by: Laurent Vivier --- tests/libqos/pci-spapr.c | 113 ++++++++++++++++++++++----------------- 1 file changed, 64 insertions(+), 49 deletions(-) diff --git a/tests/libqos/pci-spapr.c b/tests/libqos/pci-spapr.c index 2f73badfd94..1765a54c808 100644 --- a/tests/libqos/pci-spapr.c +++ b/tests/libqos/pci-spapr.c @@ -18,30 +18,23 @@ /* From include/hw/pci-host/spapr.h */ -#define SPAPR_PCI_BASE_BUID 0x800000020000000ULL - -#define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL - -#define SPAPR_PCI_WINDOW_BASE 0x10000000000ULL -#define SPAPR_PCI_WINDOW_SPACING 0x1000000000ULL -#define SPAPR_PCI_MMIO_WIN_OFF 0xA0000000 -#define SPAPR_PCI_MMIO_WIN_SIZE (SPAPR_PCI_WINDOW_SPACING - \ - SPAPR_PCI_MEM_WIN_BUS_OFFSET) -#define SPAPR_PCI_IO_WIN_OFF 0x80000000 -#define SPAPR_PCI_IO_WIN_SIZE 0x10000 - -/* index is the phb index */ - -#define BUIDBASE(index) (SPAPR_PCI_BASE_BUID + (index)) -#define PCIBASE(index) (SPAPR_PCI_WINDOW_BASE + \ - (index) * SPAPR_PCI_WINDOW_SPACING) -#define IOBASE(index) (PCIBASE(index) + SPAPR_PCI_IO_WIN_OFF) -#define MMIOBASE(index) (PCIBASE(index) + SPAPR_PCI_MMIO_WIN_OFF) +typedef struct QPCIWindow { + uint64_t pci_base; /* window address in PCI space */ + uint64_t size; /* window size */ +} QPCIWindow; typedef struct QPCIBusSPAPR { QPCIBus bus; QGuestAllocator *alloc; + uint64_t buid; + + uint64_t pio_cpu_base; + QPCIWindow pio; + + uint64_t mmio_cpu_base; + QPCIWindow mmio; + uint64_t pci_hole_start; uint64_t pci_hole_size; uint64_t pci_hole_alloc; @@ -59,69 +52,75 @@ typedef struct QPCIBusSPAPR { static uint8_t qpci_spapr_io_readb(QPCIBus *bus, void *addr) { + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); uint64_t port = (uintptr_t)addr; uint8_t v; - if (port < SPAPR_PCI_IO_WIN_SIZE) { - v = readb(IOBASE(0) + port); + if (port < s->pio.size) { + v = readb(s->pio_cpu_base + port); } else { - v = readb(MMIOBASE(0) + port); + v = readb(s->mmio_cpu_base + port); } return v; } static uint16_t qpci_spapr_io_readw(QPCIBus *bus, void *addr) { + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); uint64_t port = (uintptr_t)addr; uint16_t v; - if (port < SPAPR_PCI_IO_WIN_SIZE) { - v = readw(IOBASE(0) + port); + if (port < s->pio.size) { + v = readw(s->pio_cpu_base + port); } else { - v = readw(MMIOBASE(0) + port); + v = readw(s->mmio_cpu_base + port); } return bswap16(v); } static uint32_t qpci_spapr_io_readl(QPCIBus *bus, void *addr) { + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); uint64_t port = (uintptr_t)addr; uint32_t v; - if (port < SPAPR_PCI_IO_WIN_SIZE) { - v = readl(IOBASE(0) + port); + if (port < s->pio.size) { + v = readl(s->pio_cpu_base + port); } else { - v = readl(MMIOBASE(0) + port); + v = readl(s->mmio_cpu_base + port); } return bswap32(v); } static void qpci_spapr_io_writeb(QPCIBus *bus, void *addr, uint8_t value) { + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); uint64_t port = (uintptr_t)addr; - if (port < SPAPR_PCI_IO_WIN_SIZE) { - writeb(IOBASE(0) + port, value); + if (port < s->pio.size) { + writeb(s->pio_cpu_base + port, value); } else { - writeb(MMIOBASE(0) + port, value); + writeb(s->mmio_cpu_base + port, value); } } static void qpci_spapr_io_writew(QPCIBus *bus, void *addr, uint16_t value) { + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); uint64_t port = (uintptr_t)addr; value = bswap16(value); - if (port < SPAPR_PCI_IO_WIN_SIZE) { - writew(IOBASE(0) + port, value); + if (port < s->pio.size) { + writew(s->pio_cpu_base + port, value); } else { - writew(MMIOBASE(0) + port, value); + writew(s->mmio_cpu_base + port, value); } } static void qpci_spapr_io_writel(QPCIBus *bus, void *addr, uint32_t value) { + QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); uint64_t port = (uintptr_t)addr; value = bswap32(value); - if (port < SPAPR_PCI_IO_WIN_SIZE) { - writel(IOBASE(0) + port, value); + if (port < s->pio.size) { + writel(s->pio_cpu_base + port, value); } else { - writel(MMIOBASE(0) + port, value); + writel(s->mmio_cpu_base + port, value); } } @@ -129,24 +128,21 @@ static uint8_t qpci_spapr_config_readb(QPCIBus *bus, int devfn, uint8_t offset) { QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); uint32_t config_addr = (devfn << 8) | offset; - return qrtas_ibm_read_pci_config(s->alloc, BUIDBASE(0), - config_addr, 1); + return qrtas_ibm_read_pci_config(s->alloc, s->buid, config_addr, 1); } static uint16_t qpci_spapr_config_readw(QPCIBus *bus, int devfn, uint8_t offset) { QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); uint32_t config_addr = (devfn << 8) | offset; - return qrtas_ibm_read_pci_config(s->alloc, BUIDBASE(0), - config_addr, 2); + return qrtas_ibm_read_pci_config(s->alloc, s->buid, config_addr, 2); } static uint32_t qpci_spapr_config_readl(QPCIBus *bus, int devfn, uint8_t offset) { QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); uint32_t config_addr = (devfn << 8) | offset; - return qrtas_ibm_read_pci_config(s->alloc, BUIDBASE(0), - config_addr, 4); + return qrtas_ibm_read_pci_config(s->alloc, s->buid, config_addr, 4); } static void qpci_spapr_config_writeb(QPCIBus *bus, int devfn, uint8_t offset, @@ -154,8 +150,7 @@ static void qpci_spapr_config_writeb(QPCIBus *bus, int devfn, uint8_t offset, { QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); uint32_t config_addr = (devfn << 8) | offset; - qrtas_ibm_write_pci_config(s->alloc, BUIDBASE(0), - config_addr, 1, value); + qrtas_ibm_write_pci_config(s->alloc, s->buid, config_addr, 1, value); } static void qpci_spapr_config_writew(QPCIBus *bus, int devfn, uint8_t offset, @@ -163,8 +158,7 @@ static void qpci_spapr_config_writew(QPCIBus *bus, int devfn, uint8_t offset, { QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); uint32_t config_addr = (devfn << 8) | offset; - qrtas_ibm_write_pci_config(s->alloc, BUIDBASE(0), - config_addr, 2, value); + qrtas_ibm_write_pci_config(s->alloc, s->buid, config_addr, 2, value); } static void qpci_spapr_config_writel(QPCIBus *bus, int devfn, uint8_t offset, @@ -172,8 +166,7 @@ static void qpci_spapr_config_writel(QPCIBus *bus, int devfn, uint8_t offset, { QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus); uint32_t config_addr = (devfn << 8) | offset; - qrtas_ibm_write_pci_config(s->alloc, BUIDBASE(0), - config_addr, 4, value); + qrtas_ibm_write_pci_config(s->alloc, s->buid, config_addr, 4, value); } static void *qpci_spapr_iomap(QPCIBus *bus, QPCIDevice *dev, int barno, @@ -242,6 +235,15 @@ static void qpci_spapr_iounmap(QPCIBus *bus, void *data) /* FIXME */ } +#define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL +#define SPAPR_PCI_WINDOW_BASE 0x10000000000ULL +#define SPAPR_PCI_WINDOW_SPACING 0x1000000000ULL +#define SPAPR_PCI_MMIO_WIN_OFF 0xA0000000 +#define SPAPR_PCI_MMIO_WIN_SIZE (SPAPR_PCI_WINDOW_SPACING - \ + SPAPR_PCI_MEM_WIN_BUS_OFFSET) +#define SPAPR_PCI_IO_WIN_OFF 0x80000000 +#define SPAPR_PCI_IO_WIN_SIZE 0x10000 + QPCIBus *qpci_init_spapr(QGuestAllocator *alloc) { QPCIBusSPAPR *ret; @@ -269,6 +271,19 @@ QPCIBus *qpci_init_spapr(QGuestAllocator *alloc) ret->bus.iomap = qpci_spapr_iomap; ret->bus.iounmap = qpci_spapr_iounmap; + /* FIXME: We assume the default location of the PHB for now. + * Ideally we'd parse the device tree deposited in the guest to + * get the window locations */ + ret->buid = 0x800000020000000ULL; + + ret->pio_cpu_base = SPAPR_PCI_WINDOW_BASE + SPAPR_PCI_IO_WIN_OFF; + ret->pio.pci_base = 0; + ret->pio.size = SPAPR_PCI_IO_WIN_SIZE; + + ret->mmio_cpu_base = SPAPR_PCI_WINDOW_BASE + SPAPR_PCI_MMIO_WIN_OFF; + ret->mmio.pci_base = SPAPR_PCI_MEM_WIN_BUS_OFFSET; + ret->mmio.size = SPAPR_PCI_MMIO_WIN_SIZE; + ret->pci_hole_start = 0xC0000000; ret->pci_hole_size = SPAPR_PCI_MMIO_WIN_SIZE; ret->pci_hole_alloc = 0; From c711369087d5964ea77b0fd0e0ff1f268e1a67ee Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 12 Oct 2016 13:38:25 +1100 Subject: [PATCH 702/723] libqos: Correct error in PCI hole sizing for spapr In pci-spapr.c (as in pci-pc.c from which it was derived), the pci_hole_start/pci_hole_size and pci_iohole_start/pci_iohole_size pairs[1] essentially define the region of PCI (not CPU) addresses in which MMIO or PIO BARs respectively will be allocated. The size value is relative to the start value. But in pci-spapr.c it is set to the entire size of the window supported by the (emulated) hardware, but the start values are *not* at the beginning of the emulated windows. That means if you tried to map enough PCI BARs, we'd messily overrun the IO windows, instead of failing in iomap as we should. This patch corrects this by calculating the hole sizes from the location of the window in PCI space and the hole start. [1] Those are bad names, but that's a problem for another time. Signed-off-by: David Gibson Reviewed-by: Laurent Vivier --- tests/libqos/pci-spapr.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/libqos/pci-spapr.c b/tests/libqos/pci-spapr.c index 1765a54c808..3192903497e 100644 --- a/tests/libqos/pci-spapr.c +++ b/tests/libqos/pci-spapr.c @@ -285,11 +285,13 @@ QPCIBus *qpci_init_spapr(QGuestAllocator *alloc) ret->mmio.size = SPAPR_PCI_MMIO_WIN_SIZE; ret->pci_hole_start = 0xC0000000; - ret->pci_hole_size = SPAPR_PCI_MMIO_WIN_SIZE; + ret->pci_hole_size = + ret->mmio.pci_base + ret->mmio.size - ret->pci_hole_start; ret->pci_hole_alloc = 0; ret->pci_iohole_start = 0xc000; - ret->pci_iohole_size = SPAPR_PCI_IO_WIN_SIZE; + ret->pci_iohole_size = + ret->pio.pci_base + ret->pio.size - ret->pci_iohole_start; ret->pci_iohole_alloc = 0; return &ret->bus; From 8360544a6d3a54df1fce80f55ba4ad075a8ded54 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 12 Oct 2016 14:07:04 +1100 Subject: [PATCH 703/723] libqos: Limit spapr-pci to 32-bit MMIO for now Currently the functions in pci-spapr.c (like pci-pc.c on which it's based) don't distinguish between 32-bit and 64-bit PCI MMIO. At the moment, the qemu side implementation is a bit weird and has a single MMIO window straddling 32-bit and 64-bit regions, but we're likely to change that in future. In any case, pci-pc.c - and therefore the testcases using PCI - only handle 32-bit MMIOs for now. For spapr despite whatever changes might happen with the MMIO windows, the 32-bit window is likely to remain at 2..4 GiB in PCI space. So, explicitly limit pci-spapr.c to 32-bit MMIOs for now, we can add 64-bit MMIO support back in when and if we need it. Signed-off-by: David Gibson Reviewed-by: Laurent Vivier --- tests/libqos/pci-spapr.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/tests/libqos/pci-spapr.c b/tests/libqos/pci-spapr.c index 3192903497e..558dfc3bdcc 100644 --- a/tests/libqos/pci-spapr.c +++ b/tests/libqos/pci-spapr.c @@ -32,8 +32,8 @@ typedef struct QPCIBusSPAPR { uint64_t pio_cpu_base; QPCIWindow pio; - uint64_t mmio_cpu_base; - QPCIWindow mmio; + uint64_t mmio32_cpu_base; + QPCIWindow mmio32; uint64_t pci_hole_start; uint64_t pci_hole_size; @@ -58,7 +58,7 @@ static uint8_t qpci_spapr_io_readb(QPCIBus *bus, void *addr) if (port < s->pio.size) { v = readb(s->pio_cpu_base + port); } else { - v = readb(s->mmio_cpu_base + port); + v = readb(s->mmio32_cpu_base + port); } return v; } @@ -71,7 +71,7 @@ static uint16_t qpci_spapr_io_readw(QPCIBus *bus, void *addr) if (port < s->pio.size) { v = readw(s->pio_cpu_base + port); } else { - v = readw(s->mmio_cpu_base + port); + v = readw(s->mmio32_cpu_base + port); } return bswap16(v); } @@ -84,7 +84,7 @@ static uint32_t qpci_spapr_io_readl(QPCIBus *bus, void *addr) if (port < s->pio.size) { v = readl(s->pio_cpu_base + port); } else { - v = readl(s->mmio_cpu_base + port); + v = readl(s->mmio32_cpu_base + port); } return bswap32(v); } @@ -96,7 +96,7 @@ static void qpci_spapr_io_writeb(QPCIBus *bus, void *addr, uint8_t value) if (port < s->pio.size) { writeb(s->pio_cpu_base + port, value); } else { - writeb(s->mmio_cpu_base + port, value); + writeb(s->mmio32_cpu_base + port, value); } } @@ -108,7 +108,7 @@ static void qpci_spapr_io_writew(QPCIBus *bus, void *addr, uint16_t value) if (port < s->pio.size) { writew(s->pio_cpu_base + port, value); } else { - writew(s->mmio_cpu_base + port, value); + writew(s->mmio32_cpu_base + port, value); } } @@ -120,7 +120,7 @@ static void qpci_spapr_io_writel(QPCIBus *bus, void *addr, uint32_t value) if (port < s->pio.size) { writel(s->pio_cpu_base + port, value); } else { - writel(s->mmio_cpu_base + port, value); + writel(s->mmio32_cpu_base + port, value); } } @@ -235,12 +235,9 @@ static void qpci_spapr_iounmap(QPCIBus *bus, void *data) /* FIXME */ } -#define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL #define SPAPR_PCI_WINDOW_BASE 0x10000000000ULL -#define SPAPR_PCI_WINDOW_SPACING 0x1000000000ULL -#define SPAPR_PCI_MMIO_WIN_OFF 0xA0000000 -#define SPAPR_PCI_MMIO_WIN_SIZE (SPAPR_PCI_WINDOW_SPACING - \ - SPAPR_PCI_MEM_WIN_BUS_OFFSET) +#define SPAPR_PCI_MMIO32_WIN_OFF 0xA0000000 +#define SPAPR_PCI_MMIO32_WIN_SIZE 0x80000000 /* 2 GiB */ #define SPAPR_PCI_IO_WIN_OFF 0x80000000 #define SPAPR_PCI_IO_WIN_SIZE 0x10000 @@ -280,13 +277,14 @@ QPCIBus *qpci_init_spapr(QGuestAllocator *alloc) ret->pio.pci_base = 0; ret->pio.size = SPAPR_PCI_IO_WIN_SIZE; - ret->mmio_cpu_base = SPAPR_PCI_WINDOW_BASE + SPAPR_PCI_MMIO_WIN_OFF; - ret->mmio.pci_base = SPAPR_PCI_MEM_WIN_BUS_OFFSET; - ret->mmio.size = SPAPR_PCI_MMIO_WIN_SIZE; + /* 32-bit portion of the MMIO window is at PCI address 2..4 GiB */ + ret->mmio32_cpu_base = SPAPR_PCI_WINDOW_BASE + SPAPR_PCI_MMIO32_WIN_OFF; + ret->mmio32.pci_base = 0x80000000; /* 2 GiB */ + ret->mmio32.size = SPAPR_PCI_MMIO32_WIN_SIZE; ret->pci_hole_start = 0xC0000000; ret->pci_hole_size = - ret->mmio.pci_base + ret->mmio.size - ret->pci_hole_start; + ret->mmio32.pci_base + ret->mmio32.size - ret->pci_hole_start; ret->pci_hole_alloc = 0; ret->pci_iohole_start = 0xc000; From 6737d9ad79f6db657c7fc5658355aa5045dbfa2c Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 13 Oct 2016 10:26:09 +1100 Subject: [PATCH 704/723] spapr_pci: Delegate placement of PCI host bridges to machine type The 'spapr-pci-host-bridge' represents the virtual PCI host bridge (PHB) for a PAPR guest. Unlike on x86, it's routine on Power (both bare metal and PAPR guests) to have numerous independent PHBs, each controlling a separate PCI domain. There are two ways of configuring the spapr-pci-host-bridge device: first it can be done fully manually, specifying the locations and sizes of all the IO windows. This gives the most control, but is very awkward with 6 mandatory parameters. Alternatively just an "index" can be specified which essentially selects from an array of predefined PHB locations. The PHB at index 0 is automatically created as the default PHB. The current set of default locations causes some problems for guests with large RAM (> 1 TiB) or PCI devices with very large BARs (e.g. big nVidia GPGPU cards via VFIO). Obviously, for migration we can only change the locations on a new machine type, however. This is awkward, because the placement is currently decided within the spapr-pci-host-bridge code, so it breaks abstraction to look inside the machine type version. So, this patch delegates the "default mode" PHB placement from the spapr-pci-host-bridge device back to the machine type via a public method in sPAPRMachineClass. It's still a bit ugly, but it's about the best we can do. For now, this just changes where the calculation is done. It doesn't change the actual location of the host bridges, or any other behaviour. Signed-off-by: David Gibson Reviewed-by: Laurent Vivier --- hw/ppc/spapr.c | 31 +++++++++++++++++++++++++++++++ hw/ppc/spapr_pci.c | 21 +++++++-------------- include/hw/pci-host/spapr.h | 11 +---------- include/hw/ppc/spapr.h | 3 +++ 4 files changed, 42 insertions(+), 24 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index fc4c3c98c8e..2bfd187bc51 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -2370,6 +2370,36 @@ static HotpluggableCPUList *spapr_query_hotpluggable_cpus(MachineState *machine) return head; } +static void spapr_phb_placement(sPAPRMachineState *spapr, uint32_t index, + uint64_t *buid, hwaddr *pio, hwaddr *mmio, + unsigned n_dma, uint32_t *liobns, Error **errp) +{ + const uint64_t base_buid = 0x800000020000000ULL; + const hwaddr phb0_base = 0x10000000000ULL; /* 1 TiB */ + const hwaddr phb_spacing = 0x1000000000ULL; /* 64 GiB */ + const hwaddr mmio_offset = 0xa0000000; /* 2 GiB + 512 MiB */ + const hwaddr pio_offset = 0x80000000; /* 2 GiB */ + const uint32_t max_index = 255; + + hwaddr phb_base; + int i; + + if (index > max_index) { + error_setg(errp, "\"index\" for PAPR PHB is too large (max %u)", + max_index); + return; + } + + *buid = base_buid + index; + for (i = 0; i < n_dma; ++i) { + liobns[i] = SPAPR_PCI_LIOBN(index, i); + } + + phb_base = phb0_base + index * phb_spacing; + *pio = phb_base + pio_offset; + *mmio = phb_base + mmio_offset; +} + static void spapr_machine_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -2406,6 +2436,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) mc->query_hotpluggable_cpus = spapr_query_hotpluggable_cpus; fwc->get_dev_path = spapr_get_fw_dev_path; nc->nmi_monitor_handler = spapr_nmi; + smc->phb_placement = spapr_phb_placement; } static const TypeInfo spapr_machine_info = { diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index a7ca9883879..8bd7f598a0a 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -1311,7 +1311,8 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp) sphb->ddw_enabled ? SPAPR_PCI_DMA_MAX_WINDOWS : 1; if (sphb->index != (uint32_t)-1) { - hwaddr windows_base; + sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr); + Error *local_err = NULL; if ((sphb->buid != (uint64_t)-1) || (sphb->dma_liobn[0] != (uint32_t)-1) || (sphb->dma_liobn[1] != (uint32_t)-1 && windows_supported == 2) @@ -1322,21 +1323,13 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp) return; } - if (sphb->index > SPAPR_PCI_MAX_INDEX) { - error_setg(errp, "\"index\" for PAPR PHB is too large (max %u)", - SPAPR_PCI_MAX_INDEX); + smc->phb_placement(spapr, sphb->index, &sphb->buid, + &sphb->io_win_addr, &sphb->mem_win_addr, + windows_supported, sphb->dma_liobn, &local_err); + if (local_err) { + error_propagate(errp, local_err); return; } - - sphb->buid = SPAPR_PCI_BASE_BUID + sphb->index; - for (i = 0; i < windows_supported; ++i) { - sphb->dma_liobn[i] = SPAPR_PCI_LIOBN(sphb->index, i); - } - - windows_base = SPAPR_PCI_WINDOW_BASE - + sphb->index * SPAPR_PCI_WINDOW_SPACING; - sphb->mem_win_addr = windows_base + SPAPR_PCI_MMIO_WIN_OFF; - sphb->io_win_addr = windows_base + SPAPR_PCI_IO_WIN_OFF; } if (sphb->buid == (uint64_t)-1) { diff --git a/include/hw/pci-host/spapr.h b/include/hw/pci-host/spapr.h index 30dbd461d49..8c9ebfda419 100644 --- a/include/hw/pci-host/spapr.h +++ b/include/hw/pci-host/spapr.h @@ -79,18 +79,9 @@ struct sPAPRPHBState { uint32_t numa_node; }; -#define SPAPR_PCI_MAX_INDEX 255 - -#define SPAPR_PCI_BASE_BUID 0x800000020000000ULL - #define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL -#define SPAPR_PCI_WINDOW_BASE 0x10000000000ULL -#define SPAPR_PCI_WINDOW_SPACING 0x1000000000ULL -#define SPAPR_PCI_MMIO_WIN_OFF 0xA0000000 -#define SPAPR_PCI_MMIO_WIN_SIZE (SPAPR_PCI_WINDOW_SPACING - \ - SPAPR_PCI_MEM_WIN_BUS_OFFSET) -#define SPAPR_PCI_IO_WIN_OFF 0x80000000 +#define SPAPR_PCI_MMIO_WIN_SIZE 0xf80000000 #define SPAPR_PCI_IO_WIN_SIZE 0x10000 #define SPAPR_PCI_MSI_WINDOW 0x40000000000ULL diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index 39dadaa9ce6..a05783cb3f1 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -40,6 +40,9 @@ struct sPAPRMachineClass { bool dr_lmb_enabled; /* enable dynamic-reconfig/hotplug of LMBs */ bool use_ohci_by_default; /* use USB-OHCI instead of XHCI */ const char *tcg_default_cpu; /* which (TCG) CPU to simulate by default */ + void (*phb_placement)(sPAPRMachineState *spapr, uint32_t index, + uint64_t *buid, hwaddr *pio, hwaddr *mmio, + unsigned n_dma, uint32_t *liobns, Error **errp); }; /** From 2efff1c0dd15c8debeb1647d574bec97355cd5e6 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 13 Oct 2016 10:44:34 +1100 Subject: [PATCH 705/723] spapr: Adjust placement of PCI host bridge to allow > 1TiB RAM Currently the default PCI host bridge for the 'pseries' machine type is constructed with its IO windows in the 1TiB..(1TiB + 64GiB) range in guest memory space. This means that if > 1TiB of guest RAM is specified, the RAM will collide with the PCI IO windows, causing serious problems. Problems won't be obvious until guest RAM goes a bit beyond 1TiB, because there's a little unused space at the bottom of the area reserved for PCI, but essentially this means that > 1TiB of RAM has never worked with the pseries machine type. This patch fixes this by altering the placement of PHBs on large-RAM VMs. Instead of always placing the first PHB at 1TiB, it is placed at the next 1 TiB boundary after the maximum RAM address. Technically, this changes behaviour in a migration-breaking way for existing machines with > 1TiB maximum memory, but since having > 1 TiB memory was broken anyway, this seems like a reasonable trade-off. Signed-off-by: David Gibson Reviewed-by: Laurent Vivier --- hw/ppc/spapr.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 2bfd187bc51..d747e586c18 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -2375,15 +2375,27 @@ static void spapr_phb_placement(sPAPRMachineState *spapr, uint32_t index, unsigned n_dma, uint32_t *liobns, Error **errp) { const uint64_t base_buid = 0x800000020000000ULL; - const hwaddr phb0_base = 0x10000000000ULL; /* 1 TiB */ const hwaddr phb_spacing = 0x1000000000ULL; /* 64 GiB */ const hwaddr mmio_offset = 0xa0000000; /* 2 GiB + 512 MiB */ const hwaddr pio_offset = 0x80000000; /* 2 GiB */ const uint32_t max_index = 255; + const hwaddr phb0_alignment = 0x10000000000ULL; /* 1 TiB */ - hwaddr phb_base; + uint64_t ram_top = MACHINE(spapr)->ram_size; + hwaddr phb0_base, phb_base; int i; + /* Do we have hotpluggable memory? */ + if (MACHINE(spapr)->maxram_size > ram_top) { + /* Can't just use maxram_size, because there may be an + * alignment gap between normal and hotpluggable memory + * regions */ + ram_top = spapr->hotplug_memory.base + + memory_region_size(&spapr->hotplug_memory.mr); + } + + phb0_base = QEMU_ALIGN_UP(ram_top, phb0_alignment); + if (index > max_index) { error_setg(errp, "\"index\" for PAPR PHB is too large (max %u)", max_index); From daa23699031693b434ec263b212f77ba505e353e Mon Sep 17 00:00:00 2001 From: David Gibson Date: Tue, 11 Oct 2016 14:23:33 +1100 Subject: [PATCH 706/723] spapr_pci: Add a 64-bit MMIO window On real hardware, and under pHyp, the PCI host bridges on Power machines typically advertise two outbound MMIO windows from the guest's physical memory space to PCI memory space: - A 32-bit window which maps onto 2GiB..4GiB in the PCI address space - A 64-bit window which maps onto a large region somewhere high in PCI address space (traditionally this used an identity mapping from guest physical address to PCI address, but that's not always the case) The qemu implementation in spapr-pci-host-bridge, however, only supports a single outbound MMIO window, however. At least some Linux versions expect the two windows however, so we arranged this window to map onto the PCI memory space from 2 GiB..~64 GiB, then advertised it as two contiguous windows, the "32-bit" window from 2G..4G and the "64-bit" window from 4G..~64G. This approach means, however, that the 64G window is not naturally aligned. In turn this limits the size of the largest BAR we can map (which does have to be naturally aligned) to roughly half of the total window. With some large nVidia GPGPU cards which have huge memory BARs, this is starting to be a problem. This patch adds true support for separate 32-bit and 64-bit outbound MMIO windows to the spapr-pci-host-bridge implementation, each of which can be independently configured. The 32-bit window always maps to 2G.. in PCI space, but the PCI address of the 64-bit window can be configured (it defaults to the same as the guest physical address). So as not to break possible existing configurations, as long as a 64-bit window is not specified, a large single window can be specified. This will appear the same way to the guest as the old approach, although it's now implemented by two contiguous memory regions rather than a single one. For now, this only adds the possibility of 64-bit windows. The default configuration still uses the legacy mode. Signed-off-by: David Gibson Reviewed-by: Laurent Vivier --- hw/ppc/spapr.c | 10 ++++-- hw/ppc/spapr_pci.c | 70 +++++++++++++++++++++++++++++-------- include/hw/pci-host/spapr.h | 8 +++-- include/hw/ppc/spapr.h | 3 +- 4 files changed, 72 insertions(+), 19 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index d747e586c18..ea5d0e66f81 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -2371,7 +2371,8 @@ static HotpluggableCPUList *spapr_query_hotpluggable_cpus(MachineState *machine) } static void spapr_phb_placement(sPAPRMachineState *spapr, uint32_t index, - uint64_t *buid, hwaddr *pio, hwaddr *mmio, + uint64_t *buid, hwaddr *pio, + hwaddr *mmio32, hwaddr *mmio64, unsigned n_dma, uint32_t *liobns, Error **errp) { const uint64_t base_buid = 0x800000020000000ULL; @@ -2409,7 +2410,12 @@ static void spapr_phb_placement(sPAPRMachineState *spapr, uint32_t index, phb_base = phb0_base + index * phb_spacing; *pio = phb_base + pio_offset; - *mmio = phb_base + mmio_offset; + *mmio32 = phb_base + mmio_offset; + /* + * We don't set the 64-bit MMIO window, relying on the PHB's + * fallback behaviour of automatically splitting a large "32-bit" + * window into contiguous 32-bit and 64-bit windows + */ } static void spapr_machine_class_init(ObjectClass *oc, void *data) diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 8bd7f598a0a..10d5de2d707 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -1317,14 +1317,16 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp) if ((sphb->buid != (uint64_t)-1) || (sphb->dma_liobn[0] != (uint32_t)-1) || (sphb->dma_liobn[1] != (uint32_t)-1 && windows_supported == 2) || (sphb->mem_win_addr != (hwaddr)-1) + || (sphb->mem64_win_addr != (hwaddr)-1) || (sphb->io_win_addr != (hwaddr)-1)) { error_setg(errp, "Either \"index\" or other parameters must" " be specified for PAPR PHB, not both"); return; } - smc->phb_placement(spapr, sphb->index, &sphb->buid, - &sphb->io_win_addr, &sphb->mem_win_addr, + smc->phb_placement(spapr, sphb->index, + &sphb->buid, &sphb->io_win_addr, + &sphb->mem_win_addr, &sphb->mem64_win_addr, windows_supported, sphb->dma_liobn, &local_err); if (local_err) { error_propagate(errp, local_err); @@ -1353,6 +1355,38 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp) return; } + if (sphb->mem64_win_size != 0) { + if (sphb->mem64_win_addr == (hwaddr)-1) { + error_setg(errp, + "64-bit memory window address not specified for PHB"); + return; + } + + if (sphb->mem_win_size > SPAPR_PCI_MEM32_WIN_SIZE) { + error_setg(errp, "32-bit memory window of size 0x%"HWADDR_PRIx + " (max 2 GiB)", sphb->mem_win_size); + return; + } + + if (sphb->mem64_win_pciaddr == (hwaddr)-1) { + /* 64-bit window defaults to identity mapping */ + sphb->mem64_win_pciaddr = sphb->mem64_win_addr; + } + } else if (sphb->mem_win_size > SPAPR_PCI_MEM32_WIN_SIZE) { + /* + * For compatibility with old configuration, if no 64-bit MMIO + * window is specified, but the ordinary (32-bit) memory + * window is specified as > 2GiB, we treat it as a 2GiB 32-bit + * window, with a 64-bit MMIO window following on immediately + * afterwards + */ + sphb->mem64_win_size = sphb->mem_win_size - SPAPR_PCI_MEM32_WIN_SIZE; + sphb->mem64_win_addr = sphb->mem_win_addr + SPAPR_PCI_MEM32_WIN_SIZE; + sphb->mem64_win_pciaddr = + SPAPR_PCI_MEM_WIN_BUS_OFFSET + SPAPR_PCI_MEM32_WIN_SIZE; + sphb->mem_win_size = SPAPR_PCI_MEM32_WIN_SIZE; + } + if (spapr_pci_find_phb(spapr, sphb->buid)) { error_setg(errp, "PCI host bridges must have unique BUIDs"); return; @@ -1366,12 +1400,19 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp) sprintf(namebuf, "%s.mmio", sphb->dtbusname); memory_region_init(&sphb->memspace, OBJECT(sphb), namebuf, UINT64_MAX); - sprintf(namebuf, "%s.mmio-alias", sphb->dtbusname); - memory_region_init_alias(&sphb->memwindow, OBJECT(sphb), + sprintf(namebuf, "%s.mmio32-alias", sphb->dtbusname); + memory_region_init_alias(&sphb->mem32window, OBJECT(sphb), namebuf, &sphb->memspace, SPAPR_PCI_MEM_WIN_BUS_OFFSET, sphb->mem_win_size); memory_region_add_subregion(get_system_memory(), sphb->mem_win_addr, - &sphb->memwindow); + &sphb->mem32window); + + sprintf(namebuf, "%s.mmio64-alias", sphb->dtbusname); + memory_region_init_alias(&sphb->mem64window, OBJECT(sphb), + namebuf, &sphb->memspace, + sphb->mem64_win_pciaddr, sphb->mem64_win_size); + memory_region_add_subregion(get_system_memory(), sphb->mem64_win_addr, + &sphb->mem64window); /* Initialize IO regions */ sprintf(namebuf, "%s.io", sphb->dtbusname); @@ -1524,6 +1565,10 @@ static Property spapr_phb_properties[] = { DEFINE_PROP_UINT64("mem_win_addr", sPAPRPHBState, mem_win_addr, -1), DEFINE_PROP_UINT64("mem_win_size", sPAPRPHBState, mem_win_size, SPAPR_PCI_MMIO_WIN_SIZE), + DEFINE_PROP_UINT64("mem64_win_addr", sPAPRPHBState, mem64_win_addr, -1), + DEFINE_PROP_UINT64("mem64_win_size", sPAPRPHBState, mem64_win_size, 0), + DEFINE_PROP_UINT64("mem64_win_pciaddr", sPAPRPHBState, mem64_win_pciaddr, + -1), DEFINE_PROP_UINT64("io_win_addr", sPAPRPHBState, io_win_addr, -1), DEFINE_PROP_UINT64("io_win_size", sPAPRPHBState, io_win_size, SPAPR_PCI_IO_WIN_SIZE), @@ -1759,10 +1804,6 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb, int bus_off, i, j, ret; char nodename[FDT_NAME_MAX]; uint32_t bus_range[] = { cpu_to_be32(0), cpu_to_be32(0xff) }; - const uint64_t mmiosize = memory_region_size(&phb->memwindow); - const uint64_t w32max = (1ULL << 32) - SPAPR_PCI_MEM_WIN_BUS_OFFSET; - const uint64_t w32size = MIN(w32max, mmiosize); - const uint64_t w64size = (mmiosize > w32size) ? (mmiosize - w32size) : 0; struct { uint32_t hi; uint64_t child; @@ -1777,15 +1818,16 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb, { cpu_to_be32(b_ss(2)), cpu_to_be64(SPAPR_PCI_MEM_WIN_BUS_OFFSET), cpu_to_be64(phb->mem_win_addr), - cpu_to_be64(w32size), + cpu_to_be64(phb->mem_win_size), }, { - cpu_to_be32(b_ss(3)), cpu_to_be64(1ULL << 32), - cpu_to_be64(phb->mem_win_addr + w32size), - cpu_to_be64(w64size) + cpu_to_be32(b_ss(3)), cpu_to_be64(phb->mem64_win_pciaddr), + cpu_to_be64(phb->mem64_win_addr), + cpu_to_be64(phb->mem64_win_size), }, }; - const unsigned sizeof_ranges = (w64size ? 3 : 2) * sizeof(ranges[0]); + const unsigned sizeof_ranges = + (phb->mem64_win_size ? 3 : 2) * sizeof(ranges[0]); uint64_t bus_reg[] = { cpu_to_be64(phb->buid), 0 }; uint32_t interrupt_map_mask[] = { cpu_to_be32(b_ddddd(-1)|b_fff(0)), 0x0, 0x0, cpu_to_be32(-1)}; diff --git a/include/hw/pci-host/spapr.h b/include/hw/pci-host/spapr.h index 8c9ebfda419..23dfb09d364 100644 --- a/include/hw/pci-host/spapr.h +++ b/include/hw/pci-host/spapr.h @@ -53,8 +53,10 @@ struct sPAPRPHBState { bool dr_enabled; MemoryRegion memspace, iospace; - hwaddr mem_win_addr, mem_win_size, io_win_addr, io_win_size; - MemoryRegion memwindow, iowindow, msiwindow; + hwaddr mem_win_addr, mem_win_size, mem64_win_addr, mem64_win_size; + uint64_t mem64_win_pciaddr; + hwaddr io_win_addr, io_win_size; + MemoryRegion mem32window, mem64window, iowindow, msiwindow; uint32_t dma_liobn[SPAPR_PCI_DMA_MAX_WINDOWS]; hwaddr dma_win_addr, dma_win_size; @@ -80,6 +82,8 @@ struct sPAPRPHBState { }; #define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL +#define SPAPR_PCI_MEM32_WIN_SIZE \ + ((1ULL << 32) - SPAPR_PCI_MEM_WIN_BUS_OFFSET) #define SPAPR_PCI_MMIO_WIN_SIZE 0xf80000000 #define SPAPR_PCI_IO_WIN_SIZE 0x10000 diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index a05783cb3f1..aeaba3edf9f 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -41,7 +41,8 @@ struct sPAPRMachineClass { bool use_ohci_by_default; /* use USB-OHCI instead of XHCI */ const char *tcg_default_cpu; /* which (TCG) CPU to simulate by default */ void (*phb_placement)(sPAPRMachineState *spapr, uint32_t index, - uint64_t *buid, hwaddr *pio, hwaddr *mmio, + uint64_t *buid, hwaddr *pio, + hwaddr *mmio32, hwaddr *mmio64, unsigned n_dma, uint32_t *liobns, Error **errp); }; From 357d1e3bc7d2d80e5271bc4f3ac8537e30dc8046 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Sun, 16 Oct 2016 12:04:15 +1100 Subject: [PATCH 707/723] spapr: Improved placement of PCI host bridges in guest memory map Currently, the MMIO space for accessing PCI on pseries guests begins at 1 TiB in guest address space. Each PCI host bridge (PHB) has a 64 GiB chunk of address space in which it places its outbound PIO and 32-bit and 64-bit MMIO windows. This scheme as several problems: - It limits guest RAM to 1 TiB (though we have a limited fix for this now) - It limits the total MMIO window to 64 GiB. This is not always enough for some of the large nVidia GPGPU cards - Putting all the windows into a single 64 GiB area means that naturally aligning things within there will waste more address space. In addition there was a miscalculation in some of the defaults, which meant that the MMIO windows for each PHB actually slightly overran the 64 GiB region for that PHB. We got away without nasty consequences because the overrun fit within an unused area at the beginning of the next PHB's region, but it's not pretty. This patch implements a new scheme which addresses those problems, and is also closer to what bare metal hardware and pHyp guests generally use. Because some guest versions (including most current distro kernels) can't access PCI MMIO above 64 TiB, we put all the PCI windows between 32 TiB and 64 TiB. This is broken into 1 TiB chunks. The first 1 TiB contains the PIO (64 kiB) and 32-bit MMIO (2 GiB) windows for all of the PHBs. Each subsequent TiB chunk contains a naturally aligned 64-bit MMIO window for one PHB each. This reduces the number of allowed PHBs (without full manual configuration of all the windows) from 256 to 31, but this should still be plenty in practice. We also change some of the default window sizes for manually configured PHBs to saner values. Finally we adjust some tests and libqos so that it correctly uses the new default locations. Ideally it would parse the device tree given to the guest, but that's a more complex problem for another time. Signed-off-by: David Gibson Reviewed-by: Laurent Vivier --- hw/ppc/spapr.c | 122 +++++++++++++++++++++++++++--------- hw/ppc/spapr_pci.c | 5 +- include/hw/pci-host/spapr.h | 8 ++- tests/endianness-test.c | 3 +- tests/libqos/pci-spapr.c | 9 ++- tests/spapr-phb-test.c | 2 +- 6 files changed, 109 insertions(+), 40 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index ea5d0e66f81..ddb74384348 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -2375,31 +2375,38 @@ static void spapr_phb_placement(sPAPRMachineState *spapr, uint32_t index, hwaddr *mmio32, hwaddr *mmio64, unsigned n_dma, uint32_t *liobns, Error **errp) { + /* + * New-style PHB window placement. + * + * Goals: Gives large (1TiB), naturally aligned 64-bit MMIO window + * for each PHB, in addition to 2GiB 32-bit MMIO and 64kiB PIO + * windows. + * + * Some guest kernels can't work with MMIO windows above 1<<46 + * (64TiB), so we place up to 31 PHBs in the area 32TiB..64TiB + * + * 32TiB..(33TiB+1984kiB) contains the 64kiB PIO windows for each + * PHB stacked together. (32TiB+2GiB)..(32TiB+64GiB) contains the + * 2GiB 32-bit MMIO windows for each PHB. Then 33..64TiB has the + * 1TiB 64-bit MMIO windows for each PHB. + */ const uint64_t base_buid = 0x800000020000000ULL; - const hwaddr phb_spacing = 0x1000000000ULL; /* 64 GiB */ - const hwaddr mmio_offset = 0xa0000000; /* 2 GiB + 512 MiB */ - const hwaddr pio_offset = 0x80000000; /* 2 GiB */ - const uint32_t max_index = 255; - const hwaddr phb0_alignment = 0x10000000000ULL; /* 1 TiB */ - - uint64_t ram_top = MACHINE(spapr)->ram_size; - hwaddr phb0_base, phb_base; + const int max_phbs = + (SPAPR_PCI_LIMIT - SPAPR_PCI_BASE) / SPAPR_PCI_MEM64_WIN_SIZE - 1; int i; - /* Do we have hotpluggable memory? */ - if (MACHINE(spapr)->maxram_size > ram_top) { - /* Can't just use maxram_size, because there may be an - * alignment gap between normal and hotpluggable memory - * regions */ - ram_top = spapr->hotplug_memory.base + - memory_region_size(&spapr->hotplug_memory.mr); - } - - phb0_base = QEMU_ALIGN_UP(ram_top, phb0_alignment); + /* Sanity check natural alignments */ + QEMU_BUILD_BUG_ON((SPAPR_PCI_BASE % SPAPR_PCI_MEM64_WIN_SIZE) != 0); + QEMU_BUILD_BUG_ON((SPAPR_PCI_LIMIT % SPAPR_PCI_MEM64_WIN_SIZE) != 0); + QEMU_BUILD_BUG_ON((SPAPR_PCI_MEM64_WIN_SIZE % SPAPR_PCI_MEM32_WIN_SIZE) != 0); + QEMU_BUILD_BUG_ON((SPAPR_PCI_MEM32_WIN_SIZE % SPAPR_PCI_IO_WIN_SIZE) != 0); + /* Sanity check bounds */ + QEMU_BUILD_BUG_ON((max_phbs * SPAPR_PCI_IO_WIN_SIZE) > SPAPR_PCI_MEM32_WIN_SIZE); + QEMU_BUILD_BUG_ON((max_phbs * SPAPR_PCI_MEM32_WIN_SIZE) > SPAPR_PCI_MEM64_WIN_SIZE); - if (index > max_index) { + if (index >= max_phbs) { error_setg(errp, "\"index\" for PAPR PHB is too large (max %u)", - max_index); + max_phbs - 1); return; } @@ -2408,14 +2415,9 @@ static void spapr_phb_placement(sPAPRMachineState *spapr, uint32_t index, liobns[i] = SPAPR_PCI_LIOBN(index, i); } - phb_base = phb0_base + index * phb_spacing; - *pio = phb_base + pio_offset; - *mmio32 = phb_base + mmio_offset; - /* - * We don't set the 64-bit MMIO window, relying on the PHB's - * fallback behaviour of automatically splitting a large "32-bit" - * window into contiguous 32-bit and 64-bit windows - */ + *pio = SPAPR_PCI_BASE + index * SPAPR_PCI_IO_WIN_SIZE; + *mmio32 = SPAPR_PCI_BASE + (index + 1) * SPAPR_PCI_MEM32_WIN_SIZE; + *mmio64 = SPAPR_PCI_BASE + (index + 1) * SPAPR_PCI_MEM64_WIN_SIZE; } static void spapr_machine_class_init(ObjectClass *oc, void *data) @@ -2519,8 +2521,67 @@ DEFINE_SPAPR_MACHINE(2_8, "2.8", true); /* * pseries-2.7 */ -#define SPAPR_COMPAT_2_7 \ - HW_COMPAT_2_7 \ +#define SPAPR_COMPAT_2_7 \ + HW_COMPAT_2_7 \ + { \ + .driver = TYPE_SPAPR_PCI_HOST_BRIDGE, \ + .property = "mem_win_size", \ + .value = stringify(SPAPR_PCI_2_7_MMIO_WIN_SIZE),\ + }, \ + { \ + .driver = TYPE_SPAPR_PCI_HOST_BRIDGE, \ + .property = "mem64_win_size", \ + .value = "0", \ + }, + +static void phb_placement_2_7(sPAPRMachineState *spapr, uint32_t index, + uint64_t *buid, hwaddr *pio, + hwaddr *mmio32, hwaddr *mmio64, + unsigned n_dma, uint32_t *liobns, Error **errp) +{ + /* Legacy PHB placement for pseries-2.7 and earlier machine types */ + const uint64_t base_buid = 0x800000020000000ULL; + const hwaddr phb_spacing = 0x1000000000ULL; /* 64 GiB */ + const hwaddr mmio_offset = 0xa0000000; /* 2 GiB + 512 MiB */ + const hwaddr pio_offset = 0x80000000; /* 2 GiB */ + const uint32_t max_index = 255; + const hwaddr phb0_alignment = 0x10000000000ULL; /* 1 TiB */ + + uint64_t ram_top = MACHINE(spapr)->ram_size; + hwaddr phb0_base, phb_base; + int i; + + /* Do we have hotpluggable memory? */ + if (MACHINE(spapr)->maxram_size > ram_top) { + /* Can't just use maxram_size, because there may be an + * alignment gap between normal and hotpluggable memory + * regions */ + ram_top = spapr->hotplug_memory.base + + memory_region_size(&spapr->hotplug_memory.mr); + } + + phb0_base = QEMU_ALIGN_UP(ram_top, phb0_alignment); + + if (index > max_index) { + error_setg(errp, "\"index\" for PAPR PHB is too large (max %u)", + max_index); + return; + } + + *buid = base_buid + index; + for (i = 0; i < n_dma; ++i) { + liobns[i] = SPAPR_PCI_LIOBN(index, i); + } + + phb_base = phb0_base + index * phb_spacing; + *pio = phb_base + pio_offset; + *mmio32 = phb_base + mmio_offset; + /* + * We don't set the 64-bit MMIO window, relying on the PHB's + * fallback behaviour of automatically splitting a large "32-bit" + * window into contiguous 32-bit and 64-bit windows + */ +} static void spapr_machine_2_7_instance_options(MachineState *machine) { @@ -2534,6 +2595,7 @@ static void spapr_machine_2_7_class_options(MachineClass *mc) spapr_machine_2_8_class_options(mc); smc->tcg_default_cpu = "POWER7"; SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_7); + smc->phb_placement = phb_placement_2_7; } DEFINE_SPAPR_MACHINE(2_7, "2.7", false); diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 10d5de2d707..2a1ccf59eaa 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -1564,9 +1564,10 @@ static Property spapr_phb_properties[] = { DEFINE_PROP_UINT32("liobn64", sPAPRPHBState, dma_liobn[1], -1), DEFINE_PROP_UINT64("mem_win_addr", sPAPRPHBState, mem_win_addr, -1), DEFINE_PROP_UINT64("mem_win_size", sPAPRPHBState, mem_win_size, - SPAPR_PCI_MMIO_WIN_SIZE), + SPAPR_PCI_MEM32_WIN_SIZE), DEFINE_PROP_UINT64("mem64_win_addr", sPAPRPHBState, mem64_win_addr, -1), - DEFINE_PROP_UINT64("mem64_win_size", sPAPRPHBState, mem64_win_size, 0), + DEFINE_PROP_UINT64("mem64_win_size", sPAPRPHBState, mem64_win_size, + SPAPR_PCI_MEM64_WIN_SIZE), DEFINE_PROP_UINT64("mem64_win_pciaddr", sPAPRPHBState, mem64_win_pciaddr, -1), DEFINE_PROP_UINT64("io_win_addr", sPAPRPHBState, io_win_addr, -1), diff --git a/include/hw/pci-host/spapr.h b/include/hw/pci-host/spapr.h index 23dfb09d364..b92c1b59f14 100644 --- a/include/hw/pci-host/spapr.h +++ b/include/hw/pci-host/spapr.h @@ -84,8 +84,14 @@ struct sPAPRPHBState { #define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL #define SPAPR_PCI_MEM32_WIN_SIZE \ ((1ULL << 32) - SPAPR_PCI_MEM_WIN_BUS_OFFSET) +#define SPAPR_PCI_MEM64_WIN_SIZE 0x10000000000ULL /* 1 TiB */ -#define SPAPR_PCI_MMIO_WIN_SIZE 0xf80000000 +/* Without manual configuration, all PCI outbound windows will be + * within this range */ +#define SPAPR_PCI_BASE (1ULL << 45) /* 32 TiB */ +#define SPAPR_PCI_LIMIT (1ULL << 46) /* 64 TiB */ + +#define SPAPR_PCI_2_7_MMIO_WIN_SIZE 0xf80000000 #define SPAPR_PCI_IO_WIN_SIZE 0x10000 #define SPAPR_PCI_MSI_WINDOW 0x40000000000ULL diff --git a/tests/endianness-test.c b/tests/endianness-test.c index b7a120e0a47..cf8d41b7b47 100644 --- a/tests/endianness-test.c +++ b/tests/endianness-test.c @@ -38,7 +38,8 @@ static const TestCase test_cases[] = { { "ppc", "prep", 0x80000000, .bswap = true }, { "ppc", "bamboo", 0xe8000000, .bswap = true, .superio = "i82378" }, { "ppc64", "mac99", 0xf2000000, .bswap = true, .superio = "i82378" }, - { "ppc64", "pseries", 0x10080000000ULL, + { "ppc64", "pseries", (1ULL << 45), .bswap = true, .superio = "i82378" }, + { "ppc64", "pseries-2.7", 0x10080000000ULL, .bswap = true, .superio = "i82378" }, { "sh4", "r2d", 0xfe240000, .superio = "i82378" }, { "sh4eb", "r2d", 0xfe240000, .bswap = true, .superio = "i82378" }, diff --git a/tests/libqos/pci-spapr.c b/tests/libqos/pci-spapr.c index 558dfc3bdcc..2eaaf9159a1 100644 --- a/tests/libqos/pci-spapr.c +++ b/tests/libqos/pci-spapr.c @@ -235,10 +235,9 @@ static void qpci_spapr_iounmap(QPCIBus *bus, void *data) /* FIXME */ } -#define SPAPR_PCI_WINDOW_BASE 0x10000000000ULL -#define SPAPR_PCI_MMIO32_WIN_OFF 0xA0000000 +#define SPAPR_PCI_BASE (1ULL << 45) + #define SPAPR_PCI_MMIO32_WIN_SIZE 0x80000000 /* 2 GiB */ -#define SPAPR_PCI_IO_WIN_OFF 0x80000000 #define SPAPR_PCI_IO_WIN_SIZE 0x10000 QPCIBus *qpci_init_spapr(QGuestAllocator *alloc) @@ -273,12 +272,12 @@ QPCIBus *qpci_init_spapr(QGuestAllocator *alloc) * get the window locations */ ret->buid = 0x800000020000000ULL; - ret->pio_cpu_base = SPAPR_PCI_WINDOW_BASE + SPAPR_PCI_IO_WIN_OFF; + ret->pio_cpu_base = SPAPR_PCI_BASE; ret->pio.pci_base = 0; ret->pio.size = SPAPR_PCI_IO_WIN_SIZE; /* 32-bit portion of the MMIO window is at PCI address 2..4 GiB */ - ret->mmio32_cpu_base = SPAPR_PCI_WINDOW_BASE + SPAPR_PCI_MMIO32_WIN_OFF; + ret->mmio32_cpu_base = SPAPR_PCI_BASE + SPAPR_PCI_MMIO32_WIN_SIZE; ret->mmio32.pci_base = 0x80000000; /* 2 GiB */ ret->mmio32.size = SPAPR_PCI_MMIO32_WIN_SIZE; diff --git a/tests/spapr-phb-test.c b/tests/spapr-phb-test.c index 21004a76ec1..d3522ea0934 100644 --- a/tests/spapr-phb-test.c +++ b/tests/spapr-phb-test.c @@ -25,7 +25,7 @@ int main(int argc, char **argv) g_test_init(&argc, &argv, NULL); qtest_add_func("/spapr-phb/device", test_phb_device); - qtest_start("-device " TYPE_SPAPR_PCI_HOST_BRIDGE ",index=100"); + qtest_start("-device " TYPE_SPAPR_PCI_HOST_BRIDGE ",index=30"); ret = g_test_run(); From 8b9b3177a2e588db16274b2bf6d390a95e837f80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 11 Oct 2016 17:16:21 +0100 Subject: [PATCH 708/723] tests/docker: add travis dockerfile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This target grabs the latest Travis containers from their repository at quay.io and then installs QEMU's build dependencies. With this it is possible to run on broadly the same setup as they have on travis-ci.org. Signed-off-by: Alex Bennée Message-Id: <20161011161625.9070-2-alex.bennee@linaro.org> Signed-off-by: Fam Zheng --- tests/docker/dockerfiles/travis.docker | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 tests/docker/dockerfiles/travis.docker diff --git a/tests/docker/dockerfiles/travis.docker b/tests/docker/dockerfiles/travis.docker new file mode 100644 index 00000000000..e4983ae2d3b --- /dev/null +++ b/tests/docker/dockerfiles/travis.docker @@ -0,0 +1,6 @@ +FROM quay.io/travisci/travis-ruby +RUN apt-get update +RUN apt-get -y build-dep qemu +RUN apt-get -y build-dep device-tree-compiler +RUN apt-get -y install python2.7 dh-autoreconf +ENV FEATURES pyyaml From bdecba6e978b950873255f5185dcbe2632aaa6fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 11 Oct 2016 17:16:22 +0100 Subject: [PATCH 709/723] tests/docker: test-build script MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Much like test-quick but only builds. This is useful for some of the build targets like ThreadSanitizer that don't yet pass "make check". Signed-off-by: Alex Bennée Message-Id: <20161011161625.9070-3-alex.bennee@linaro.org> Signed-off-by: Fam Zheng --- tests/docker/test-build | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100755 tests/docker/test-build diff --git a/tests/docker/test-build b/tests/docker/test-build new file mode 100755 index 00000000000..031a7d9d302 --- /dev/null +++ b/tests/docker/test-build @@ -0,0 +1,20 @@ +#!/bin/bash -e +# +# Quick compile test without the make check step of test-quick. +# +# Copyright (c) 2016 Red Hat Inc. +# +# Authors: +# Fam Zheng +# +# This work is licensed under the terms of the GNU GPL, version 2 +# or (at your option) any later version. See the COPYING file in +# the top-level directory. + +. common.rc + +cd "$BUILD_DIR" + +DEF_TARGET_LIST="x86_64-softmmu,aarch64-softmmu" +TARGET_LIST=${TARGET_LIST:-$DEF_TARGET_LIST} \ +build_qemu From 86a17cb3f43f987d0b2a65dd41284b4d6e2006cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 11 Oct 2016 17:16:23 +0100 Subject: [PATCH 710/723] tests/docker: make test-mingw honour TARGET_LIST MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The other builders honour this variable, so should the mingw build. Signed-off-by: Alex Bennée Message-Id: <20161011161625.9070-4-alex.bennee@linaro.org> Signed-off-by: Fam Zheng --- tests/docker/test-mingw | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/docker/test-mingw b/tests/docker/test-mingw index 33968769f88..2adadcb58dc 100755 --- a/tests/docker/test-mingw +++ b/tests/docker/test-mingw @@ -16,9 +16,10 @@ requires mingw dtc cd "$BUILD_DIR" +DEF_TARGET_LIST="x86_64-softmmu,aarch64-softmmu" for prefix in x86_64-w64-mingw32- i686-w64-mingw32-; do - TARGET_LIST=x86_64-softmmu,aarch64-softmmu \ + TARGET_LIST=${TARGET_LIST:-$DEF_TARGET_LIST} \ build_qemu --cross-prefix=$prefix \ --enable-trace-backends=simple \ --enable-debug \ From e86c9a64f455018fb04d631e14c5f926e36c69fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 11 Oct 2016 17:16:24 +0100 Subject: [PATCH 711/723] tests/docker/Makefile.include: add a generic docker-run target MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This re-factors the docker makefile to include a docker-run target which can be controlled entirely from environment variables specified on the make command line. This allows us to run against any given docker image we may have in our repository, for example: make docker-run TEST="test-quick" IMAGE="debian:arm64" \ EXECUTABLE=./aarch64-linux-user/qemu-aarch64 The existing docker-foo@bar targets still work but the inline verification has been dropped because we already don't hit that due to other pattern rules in rules.mak. Signed-off-by: Alex Bennée Message-Id: <20161011161625.9070-5-alex.bennee@linaro.org> Message-Id: <20161011161625.9070-6-alex.bennee@linaro.org> [Squash in the verification removal patch. - Fam] Signed-off-by: Fam Zheng --- tests/docker/Makefile.include | 61 ++++++++++++++++++++++------------- 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include index b44daabbce0..3f15d5aea89 100644 --- a/tests/docker/Makefile.include +++ b/tests/docker/Makefile.include @@ -78,6 +78,7 @@ docker: @echo ' "IMAGE" is one of the listed container name."' @echo ' docker-image: Build all images.' @echo ' docker-image-IMAGE: Build image "IMAGE".' + @echo ' docker-run: For manually running a "TEST" with "IMAGE"' @echo @echo 'Available container images:' @echo ' $(DOCKER_IMAGES)' @@ -101,31 +102,45 @@ docker: @echo ' NOCACHE=1 Ignore cache when build images.' @echo ' EXECUTABLE= Include executable in image.' -docker-run-%: CMD = $(shell echo '$@' | sed -e 's/docker-run-\([^@]*\)@\(.*\)/\1/') -docker-run-%: IMAGE = $(shell echo '$@' | sed -e 's/docker-run-\([^@]*\)@\(.*\)/\2/') -docker-run-%: docker-qemu-src +# This rule if for directly running against an arbitrary docker target. +# It is called by the expanded docker targets (e.g. make +# docker-test-foo@bar) which will do additional verification. +# +# For example: make docker-run TEST="test-quick" IMAGE="debian:arm64" EXECUTABLE=./aarch64-linux-user/qemu-aarch64 +# +docker-run: docker-qemu-src @mkdir -p "$(DOCKER_CCACHE_DIR)" - @if test -z "$(IMAGE)" || test -z "$(CMD)"; \ - then echo "Invalid target"; exit 1; \ + @if test -z "$(IMAGE)" || test -z "$(TEST)"; \ + then echo "Invalid target $(IMAGE)/$(TEST)"; exit 1; \ fi - $(if $(filter $(TESTS),$(CMD)),$(if $(filter $(IMAGES),$(IMAGE)), \ - $(call quiet-command,\ - if $(SRC_PATH)/tests/docker/docker.py images | \ - awk '$$1=="qemu" && $$2=="$(IMAGE)"{found=1} END{exit(!found)}'; then \ - $(SRC_PATH)/tests/docker/docker.py run $(if $V,,--rm) \ - -t \ - $(if $(DEBUG),-i,--net=none) \ - -e TARGET_LIST=$(TARGET_LIST) \ - -e EXTRA_CONFIGURE_OPTS=$(EXTRA_CONFIGURE_OPTS) \ - -e V=$V -e J=$J -e DEBUG=$(DEBUG) -e SHOW_ENV=$(SHOW_ENV)\ - -e CCACHE_DIR=/var/tmp/ccache \ - -v $$(readlink -e $(DOCKER_SRC_COPY)):/var/tmp/qemu:z$(COMMA)ro \ - -v $(DOCKER_CCACHE_DIR):/var/tmp/ccache:z \ - qemu:$(IMAGE) \ - /var/tmp/qemu/run \ - $(CMD); \ - fi \ - ,"RUN","$(CMD) in $(IMAGE)"))) + $(if $(EXECUTABLE), \ + $(call quiet-command, \ + $(SRC_PATH)/tests/docker/docker.py update \ + $(IMAGE) $(EXECUTABLE), \ + " COPYING $(EXECUTABLE) to $(IMAGE)")) + $(call quiet-command, \ + $(SRC_PATH)/tests/docker/docker.py run \ + -t \ + $(if $V,,--rm) \ + $(if $(DEBUG),-i,--net=none) \ + -e TARGET_LIST=$(TARGET_LIST) \ + -e EXTRA_CONFIGURE_OPTS="$(EXTRA_CONFIGURE_OPTS)" \ + -e V=$V -e J=$J -e DEBUG=$(DEBUG) \ + -e SHOW_ENV=$(SHOW_ENV) \ + -e CCACHE_DIR=/var/tmp/ccache \ + -v $$(readlink -e $(DOCKER_SRC_COPY)):/var/tmp/qemu:z$(COMMA)ro \ + -v $(DOCKER_CCACHE_DIR):/var/tmp/ccache:z \ + $(IMAGE) \ + /var/tmp/qemu/run \ + $(TEST), " RUN $(TEST) in ${IMAGE}") + +# Run targets: +# +# Of the form docker-TEST-FOO@IMAGE-BAR which will then be expanded into a call to "make docker-run" +docker-run-%: CMD = $(shell echo '$@' | sed -e 's/docker-run-\([^@]*\)@\(.*\)/\1/') +docker-run-%: IMAGE = $(shell echo '$@' | sed -e 's/docker-run-\([^@]*\)@\(.*\)/\2/') +docker-run-%: + @$(MAKE) docker-run TEST=$(CMD) IMAGE=qemu:$(IMAGE) docker-clean: $(call quiet-command, $(SRC_PATH)/tests/docker/docker.py clean) From ba42ebb863ab7d40adc79298422ed9596df8f73a Mon Sep 17 00:00:00 2001 From: Li Qiang Date: Mon, 17 Oct 2016 14:13:58 +0200 Subject: [PATCH 712/723] 9pfs: allocate space for guest originated empty strings If a guest sends an empty string paramater to any 9P operation, the current code unmarshals it into a V9fsString equal to { .size = 0, .data = NULL }. This is unfortunate because it can cause NULL pointer dereference to happen at various locations in the 9pfs code. And we don't want to check str->data everywhere we pass it to strcmp() or any other function which expects a dereferenceable pointer. This patch enforces the allocation of genuine C empty strings instead, so callers don't have to bother. Out of all v9fs_iov_vunmarshal() users, only v9fs_xattrwalk() checks if the returned string is empty. It now uses v9fs_string_size() since name.data cannot be NULL anymore. Signed-off-by: Li Qiang [groug, rewritten title and changelog, fix empty string check in v9fs_xattrwalk()] Signed-off-by: Greg Kurz --- fsdev/9p-iov-marshal.c | 2 +- hw/9pfs/9p.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fsdev/9p-iov-marshal.c b/fsdev/9p-iov-marshal.c index 663cad54290..1d16f8df4bd 100644 --- a/fsdev/9p-iov-marshal.c +++ b/fsdev/9p-iov-marshal.c @@ -125,7 +125,7 @@ ssize_t v9fs_iov_vunmarshal(struct iovec *out_sg, int out_num, size_t offset, str->data = g_malloc(str->size + 1); copied = v9fs_unpack(str->data, out_sg, out_num, offset, str->size); - if (copied > 0) { + if (copied >= 0) { str->data[str->size] = 0; } else { v9fs_string_free(str); diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index 119ee584969..39a7e1d52d2 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -3174,7 +3174,7 @@ static void v9fs_xattrwalk(void *opaque) goto out; } v9fs_path_copy(&xattr_fidp->path, &file_fidp->path); - if (name.data == NULL) { + if (!v9fs_string_size(&name)) { /* * listxattr request. Get the size first */ From e95c9a493a5a8d6f969e86c9f19f80ffe6587e19 Mon Sep 17 00:00:00 2001 From: Li Qiang Date: Mon, 17 Oct 2016 14:13:58 +0200 Subject: [PATCH 713/723] 9pfs: fix potential host memory leak in v9fs_read In 9pfs read dispatch function, it doesn't free two QEMUIOVector object thus causing potential memory leak. This patch avoid this. Signed-off-by: Li Qiang Signed-off-by: Greg Kurz --- hw/9pfs/9p.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index 39a7e1d52d2..ff94a6272c3 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -1826,14 +1826,15 @@ static void v9fs_read(void *opaque) if (len < 0) { /* IO error return the error */ err = len; - goto out; + goto out_free_iovec; } } while (count < max_count && len > 0); err = pdu_marshal(pdu, offset, "d", count); if (err < 0) { - goto out; + goto out_free_iovec; } err += offset + count; +out_free_iovec: qemu_iovec_destroy(&qiov); qemu_iovec_destroy(&qiov_full); } else if (fidp->fid_type == P9_FID_XATTR) { From bc70a5925f1928623b1fcc033f772daa0d0d271f Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Mon, 17 Oct 2016 14:13:58 +0200 Subject: [PATCH 714/723] 9pfs: fsdev: drop useless extern annotation for functions Signed-off-by: Greg Kurz --- fsdev/9p-marshal.h | 6 +-- hw/9pfs/9p-synth.h | 10 ++--- hw/9pfs/9p.h | 18 ++++----- hw/9pfs/coth.h | 94 ++++++++++++++++++++++----------------------- hw/9pfs/virtio-9p.h | 2 +- 5 files changed, 65 insertions(+), 65 deletions(-) diff --git a/fsdev/9p-marshal.h b/fsdev/9p-marshal.h index 77f7fef326e..c8823d878f9 100644 --- a/fsdev/9p-marshal.h +++ b/fsdev/9p-marshal.h @@ -76,8 +76,8 @@ static inline void v9fs_string_init(V9fsString *str) str->data = NULL; str->size = 0; } -extern void v9fs_string_free(V9fsString *str); -extern void v9fs_string_sprintf(V9fsString *str, const char *fmt, ...); -extern void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs); +void v9fs_string_free(V9fsString *str); +void v9fs_string_sprintf(V9fsString *str, const char *fmt, ...); +void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs); #endif diff --git a/hw/9pfs/9p-synth.h b/hw/9pfs/9p-synth.h index 6bcb44ace23..49c2fc7b274 100644 --- a/hw/9pfs/9p-synth.h +++ b/hw/9pfs/9p-synth.h @@ -43,10 +43,10 @@ typedef struct V9fsSynthOpenState { struct dirent dent; } V9fsSynthOpenState; -extern int qemu_v9fs_synth_mkdir(V9fsSynthNode *parent, int mode, - const char *name, V9fsSynthNode **result); -extern int qemu_v9fs_synth_add_file(V9fsSynthNode *parent, int mode, - const char *name, v9fs_synth_read read, - v9fs_synth_write write, void *arg); +int qemu_v9fs_synth_mkdir(V9fsSynthNode *parent, int mode, + const char *name, V9fsSynthNode **result); +int qemu_v9fs_synth_add_file(V9fsSynthNode *parent, int mode, + const char *name, v9fs_synth_read read, + v9fs_synth_write write, void *arg); #endif diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h index d539d2ebe9c..5225b4f1207 100644 --- a/hw/9pfs/9p.h +++ b/hw/9pfs/9p.h @@ -324,15 +324,15 @@ static inline uint8_t v9fs_request_cancelled(V9fsPDU *pdu) return pdu->cancelled; } -extern void v9fs_reclaim_fd(V9fsPDU *pdu); -extern void v9fs_path_init(V9fsPath *path); -extern void v9fs_path_free(V9fsPath *path); -extern void v9fs_path_sprintf(V9fsPath *path, const char *fmt, ...); -extern void v9fs_path_copy(V9fsPath *lhs, V9fsPath *rhs); -extern int v9fs_name_to_path(V9fsState *s, V9fsPath *dirpath, - const char *name, V9fsPath *path); -extern int v9fs_device_realize_common(V9fsState *s, Error **errp); -extern void v9fs_device_unrealize_common(V9fsState *s, Error **errp); +void v9fs_reclaim_fd(V9fsPDU *pdu); +void v9fs_path_init(V9fsPath *path); +void v9fs_path_free(V9fsPath *path); +void v9fs_path_sprintf(V9fsPath *path, const char *fmt, ...); +void v9fs_path_copy(V9fsPath *lhs, V9fsPath *rhs); +int v9fs_name_to_path(V9fsState *s, V9fsPath *dirpath, + const char *name, V9fsPath *path); +int v9fs_device_realize_common(V9fsState *s, Error **errp); +void v9fs_device_unrealize_common(V9fsState *s, Error **errp); ssize_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...); ssize_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...); diff --git a/hw/9pfs/coth.h b/hw/9pfs/coth.h index 3c7424e423d..af6db5e84e3 100644 --- a/hw/9pfs/coth.h +++ b/hw/9pfs/coth.h @@ -47,52 +47,52 @@ qemu_coroutine_yield(); \ } while (0) -extern void co_run_in_worker_bh(void *); -extern int v9fs_co_readlink(V9fsPDU *, V9fsPath *, V9fsString *); -extern int v9fs_co_readdir(V9fsPDU *, V9fsFidState *, struct dirent **); -extern off_t v9fs_co_telldir(V9fsPDU *, V9fsFidState *); -extern void v9fs_co_seekdir(V9fsPDU *, V9fsFidState *, off_t); -extern void v9fs_co_rewinddir(V9fsPDU *, V9fsFidState *); -extern int v9fs_co_statfs(V9fsPDU *, V9fsPath *, struct statfs *); -extern int v9fs_co_lstat(V9fsPDU *, V9fsPath *, struct stat *); -extern int v9fs_co_chmod(V9fsPDU *, V9fsPath *, mode_t); -extern int v9fs_co_utimensat(V9fsPDU *, V9fsPath *, struct timespec [2]); -extern int v9fs_co_chown(V9fsPDU *, V9fsPath *, uid_t, gid_t); -extern int v9fs_co_truncate(V9fsPDU *, V9fsPath *, off_t); -extern int v9fs_co_llistxattr(V9fsPDU *, V9fsPath *, void *, size_t); -extern int v9fs_co_lgetxattr(V9fsPDU *, V9fsPath *, - V9fsString *, void *, size_t); -extern int v9fs_co_mknod(V9fsPDU *, V9fsFidState *, V9fsString *, uid_t, - gid_t, dev_t, mode_t, struct stat *); -extern int v9fs_co_mkdir(V9fsPDU *, V9fsFidState *, V9fsString *, - mode_t, uid_t, gid_t, struct stat *); -extern int v9fs_co_remove(V9fsPDU *, V9fsPath *); -extern int v9fs_co_rename(V9fsPDU *, V9fsPath *, V9fsPath *); -extern int v9fs_co_unlinkat(V9fsPDU *, V9fsPath *, V9fsString *, int flags); -extern int v9fs_co_renameat(V9fsPDU *, V9fsPath *, V9fsString *, - V9fsPath *, V9fsString *); -extern int v9fs_co_fstat(V9fsPDU *, V9fsFidState *, struct stat *); -extern int v9fs_co_opendir(V9fsPDU *, V9fsFidState *); -extern int v9fs_co_open(V9fsPDU *, V9fsFidState *, int); -extern int v9fs_co_open2(V9fsPDU *, V9fsFidState *, V9fsString *, - gid_t, int, int, struct stat *); -extern int v9fs_co_lsetxattr(V9fsPDU *, V9fsPath *, V9fsString *, - void *, size_t, int); -extern int v9fs_co_lremovexattr(V9fsPDU *, V9fsPath *, V9fsString *); -extern int v9fs_co_closedir(V9fsPDU *, V9fsFidOpenState *); -extern int v9fs_co_close(V9fsPDU *, V9fsFidOpenState *); -extern int v9fs_co_fsync(V9fsPDU *, V9fsFidState *, int); -extern int v9fs_co_symlink(V9fsPDU *, V9fsFidState *, V9fsString *, - const char *, gid_t, struct stat *); -extern int v9fs_co_link(V9fsPDU *, V9fsFidState *, - V9fsFidState *, V9fsString *); -extern int v9fs_co_pwritev(V9fsPDU *, V9fsFidState *, - struct iovec *, int, int64_t); -extern int v9fs_co_preadv(V9fsPDU *, V9fsFidState *, - struct iovec *, int, int64_t); -extern int v9fs_co_name_to_path(V9fsPDU *, V9fsPath *, - const char *, V9fsPath *); -extern int v9fs_co_st_gen(V9fsPDU *pdu, V9fsPath *path, mode_t, - V9fsStatDotl *v9stat); +void co_run_in_worker_bh(void *); +int v9fs_co_readlink(V9fsPDU *, V9fsPath *, V9fsString *); +int v9fs_co_readdir(V9fsPDU *, V9fsFidState *, struct dirent **); +off_t v9fs_co_telldir(V9fsPDU *, V9fsFidState *); +void v9fs_co_seekdir(V9fsPDU *, V9fsFidState *, off_t); +void v9fs_co_rewinddir(V9fsPDU *, V9fsFidState *); +int v9fs_co_statfs(V9fsPDU *, V9fsPath *, struct statfs *); +int v9fs_co_lstat(V9fsPDU *, V9fsPath *, struct stat *); +int v9fs_co_chmod(V9fsPDU *, V9fsPath *, mode_t); +int v9fs_co_utimensat(V9fsPDU *, V9fsPath *, struct timespec [2]); +int v9fs_co_chown(V9fsPDU *, V9fsPath *, uid_t, gid_t); +int v9fs_co_truncate(V9fsPDU *, V9fsPath *, off_t); +int v9fs_co_llistxattr(V9fsPDU *, V9fsPath *, void *, size_t); +int v9fs_co_lgetxattr(V9fsPDU *, V9fsPath *, + V9fsString *, void *, size_t); +int v9fs_co_mknod(V9fsPDU *, V9fsFidState *, V9fsString *, uid_t, + gid_t, dev_t, mode_t, struct stat *); +int v9fs_co_mkdir(V9fsPDU *, V9fsFidState *, V9fsString *, + mode_t, uid_t, gid_t, struct stat *); +int v9fs_co_remove(V9fsPDU *, V9fsPath *); +int v9fs_co_rename(V9fsPDU *, V9fsPath *, V9fsPath *); +int v9fs_co_unlinkat(V9fsPDU *, V9fsPath *, V9fsString *, int flags); +int v9fs_co_renameat(V9fsPDU *, V9fsPath *, V9fsString *, + V9fsPath *, V9fsString *); +int v9fs_co_fstat(V9fsPDU *, V9fsFidState *, struct stat *); +int v9fs_co_opendir(V9fsPDU *, V9fsFidState *); +int v9fs_co_open(V9fsPDU *, V9fsFidState *, int); +int v9fs_co_open2(V9fsPDU *, V9fsFidState *, V9fsString *, + gid_t, int, int, struct stat *); +int v9fs_co_lsetxattr(V9fsPDU *, V9fsPath *, V9fsString *, + void *, size_t, int); +int v9fs_co_lremovexattr(V9fsPDU *, V9fsPath *, V9fsString *); +int v9fs_co_closedir(V9fsPDU *, V9fsFidOpenState *); +int v9fs_co_close(V9fsPDU *, V9fsFidOpenState *); +int v9fs_co_fsync(V9fsPDU *, V9fsFidState *, int); +int v9fs_co_symlink(V9fsPDU *, V9fsFidState *, V9fsString *, + const char *, gid_t, struct stat *); +int v9fs_co_link(V9fsPDU *, V9fsFidState *, + V9fsFidState *, V9fsString *); +int v9fs_co_pwritev(V9fsPDU *, V9fsFidState *, + struct iovec *, int, int64_t); +int v9fs_co_preadv(V9fsPDU *, V9fsFidState *, + struct iovec *, int, int64_t); +int v9fs_co_name_to_path(V9fsPDU *, V9fsPath *, + const char *, V9fsPath *); +int v9fs_co_st_gen(V9fsPDU *pdu, V9fsPath *path, mode_t, + V9fsStatDotl *v9stat); #endif diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h index 7586b792d61..25c47c7cb6d 100644 --- a/hw/9pfs/virtio-9p.h +++ b/hw/9pfs/virtio-9p.h @@ -15,7 +15,7 @@ typedef struct V9fsVirtioState V9fsState state; } V9fsVirtioState; -extern void virtio_9p_push_and_notify(V9fsPDU *pdu); +void virtio_9p_push_and_notify(V9fsPDU *pdu); ssize_t virtio_pdu_vmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, va_list ap); From 5bdade66211c8023d8e81c535f4944cbf830b25a Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Mon, 17 Oct 2016 14:13:58 +0200 Subject: [PATCH 715/723] 9pfs: use coroutine_fn annotation in hw/9pfs/co*.[ch] All these functions use the v9fs_co_run_in_worker() macro, and thus always call qemu_coroutine_self() and qemu_coroutine_yield(). Let's mark them to make it obvious they execute in coroutine context. Signed-off-by: Greg Kurz --- hw/9pfs/codir.c | 17 +++++---- hw/9pfs/cofile.c | 32 ++++++++-------- hw/9pfs/cofs.c | 43 +++++++++++++--------- hw/9pfs/coth.h | 93 ++++++++++++++++++++++++----------------------- hw/9pfs/coxattr.c | 19 +++++----- 5 files changed, 109 insertions(+), 95 deletions(-) diff --git a/hw/9pfs/codir.c b/hw/9pfs/codir.c index d91f9ad6eb9..7cd6fce1ad3 100644 --- a/hw/9pfs/codir.c +++ b/hw/9pfs/codir.c @@ -17,7 +17,8 @@ #include "qemu/coroutine.h" #include "coth.h" -int v9fs_co_readdir(V9fsPDU *pdu, V9fsFidState *fidp, struct dirent **dent) +int coroutine_fn v9fs_co_readdir(V9fsPDU *pdu, V9fsFidState *fidp, + struct dirent **dent) { int err; V9fsState *s = pdu->s; @@ -59,7 +60,8 @@ off_t v9fs_co_telldir(V9fsPDU *pdu, V9fsFidState *fidp) return err; } -void v9fs_co_seekdir(V9fsPDU *pdu, V9fsFidState *fidp, off_t offset) +void coroutine_fn v9fs_co_seekdir(V9fsPDU *pdu, V9fsFidState *fidp, + off_t offset) { V9fsState *s = pdu->s; if (v9fs_request_cancelled(pdu)) { @@ -71,7 +73,7 @@ void v9fs_co_seekdir(V9fsPDU *pdu, V9fsFidState *fidp, off_t offset) }); } -void v9fs_co_rewinddir(V9fsPDU *pdu, V9fsFidState *fidp) +void coroutine_fn v9fs_co_rewinddir(V9fsPDU *pdu, V9fsFidState *fidp) { V9fsState *s = pdu->s; if (v9fs_request_cancelled(pdu)) { @@ -83,8 +85,9 @@ void v9fs_co_rewinddir(V9fsPDU *pdu, V9fsFidState *fidp) }); } -int v9fs_co_mkdir(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name, - mode_t mode, uid_t uid, gid_t gid, struct stat *stbuf) +int coroutine_fn v9fs_co_mkdir(V9fsPDU *pdu, V9fsFidState *fidp, + V9fsString *name, mode_t mode, uid_t uid, + gid_t gid, struct stat *stbuf) { int err; FsCred cred; @@ -120,7 +123,7 @@ int v9fs_co_mkdir(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name, return err; } -int v9fs_co_opendir(V9fsPDU *pdu, V9fsFidState *fidp) +int coroutine_fn v9fs_co_opendir(V9fsPDU *pdu, V9fsFidState *fidp) { int err; V9fsState *s = pdu->s; @@ -148,7 +151,7 @@ int v9fs_co_opendir(V9fsPDU *pdu, V9fsFidState *fidp) return err; } -int v9fs_co_closedir(V9fsPDU *pdu, V9fsFidOpenState *fs) +int coroutine_fn v9fs_co_closedir(V9fsPDU *pdu, V9fsFidOpenState *fs) { int err; V9fsState *s = pdu->s; diff --git a/hw/9pfs/cofile.c b/hw/9pfs/cofile.c index 10343c0a93b..120e2671080 100644 --- a/hw/9pfs/cofile.c +++ b/hw/9pfs/cofile.c @@ -17,8 +17,8 @@ #include "qemu/coroutine.h" #include "coth.h" -int v9fs_co_st_gen(V9fsPDU *pdu, V9fsPath *path, mode_t st_mode, - V9fsStatDotl *v9stat) +int coroutine_fn v9fs_co_st_gen(V9fsPDU *pdu, V9fsPath *path, mode_t st_mode, + V9fsStatDotl *v9stat) { int err = 0; V9fsState *s = pdu->s; @@ -41,7 +41,7 @@ int v9fs_co_st_gen(V9fsPDU *pdu, V9fsPath *path, mode_t st_mode, return err; } -int v9fs_co_lstat(V9fsPDU *pdu, V9fsPath *path, struct stat *stbuf) +int coroutine_fn v9fs_co_lstat(V9fsPDU *pdu, V9fsPath *path, struct stat *stbuf) { int err; V9fsState *s = pdu->s; @@ -61,7 +61,8 @@ int v9fs_co_lstat(V9fsPDU *pdu, V9fsPath *path, struct stat *stbuf) return err; } -int v9fs_co_fstat(V9fsPDU *pdu, V9fsFidState *fidp, struct stat *stbuf) +int coroutine_fn v9fs_co_fstat(V9fsPDU *pdu, V9fsFidState *fidp, + struct stat *stbuf) { int err; V9fsState *s = pdu->s; @@ -93,7 +94,7 @@ int v9fs_co_fstat(V9fsPDU *pdu, V9fsFidState *fidp, struct stat *stbuf) return err; } -int v9fs_co_open(V9fsPDU *pdu, V9fsFidState *fidp, int flags) +int coroutine_fn v9fs_co_open(V9fsPDU *pdu, V9fsFidState *fidp, int flags) { int err; V9fsState *s = pdu->s; @@ -121,8 +122,9 @@ int v9fs_co_open(V9fsPDU *pdu, V9fsFidState *fidp, int flags) return err; } -int v9fs_co_open2(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name, gid_t gid, - int flags, int mode, struct stat *stbuf) +int coroutine_fn v9fs_co_open2(V9fsPDU *pdu, V9fsFidState *fidp, + V9fsString *name, gid_t gid, int flags, int mode, + struct stat *stbuf) { int err; FsCred cred; @@ -175,7 +177,7 @@ int v9fs_co_open2(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name, gid_t gid, return err; } -int v9fs_co_close(V9fsPDU *pdu, V9fsFidOpenState *fs) +int coroutine_fn v9fs_co_close(V9fsPDU *pdu, V9fsFidOpenState *fs) { int err; V9fsState *s = pdu->s; @@ -196,7 +198,7 @@ int v9fs_co_close(V9fsPDU *pdu, V9fsFidOpenState *fs) return err; } -int v9fs_co_fsync(V9fsPDU *pdu, V9fsFidState *fidp, int datasync) +int coroutine_fn v9fs_co_fsync(V9fsPDU *pdu, V9fsFidState *fidp, int datasync) { int err; V9fsState *s = pdu->s; @@ -214,8 +216,8 @@ int v9fs_co_fsync(V9fsPDU *pdu, V9fsFidState *fidp, int datasync) return err; } -int v9fs_co_link(V9fsPDU *pdu, V9fsFidState *oldfid, - V9fsFidState *newdirfid, V9fsString *name) +int coroutine_fn v9fs_co_link(V9fsPDU *pdu, V9fsFidState *oldfid, + V9fsFidState *newdirfid, V9fsString *name) { int err; V9fsState *s = pdu->s; @@ -236,8 +238,8 @@ int v9fs_co_link(V9fsPDU *pdu, V9fsFidState *oldfid, return err; } -int v9fs_co_pwritev(V9fsPDU *pdu, V9fsFidState *fidp, - struct iovec *iov, int iovcnt, int64_t offset) +int coroutine_fn v9fs_co_pwritev(V9fsPDU *pdu, V9fsFidState *fidp, + struct iovec *iov, int iovcnt, int64_t offset) { int err; V9fsState *s = pdu->s; @@ -255,8 +257,8 @@ int v9fs_co_pwritev(V9fsPDU *pdu, V9fsFidState *fidp, return err; } -int v9fs_co_preadv(V9fsPDU *pdu, V9fsFidState *fidp, - struct iovec *iov, int iovcnt, int64_t offset) +int coroutine_fn v9fs_co_preadv(V9fsPDU *pdu, V9fsFidState *fidp, + struct iovec *iov, int iovcnt, int64_t offset) { int err; V9fsState *s = pdu->s; diff --git a/hw/9pfs/cofs.c b/hw/9pfs/cofs.c index 70f584fcbd2..c62103221d2 100644 --- a/hw/9pfs/cofs.c +++ b/hw/9pfs/cofs.c @@ -49,7 +49,7 @@ static ssize_t __readlink(V9fsState *s, V9fsPath *path, V9fsString *buf) return len; } -int v9fs_co_readlink(V9fsPDU *pdu, V9fsPath *path, V9fsString *buf) +int coroutine_fn v9fs_co_readlink(V9fsPDU *pdu, V9fsPath *path, V9fsString *buf) { int err; V9fsState *s = pdu->s; @@ -69,7 +69,8 @@ int v9fs_co_readlink(V9fsPDU *pdu, V9fsPath *path, V9fsString *buf) return err; } -int v9fs_co_statfs(V9fsPDU *pdu, V9fsPath *path, struct statfs *stbuf) +int coroutine_fn v9fs_co_statfs(V9fsPDU *pdu, V9fsPath *path, + struct statfs *stbuf) { int err; V9fsState *s = pdu->s; @@ -89,7 +90,7 @@ int v9fs_co_statfs(V9fsPDU *pdu, V9fsPath *path, struct statfs *stbuf) return err; } -int v9fs_co_chmod(V9fsPDU *pdu, V9fsPath *path, mode_t mode) +int coroutine_fn v9fs_co_chmod(V9fsPDU *pdu, V9fsPath *path, mode_t mode) { int err; FsCred cred; @@ -112,8 +113,8 @@ int v9fs_co_chmod(V9fsPDU *pdu, V9fsPath *path, mode_t mode) return err; } -int v9fs_co_utimensat(V9fsPDU *pdu, V9fsPath *path, - struct timespec times[2]) +int coroutine_fn v9fs_co_utimensat(V9fsPDU *pdu, V9fsPath *path, + struct timespec times[2]) { int err; V9fsState *s = pdu->s; @@ -133,7 +134,8 @@ int v9fs_co_utimensat(V9fsPDU *pdu, V9fsPath *path, return err; } -int v9fs_co_chown(V9fsPDU *pdu, V9fsPath *path, uid_t uid, gid_t gid) +int coroutine_fn v9fs_co_chown(V9fsPDU *pdu, V9fsPath *path, uid_t uid, + gid_t gid) { int err; FsCred cred; @@ -157,7 +159,7 @@ int v9fs_co_chown(V9fsPDU *pdu, V9fsPath *path, uid_t uid, gid_t gid) return err; } -int v9fs_co_truncate(V9fsPDU *pdu, V9fsPath *path, off_t size) +int coroutine_fn v9fs_co_truncate(V9fsPDU *pdu, V9fsPath *path, off_t size) { int err; V9fsState *s = pdu->s; @@ -177,8 +179,9 @@ int v9fs_co_truncate(V9fsPDU *pdu, V9fsPath *path, off_t size) return err; } -int v9fs_co_mknod(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name, uid_t uid, - gid_t gid, dev_t dev, mode_t mode, struct stat *stbuf) +int coroutine_fn v9fs_co_mknod(V9fsPDU *pdu, V9fsFidState *fidp, + V9fsString *name, uid_t uid, gid_t gid, + dev_t dev, mode_t mode, struct stat *stbuf) { int err; V9fsPath path; @@ -216,7 +219,7 @@ int v9fs_co_mknod(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name, uid_t uid, } /* Only works with path name based fid */ -int v9fs_co_remove(V9fsPDU *pdu, V9fsPath *path) +int coroutine_fn v9fs_co_remove(V9fsPDU *pdu, V9fsPath *path) { int err; V9fsState *s = pdu->s; @@ -236,7 +239,8 @@ int v9fs_co_remove(V9fsPDU *pdu, V9fsPath *path) return err; } -int v9fs_co_unlinkat(V9fsPDU *pdu, V9fsPath *path, V9fsString *name, int flags) +int coroutine_fn v9fs_co_unlinkat(V9fsPDU *pdu, V9fsPath *path, + V9fsString *name, int flags) { int err; V9fsState *s = pdu->s; @@ -257,7 +261,8 @@ int v9fs_co_unlinkat(V9fsPDU *pdu, V9fsPath *path, V9fsString *name, int flags) } /* Only work with path name based fid */ -int v9fs_co_rename(V9fsPDU *pdu, V9fsPath *oldpath, V9fsPath *newpath) +int coroutine_fn v9fs_co_rename(V9fsPDU *pdu, V9fsPath *oldpath, + V9fsPath *newpath) { int err; V9fsState *s = pdu->s; @@ -275,8 +280,9 @@ int v9fs_co_rename(V9fsPDU *pdu, V9fsPath *oldpath, V9fsPath *newpath) return err; } -int v9fs_co_renameat(V9fsPDU *pdu, V9fsPath *olddirpath, V9fsString *oldname, - V9fsPath *newdirpath, V9fsString *newname) +int coroutine_fn v9fs_co_renameat(V9fsPDU *pdu, V9fsPath *olddirpath, + V9fsString *oldname, V9fsPath *newdirpath, + V9fsString *newname) { int err; V9fsState *s = pdu->s; @@ -295,8 +301,9 @@ int v9fs_co_renameat(V9fsPDU *pdu, V9fsPath *olddirpath, V9fsString *oldname, return err; } -int v9fs_co_symlink(V9fsPDU *pdu, V9fsFidState *dfidp, V9fsString *name, - const char *oldpath, gid_t gid, struct stat *stbuf) +int coroutine_fn v9fs_co_symlink(V9fsPDU *pdu, V9fsFidState *dfidp, + V9fsString *name, const char *oldpath, + gid_t gid, struct stat *stbuf) { int err; FsCred cred; @@ -337,8 +344,8 @@ int v9fs_co_symlink(V9fsPDU *pdu, V9fsFidState *dfidp, V9fsString *name, * For path name based fid we don't block. So we can * directly call the fs driver ops. */ -int v9fs_co_name_to_path(V9fsPDU *pdu, V9fsPath *dirpath, - const char *name, V9fsPath *path) +int coroutine_fn v9fs_co_name_to_path(V9fsPDU *pdu, V9fsPath *dirpath, + const char *name, V9fsPath *path) { int err; V9fsState *s = pdu->s; diff --git a/hw/9pfs/coth.h b/hw/9pfs/coth.h index af6db5e84e3..19e4d9287ee 100644 --- a/hw/9pfs/coth.h +++ b/hw/9pfs/coth.h @@ -48,51 +48,52 @@ } while (0) void co_run_in_worker_bh(void *); -int v9fs_co_readlink(V9fsPDU *, V9fsPath *, V9fsString *); -int v9fs_co_readdir(V9fsPDU *, V9fsFidState *, struct dirent **); -off_t v9fs_co_telldir(V9fsPDU *, V9fsFidState *); -void v9fs_co_seekdir(V9fsPDU *, V9fsFidState *, off_t); -void v9fs_co_rewinddir(V9fsPDU *, V9fsFidState *); -int v9fs_co_statfs(V9fsPDU *, V9fsPath *, struct statfs *); -int v9fs_co_lstat(V9fsPDU *, V9fsPath *, struct stat *); -int v9fs_co_chmod(V9fsPDU *, V9fsPath *, mode_t); -int v9fs_co_utimensat(V9fsPDU *, V9fsPath *, struct timespec [2]); -int v9fs_co_chown(V9fsPDU *, V9fsPath *, uid_t, gid_t); -int v9fs_co_truncate(V9fsPDU *, V9fsPath *, off_t); -int v9fs_co_llistxattr(V9fsPDU *, V9fsPath *, void *, size_t); -int v9fs_co_lgetxattr(V9fsPDU *, V9fsPath *, - V9fsString *, void *, size_t); -int v9fs_co_mknod(V9fsPDU *, V9fsFidState *, V9fsString *, uid_t, - gid_t, dev_t, mode_t, struct stat *); -int v9fs_co_mkdir(V9fsPDU *, V9fsFidState *, V9fsString *, - mode_t, uid_t, gid_t, struct stat *); -int v9fs_co_remove(V9fsPDU *, V9fsPath *); -int v9fs_co_rename(V9fsPDU *, V9fsPath *, V9fsPath *); -int v9fs_co_unlinkat(V9fsPDU *, V9fsPath *, V9fsString *, int flags); -int v9fs_co_renameat(V9fsPDU *, V9fsPath *, V9fsString *, - V9fsPath *, V9fsString *); -int v9fs_co_fstat(V9fsPDU *, V9fsFidState *, struct stat *); -int v9fs_co_opendir(V9fsPDU *, V9fsFidState *); -int v9fs_co_open(V9fsPDU *, V9fsFidState *, int); -int v9fs_co_open2(V9fsPDU *, V9fsFidState *, V9fsString *, - gid_t, int, int, struct stat *); -int v9fs_co_lsetxattr(V9fsPDU *, V9fsPath *, V9fsString *, - void *, size_t, int); -int v9fs_co_lremovexattr(V9fsPDU *, V9fsPath *, V9fsString *); -int v9fs_co_closedir(V9fsPDU *, V9fsFidOpenState *); -int v9fs_co_close(V9fsPDU *, V9fsFidOpenState *); -int v9fs_co_fsync(V9fsPDU *, V9fsFidState *, int); -int v9fs_co_symlink(V9fsPDU *, V9fsFidState *, V9fsString *, - const char *, gid_t, struct stat *); -int v9fs_co_link(V9fsPDU *, V9fsFidState *, - V9fsFidState *, V9fsString *); -int v9fs_co_pwritev(V9fsPDU *, V9fsFidState *, - struct iovec *, int, int64_t); -int v9fs_co_preadv(V9fsPDU *, V9fsFidState *, - struct iovec *, int, int64_t); -int v9fs_co_name_to_path(V9fsPDU *, V9fsPath *, - const char *, V9fsPath *); -int v9fs_co_st_gen(V9fsPDU *pdu, V9fsPath *path, mode_t, - V9fsStatDotl *v9stat); +int coroutine_fn v9fs_co_readlink(V9fsPDU *, V9fsPath *, V9fsString *); +int coroutine_fn v9fs_co_readdir(V9fsPDU *, V9fsFidState *, struct dirent **); +off_t coroutine_fn v9fs_co_telldir(V9fsPDU *, V9fsFidState *); +void coroutine_fn v9fs_co_seekdir(V9fsPDU *, V9fsFidState *, off_t); +void coroutine_fn v9fs_co_rewinddir(V9fsPDU *, V9fsFidState *); +int coroutine_fn v9fs_co_statfs(V9fsPDU *, V9fsPath *, struct statfs *); +int coroutine_fn v9fs_co_lstat(V9fsPDU *, V9fsPath *, struct stat *); +int coroutine_fn v9fs_co_chmod(V9fsPDU *, V9fsPath *, mode_t); +int coroutine_fn v9fs_co_utimensat(V9fsPDU *, V9fsPath *, struct timespec [2]); +int coroutine_fn v9fs_co_chown(V9fsPDU *, V9fsPath *, uid_t, gid_t); +int coroutine_fn v9fs_co_truncate(V9fsPDU *, V9fsPath *, off_t); +int coroutine_fn v9fs_co_llistxattr(V9fsPDU *, V9fsPath *, void *, size_t); +int coroutine_fn v9fs_co_lgetxattr(V9fsPDU *, V9fsPath *, + V9fsString *, void *, size_t); +int coroutine_fn v9fs_co_mknod(V9fsPDU *, V9fsFidState *, V9fsString *, uid_t, + gid_t, dev_t, mode_t, struct stat *); +int coroutine_fn v9fs_co_mkdir(V9fsPDU *, V9fsFidState *, V9fsString *, + mode_t, uid_t, gid_t, struct stat *); +int coroutine_fn v9fs_co_remove(V9fsPDU *, V9fsPath *); +int coroutine_fn v9fs_co_rename(V9fsPDU *, V9fsPath *, V9fsPath *); +int coroutine_fn v9fs_co_unlinkat(V9fsPDU *, V9fsPath *, V9fsString *, + int flags); +int coroutine_fn v9fs_co_renameat(V9fsPDU *, V9fsPath *, V9fsString *, + V9fsPath *, V9fsString *); +int coroutine_fn v9fs_co_fstat(V9fsPDU *, V9fsFidState *, struct stat *); +int coroutine_fn v9fs_co_opendir(V9fsPDU *, V9fsFidState *); +int coroutine_fn v9fs_co_open(V9fsPDU *, V9fsFidState *, int); +int coroutine_fn v9fs_co_open2(V9fsPDU *, V9fsFidState *, V9fsString *, + gid_t, int, int, struct stat *); +int coroutine_fn v9fs_co_lsetxattr(V9fsPDU *, V9fsPath *, V9fsString *, + void *, size_t, int); +int coroutine_fn v9fs_co_lremovexattr(V9fsPDU *, V9fsPath *, V9fsString *); +int coroutine_fn v9fs_co_closedir(V9fsPDU *, V9fsFidOpenState *); +int coroutine_fn v9fs_co_close(V9fsPDU *, V9fsFidOpenState *); +int coroutine_fn v9fs_co_fsync(V9fsPDU *, V9fsFidState *, int); +int coroutine_fn v9fs_co_symlink(V9fsPDU *, V9fsFidState *, V9fsString *, + const char *, gid_t, struct stat *); +int coroutine_fn v9fs_co_link(V9fsPDU *, V9fsFidState *, + V9fsFidState *, V9fsString *); +int coroutine_fn v9fs_co_pwritev(V9fsPDU *, V9fsFidState *, + struct iovec *, int, int64_t); +int coroutine_fn v9fs_co_preadv(V9fsPDU *, V9fsFidState *, + struct iovec *, int, int64_t); +int coroutine_fn v9fs_co_name_to_path(V9fsPDU *, V9fsPath *, + const char *, V9fsPath *); +int coroutine_fn v9fs_co_st_gen(V9fsPDU *pdu, V9fsPath *path, mode_t, + V9fsStatDotl *v9stat); #endif diff --git a/hw/9pfs/coxattr.c b/hw/9pfs/coxattr.c index 133c4ead37b..154392eade7 100644 --- a/hw/9pfs/coxattr.c +++ b/hw/9pfs/coxattr.c @@ -17,7 +17,8 @@ #include "qemu/coroutine.h" #include "coth.h" -int v9fs_co_llistxattr(V9fsPDU *pdu, V9fsPath *path, void *value, size_t size) +int coroutine_fn v9fs_co_llistxattr(V9fsPDU *pdu, V9fsPath *path, void *value, + size_t size) { int err; V9fsState *s = pdu->s; @@ -37,9 +38,9 @@ int v9fs_co_llistxattr(V9fsPDU *pdu, V9fsPath *path, void *value, size_t size) return err; } -int v9fs_co_lgetxattr(V9fsPDU *pdu, V9fsPath *path, - V9fsString *xattr_name, - void *value, size_t size) +int coroutine_fn v9fs_co_lgetxattr(V9fsPDU *pdu, V9fsPath *path, + V9fsString *xattr_name, void *value, + size_t size) { int err; V9fsState *s = pdu->s; @@ -61,9 +62,9 @@ int v9fs_co_lgetxattr(V9fsPDU *pdu, V9fsPath *path, return err; } -int v9fs_co_lsetxattr(V9fsPDU *pdu, V9fsPath *path, - V9fsString *xattr_name, void *value, - size_t size, int flags) +int coroutine_fn v9fs_co_lsetxattr(V9fsPDU *pdu, V9fsPath *path, + V9fsString *xattr_name, void *value, + size_t size, int flags) { int err; V9fsState *s = pdu->s; @@ -85,8 +86,8 @@ int v9fs_co_lsetxattr(V9fsPDU *pdu, V9fsPath *path, return err; } -int v9fs_co_lremovexattr(V9fsPDU *pdu, V9fsPath *path, - V9fsString *xattr_name) +int coroutine_fn v9fs_co_lremovexattr(V9fsPDU *pdu, V9fsPath *path, + V9fsString *xattr_name) { int err; V9fsState *s = pdu->s; From 8440e22ec1a5deabc4fcf5c4826d5c73ddc15765 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Mon, 17 Oct 2016 14:13:58 +0200 Subject: [PATCH 716/723] 9pfs: use coroutine_fn annotation in hw/9pfs/9p.[ch] All these functions either call the v9fs_co_* functions which have the coroutine_fn annotation, or pdu_complete() which calls qemu_co_queue_next(). Let's mark them to make it obvious they execute in coroutine context. Signed-off-by: Greg Kurz --- hw/9pfs/9p.c | 117 +++++++++++++++++++++++++++------------------------ hw/9pfs/9p.h | 2 +- 2 files changed, 62 insertions(+), 57 deletions(-) diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index ff94a6272c3..f2ab1dfab2b 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -236,7 +236,7 @@ static size_t v9fs_string_size(V9fsString *str) /* * returns 0 if fid got re-opened, 1 if not, < 0 on error */ -static int v9fs_reopen_fid(V9fsPDU *pdu, V9fsFidState *f) +static int coroutine_fn v9fs_reopen_fid(V9fsPDU *pdu, V9fsFidState *f) { int err = 1; if (f->fid_type == P9_FID_FILE) { @@ -255,7 +255,7 @@ static int v9fs_reopen_fid(V9fsPDU *pdu, V9fsFidState *f) return err; } -static V9fsFidState *get_fid(V9fsPDU *pdu, int32_t fid) +static V9fsFidState *coroutine_fn get_fid(V9fsPDU *pdu, int32_t fid) { int err; V9fsFidState *f; @@ -321,7 +321,7 @@ static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid) return f; } -static int v9fs_xattr_fid_clunk(V9fsPDU *pdu, V9fsFidState *fidp) +static int coroutine_fn v9fs_xattr_fid_clunk(V9fsPDU *pdu, V9fsFidState *fidp) { int retval = 0; @@ -353,7 +353,7 @@ static int v9fs_xattr_fid_clunk(V9fsPDU *pdu, V9fsFidState *fidp) return retval; } -static int free_fid(V9fsPDU *pdu, V9fsFidState *fidp) +static int coroutine_fn free_fid(V9fsPDU *pdu, V9fsFidState *fidp) { int retval = 0; @@ -374,7 +374,7 @@ static int free_fid(V9fsPDU *pdu, V9fsFidState *fidp) return retval; } -static int put_fid(V9fsPDU *pdu, V9fsFidState *fidp) +static int coroutine_fn put_fid(V9fsPDU *pdu, V9fsFidState *fidp) { BUG_ON(!fidp->ref); fidp->ref--; @@ -418,7 +418,7 @@ static V9fsFidState *clunk_fid(V9fsState *s, int32_t fid) return fidp; } -void v9fs_reclaim_fd(V9fsPDU *pdu) +void coroutine_fn v9fs_reclaim_fd(V9fsPDU *pdu) { int reclaim_count = 0; V9fsState *s = pdu->s; @@ -499,7 +499,7 @@ void v9fs_reclaim_fd(V9fsPDU *pdu) } } -static int v9fs_mark_fids_unreclaim(V9fsPDU *pdu, V9fsPath *path) +static int coroutine_fn v9fs_mark_fids_unreclaim(V9fsPDU *pdu, V9fsPath *path) { int err; V9fsState *s = pdu->s; @@ -532,7 +532,7 @@ static int v9fs_mark_fids_unreclaim(V9fsPDU *pdu, V9fsPath *path) return 0; } -static void virtfs_reset(V9fsPDU *pdu) +static void coroutine_fn virtfs_reset(V9fsPDU *pdu) { V9fsState *s = pdu->s; V9fsFidState *fidp = NULL; @@ -598,7 +598,8 @@ static void stat_to_qid(const struct stat *stbuf, V9fsQID *qidp) } } -static int fid_to_qid(V9fsPDU *pdu, V9fsFidState *fidp, V9fsQID *qidp) +static int coroutine_fn fid_to_qid(V9fsPDU *pdu, V9fsFidState *fidp, + V9fsQID *qidp) { struct stat stbuf; int err; @@ -643,7 +644,7 @@ void pdu_free(V9fsPDU *pdu) * because we always expect to have enough space to encode * error details */ -static void pdu_complete(V9fsPDU *pdu, ssize_t len) +static void coroutine_fn pdu_complete(V9fsPDU *pdu, ssize_t len) { int8_t id = pdu->id + 1; /* Response */ V9fsState *s = pdu->s; @@ -810,9 +811,9 @@ static uint32_t stat_to_v9mode(const struct stat *stbuf) return mode; } -static int stat_to_v9stat(V9fsPDU *pdu, V9fsPath *name, - const struct stat *stbuf, - V9fsStat *v9stat) +static int coroutine_fn stat_to_v9stat(V9fsPDU *pdu, V9fsPath *name, + const struct stat *stbuf, + V9fsStat *v9stat) { int err; const char *str; @@ -941,7 +942,7 @@ static inline bool is_ro_export(FsContext *ctx) return ctx->export_flags & V9FS_RDONLY; } -static void v9fs_version(void *opaque) +static void coroutine_fn v9fs_version(void *opaque) { ssize_t err; V9fsPDU *pdu = opaque; @@ -979,7 +980,7 @@ static void v9fs_version(void *opaque) v9fs_string_free(&version); } -static void v9fs_attach(void *opaque) +static void coroutine_fn v9fs_attach(void *opaque) { V9fsPDU *pdu = opaque; V9fsState *s = pdu->s; @@ -1045,7 +1046,7 @@ static void v9fs_attach(void *opaque) v9fs_string_free(&aname); } -static void v9fs_stat(void *opaque) +static void coroutine_fn v9fs_stat(void *opaque) { int32_t fid; V9fsStat v9stat; @@ -1089,7 +1090,7 @@ static void v9fs_stat(void *opaque) pdu_complete(pdu, err); } -static void v9fs_getattr(void *opaque) +static void coroutine_fn v9fs_getattr(void *opaque) { int32_t fid; size_t offset = 7; @@ -1165,7 +1166,7 @@ static void v9fs_getattr(void *opaque) #define P9_ATTR_MASK 127 -static void v9fs_setattr(void *opaque) +static void coroutine_fn v9fs_setattr(void *opaque) { int err = 0; int32_t fid; @@ -1283,7 +1284,7 @@ static bool not_same_qid(const V9fsQID *qid1, const V9fsQID *qid2) qid1->path != qid2->path; } -static void v9fs_walk(void *opaque) +static void coroutine_fn v9fs_walk(void *opaque) { int name_idx; V9fsQID *qids = NULL; @@ -1397,7 +1398,7 @@ static void v9fs_walk(void *opaque) } } -static int32_t get_iounit(V9fsPDU *pdu, V9fsPath *path) +static int32_t coroutine_fn get_iounit(V9fsPDU *pdu, V9fsPath *path) { struct statfs stbuf; int32_t iounit = 0; @@ -1417,7 +1418,7 @@ static int32_t get_iounit(V9fsPDU *pdu, V9fsPath *path) return iounit; } -static void v9fs_open(void *opaque) +static void coroutine_fn v9fs_open(void *opaque) { int flags; int32_t fid; @@ -1507,7 +1508,7 @@ static void v9fs_open(void *opaque) pdu_complete(pdu, err); } -static void v9fs_lcreate(void *opaque) +static void coroutine_fn v9fs_lcreate(void *opaque) { int32_t dfid, flags, mode; gid_t gid; @@ -1604,7 +1605,7 @@ static void v9fs_fsync(void *opaque) pdu_complete(pdu, err); } -static void v9fs_clunk(void *opaque) +static void coroutine_fn v9fs_clunk(void *opaque) { int err; int32_t fid; @@ -1673,8 +1674,9 @@ static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp, return offset; } -static int v9fs_do_readdir_with_stat(V9fsPDU *pdu, - V9fsFidState *fidp, uint32_t max_count) +static int coroutine_fn v9fs_do_readdir_with_stat(V9fsPDU *pdu, + V9fsFidState *fidp, + uint32_t max_count) { V9fsPath path; V9fsStat v9stat; @@ -1764,7 +1766,7 @@ static void v9fs_init_qiov_from_pdu(QEMUIOVector *qiov, V9fsPDU *pdu, qemu_iovec_concat(qiov, &elem, skip, size); } -static void v9fs_read(void *opaque) +static void coroutine_fn v9fs_read(void *opaque) { int32_t fid; uint64_t off; @@ -1858,8 +1860,8 @@ static size_t v9fs_readdir_data_size(V9fsString *name) return 24 + v9fs_string_size(name); } -static int v9fs_do_readdir(V9fsPDU *pdu, - V9fsFidState *fidp, int32_t max_count) +static int coroutine_fn v9fs_do_readdir(V9fsPDU *pdu, V9fsFidState *fidp, + int32_t max_count) { size_t size; V9fsQID qid; @@ -1928,7 +1930,7 @@ static int v9fs_do_readdir(V9fsPDU *pdu, return count; } -static void v9fs_readdir(void *opaque) +static void coroutine_fn v9fs_readdir(void *opaque) { int32_t fid; V9fsFidState *fidp; @@ -2024,7 +2026,7 @@ static int v9fs_xattr_write(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp, return err; } -static void v9fs_write(void *opaque) +static void coroutine_fn v9fs_write(void *opaque) { ssize_t err; int32_t fid; @@ -2107,7 +2109,7 @@ static void v9fs_write(void *opaque) pdu_complete(pdu, err); } -static void v9fs_create(void *opaque) +static void coroutine_fn v9fs_create(void *opaque) { int32_t fid; int err = 0; @@ -2287,7 +2289,7 @@ static void v9fs_create(void *opaque) v9fs_path_free(&path); } -static void v9fs_symlink(void *opaque) +static void coroutine_fn v9fs_symlink(void *opaque) { V9fsPDU *pdu = opaque; V9fsString name; @@ -2376,7 +2378,7 @@ static void v9fs_flush(void *opaque) pdu_complete(pdu, 7); } -static void v9fs_link(void *opaque) +static void coroutine_fn v9fs_link(void *opaque) { V9fsPDU *pdu = opaque; int32_t dfid, oldfid; @@ -2425,7 +2427,7 @@ static void v9fs_link(void *opaque) } /* Only works with path name based fid */ -static void v9fs_remove(void *opaque) +static void coroutine_fn v9fs_remove(void *opaque) { int32_t fid; int err = 0; @@ -2469,7 +2471,7 @@ static void v9fs_remove(void *opaque) pdu_complete(pdu, err); } -static void v9fs_unlinkat(void *opaque) +static void coroutine_fn v9fs_unlinkat(void *opaque) { int err = 0; V9fsString name; @@ -2532,8 +2534,9 @@ static void v9fs_unlinkat(void *opaque) /* Only works with path name based fid */ -static int v9fs_complete_rename(V9fsPDU *pdu, V9fsFidState *fidp, - int32_t newdirfid, V9fsString *name) +static int coroutine_fn v9fs_complete_rename(V9fsPDU *pdu, V9fsFidState *fidp, + int32_t newdirfid, + V9fsString *name) { char *end; int err = 0; @@ -2590,7 +2593,7 @@ static int v9fs_complete_rename(V9fsPDU *pdu, V9fsFidState *fidp, } /* Only works with path name based fid */ -static void v9fs_rename(void *opaque) +static void coroutine_fn v9fs_rename(void *opaque) { int32_t fid; ssize_t err = 0; @@ -2641,9 +2644,10 @@ static void v9fs_rename(void *opaque) v9fs_string_free(&name); } -static void v9fs_fix_fid_paths(V9fsPDU *pdu, V9fsPath *olddir, - V9fsString *old_name, V9fsPath *newdir, - V9fsString *new_name) +static void coroutine_fn v9fs_fix_fid_paths(V9fsPDU *pdu, V9fsPath *olddir, + V9fsString *old_name, + V9fsPath *newdir, + V9fsString *new_name) { V9fsFidState *tfidp; V9fsPath oldpath, newpath; @@ -2669,9 +2673,10 @@ static void v9fs_fix_fid_paths(V9fsPDU *pdu, V9fsPath *olddir, v9fs_path_free(&newpath); } -static int v9fs_complete_renameat(V9fsPDU *pdu, int32_t olddirfid, - V9fsString *old_name, int32_t newdirfid, - V9fsString *new_name) +static int coroutine_fn v9fs_complete_renameat(V9fsPDU *pdu, int32_t olddirfid, + V9fsString *old_name, + int32_t newdirfid, + V9fsString *new_name) { int err = 0; V9fsState *s = pdu->s; @@ -2712,7 +2717,7 @@ static int v9fs_complete_renameat(V9fsPDU *pdu, int32_t olddirfid, return err; } -static void v9fs_renameat(void *opaque) +static void coroutine_fn v9fs_renameat(void *opaque) { ssize_t err = 0; size_t offset = 7; @@ -2754,7 +2759,7 @@ static void v9fs_renameat(void *opaque) v9fs_string_free(&new_name); } -static void v9fs_wstat(void *opaque) +static void coroutine_fn v9fs_wstat(void *opaque) { int32_t fid; int err = 0; @@ -2893,7 +2898,7 @@ static int v9fs_fill_statfs(V9fsState *s, V9fsPDU *pdu, struct statfs *stbuf) fsid_val, f_namelen); } -static void v9fs_statfs(void *opaque) +static void coroutine_fn v9fs_statfs(void *opaque) { int32_t fid; ssize_t retval = 0; @@ -2927,7 +2932,7 @@ static void v9fs_statfs(void *opaque) pdu_complete(pdu, retval); } -static void v9fs_mknod(void *opaque) +static void coroutine_fn v9fs_mknod(void *opaque) { int mode; @@ -2993,7 +2998,7 @@ static void v9fs_mknod(void *opaque) * do any thing in * qemu 9p server side lock code path. * So when a TLOCK request comes, always return success */ -static void v9fs_lock(void *opaque) +static void coroutine_fn v9fs_lock(void *opaque) { int8_t status; V9fsFlock flock; @@ -3046,7 +3051,7 @@ static void v9fs_lock(void *opaque) * When a TGETLOCK request comes, always return success because all lock * handling is done by client's VFS layer. */ -static void v9fs_getlock(void *opaque) +static void coroutine_fn v9fs_getlock(void *opaque) { size_t offset = 7; struct stat stbuf; @@ -3091,7 +3096,7 @@ static void v9fs_getlock(void *opaque) v9fs_string_free(&glock.client_id); } -static void v9fs_mkdir(void *opaque) +static void coroutine_fn v9fs_mkdir(void *opaque) { V9fsPDU *pdu = opaque; size_t offset = 7; @@ -3145,7 +3150,7 @@ static void v9fs_mkdir(void *opaque) v9fs_string_free(&name); } -static void v9fs_xattrwalk(void *opaque) +static void coroutine_fn v9fs_xattrwalk(void *opaque) { int64_t size; V9fsString name; @@ -3251,7 +3256,7 @@ static void v9fs_xattrwalk(void *opaque) v9fs_string_free(&name); } -static void v9fs_xattrcreate(void *opaque) +static void coroutine_fn v9fs_xattrcreate(void *opaque) { int flags; int32_t fid; @@ -3291,7 +3296,7 @@ static void v9fs_xattrcreate(void *opaque) v9fs_string_free(&name); } -static void v9fs_readlink(void *opaque) +static void coroutine_fn v9fs_readlink(void *opaque) { V9fsPDU *pdu = opaque; size_t offset = 7; @@ -3367,13 +3372,13 @@ static CoroutineEntry *pdu_co_handlers[] = { [P9_TREMOVE] = v9fs_remove, }; -static void v9fs_op_not_supp(void *opaque) +static void coroutine_fn v9fs_op_not_supp(void *opaque) { V9fsPDU *pdu = opaque; pdu_complete(pdu, -EOPNOTSUPP); } -static void v9fs_fs_ro(void *opaque) +static void coroutine_fn v9fs_fs_ro(void *opaque) { V9fsPDU *pdu = opaque; pdu_complete(pdu, -EROFS); diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h index 5225b4f1207..c4df66d1c4e 100644 --- a/hw/9pfs/9p.h +++ b/hw/9pfs/9p.h @@ -324,7 +324,7 @@ static inline uint8_t v9fs_request_cancelled(V9fsPDU *pdu) return pdu->cancelled; } -void v9fs_reclaim_fd(V9fsPDU *pdu); +void coroutine_fn v9fs_reclaim_fd(V9fsPDU *pdu); void v9fs_path_init(V9fsPath *path); void v9fs_path_free(V9fsPath *path); void v9fs_path_sprintf(V9fsPath *path, const char *fmt, ...); From 6868a420c519d74926ea814d48f6ce9beda35b98 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Mon, 17 Oct 2016 14:13:58 +0200 Subject: [PATCH 717/723] 9pfs: drop useless check in pdu_free() Out of the three users of pdu_free(), none ever passes a NULL pointer to this function. Signed-off-by: Greg Kurz --- hw/9pfs/9p.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index f2ab1dfab2b..df8aa726c9a 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -626,16 +626,14 @@ V9fsPDU *pdu_alloc(V9fsState *s) void pdu_free(V9fsPDU *pdu) { - if (pdu) { - V9fsState *s = pdu->s; - /* - * Cancelled pdu are added back to the freelist - * by flush request . - */ - if (!pdu->cancelled) { - QLIST_REMOVE(pdu, next); - QLIST_INSERT_HEAD(&s->free_list, pdu, next); - } + V9fsState *s = pdu->s; + /* + * Cancelled pdu are added back to the freelist + * by flush request . + */ + if (!pdu->cancelled) { + QLIST_REMOVE(pdu, next); + QLIST_INSERT_HEAD(&s->free_list, pdu, next); } } From f74e27bf0f07425aba6cb812aa7f5aa98bb68542 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Mon, 17 Oct 2016 14:13:58 +0200 Subject: [PATCH 718/723] 9pfs: only free completed request if not flushed If a PDU has a flush request pending, the current code calls pdu_free() twice: 1) pdu_complete()->pdu_free() with pdu->cancelled set, which does nothing 2) v9fs_flush()->pdu_free() with pdu->cancelled cleared, which moves the PDU back to the free list. This works but it complexifies the logic of pdu_free(). With this patch, pdu_complete() only calls pdu_free() if no flush request is pending, i.e. qemu_co_queue_next() returns false. Since pdu_free() is now supposed to be called with pdu->cancelled cleared, the check in pdu_free() is dropped and replaced by an assertion. Signed-off-by: Greg Kurz --- hw/9pfs/9p.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index df8aa726c9a..f0dc2ce589c 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -627,14 +627,10 @@ V9fsPDU *pdu_alloc(V9fsState *s) void pdu_free(V9fsPDU *pdu) { V9fsState *s = pdu->s; - /* - * Cancelled pdu are added back to the freelist - * by flush request . - */ - if (!pdu->cancelled) { - QLIST_REMOVE(pdu, next); - QLIST_INSERT_HEAD(&s->free_list, pdu, next); - } + + g_assert(!pdu->cancelled); + QLIST_REMOVE(pdu, next); + QLIST_INSERT_HEAD(&s->free_list, pdu, next); } /* @@ -679,9 +675,9 @@ static void coroutine_fn pdu_complete(V9fsPDU *pdu, ssize_t len) pdu_push_and_notify(pdu); /* Now wakeup anybody waiting in flush for this request */ - qemu_co_queue_next(&pdu->complete); - - pdu_free(pdu); + if (!qemu_co_queue_next(&pdu->complete)) { + pdu_free(pdu); + } } static mode_t v9mode_to_mode(uint32_t mode, V9fsString *extension) From 0e44a0fd3f28cccb8963fdfc05c53c546b3f46b6 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Mon, 17 Oct 2016 14:13:58 +0200 Subject: [PATCH 719/723] virtio-9p: add reset handler Virtio devices should implement the VirtIODevice->reset() function to perform necessary cleanup actions and to bring the device to a quiescent state. In the case of the virtio-9p device, this means: - emptying the list of active PDUs (i.e. draining all in-flight I/O) - freeing all fids (i.e. close open file descriptors and free memory) That's what this patch does. The reset handler first waits for all active PDUs to complete. Since completion happens in the QEMU global aio context, we just have to loop around aio_poll() until the active list is empty. The freeing part involves some actions to be performed on the backend, like closing file descriptors or flushing extended attributes to the underlying filesystem. The virtfs_reset() function already does the job: it calls free_fid() for all open fids not involved in an ongoing I/O operation. We are sure this is the case since we have drained the PDU active list. The current code implements all backend accesses with coroutines, but we want to stay synchronous on the reset path. We can either change the current code to be able to run when not in coroutine context, or create a coroutine context and wait for virtfs_reset() to complete. This patch goes for the latter because it results in simpler code. Note that we also need to create a dummy PDU because it is also an API to pass the FsContext pointer to all backend callbacks. Signed-off-by: Greg Kurz Reviewed-by: Michael S. Tsirkin Reviewed-by: Stefan Hajnoczi --- hw/9pfs/9p.c | 30 ++++++++++++++++++++++++++++++ hw/9pfs/9p.h | 1 + hw/9pfs/virtio-9p-device.c | 8 ++++++++ 3 files changed, 39 insertions(+) diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index f0dc2ce589c..26aa7d56481 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -3522,6 +3522,36 @@ void v9fs_device_unrealize_common(V9fsState *s, Error **errp) g_free(s->tag); } +typedef struct VirtfsCoResetData { + V9fsPDU pdu; + bool done; +} VirtfsCoResetData; + +static void coroutine_fn virtfs_co_reset(void *opaque) +{ + VirtfsCoResetData *data = opaque; + + virtfs_reset(&data->pdu); + data->done = true; +} + +void v9fs_reset(V9fsState *s) +{ + VirtfsCoResetData data = { .pdu = { .s = s }, .done = false }; + Coroutine *co; + + while (!QLIST_EMPTY(&s->active_list)) { + aio_poll(qemu_get_aio_context(), true); + } + + co = qemu_coroutine_create(virtfs_co_reset, &data); + qemu_coroutine_enter(co); + + while (!data.done) { + aio_poll(qemu_get_aio_context(), true); + } +} + static void __attribute__((__constructor__)) v9fs_set_fd_limit(void) { struct rlimit rlim; diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h index c4df66d1c4e..2523a445f81 100644 --- a/hw/9pfs/9p.h +++ b/hw/9pfs/9p.h @@ -339,5 +339,6 @@ ssize_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...); V9fsPDU *pdu_alloc(V9fsState *s); void pdu_free(V9fsPDU *pdu); void pdu_submit(V9fsPDU *pdu); +void v9fs_reset(V9fsState *s); #endif diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c index e98dd0c4c0a..1782e4a2277 100644 --- a/hw/9pfs/virtio-9p-device.c +++ b/hw/9pfs/virtio-9p-device.c @@ -141,6 +141,13 @@ static void virtio_9p_device_unrealize(DeviceState *dev, Error **errp) v9fs_device_unrealize_common(s, errp); } +static void virtio_9p_reset(VirtIODevice *vdev) +{ + V9fsVirtioState *v = (V9fsVirtioState *)vdev; + + v9fs_reset(&v->state); +} + ssize_t virtio_pdu_vmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, va_list ap) { @@ -207,6 +214,7 @@ static void virtio_9p_class_init(ObjectClass *klass, void *data) vdc->unrealize = virtio_9p_device_unrealize; vdc->get_features = virtio_9p_get_features; vdc->get_config = virtio_9p_get_config; + vdc->reset = virtio_9p_reset; } static const TypeInfo virtio_device_info = { From eb687602853b4ae656e9236ee4222609f3a6887d Mon Sep 17 00:00:00 2001 From: Li Qiang Date: Mon, 17 Oct 2016 14:13:58 +0200 Subject: [PATCH 720/723] 9pfs: fix information leak in xattr read 9pfs uses g_malloc() to allocate the xattr memory space, if the guest reads this memory before writing to it, this will leak host heap memory to the guest. This patch avoid this. Signed-off-by: Li Qiang Reviewed-by: Greg Kurz Signed-off-by: Greg Kurz --- hw/9pfs/9p.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index 26aa7d56481..bf23b011a8e 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -3282,7 +3282,7 @@ static void coroutine_fn v9fs_xattrcreate(void *opaque) xattr_fidp->fs.xattr.flags = flags; v9fs_string_init(&xattr_fidp->fs.xattr.name); v9fs_string_copy(&xattr_fidp->fs.xattr.name, &name); - xattr_fidp->fs.xattr.value = g_malloc(size); + xattr_fidp->fs.xattr.value = g_malloc0(size); err = offset; put_fid(pdu, file_fidp); out_nofid: From ff55e94d23ae94c8628b0115320157c763eb3e06 Mon Sep 17 00:00:00 2001 From: Li Qiang Date: Mon, 17 Oct 2016 14:13:58 +0200 Subject: [PATCH 721/723] 9pfs: fix memory leak in v9fs_xattrcreate The 'fs.xattr.value' field in V9fsFidState object doesn't consider the situation that this field has been allocated previously. Every time, it will be allocated directly. This leads to a host memory leak issue if the client sends another Txattrcreate message with the same fid number before the fid from the previous time got clunked. Signed-off-by: Li Qiang Reviewed-by: Greg Kurz [groug, updated the changelog to indicate how the leak can occur] Signed-off-by: Greg Kurz --- hw/9pfs/9p.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index bf23b011a8e..66135cf1218 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -3282,6 +3282,7 @@ static void coroutine_fn v9fs_xattrcreate(void *opaque) xattr_fidp->fs.xattr.flags = flags; v9fs_string_init(&xattr_fidp->fs.xattr.name); v9fs_string_copy(&xattr_fidp->fs.xattr.name, &name); + g_free(xattr_fidp->fs.xattr.value); xattr_fidp->fs.xattr.value = g_malloc0(size); err = offset; put_fid(pdu, file_fidp); From 4c1586787ff43c9acd18a56c12d720e3e6be9f7c Mon Sep 17 00:00:00 2001 From: Li Qiang Date: Mon, 17 Oct 2016 14:13:58 +0200 Subject: [PATCH 722/723] 9pfs: fix memory leak in v9fs_link The v9fs_link() function keeps a reference on the source fid object. This causes a memory leak since the reference never goes down to 0. This patch fixes the issue. Signed-off-by: Li Qiang Reviewed-by: Greg Kurz [groug, rephrased the changelog] Signed-off-by: Greg Kurz --- hw/9pfs/9p.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index 66135cf1218..d43a5522349 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -2413,6 +2413,7 @@ static void coroutine_fn v9fs_link(void *opaque) if (!err) { err = offset; } + put_fid(pdu, oldfidp); out: put_fid(pdu, dfidp); out_nofid: From fdfcc9aeea1492f4b819a24c94dfb678145b1bf9 Mon Sep 17 00:00:00 2001 From: Li Qiang Date: Mon, 17 Oct 2016 14:13:58 +0200 Subject: [PATCH 723/723] 9pfs: fix memory leak in v9fs_write If an error occurs when marshalling the transfer length to the guest, the v9fs_write() function doesn't free an IO vector, thus leading to a memory leak. This patch fixes the issue. Signed-off-by: Li Qiang Reviewed-by: Greg Kurz [groug, rephrased the changelog] Signed-off-by: Greg Kurz --- hw/9pfs/9p.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index d43a5522349..e88cf257a2b 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -2090,7 +2090,7 @@ static void coroutine_fn v9fs_write(void *opaque) offset = 7; err = pdu_marshal(pdu, offset, "d", total); if (err < 0) { - goto out; + goto out_qiov; } err += offset; trace_v9fs_write_return(pdu->tag, pdu->id, total, err);