diff options
110 files changed, 6344 insertions, 3259 deletions
@@ -82,7 +82,6 @@ fsdev/virtfs-proxy-helper.pod *.swp *.orig .pc -*.patch *.gcda *.gcno patches diff --git a/MAINTAINERS b/MAINTAINERS index be02724..3412b07 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -685,11 +685,12 @@ M: Anthony Liguori <aliguori@us.ibm.com> S: Supported F: vl.c -Monitor (QMP/HMP) +Human Monitor (HMP) M: Luiz Capitulino <lcapitulino@redhat.com> -M: Markus Armbruster <armbru@redhat.com> S: Supported F: monitor.c +F: hmp.c +F: hmp-commands.hx Network device layer M: Anthony Liguori <aliguori@us.ibm.com> @@ -706,6 +707,27 @@ F: nbd.* F: qemu-nbd.c T: git git://github.com/bonzini/qemu.git nbd-next +QAPI +M: Luiz Capitulino <lcapitulino@redhat.com> +M: Michael Roth <mdroth@linux.vnet.ibm.com> +S: Supported +F: qapi/ + +QAPI Schema +M: Eric Blake <eblake@redhat.com> +M: Luiz Capitulino <lcapitulino@redhat.com> +M: Markus Armbruster <armbru@redhat.com> +S: Supported +F: qapi-schema.json + +QMP +M: Luiz Capitulino <lcapitulino@redhat.com> +S: Supported +F: qmp.c +F: monitor.c +F: qmp-commands.hx +F: QMP/ + SLIRP M: Jan Kiszka <jan.kiszka@siemens.com> S: Maintained @@ -745,6 +767,12 @@ M: qemu-devel@nongnu.org S: Maintained F: tcg/ +AArch64 target +M: Claudio Fontana <claudio.fontana@huawei.com> +M: Claudio Fontana <claudio.fontana@gmail.com> +S: Maintained +F: tcg/aarch64/ + ARM target M: Andrzej Zaborowski <balrogg@gmail.com> S: Maintained @@ -186,7 +186,7 @@ qemu-img.o: qemu-img-cmds.h qemu-img$(EXESUF): qemu-img.o $(block-obj-y) libqemuutil.a libqemustub.a qemu-nbd$(EXESUF): qemu-nbd.o $(block-obj-y) libqemuutil.a libqemustub.a -qemu-io$(EXESUF): qemu-io.o cmd.o $(block-obj-y) libqemuutil.a libqemustub.a +qemu-io$(EXESUF): qemu-io.o $(block-obj-y) libqemuutil.a libqemustub.a qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o @@ -289,7 +289,7 @@ pxe-e1000.rom pxe-eepro100.rom pxe-ne2k_pci.rom \ pxe-pcnet.rom pxe-rtl8139.rom pxe-virtio.rom \ efi-e1000.rom efi-eepro100.rom efi-ne2k_pci.rom \ efi-pcnet.rom efi-rtl8139.rom efi-virtio.rom \ -qemu-icon.bmp \ +qemu-icon.bmp qemu_logo_no_text.svg \ bamboo.dtb petalogix-s3adsp1800.dtb petalogix-ml605.dtb \ multiboot.bin linuxboot.bin kvmvapic.bin \ s390-zipl.rom \ @@ -306,10 +306,13 @@ install-doc: $(DOCS) $(INSTALL_DATA) QMP/qmp-commands.txt "$(DESTDIR)$(qemu_docdir)" ifdef CONFIG_POSIX $(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1" - $(INSTALL_DATA) qemu.1 qemu-img.1 "$(DESTDIR)$(mandir)/man1" + $(INSTALL_DATA) qemu.1 "$(DESTDIR)$(mandir)/man1" +ifneq ($(TOOLS),) + $(INSTALL_DATA) qemu-img.1 "$(DESTDIR)$(mandir)/man1" $(INSTALL_DIR) "$(DESTDIR)$(mandir)/man8" $(INSTALL_DATA) qemu-nbd.8 "$(DESTDIR)$(mandir)/man8" endif +endif ifdef CONFIG_VIRTFS $(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1" $(INSTALL_DATA) fsdev/virtfs-proxy-helper.1 "$(DESTDIR)$(mandir)/man1" diff --git a/Makefile.objs b/Makefile.objs index 286ce06..5b288ba 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -13,6 +13,7 @@ block-obj-$(CONFIG_POSIX) += aio-posix.o block-obj-$(CONFIG_WIN32) += aio-win32.o block-obj-y += block/ block-obj-y += qapi-types.o qapi-visit.o +block-obj-y += qemu-io-cmds.o block-obj-y += qemu-coroutine.o qemu-coroutine-lock.o qemu-coroutine-io.o block-obj-y += qemu-coroutine-sleep.o diff --git a/Makefile.target b/Makefile.target index ce4391f..b0be124 100644 --- a/Makefile.target +++ b/Makefile.target @@ -63,8 +63,6 @@ all: $(PROGS) stap CONFIG_NO_PCI = $(if $(subst n,,$(CONFIG_PCI)),n,y) CONFIG_NO_KVM = $(if $(subst n,,$(CONFIG_KVM)),n,y) CONFIG_NO_XEN = $(if $(subst n,,$(CONFIG_XEN)),n,y) -CONFIG_NO_GET_MEMORY_MAPPING = $(if $(subst n,,$(CONFIG_HAVE_GET_MEMORY_MAPPING)),n,y) -CONFIG_NO_CORE_DUMP = $(if $(subst n,,$(CONFIG_HAVE_CORE_DUMP)),n,y) ######################################################### # cpu emulator library @@ -111,10 +109,8 @@ obj-y += hw/ obj-$(CONFIG_FDT) += device_tree.o obj-$(CONFIG_KVM) += kvm-all.o obj-y += memory.o savevm.o cputlb.o -obj-$(CONFIG_HAVE_GET_MEMORY_MAPPING) += memory_mapping.o -obj-$(CONFIG_HAVE_CORE_DUMP) += dump.o -obj-$(CONFIG_NO_GET_MEMORY_MAPPING) += memory_mapping-stub.o -obj-$(CONFIG_NO_CORE_DUMP) += dump-stub.o +obj-y += memory_mapping.o +obj-y += dump.o LIBS+=$(libs_softmmu) # xen support diff --git a/QMP/qmp-events.txt b/QMP/qmp-events.txt index 92fe5fb..24e804e9 100644 --- a/QMP/qmp-events.txt +++ b/QMP/qmp-events.txt @@ -203,7 +203,8 @@ Emitted when the guest changes the RTC time. Data: -- "offset": delta against the host UTC in seconds (json-number) +- "offset": Offset between base RTC clock (as specified by -rtc base), and +new RTC clock value (json-number) Example: diff --git a/arch_init.c b/arch_init.c index 5d32ecf..872020e 100644 --- a/arch_init.c +++ b/arch_init.c @@ -1029,7 +1029,7 @@ int qemu_uuid_parse(const char *str, uint8_t *uuid) return -1; } #ifdef TARGET_I386 - smbios_add_field(1, offsetof(struct smbios_type_1, uuid), 16, uuid); + smbios_add_field(1, offsetof(struct smbios_type_1, uuid), uuid, 16); #endif return 0; } @@ -1053,7 +1053,6 @@ void do_smbios_option(const char *optarg) { #ifdef TARGET_I386 if (smbios_entry_add(optarg) < 0) { - fprintf(stderr, "Wrong smbios provided\n"); exit(1); } #endif diff --git a/backends/baum.c b/backends/baum.c index 4cba79f..62aa784 100644 --- a/backends/baum.c +++ b/backends/baum.c @@ -611,8 +611,6 @@ CharDriverState *chr_baum_init(void) qemu_set_fd_handler(baum->brlapi_fd, baum_chr_read, NULL, baum); - qemu_chr_be_generic_open(chr); - return chr; fail: diff --git a/backends/msmouse.c b/backends/msmouse.c index 0ac05a0..c0dbfcd 100644 --- a/backends/msmouse.c +++ b/backends/msmouse.c @@ -70,6 +70,7 @@ CharDriverState *qemu_chr_open_msmouse(void) chr = g_malloc0(sizeof(CharDriverState)); chr->chr_write = msmouse_chr_write; chr->chr_close = msmouse_chr_close; + chr->explicit_be_open = true; qemu_add_mouse_event_handler(msmouse_event, chr, 0, "QEMU Microsoft Mouse"); @@ -3186,13 +3186,11 @@ int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf, void bdrv_debug_event(BlockDriverState *bs, BlkDebugEvent event) { - BlockDriver *drv = bs->drv; - - if (!drv || !drv->bdrv_debug_event) { + if (!bs || !bs->drv || !bs->drv->bdrv_debug_event) { return; } - drv->bdrv_debug_event(bs, event); + bs->drv->bdrv_debug_event(bs, event); } int bdrv_debug_breakpoint(BlockDriverState *bs, const char *event, @@ -4024,6 +4022,7 @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs) } /* Write back cached data to the OS even with cache=unsafe */ + BLKDBG_EVENT(bs->file, BLKDBG_FLUSH_TO_OS); if (bs->drv->bdrv_co_flush_to_os) { ret = bs->drv->bdrv_co_flush_to_os(bs); if (ret < 0) { @@ -4036,6 +4035,7 @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs) goto flush_parent; } + BLKDBG_EVENT(bs->file, BLKDBG_FLUSH_TO_DISK); if (bs->drv->bdrv_co_flush_to_disk) { ret = bs->drv->bdrv_co_flush_to_disk(bs); } else if (bs->drv->bdrv_aio_flush) { diff --git a/block/blkdebug.c b/block/blkdebug.c index 71f99e4..ccb627a 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -182,6 +182,9 @@ static const char *event_names[BLKDBG_EVENT_MAX] = { [BLKDBG_CLUSTER_ALLOC] = "cluster_alloc", [BLKDBG_CLUSTER_ALLOC_BYTES] = "cluster_alloc_bytes", [BLKDBG_CLUSTER_FREE] = "cluster_free", + + [BLKDBG_FLUSH_TO_OS] = "flush_to_os", + [BLKDBG_FLUSH_TO_DISK] = "flush_to_disk", }; static int get_event_by_name(const char *name, BlkDebugEvent *event) diff --git a/block/curl.c b/block/curl.c index b8935fd..4dc3b4b 100644 --- a/block/curl.c +++ b/block/curl.c @@ -462,8 +462,8 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags) // initialize the multi interface! s->multi = curl_multi_init(); - curl_multi_setopt( s->multi, CURLMOPT_SOCKETDATA, s); - curl_multi_setopt( s->multi, CURLMOPT_SOCKETFUNCTION, curl_sock_cb ); + curl_multi_setopt(s->multi, CURLMOPT_SOCKETDATA, s); + curl_multi_setopt(s->multi, CURLMOPT_SOCKETFUNCTION, curl_sock_cb); curl_multi_do(s); qemu_opts_del(opts); diff --git a/block/qapi.c b/block/qapi.c index 794dbf8..a4bc411 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -26,29 +26,56 @@ #include "block/block_int.h" #include "qmp-commands.h" -void bdrv_collect_snapshots(BlockDriverState *bs , ImageInfo *info) +/* + * Returns 0 on success, with *p_list either set to describe snapshot + * information, or NULL because there are no snapshots. Returns -errno on + * error, with *p_list untouched. + */ +int bdrv_query_snapshot_info_list(BlockDriverState *bs, + SnapshotInfoList **p_list, + Error **errp) { int i, sn_count; QEMUSnapshotInfo *sn_tab = NULL; - SnapshotInfoList *info_list, *cur_item = NULL; + SnapshotInfoList *info_list, *cur_item = NULL, *head = NULL; + SnapshotInfo *info; + sn_count = bdrv_snapshot_list(bs, &sn_tab); + if (sn_count < 0) { + const char *dev = bdrv_get_device_name(bs); + switch (sn_count) { + case -ENOMEDIUM: + error_setg(errp, "Device '%s' is not inserted", dev); + break; + case -ENOTSUP: + error_setg(errp, + "Device '%s' does not support internal snapshots", + dev); + break; + default: + error_setg_errno(errp, -sn_count, + "Can't list snapshots of device '%s'", dev); + break; + } + return sn_count; + } for (i = 0; i < sn_count; i++) { - info->has_snapshots = true; - info_list = g_new0(SnapshotInfoList, 1); + info = g_new0(SnapshotInfo, 1); + info->id = g_strdup(sn_tab[i].id_str); + info->name = g_strdup(sn_tab[i].name); + info->vm_state_size = sn_tab[i].vm_state_size; + info->date_sec = sn_tab[i].date_sec; + info->date_nsec = sn_tab[i].date_nsec; + info->vm_clock_sec = sn_tab[i].vm_clock_nsec / 1000000000; + info->vm_clock_nsec = sn_tab[i].vm_clock_nsec % 1000000000; - info_list->value = g_new0(SnapshotInfo, 1); - info_list->value->id = g_strdup(sn_tab[i].id_str); - info_list->value->name = g_strdup(sn_tab[i].name); - info_list->value->vm_state_size = sn_tab[i].vm_state_size; - info_list->value->date_sec = sn_tab[i].date_sec; - info_list->value->date_nsec = sn_tab[i].date_nsec; - info_list->value->vm_clock_sec = sn_tab[i].vm_clock_nsec / 1000000000; - info_list->value->vm_clock_nsec = sn_tab[i].vm_clock_nsec % 1000000000; + info_list = g_new0(SnapshotInfoList, 1); + info_list->value = info; /* XXX: waiting for the qapi to support qemu-queue.h types */ if (!cur_item) { - info->snapshots = cur_item = info_list; + head = cur_item = info_list; } else { cur_item->next = info_list; cur_item = info_list; @@ -57,20 +84,40 @@ void bdrv_collect_snapshots(BlockDriverState *bs , ImageInfo *info) } g_free(sn_tab); + *p_list = head; + return 0; } -void bdrv_collect_image_info(BlockDriverState *bs, - ImageInfo *info, - const char *filename) +/** + * bdrv_query_image_info: + * @bs: block device to examine + * @p_info: location to store image information + * @errp: location to store error information + * + * Store "flat" image information in @p_info. + * + * "Flat" means it does *not* query backing image information, + * i.e. (*pinfo)->has_backing_image will be set to false and + * (*pinfo)->backing_image to NULL even when the image does in fact have + * a backing image. + * + * @p_info will be set only on success. On error, store error in @errp. + */ +void bdrv_query_image_info(BlockDriverState *bs, + ImageInfo **p_info, + Error **errp) { uint64_t total_sectors; - char backing_filename[1024]; + const char *backing_filename; char backing_filename2[1024]; BlockDriverInfo bdi; + int ret; + Error *err = NULL; + ImageInfo *info = g_new0(ImageInfo, 1); bdrv_get_geometry(bs, &total_sectors); - info->filename = g_strdup(filename); + info->filename = g_strdup(bs->filename); info->format = g_strdup(bdrv_get_format_name(bs)); info->virtual_size = total_sectors * 512; info->actual_size = bdrv_get_allocated_file_size(bs); @@ -87,7 +134,7 @@ void bdrv_collect_image_info(BlockDriverState *bs, info->dirty_flag = bdi.is_dirty; info->has_dirty_flag = true; } - bdrv_get_backing_filename(bs, backing_filename, sizeof(backing_filename)); + backing_filename = bs->backing_file; if (backing_filename[0] != '\0') { info->backing_filename = g_strdup(backing_filename); info->has_backing_filename = true; @@ -105,11 +152,37 @@ void bdrv_collect_image_info(BlockDriverState *bs, info->has_backing_filename_format = true; } } + + ret = bdrv_query_snapshot_info_list(bs, &info->snapshots, &err); + switch (ret) { + case 0: + if (info->snapshots) { + info->has_snapshots = true; + } + break; + /* recoverable error */ + case -ENOMEDIUM: + case -ENOTSUP: + error_free(err); + break; + default: + error_propagate(errp, err); + qapi_free_ImageInfo(info); + return; + } + + *p_info = info; } -BlockInfo *bdrv_query_info(BlockDriverState *bs) +/* @p_info will be set only on success. */ +void bdrv_query_info(BlockDriverState *bs, + BlockInfo **p_info, + Error **errp) { BlockInfo *info = g_malloc0(sizeof(*info)); + BlockDriverState *bs0; + ImageInfo **p_image_info; + Error *local_err = NULL; info->device = g_strdup(bs->device_name); info->type = g_strdup("unknown"); info->locked = bdrv_dev_is_medium_locked(bs); @@ -163,8 +236,30 @@ BlockInfo *bdrv_query_info(BlockDriverState *bs) info->inserted->iops_wr = bs->io_limits.iops[BLOCK_IO_LIMIT_WRITE]; } + + bs0 = bs; + p_image_info = &info->inserted->image; + while (1) { + bdrv_query_image_info(bs0, p_image_info, &local_err); + if (error_is_set(&local_err)) { + error_propagate(errp, local_err); + goto err; + } + if (bs0->drv && bs0->backing_hd) { + bs0 = bs0->backing_hd; + (*p_image_info)->has_backing_image = true; + p_image_info = &((*p_image_info)->backing_image); + } else { + break; + } + } } - return info; + + *p_info = info; + return; + + err: + qapi_free_BlockInfo(info); } BlockStats *bdrv_query_stats(const BlockDriverState *bs) @@ -201,16 +296,25 @@ BlockInfoList *qmp_query_block(Error **errp) { BlockInfoList *head = NULL, **p_next = &head; BlockDriverState *bs = NULL; + Error *local_err = NULL; while ((bs = bdrv_next(bs))) { BlockInfoList *info = g_malloc0(sizeof(*info)); - info->value = bdrv_query_info(bs); + bdrv_query_info(bs, &info->value, &local_err); + if (error_is_set(&local_err)) { + error_propagate(errp, local_err); + goto err; + } *p_next = info; p_next = &info->next; } return head; + + err: + qapi_free_BlockInfoList(head); + return NULL; } BlockStatsList *qmp_query_blockstats(Error **errp) @@ -1180,6 +1180,10 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data) */ if (bdrv_get_attached_dev(bs)) { bdrv_make_anon(bs); + + /* Further I/O must not pause the guest */ + bdrv_set_on_error(bs, BLOCKDEV_ON_ERROR_REPORT, + BLOCKDEV_ON_ERROR_REPORT); } else { drive_uninit(drive_get_by_blockdev(bs)); } @@ -1,612 +0,0 @@ -/* - * Copyright (c) 2003-2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * 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. - * - * This program is distributed in the hope that it would 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 <http://www.gnu.org/licenses/>. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include <errno.h> -#include <sys/time.h> -#include <getopt.h> - -#include "cmd.h" -#include "block/aio.h" -#include "qemu/main-loop.h" - -#define _(x) x /* not gettext support yet */ - -/* from libxcmd/command.c */ - -cmdinfo_t *cmdtab; -int ncmds; - -static argsfunc_t args_func; -static checkfunc_t check_func; -static int ncmdline; -static char **cmdline; - -static int -compare(const void *a, const void *b) -{ - return strcmp(((const cmdinfo_t *)a)->name, - ((const cmdinfo_t *)b)->name); -} - -void add_command(const cmdinfo_t *ci) -{ - cmdtab = g_realloc((void *)cmdtab, ++ncmds * sizeof(*cmdtab)); - cmdtab[ncmds - 1] = *ci; - qsort(cmdtab, ncmds, sizeof(*cmdtab), compare); -} - -static int -check_command( - const cmdinfo_t *ci) -{ - if (check_func) - return check_func(ci); - return 1; -} - -void -add_check_command( - checkfunc_t cf) -{ - check_func = cf; -} - -int -command_usage( - const cmdinfo_t *ci) -{ - printf("%s %s -- %s\n", ci->name, ci->args, ci->oneline); - return 0; -} - -int -command( - const cmdinfo_t *ct, - int argc, - char **argv) -{ - char *cmd = argv[0]; - - if (!check_command(ct)) - return 0; - - if (argc-1 < ct->argmin || (ct->argmax != -1 && argc-1 > ct->argmax)) { - if (ct->argmax == -1) - fprintf(stderr, - _("bad argument count %d to %s, expected at least %d arguments\n"), - argc-1, cmd, ct->argmin); - else if (ct->argmin == ct->argmax) - fprintf(stderr, - _("bad argument count %d to %s, expected %d arguments\n"), - argc-1, cmd, ct->argmin); - else - fprintf(stderr, - _("bad argument count %d to %s, expected between %d and %d arguments\n"), - argc-1, cmd, ct->argmin, ct->argmax); - return 0; - } - optind = 0; - return ct->cfunc(argc, argv); -} - -const cmdinfo_t * -find_command( - const char *cmd) -{ - cmdinfo_t *ct; - - for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) { - if (strcmp(ct->name, cmd) == 0 || - (ct->altname && strcmp(ct->altname, cmd) == 0)) - return (const cmdinfo_t *)ct; - } - return NULL; -} - -void add_user_command(char *optarg) -{ - cmdline = g_realloc(cmdline, ++ncmdline * sizeof(char *)); - cmdline[ncmdline-1] = optarg; -} - -static int -args_command( - int index) -{ - if (args_func) - return args_func(index); - return 0; -} - -void -add_args_command( - argsfunc_t af) -{ - args_func = af; -} - -static void prep_fetchline(void *opaque) -{ - int *fetchable = opaque; - - qemu_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL); - *fetchable= 1; -} - -static char *get_prompt(void); - -void command_loop(void) -{ - int c, i, j = 0, done = 0, fetchable = 0, prompted = 0; - char *input; - char **v; - const cmdinfo_t *ct; - - for (i = 0; !done && i < ncmdline; i++) { - input = strdup(cmdline[i]); - if (!input) { - fprintf(stderr, _("cannot strdup command '%s': %s\n"), - cmdline[i], strerror(errno)); - exit(1); - } - v = breakline(input, &c); - if (c) { - ct = find_command(v[0]); - if (ct) { - if (ct->flags & CMD_FLAG_GLOBAL) { - done = command(ct, c, v); - } else { - j = 0; - while (!done && (j = args_command(j))) { - done = command(ct, c, v); - } - } - } else { - fprintf(stderr, _("command \"%s\" not found\n"), v[0]); - } - } - doneline(input, v); - } - if (cmdline) { - g_free(cmdline); - return; - } - - while (!done) { - if (!prompted) { - printf("%s", get_prompt()); - fflush(stdout); - qemu_set_fd_handler(STDIN_FILENO, prep_fetchline, NULL, &fetchable); - prompted = 1; - } - - main_loop_wait(false); - - if (!fetchable) { - continue; - } - input = fetchline(); - if (input == NULL) { - break; - } - v = breakline(input, &c); - if (c) { - ct = find_command(v[0]); - if (ct) { - done = command(ct, c, v); - } else { - fprintf(stderr, _("command \"%s\" not found\n"), v[0]); - } - } - doneline(input, v); - - prompted = 0; - fetchable = 0; - } - qemu_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL); -} - -/* from libxcmd/input.c */ - -#if defined(ENABLE_READLINE) -# include <readline/history.h> -# include <readline/readline.h> -#elif defined(ENABLE_EDITLINE) -# include <histedit.h> -#endif - -static char * -get_prompt(void) -{ - static char prompt[FILENAME_MAX + 2 /*"> "*/ + 1 /*"\0"*/ ]; - - if (!prompt[0]) - snprintf(prompt, sizeof(prompt), "%s> ", progname); - return prompt; -} - -#if defined(ENABLE_READLINE) -char * -fetchline(void) -{ - char *line; - - line = readline(get_prompt()); - if (line && *line) - add_history(line); - return line; -} -#elif defined(ENABLE_EDITLINE) -static char *el_get_prompt(EditLine *e) { return get_prompt(); } -char * -fetchline(void) -{ - static EditLine *el; - static History *hist; - HistEvent hevent; - char *line; - int count; - - if (!el) { - hist = history_init(); - history(hist, &hevent, H_SETSIZE, 100); - el = el_init(progname, stdin, stdout, stderr); - el_source(el, NULL); - el_set(el, EL_SIGNAL, 1); - el_set(el, EL_PROMPT, el_get_prompt); - el_set(el, EL_HIST, history, (const char *)hist); - } - line = strdup(el_gets(el, &count)); - if (line) { - if (count > 0) - line[count-1] = '\0'; - if (*line) - history(hist, &hevent, H_ENTER, line); - } - return line; -} -#else -# define MAXREADLINESZ 1024 -char * -fetchline(void) -{ - char *p, *line = malloc(MAXREADLINESZ); - - if (!line) - return NULL; - if (!fgets(line, MAXREADLINESZ, stdin)) { - free(line); - return NULL; - } - p = line + strlen(line); - if (p != line && p[-1] == '\n') - p[-1] = '\0'; - return line; -} -#endif - -static char *qemu_strsep(char **input, const char *delim) -{ - char *result = *input; - if (result != NULL) { - char *p; - - for (p = result; *p != '\0'; p++) { - if (strchr(delim, *p)) { - break; - } - } - if (*p == '\0') { - *input = NULL; - } else { - *p = '\0'; - *input = p + 1; - } - } - return result; -} - -char **breakline(char *input, int *count) -{ - int c = 0; - char *p; - char **rval = calloc(sizeof(char *), 1); - char **tmp; - - while (rval && (p = qemu_strsep(&input, " ")) != NULL) { - if (!*p) { - continue; - } - c++; - tmp = realloc(rval, sizeof(*rval) * (c + 1)); - if (!tmp) { - free(rval); - rval = NULL; - c = 0; - break; - } else { - rval = tmp; - } - rval[c - 1] = p; - rval[c] = NULL; - } - *count = c; - return rval; -} - -void -doneline( - char *input, - char **vec) -{ - free(input); - free(vec); -} - -#define EXABYTES(x) ((long long)(x) << 60) -#define PETABYTES(x) ((long long)(x) << 50) -#define TERABYTES(x) ((long long)(x) << 40) -#define GIGABYTES(x) ((long long)(x) << 30) -#define MEGABYTES(x) ((long long)(x) << 20) -#define KILOBYTES(x) ((long long)(x) << 10) - -long long -cvtnum( - char *s) -{ - long long i; - char *sp; - int c; - - i = strtoll(s, &sp, 0); - if (i == 0 && sp == s) - return -1LL; - if (*sp == '\0') - return i; - - if (sp[1] != '\0') - return -1LL; - - c = qemu_tolower(*sp); - switch (c) { - default: - return i; - case 'k': - return KILOBYTES(i); - case 'm': - return MEGABYTES(i); - case 'g': - return GIGABYTES(i); - case 't': - return TERABYTES(i); - case 'p': - return PETABYTES(i); - case 'e': - return EXABYTES(i); - } - return -1LL; -} - -#define TO_EXABYTES(x) ((x) / EXABYTES(1)) -#define TO_PETABYTES(x) ((x) / PETABYTES(1)) -#define TO_TERABYTES(x) ((x) / TERABYTES(1)) -#define TO_GIGABYTES(x) ((x) / GIGABYTES(1)) -#define TO_MEGABYTES(x) ((x) / MEGABYTES(1)) -#define TO_KILOBYTES(x) ((x) / KILOBYTES(1)) - -void -cvtstr( - double value, - char *str, - size_t size) -{ - char *trim; - const char *suffix; - - if (value >= EXABYTES(1)) { - suffix = " EiB"; - snprintf(str, size - 4, "%.3f", TO_EXABYTES(value)); - } else if (value >= PETABYTES(1)) { - suffix = " PiB"; - snprintf(str, size - 4, "%.3f", TO_PETABYTES(value)); - } else if (value >= TERABYTES(1)) { - suffix = " TiB"; - snprintf(str, size - 4, "%.3f", TO_TERABYTES(value)); - } else if (value >= GIGABYTES(1)) { - suffix = " GiB"; - snprintf(str, size - 4, "%.3f", TO_GIGABYTES(value)); - } else if (value >= MEGABYTES(1)) { - suffix = " MiB"; - snprintf(str, size - 4, "%.3f", TO_MEGABYTES(value)); - } else if (value >= KILOBYTES(1)) { - suffix = " KiB"; - snprintf(str, size - 4, "%.3f", TO_KILOBYTES(value)); - } else { - suffix = " bytes"; - snprintf(str, size - 6, "%f", value); - } - - trim = strstr(str, ".000"); - if (trim) { - strcpy(trim, suffix); - } else { - strcat(str, suffix); - } -} - -struct timeval -tsub(struct timeval t1, struct timeval t2) -{ - t1.tv_usec -= t2.tv_usec; - if (t1.tv_usec < 0) { - t1.tv_usec += 1000000; - t1.tv_sec--; - } - t1.tv_sec -= t2.tv_sec; - return t1; -} - -double -tdiv(double value, struct timeval tv) -{ - return value / ((double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0)); -} - -#define HOURS(sec) ((sec) / (60 * 60)) -#define MINUTES(sec) (((sec) % (60 * 60)) / 60) -#define SECONDS(sec) ((sec) % 60) - -void -timestr( - struct timeval *tv, - char *ts, - size_t size, - int format) -{ - double usec = (double)tv->tv_usec / 1000000.0; - - if (format & TERSE_FIXED_TIME) { - if (!HOURS(tv->tv_sec)) { - snprintf(ts, size, "%u:%02u.%02u", - (unsigned int) MINUTES(tv->tv_sec), - (unsigned int) SECONDS(tv->tv_sec), - (unsigned int) (usec * 100)); - return; - } - format |= VERBOSE_FIXED_TIME; /* fallback if hours needed */ - } - - if ((format & VERBOSE_FIXED_TIME) || tv->tv_sec) { - snprintf(ts, size, "%u:%02u:%02u.%02u", - (unsigned int) HOURS(tv->tv_sec), - (unsigned int) MINUTES(tv->tv_sec), - (unsigned int) SECONDS(tv->tv_sec), - (unsigned int) (usec * 100)); - } else { - snprintf(ts, size, "0.%04u sec", (unsigned int) (usec * 10000)); - } -} - - -/* from libxcmd/quit.c */ - -static cmdinfo_t quit_cmd; - -/* ARGSUSED */ -static int -quit_f( - int argc, - char **argv) -{ - return 1; -} - -void -quit_init(void) -{ - quit_cmd.name = _("quit"); - quit_cmd.altname = _("q"); - quit_cmd.cfunc = quit_f; - quit_cmd.argmin = -1; - quit_cmd.argmax = -1; - quit_cmd.flags = CMD_FLAG_GLOBAL; - quit_cmd.oneline = _("exit the program"); - - add_command(&quit_cmd); -} - -/* from libxcmd/help.c */ - -static cmdinfo_t help_cmd; -static void help_onecmd(const char *cmd, const cmdinfo_t *ct); -static void help_oneline(const char *cmd, const cmdinfo_t *ct); - -static void -help_all(void) -{ - const cmdinfo_t *ct; - - for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) - help_oneline(ct->name, ct); - printf(_("\nUse 'help commandname' for extended help.\n")); -} - -static int -help_f( - int argc, - char **argv) -{ - const cmdinfo_t *ct; - - if (argc == 1) { - help_all(); - return 0; - } - ct = find_command(argv[1]); - if (ct == NULL) { - printf(_("command %s not found\n"), argv[1]); - return 0; - } - help_onecmd(argv[1], ct); - return 0; -} - -static void -help_onecmd( - const char *cmd, - const cmdinfo_t *ct) -{ - help_oneline(cmd, ct); - if (ct->help) - ct->help(); -} - -static void -help_oneline( - const char *cmd, - const cmdinfo_t *ct) -{ - if (cmd) - printf("%s ", cmd); - else { - printf("%s ", ct->name); - if (ct->altname) - printf("(or %s) ", ct->altname); - } - if (ct->args) - printf("%s ", ct->args); - printf("-- %s\n", ct->oneline); -} - -void -help_init(void) -{ - help_cmd.name = _("help"); - help_cmd.altname = _("?"); - help_cmd.cfunc = help_f; - help_cmd.argmin = 0; - help_cmd.argmax = 1; - help_cmd.flags = CMD_FLAG_GLOBAL; - help_cmd.args = _("[command]"); - help_cmd.oneline = _("help for one or all commands"); - - add_command(&help_cmd); -} @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2000-2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * 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. - * - * This program is distributed in the hope that it would 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 <http://www.gnu.org/licenses/>. - */ -#ifndef __COMMAND_H__ -#define __COMMAND_H__ - -#define CMD_FLAG_GLOBAL ((int)0x80000000) /* don't iterate "args" */ - -typedef int (*cfunc_t)(int argc, char **argv); -typedef void (*helpfunc_t)(void); - -typedef struct cmdinfo { - const char *name; - const char *altname; - cfunc_t cfunc; - int argmin; - int argmax; - int canpush; - int flags; - const char *args; - const char *oneline; - helpfunc_t help; -} cmdinfo_t; - -extern cmdinfo_t *cmdtab; -extern int ncmds; - -void help_init(void); -void quit_init(void); - -typedef int (*argsfunc_t)(int index); -typedef int (*checkfunc_t)(const cmdinfo_t *ci); - -void add_command(const cmdinfo_t *ci); -void add_user_command(char *optarg); -void add_args_command(argsfunc_t af); -void add_check_command(checkfunc_t cf); - -const cmdinfo_t *find_command(const char *cmd); - -void command_loop(void); -int command_usage(const cmdinfo_t *ci); -int command(const cmdinfo_t *ci, int argc, char **argv); - -/* from input.h */ -char **breakline(char *input, int *count); -void doneline(char *input, char **vec); -char *fetchline(void); - -long long cvtnum(char *s); -void cvtstr(double value, char *str, size_t sz); - -struct timeval tsub(struct timeval t1, struct timeval t2); -double tdiv(double value, struct timeval tv); - -enum { - DEFAULT_TIME = 0x0, - TERSE_FIXED_TIME = 0x1, - VERBOSE_FIXED_TIME = 0x2 -}; - -void timestr(struct timeval *tv, char *str, size_t sz, int flags); - -extern char *progname; - -#endif /* __COMMAND_H__ */ @@ -386,6 +386,8 @@ elif check_define __s390__ ; then fi elif check_define __arm__ ; then cpu="arm" +elif check_define __aarch64__ ; then + cpu="aarch64" elif check_define __hppa__ ; then cpu="hppa" else @@ -408,6 +410,9 @@ case "$cpu" in armv*b|armv*l|arm) cpu="arm" ;; + aarch64) + cpu="aarch64" + ;; hppa|parisc|parisc64) cpu="hppa" ;; @@ -553,7 +558,9 @@ esac if [ "$bsd" = "yes" ] ; then if [ "$darwin" != "yes" ] ; then - usb="bsd" + if [ "$targetos" != "FreeBSD" ]; then + usb="bsd" + fi bsd_user="yes" fi fi @@ -2557,29 +2564,6 @@ EOF fi fi -# -# Check for xxxat() functions when we are building linux-user -# emulator. This is done because older glibc versions don't -# have syscall stubs for these implemented. -# -atfile=no -cat > $TMPC << EOF -#define _ATFILE_SOURCE -#include <sys/types.h> -#include <fcntl.h> -#include <unistd.h> - -int -main(void) -{ - /* try to unlink nonexisting file */ - return (unlinkat(AT_FDCWD, "nonexistent_file", 0)); -} -EOF -if compile_prog "" "" ; then - atfile=yes -fi - # Check for inotify functions when we are building linux-user # emulator. This is done because older glibc versions don't # have syscall stubs for these implemented. In that case we @@ -3556,7 +3540,6 @@ echo "-> Your SDL version is too old - please upgrade to have SDL support" fi config_host_mak="config-host.mak" -config_host_ld="config-host.ld" echo "# Automatically generated by configure - do not modify" >config-all-disas.mak @@ -3722,9 +3705,6 @@ fi if test "$curses" = "yes" ; then echo "CONFIG_CURSES=y" >> $config_host_mak fi -if test "$atfile" = "yes" ; then - echo "CONFIG_ATFILE=y" >> $config_host_mak -fi if test "$utimens" = "yes" ; then echo "CONFIG_UTIMENSAT=y" >> $config_host_mak fi @@ -4071,7 +4051,7 @@ if test "$gcov" = "yes" ; then fi # generate list of library paths for linker script -$ld --verbose -v 2> /dev/null | grep SEARCH_DIR > ${config_host_ld} +$ld --verbose -v 2> /dev/null | grep SEARCH_DIR > config-host.ld # use included Linux headers if test "$linux" = "yes" ; then @@ -4086,6 +4066,9 @@ if test "$linux" = "yes" ; then s390x) linux_arch=s390 ;; + aarch64) + linux_arch=arm64 + ;; *) # For most CPUs the kernel architecture name and QEMU CPU name match. linux_arch="$cpu" @@ -4298,19 +4281,11 @@ case "$target_arch2" in fi fi esac -case "$target_arch2" in - i386|x86_64) - echo "CONFIG_HAVE_GET_MEMORY_MAPPING=y" >> $config_target_mak -esac if test "$target_bigendian" = "yes" ; then echo "TARGET_WORDS_BIGENDIAN=y" >> $config_target_mak fi if test "$target_softmmu" = "yes" ; then echo "CONFIG_SOFTMMU=y" >> $config_target_mak - case "$target_arch2" in - i386|x86_64) - echo "CONFIG_HAVE_CORE_DUMP=y" >> $config_target_mak - esac fi if test "$target_user_only" = "yes" ; then echo "CONFIG_USER_ONLY=y" >> $config_target_mak @@ -4450,7 +4425,7 @@ fi if test "$target_linux_user" = "yes" -o "$target_bsd_user" = "yes" ; then case "$ARCH" in - alpha | s390x) + alpha | s390x | aarch64) # The default placement of the application is fine. ;; *) @@ -262,8 +262,8 @@ void tlb_set_page(CPUArchState *env, target_ulong vaddr, #if defined(DEBUG_TLB) printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x" TARGET_FMT_plx - " prot=%x idx=%d pd=0x%08lx\n", - vaddr, paddr, prot, mmu_idx, pd); + " prot=%x idx=%d\n", + vaddr, paddr, prot, mmu_idx); #endif address = vaddr; diff --git a/device_tree.c b/device_tree.c index 56af24b..69be9da 100644 --- a/device_tree.c +++ b/device_tree.c @@ -213,7 +213,7 @@ uint32_t qemu_devtree_get_phandle(void *fdt, const char *path) uint32_t r; r = fdt_get_phandle(fdt, findnode_nofail(fdt, path)); - if (r <= 0) { + if (r == 0) { fprintf(stderr, "%s: Couldn't get phandle for %s: %s\n", __func__, path, fdt_strerror(r)); exit(1); @@ -21,6 +21,7 @@ #include "sysemu/dump.h" #include "sysemu/sysemu.h" #include "sysemu/memory_mapping.h" +#include "sysemu/cpus.h" #include "qapi/error.h" #include "qmp-commands.h" @@ -706,6 +707,7 @@ static int dump_init(DumpState *s, int fd, bool paging, bool has_filter, { CPUArchState *env; int nr_cpus; + Error *err = NULL; int ret; if (runstate_is_running()) { @@ -731,12 +733,12 @@ static int dump_init(DumpState *s, int fd, bool paging, bool has_filter, * If the target architecture is not supported, cpu_get_dump_info() will * return -1. * - * if we use kvm, we should synchronize the register before we get dump + * If we use KVM, we should synchronize the registers before we get dump * info. */ + cpu_synchronize_all_states(); nr_cpus = 0; for (env = first_cpu; env != NULL; env = env->next_cpu) { - cpu_synchronize_state(env); nr_cpus++; } @@ -756,7 +758,11 @@ static int dump_init(DumpState *s, int fd, bool paging, bool has_filter, /* get memory mapping */ memory_mapping_list_init(&s->list); if (paging) { - qemu_get_guest_memory_mapping(&s->list); + qemu_get_guest_memory_mapping(&s->list, &err); + if (err != NULL) { + error_propagate(errp, err); + goto cleanup; + } } else { qemu_get_guest_simple_memory_mapping(&s->list); } diff --git a/fpu/softfloat-macros.h b/fpu/softfloat-macros.h index b5164af..9b09545 100644 --- a/fpu/softfloat-macros.h +++ b/fpu/softfloat-macros.h @@ -168,7 +168,7 @@ INLINE void z0 = a0>>count; } else { - z1 = ( count < 64 ) ? ( a0>>( count & 63 ) ) : 0; + z1 = (count < 128) ? (a0 >> (count & 63)) : 0; z0 = 0; } *z1Ptr = z1; @@ -371,7 +371,10 @@ static inline void gdb_continue(GDBState *s) #ifdef CONFIG_USER_ONLY s->running_state = 1; #else - if (runstate_check(RUN_STATE_DEBUG)) { + if (runstate_check(RUN_STATE_GUEST_PANICKED)) { + runstate_set(RUN_STATE_DEBUG); + } + if (!runstate_needs_reset()) { vm_start(); } #endif diff --git a/hmp-commands.hx b/hmp-commands.hx index 9cea415..915b0d1 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -185,6 +185,8 @@ Remove host block device. The result is that guest generated IO is no longer submitted against the host device underlying the disk. Once a drive has been deleted, the QEMU Block layer returns -EIO which results in IO errors in the guest for applications that are reading/writing to the device. +These errors are always reported to the guest, regardless of the drive's error +actions (drive options rerror, werror). ETEXI { @@ -989,7 +991,6 @@ server will ask the spice/vnc client to automatically reconnect using the new parameters (if specified) once the vm migration finished successfully. ETEXI -#if defined(CONFIG_HAVE_CORE_DUMP) { .name = "dump-guest-memory", .args_type = "paging:-p,filename:F,begin:i?,length:i?", @@ -1013,7 +1014,6 @@ gdb. length: the memory size, in bytes. It's optional, and should be specified with begin together. ETEXI -#endif { .name = "snapshot_blkdev", @@ -1551,6 +1551,22 @@ Removes the chardev @var{id}. ETEXI { + .name = "qemu-io", + .args_type = "device:B,command:s", + .params = "[device] \"[command]\"", + .help = "run a qemu-io command on a block device", + .mhandler.cmd = hmp_qemu_io, + }, + +STEXI +@item qemu-io @var{device} @var{command} +@findex qemu-io + +Executes a qemu-io command on the given block device. + +ETEXI + + { .name = "info", .args_type = "item:s?", .params = "[subcommand]", @@ -22,6 +22,8 @@ #include "qemu/sockets.h" #include "monitor/monitor.h" #include "ui/console.h" +#include "block/qapi.h" +#include "qemu-io.h" static void hmp_handle_error(Monitor *mon, Error **errp) { @@ -277,10 +279,16 @@ void hmp_info_cpus(Monitor *mon, const QDict *qdict) void hmp_info_block(Monitor *mon, const QDict *qdict) { BlockInfoList *block_list, *info; + ImageInfo *image_info; + const char *device = qdict_get_try_str(qdict, "device"); + bool verbose = qdict_get_try_bool(qdict, "verbose", 0); block_list = qmp_query_block(NULL); for (info = block_list; info; info = info->next) { + if (device && strcmp(device, info->value->device)) { + continue; + } monitor_printf(mon, "%s: removable=%d", info->value->device, info->value->removable); @@ -318,6 +326,20 @@ void hmp_info_block(Monitor *mon, const QDict *qdict) info->value->inserted->iops, info->value->inserted->iops_rd, info->value->inserted->iops_wr); + + if (verbose) { + monitor_printf(mon, " images:\n"); + image_info = info->value->inserted->image; + while (1) { + bdrv_image_info_dump((fprintf_function)monitor_printf, + mon, image_info); + if (image_info->has_backing_image) { + image_info = image_info->backing_image; + } else { + break; + } + } + } } else { monitor_printf(mon, " [not inserted]"); } @@ -1425,3 +1447,20 @@ void hmp_chardev_remove(Monitor *mon, const QDict *qdict) qmp_chardev_remove(qdict_get_str(qdict, "id"), &local_err); hmp_handle_error(mon, &local_err); } + +void hmp_qemu_io(Monitor *mon, const QDict *qdict) +{ + BlockDriverState *bs; + const char* device = qdict_get_str(qdict, "device"); + const char* command = qdict_get_str(qdict, "command"); + Error *err = NULL; + + bs = bdrv_find(device); + if (bs) { + qemuio_command(bs, command); + } else { + error_set(&err, QERR_DEVICE_NOT_FOUND, device); + } + + hmp_handle_error(mon, &err); +} @@ -85,5 +85,6 @@ void hmp_nbd_server_add(Monitor *mon, const QDict *qdict); void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict); void hmp_chardev_add(Monitor *mon, const QDict *qdict); void hmp_chardev_remove(Monitor *mon, const QDict *qdict); +void hmp_qemu_io(Monitor *mon, const QDict *qdict); #endif diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c index e6525ac..756df3b 100644 --- a/hw/acpi/piix4.c +++ b/hw/acpi/piix4.c @@ -518,7 +518,7 @@ static uint64_t gpe_readb(void *opaque, hwaddr addr, unsigned width) PIIX4PMState *s = opaque; uint32_t val = acpi_gpe_ioport_readb(&s->ar, addr); - PIIX4_DPRINTF("gpe read %x == %x\n", addr, val); + PIIX4_DPRINTF("gpe read %" HWADDR_PRIx " == %" PRIu32 "\n", addr, val); return val; } @@ -530,7 +530,7 @@ static void gpe_writeb(void *opaque, hwaddr addr, uint64_t val, acpi_gpe_ioport_writeb(&s->ar, addr, val); pm_update_sci(s); - PIIX4_DPRINTF("gpe write %x <== %d\n", addr, val); + PIIX4_DPRINTF("gpe write %" HWADDR_PRIx " <== %" PRIu64 "\n", addr, val); } static const MemoryRegionOps piix4_gpe_ops = { @@ -553,15 +553,15 @@ static uint64_t pci_read(void *opaque, hwaddr addr, unsigned int size) /* Manufacture an "up" value to cause a device check on any hotplug * slot with a device. Extra device checks are harmless. */ val = s->pci0_slot_device_present & s->pci0_hotplug_enable; - PIIX4_DPRINTF("pci_up_read %x\n", val); + PIIX4_DPRINTF("pci_up_read %" PRIu32 "\n", val); break; case PCI_DOWN_BASE - PCI_HOTPLUG_ADDR: val = s->pci0_status.down; - PIIX4_DPRINTF("pci_down_read %x\n", val); + PIIX4_DPRINTF("pci_down_read %" PRIu32 "\n", val); break; case PCI_EJ_BASE - PCI_HOTPLUG_ADDR: /* No feature defined yet */ - PIIX4_DPRINTF("pci_features_read %x\n", val); + PIIX4_DPRINTF("pci_features_read %" PRIu32 "\n", val); break; case PCI_RMV_BASE - PCI_HOTPLUG_ADDR: val = s->pci0_hotplug_enable; @@ -579,7 +579,7 @@ static void pci_write(void *opaque, hwaddr addr, uint64_t data, switch (addr) { case PCI_EJ_BASE - PCI_HOTPLUG_ADDR: acpi_piix_eject_slot(opaque, (uint32_t)data); - PIIX4_DPRINTF("pciej write %" HWADDR_PRIx " <== % " PRIu64 "\n", + PIIX4_DPRINTF("pciej write %" HWADDR_PRIx " <== %" PRIu64 "\n", addr, data); break; default: diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c index 1016af0..3ac90d5 100644 --- a/hw/audio/intel-hda.c +++ b/hw/audio/intel-hda.c @@ -189,6 +189,11 @@ struct IntelHDAState { uint32_t msi; }; +#define TYPE_INTEL_HDA_GENERIC "intel-hda-generic" + +#define INTEL_HDA(obj) \ + OBJECT_CHECK(IntelHDAState, (obj), TYPE_INTEL_HDA_GENERIC) + struct IntelHDAReg { const char *name; /* register name */ uint32_t size; /* size in bytes */ @@ -498,7 +503,7 @@ static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool runn static void intel_hda_set_g_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old) { if ((d->g_ctl & ICH6_GCTL_RESET) == 0) { - intel_hda_reset(&d->pci.qdev); + intel_hda_reset(DEVICE(d)); } } @@ -1102,7 +1107,7 @@ static const MemoryRegionOps intel_hda_mmio_ops = { static void intel_hda_reset(DeviceState *dev) { BusChild *kid; - IntelHDAState *d = DO_UPCAST(IntelHDAState, pci.qdev, dev); + IntelHDAState *d = INTEL_HDA(dev); HDACodecDevice *cdev; intel_hda_regs_reset(d); @@ -1120,7 +1125,7 @@ static void intel_hda_reset(DeviceState *dev) static int intel_hda_init(PCIDevice *pci) { - IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci); + IntelHDAState *d = INTEL_HDA(pci); uint8_t *conf = d->pci.config; d->name = object_get_typename(OBJECT(d)); @@ -1137,7 +1142,7 @@ static int intel_hda_init(PCIDevice *pci) msi_init(&d->pci, 0x50, 1, true, false); } - hda_codec_bus_init(&d->pci.qdev, &d->codecs, + hda_codec_bus_init(DEVICE(pci), &d->codecs, intel_hda_response, intel_hda_xfer); return 0; @@ -1145,7 +1150,7 @@ static int intel_hda_init(PCIDevice *pci) static void intel_hda_exit(PCIDevice *pci) { - IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci); + IntelHDAState *d = INTEL_HDA(pci); msi_uninit(&d->pci); memory_region_destroy(&d->mmio); @@ -1232,7 +1237,7 @@ static Property intel_hda_properties[] = { DEFINE_PROP_END_OF_LIST(), }; -static void intel_hda_class_init_common(ObjectClass *klass) +static void intel_hda_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -1251,7 +1256,6 @@ static void intel_hda_class_init_ich6(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - intel_hda_class_init_common(klass); k->device_id = 0x2668; k->revision = 1; dc->desc = "Intel HD Audio Controller (ich6)"; @@ -1262,23 +1266,28 @@ static void intel_hda_class_init_ich9(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - intel_hda_class_init_common(klass); k->device_id = 0x293e; k->revision = 3; dc->desc = "Intel HD Audio Controller (ich9)"; } -static const TypeInfo intel_hda_info_ich6 = { - .name = "intel-hda", +static const TypeInfo intel_hda_info = { + .name = TYPE_INTEL_HDA_GENERIC, .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(IntelHDAState), + .class_init = intel_hda_class_init, + .abstract = true, +}; + +static const TypeInfo intel_hda_info_ich6 = { + .name = "intel-hda", + .parent = TYPE_INTEL_HDA_GENERIC, .class_init = intel_hda_class_init_ich6, }; static const TypeInfo intel_hda_info_ich9 = { .name = "ich9-intel-hda", - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(IntelHDAState), + .parent = TYPE_INTEL_HDA_GENERIC, .class_init = intel_hda_class_init_ich9, }; @@ -1306,12 +1315,12 @@ static const TypeInfo hda_codec_device_type_info = { */ static int intel_hda_and_codec_init(PCIBus *bus) { - PCIDevice *controller; + DeviceState *controller; BusState *hdabus; DeviceState *codec; - controller = pci_create_simple(bus, -1, "intel-hda"); - hdabus = QLIST_FIRST(&controller->qdev.child_bus); + controller = DEVICE(pci_create_simple(bus, -1, "intel-hda")); + hdabus = QLIST_FIRST(&controller->child_bus); codec = qdev_create(hdabus, "hda-duplex"); qdev_init_nofail(codec); return 0; @@ -1320,6 +1329,7 @@ static int intel_hda_and_codec_init(PCIBus *bus) static void intel_hda_register_types(void) { type_register_static(&hda_codec_bus_info); + type_register_static(&intel_hda_info); type_register_static(&intel_hda_info_ich6); type_register_static(&intel_hda_info_ich9); type_register_static(&hda_codec_device_type_info); diff --git a/hw/char/serial.c b/hw/char/serial.c index f2701e8..b537e42 100644 --- a/hw/char/serial.c +++ b/hw/char/serial.c @@ -92,8 +92,6 @@ #define UART_FCR_RFR 0x02 /* RCVR Fifo Reset */ #define UART_FCR_FE 0x01 /* FIFO Enable */ -#define XMIT_FIFO 0 -#define RECV_FIFO 1 #define MAX_XMIT_RETRY 4 #ifdef DEBUG_SERIAL @@ -106,50 +104,14 @@ do {} while (0) static void serial_receive1(void *opaque, const uint8_t *buf, int size); -static void fifo_clear(SerialState *s, int fifo) +static inline void recv_fifo_put(SerialState *s, uint8_t chr) { - SerialFIFO *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo; - memset(f->data, 0, UART_FIFO_LENGTH); - f->count = 0; - f->head = 0; - f->tail = 0; -} - -static int fifo_put(SerialState *s, int fifo, uint8_t chr) -{ - SerialFIFO *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo; - /* Receive overruns do not overwrite FIFO contents. */ - if (fifo == XMIT_FIFO || f->count < UART_FIFO_LENGTH) { - - f->data[f->head++] = chr; - - if (f->head == UART_FIFO_LENGTH) - f->head = 0; - } - - if (f->count < UART_FIFO_LENGTH) - f->count++; - else if (fifo == RECV_FIFO) + if (!fifo8_is_full(&s->recv_fifo)) { + fifo8_push(&s->recv_fifo, chr); + } else { s->lsr |= UART_LSR_OE; - - return 1; -} - -static uint8_t fifo_get(SerialState *s, int fifo) -{ - SerialFIFO *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo; - uint8_t c; - - if(f->count == 0) - return 0; - - c = f->data[f->tail++]; - if (f->tail == UART_FIFO_LENGTH) - f->tail = 0; - f->count--; - - return c; + } } static void serial_update_irq(SerialState *s) @@ -165,7 +127,7 @@ static void serial_update_irq(SerialState *s) tmp_iir = UART_IIR_CTI; } else if ((s->ier & UART_IER_RDI) && (s->lsr & UART_LSR_DR) && (!(s->fcr & UART_FCR_FE) || - s->recv_fifo.count >= s->recv_fifo.itl)) { + s->recv_fifo.num >= s->recv_fifo_itl)) { tmp_iir = UART_IIR_RDI; } else if ((s->ier & UART_IER_THRI) && s->thr_ipending) { tmp_iir = UART_IIR_THRI; @@ -262,9 +224,11 @@ static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque) if (s->tsr_retry <= 0) { if (s->fcr & UART_FCR_FE) { - s->tsr = fifo_get(s,XMIT_FIFO); - if (!s->xmit_fifo.count) + s->tsr = fifo8_is_full(&s->xmit_fifo) ? + 0 : fifo8_pop(&s->xmit_fifo); + if (!s->xmit_fifo.num) { s->lsr |= UART_LSR_THRE; + } } else if ((s->lsr & UART_LSR_THRE)) { return FALSE; } else { @@ -316,16 +280,16 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val, } else { s->thr = (uint8_t) val; if(s->fcr & UART_FCR_FE) { - fifo_put(s, XMIT_FIFO, s->thr); - s->thr_ipending = 0; + /* xmit overruns overwrite data, so make space if needed */ + if (fifo8_is_full(&s->xmit_fifo)) { + fifo8_pop(&s->xmit_fifo); + } + fifo8_push(&s->xmit_fifo, s->thr); s->lsr &= ~UART_LSR_TEMT; - s->lsr &= ~UART_LSR_THRE; - serial_update_irq(s); - } else { - s->thr_ipending = 0; - s->lsr &= ~UART_LSR_THRE; - serial_update_irq(s); } + s->thr_ipending = 0; + s->lsr &= ~UART_LSR_THRE; + serial_update_irq(s); serial_xmit(NULL, G_IO_OUT, s); } break; @@ -367,28 +331,28 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val, if (val & UART_FCR_RFR) { qemu_del_timer(s->fifo_timeout_timer); s->timeout_ipending=0; - fifo_clear(s,RECV_FIFO); + fifo8_reset(&s->recv_fifo); } if (val & UART_FCR_XFR) { - fifo_clear(s,XMIT_FIFO); + fifo8_reset(&s->xmit_fifo); } if (val & UART_FCR_FE) { s->iir |= UART_IIR_FE; - /* Set RECV_FIFO trigger Level */ + /* Set recv_fifo trigger Level */ switch (val & 0xC0) { case UART_FCR_ITL_1: - s->recv_fifo.itl = 1; + s->recv_fifo_itl = 1; break; case UART_FCR_ITL_2: - s->recv_fifo.itl = 4; + s->recv_fifo_itl = 4; break; case UART_FCR_ITL_3: - s->recv_fifo.itl = 8; + s->recv_fifo_itl = 8; break; case UART_FCR_ITL_4: - s->recv_fifo.itl = 14; + s->recv_fifo_itl = 14; break; } } else @@ -460,11 +424,13 @@ static uint64_t serial_ioport_read(void *opaque, hwaddr addr, unsigned size) ret = s->divider & 0xff; } else { if(s->fcr & UART_FCR_FE) { - ret = fifo_get(s,RECV_FIFO); - if (s->recv_fifo.count == 0) + ret = fifo8_is_full(&s->recv_fifo) ? + 0 : fifo8_pop(&s->recv_fifo); + if (s->recv_fifo.num == 0) { s->lsr &= ~(UART_LSR_DR | UART_LSR_BI); - else + } else { qemu_mod_timer(s->fifo_timeout_timer, qemu_get_clock_ns (vm_clock) + s->char_transmit_time * 4); + } s->timeout_ipending = 0; } else { ret = s->rbr; @@ -534,15 +500,21 @@ static uint64_t serial_ioport_read(void *opaque, hwaddr addr, unsigned size) static int serial_can_receive(SerialState *s) { if(s->fcr & UART_FCR_FE) { - if(s->recv_fifo.count < UART_FIFO_LENGTH) - /* Advertise (fifo.itl - fifo.count) bytes when count < ITL, and 1 if above. If UART_FIFO_LENGTH - fifo.count is - advertised the effect will be to almost always fill the fifo completely before the guest has a chance to respond, - effectively overriding the ITL that the guest has set. */ - return (s->recv_fifo.count <= s->recv_fifo.itl) ? s->recv_fifo.itl - s->recv_fifo.count : 1; - else - return 0; + if (s->recv_fifo.num < UART_FIFO_LENGTH) { + /* + * Advertise (fifo.itl - fifo.count) bytes when count < ITL, and 1 + * if above. If UART_FIFO_LENGTH - fifo.count is advertised the + * effect will be to almost always fill the fifo completely before + * the guest has a chance to respond, effectively overriding the ITL + * that the guest has set. + */ + return (s->recv_fifo.num <= s->recv_fifo_itl) ? + s->recv_fifo_itl - s->recv_fifo.num : 1; + } else { + return 0; + } } else { - return !(s->lsr & UART_LSR_DR); + return !(s->lsr & UART_LSR_DR); } } @@ -550,7 +522,7 @@ static void serial_receive_break(SerialState *s) { s->rbr = 0; /* When the LSR_DR is set a null byte is pushed into the fifo */ - fifo_put(s, RECV_FIFO, '\0'); + recv_fifo_put(s, '\0'); s->lsr |= UART_LSR_BI | UART_LSR_DR; serial_update_irq(s); } @@ -558,7 +530,7 @@ static void serial_receive_break(SerialState *s) /* There's data in recv_fifo and s->rbr has not been read for 4 char transmit times */ static void fifo_timeout_int (void *opaque) { SerialState *s = opaque; - if (s->recv_fifo.count) { + if (s->recv_fifo.num) { s->timeout_ipending = 1; serial_update_irq(s); } @@ -580,7 +552,7 @@ static void serial_receive1(void *opaque, const uint8_t *buf, int size) if(s->fcr & UART_FCR_FE) { int i; for (i = 0; i < size; i++) { - fifo_put(s, RECV_FIFO, buf[i]); + recv_fifo_put(s, buf[i]); } s->lsr |= UART_LSR_DR; /* call the timeout receive callback in 4 char transmit time */ @@ -660,8 +632,8 @@ static void serial_reset(void *opaque) s->char_transmit_time = (get_ticks_per_sec() / 9600) * 10; s->poll_msl = 0; - fifo_clear(s,RECV_FIFO); - fifo_clear(s,XMIT_FIFO); + fifo8_reset(&s->recv_fifo); + fifo8_reset(&s->xmit_fifo); s->last_xmit_ts = qemu_get_clock_ns(vm_clock); @@ -684,6 +656,8 @@ void serial_realize_core(SerialState *s, Error **errp) qemu_chr_add_handlers(s->chr, serial_can_receive1, serial_receive1, serial_event, s); + fifo8_create(&s->recv_fifo, UART_FIFO_LENGTH); + fifo8_create(&s->xmit_fifo, UART_FIFO_LENGTH); } void serial_exit_core(SerialState *s) diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c index 3a3ef8a..50054cf 100644 --- a/hw/dma/xilinx_axidma.c +++ b/hw/dma/xilinx_axidma.c @@ -514,8 +514,9 @@ static void axidma_write(void *opaque, hwaddr addr, break; } if (sid == 1 && d->notify) { - d->notify(d->notify_opaque); + StreamCanPushNotifyFn notifytmp = d->notify; d->notify = NULL; + notifytmp(d->notify_opaque); } stream_update_irq(s); } diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 0ad062c..e0fbb86 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -934,6 +934,11 @@ void pc_hot_add_cpu(const int64_t id, Error **errp) DeviceState *icc_bridge; int64_t apic_id = x86_cpu_apic_id_from_index(id); + if (id < 0) { + error_setg(errp, "Invalid CPU id: %" PRIi64, id); + return; + } + if (cpu_exists(apic_id)) { error_setg(errp, "Unable to add CPU: %" PRIi64 ", it already exists", id); diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index af1e9af..97362f2 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -327,8 +327,8 @@ static void pc_xen_hvm_init(QEMUMachineInitArgs *args) } #endif -static QEMUMachine pc_i440fx_machine_v1_5 = { - .name = "pc-i440fx-1.5", +static QEMUMachine pc_i440fx_machine_v1_6 = { + .name = "pc-i440fx-1.6", .alias = "pc", .desc = "Standard PC (i440FX + PIIX, 1996)", .init = pc_init_pci, @@ -338,6 +338,19 @@ static QEMUMachine pc_i440fx_machine_v1_5 = { DEFAULT_MACHINE_OPTIONS, }; +static QEMUMachine pc_i440fx_machine_v1_5 = { + .name = "pc-i440fx-1.5", + .desc = "Standard PC (i440FX + PIIX, 1996)", + .init = pc_init_pci, + .hot_add_cpu = pc_hot_add_cpu, + .max_cpus = 255, + .compat_props = (GlobalProperty[]) { + PC_COMPAT_1_5, + { /* end of list */ } + }, + DEFAULT_MACHINE_OPTIONS, +}; + static QEMUMachine pc_i440fx_machine_v1_4 = { .name = "pc-i440fx-1.4", .desc = "Standard PC (i440FX + PIIX, 1996)", @@ -735,6 +748,7 @@ static QEMUMachine xenfv_machine = { static void pc_machine_init(void) { + qemu_register_machine(&pc_i440fx_machine_v1_6); qemu_register_machine(&pc_i440fx_machine_v1_5); qemu_register_machine(&pc_i440fx_machine_v1_4); qemu_register_machine(&pc_machine_v1_3); diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 7888dfe..bb0ce6a 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -215,13 +215,26 @@ static void pc_q35_init_1_4(QEMUMachineInitArgs *args) pc_q35_init(args); } +static QEMUMachine pc_q35_machine_v1_6 = { + .name = "pc-q35-1.6", + .alias = "q35", + .desc = "Standard PC (Q35 + ICH9, 2009)", + .init = pc_q35_init, + .hot_add_cpu = pc_hot_add_cpu, + .max_cpus = 255, + DEFAULT_MACHINE_OPTIONS, +}; + static QEMUMachine pc_q35_machine_v1_5 = { .name = "pc-q35-1.5", - .alias = "q35", .desc = "Standard PC (Q35 + ICH9, 2009)", .init = pc_q35_init, .hot_add_cpu = pc_hot_add_cpu, .max_cpus = 255, + .compat_props = (GlobalProperty[]) { + PC_COMPAT_1_5, + { /* end of list */ } + }, DEFAULT_MACHINE_OPTIONS, }; @@ -239,6 +252,7 @@ static QEMUMachine pc_q35_machine_v1_4 = { static void pc_q35_machine_init(void) { + qemu_register_machine(&pc_q35_machine_v1_6); qemu_register_machine(&pc_q35_machine_v1_5); qemu_register_machine(&pc_q35_machine_v1_4); } diff --git a/hw/i386/smbios.c b/hw/i386/smbios.c index c00bb2f..e708cb8 100644 --- a/hw/i386/smbios.c +++ b/hw/i386/smbios.c @@ -13,6 +13,7 @@ * GNU GPL, version 2 or (at your option) any later version. */ +#include "qemu/error-report.h" #include "sysemu/sysemu.h" #include "hw/i386/smbios.h" #include "hw/loader.h" @@ -48,8 +49,7 @@ static int smbios_type4_count = 0; static void smbios_validate_table(void) { if (smbios_type4_count && smbios_type4_count != smp_cpus) { - fprintf(stderr, - "Number of SMBIOS Type 4 tables must match cpu count.\n"); + error_report("Number of SMBIOS Type 4 tables must match cpu count"); exit(1); } } @@ -82,16 +82,16 @@ static void smbios_check_collision(int type, int entry) if (entry == SMBIOS_TABLE_ENTRY && header->type == SMBIOS_FIELD_ENTRY) { struct smbios_field *field = (void *)header; if (type == field->type) { - fprintf(stderr, "SMBIOS type %d field already defined, " - "cannot add table\n", type); + error_report("SMBIOS type %d field already defined, " + "cannot add table", type); exit(1); } } else if (entry == SMBIOS_FIELD_ENTRY && header->type == SMBIOS_TABLE_ENTRY) { struct smbios_structure_header *table = (void *)(header + 1); if (type == table->type) { - fprintf(stderr, "SMBIOS type %d table already defined, " - "cannot add field\n", type); + error_report("SMBIOS type %d table already defined, " + "cannot add field", type); exit(1); } } @@ -99,7 +99,7 @@ static void smbios_check_collision(int type, int entry) } } -void smbios_add_field(int type, int offset, int len, void *data) +void smbios_add_field(int type, int offset, const void *data, size_t len) { struct smbios_field *field; @@ -127,24 +127,29 @@ void smbios_add_field(int type, int offset, int len, void *data) static void smbios_build_type_0_fields(const char *t) { char buf[1024]; + unsigned char major, minor; if (get_param_value(buf, sizeof(buf), "vendor", t)) smbios_add_field(0, offsetof(struct smbios_type_0, vendor_str), - strlen(buf) + 1, buf); + buf, strlen(buf) + 1); if (get_param_value(buf, sizeof(buf), "version", t)) smbios_add_field(0, offsetof(struct smbios_type_0, bios_version_str), - strlen(buf) + 1, buf); + buf, strlen(buf) + 1); if (get_param_value(buf, sizeof(buf), "date", t)) smbios_add_field(0, offsetof(struct smbios_type_0, bios_release_date_str), - strlen(buf) + 1, buf); + buf, strlen(buf) + 1); if (get_param_value(buf, sizeof(buf), "release", t)) { - int major, minor; - sscanf(buf, "%d.%d", &major, &minor); + if (sscanf(buf, "%hhu.%hhu", &major, &minor) != 2) { + error_report("Invalid release"); + exit(1); + } smbios_add_field(0, offsetof(struct smbios_type_0, - system_bios_major_release), 1, &major); + system_bios_major_release), + &major, 1); smbios_add_field(0, offsetof(struct smbios_type_0, - system_bios_minor_release), 1, &minor); + system_bios_minor_release), + &minor, 1); } } @@ -154,28 +159,28 @@ static void smbios_build_type_1_fields(const char *t) if (get_param_value(buf, sizeof(buf), "manufacturer", t)) smbios_add_field(1, offsetof(struct smbios_type_1, manufacturer_str), - strlen(buf) + 1, buf); + buf, strlen(buf) + 1); if (get_param_value(buf, sizeof(buf), "product", t)) smbios_add_field(1, offsetof(struct smbios_type_1, product_name_str), - strlen(buf) + 1, buf); + buf, strlen(buf) + 1); if (get_param_value(buf, sizeof(buf), "version", t)) smbios_add_field(1, offsetof(struct smbios_type_1, version_str), - strlen(buf) + 1, buf); + buf, strlen(buf) + 1); if (get_param_value(buf, sizeof(buf), "serial", t)) smbios_add_field(1, offsetof(struct smbios_type_1, serial_number_str), - strlen(buf) + 1, buf); + buf, strlen(buf) + 1); if (get_param_value(buf, sizeof(buf), "uuid", t)) { if (qemu_uuid_parse(buf, qemu_uuid) != 0) { - fprintf(stderr, "Invalid SMBIOS UUID string\n"); + error_report("Invalid UUID"); exit(1); } } if (get_param_value(buf, sizeof(buf), "sku", t)) smbios_add_field(1, offsetof(struct smbios_type_1, sku_number_str), - strlen(buf) + 1, buf); + buf, strlen(buf) + 1); if (get_param_value(buf, sizeof(buf), "family", t)) smbios_add_field(1, offsetof(struct smbios_type_1, family_str), - strlen(buf) + 1, buf); + buf, strlen(buf) + 1); } int smbios_entry_add(const char *t) @@ -188,7 +193,7 @@ int smbios_entry_add(const char *t) int size = get_image_size(buf); if (size == -1 || size < sizeof(struct smbios_structure_header)) { - fprintf(stderr, "Cannot read smbios file %s\n", buf); + error_report("Cannot read SMBIOS file %s", buf); exit(1); } @@ -204,7 +209,7 @@ int smbios_entry_add(const char *t) table->header.length = cpu_to_le16(sizeof(*table) + size); if (load_image(buf, table->data) != size) { - fprintf(stderr, "Failed to load smbios file %s", buf); + error_report("Failed to load SMBIOS file %s", buf); exit(1); } @@ -230,12 +235,12 @@ int smbios_entry_add(const char *t) smbios_build_type_1_fields(t); return 0; default: - fprintf(stderr, "Don't know how to build fields for SMBIOS type " - "%ld\n", type); + error_report("Don't know how to build fields for SMBIOS type %ld", + type); exit(1); } } - fprintf(stderr, "smbios: must specify type= or file=\n"); + error_report("Must specify type= or file="); return -1; } diff --git a/hw/ide/core.c b/hw/ide/core.c index c7a8041..9926d92 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -814,6 +814,7 @@ void ide_flush_cache(IDEState *s) return; } + s->status |= BUSY_STAT; bdrv_acct_start(s->bs, &s->acct, 0, BDRV_ACCT_FLUSH); bdrv_aio_flush(s->bs, ide_flush_cb, s); } diff --git a/hw/intc/xilinx_intc.c b/hw/intc/xilinx_intc.c index b106e72..5df7008 100644 --- a/hw/intc/xilinx_intc.c +++ b/hw/intc/xilinx_intc.c @@ -66,11 +66,7 @@ static void update_irq(struct xlx_pic *p) i = ~0; p->regs[R_IVR] = i; - if ((p->regs[R_MER] & 1) && p->regs[R_IPR]) { - qemu_irq_raise(p->parent_irq); - } else { - qemu_irq_lower(p->parent_irq); - } + qemu_set_irq(p->parent_irq, (p->regs[R_MER] & 1) && p->regs[R_IPR]); } static uint64_t diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c index a19a6d6..5658f73 100644 --- a/hw/misc/ivshmem.c +++ b/hw/misc/ivshmem.c @@ -735,6 +735,7 @@ static int pci_ivshmem_init(PCIDevice *dev) if (s->shmobj == NULL) { fprintf(stderr, "Must specify 'chardev' or 'shm' to ivshmem\n"); + exit(1); } IVSHMEM_DPRINTF("using shm_open (shm object = %s)\n", s->shmobj); diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c index 5f483e7..4c575e5 100644 --- a/hw/net/vmxnet3.c +++ b/hw/net/vmxnet3.c @@ -1892,7 +1892,7 @@ static void vmxnet3_net_uninit(VMXNET3State *s) vmxnet_tx_pkt_reset(s->tx_pkt); vmxnet_tx_pkt_uninit(s->tx_pkt); vmxnet_rx_pkt_uninit(s->rx_pkt); - qemu_del_net_client(qemu_get_queue(s->nic)); + qemu_del_nic(s->nic); } static void vmxnet3_net_init(VMXNET3State *s) diff --git a/hw/net/xilinx_axienet.c b/hw/net/xilinx_axienet.c index 8989e95..2ca1511 100644 --- a/hw/net/xilinx_axienet.c +++ b/hw/net/xilinx_axienet.c @@ -575,7 +575,7 @@ static void enet_write(void *opaque, hwaddr addr, break; case R_MC: - value &= ((1 < 7) - 1); + value &= ((1 << 7) - 1); /* Enable the MII. */ if (value & MC_EN) { diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c index 8ecaa5f..f4bd3c9 100644 --- a/hw/ppc/spapr_rtas.c +++ b/hw/ppc/spapr_rtas.c @@ -130,7 +130,6 @@ static void rtas_query_cpu_stopped_state(sPAPREnvironment *spapr, uint32_t nret, target_ulong rets) { target_ulong id; - CPUPPCState *env; CPUState *cpu; if (nargs != 1 || nret != 2) { @@ -139,12 +138,8 @@ static void rtas_query_cpu_stopped_state(sPAPREnvironment *spapr, } id = rtas_ld(args, 0); - for (env = first_cpu; env; env = env->next_cpu) { - cpu = CPU(ppc_env_get_cpu(env)); - if (cpu->cpu_index != id) { - continue; - } - + cpu = qemu_get_cpu(id); + if (cpu != NULL) { if (cpu->halted) { rtas_st(rets, 1, 0); } else { @@ -165,8 +160,7 @@ static void rtas_start_cpu(sPAPREnvironment *spapr, uint32_t nret, target_ulong rets) { target_ulong id, start, r3; - CPUState *cpu; - CPUPPCState *env; + CPUState *cs; if (nargs != 3 || nret != 1) { rtas_st(rets, 0, -3); @@ -177,14 +171,12 @@ static void rtas_start_cpu(sPAPREnvironment *spapr, start = rtas_ld(args, 1); r3 = rtas_ld(args, 2); - for (env = first_cpu; env; env = env->next_cpu) { - cpu = CPU(ppc_env_get_cpu(env)); - - if (cpu->cpu_index != id) { - continue; - } + cs = qemu_get_cpu(id); + if (cs != NULL) { + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; - if (!cpu->halted) { + if (!cs->halted) { rtas_st(rets, 0, -1); return; } @@ -197,9 +189,9 @@ static void rtas_start_cpu(sPAPREnvironment *spapr, env->msr = (1ULL << MSR_SF) | (1ULL << MSR_ME); env->nip = start; env->gpr[3] = r3; - cpu->halted = 0; + cs->halted = 0; - qemu_cpu_kick(cpu); + qemu_cpu_kick(cs); rtas_st(rets, 0, 0); return; diff --git a/hw/s390x/css.c b/hw/s390x/css.c index e526a1c..f82abfe 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -777,7 +777,7 @@ int css_do_tsch(SubchDev *sch, IRB *target_irb) (p->chars & PMCW_CHARS_MASK_CSENSE)) { irb.scsw.flags |= SCSW_FLAGS_MASK_ESWF | SCSW_FLAGS_MASK_ECTL; memcpy(irb.ecw, sch->sense_data, sizeof(sch->sense_data)); - irb.esw[1] = 0x02000000 | (sizeof(sch->sense_data) << 8); + irb.esw[1] = 0x01000000 | (sizeof(sch->sense_data) << 8); } } /* Store the irb to the guest. */ diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index 5f5e267..44f5772 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -328,10 +328,10 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) ret = -EINVAL; break; } - indicators = ldq_phys(ccw.cda); - if (!indicators) { + if (!ccw.cda) { ret = -EFAULT; } else { + indicators = ldq_phys(ccw.cda); dev->indicators = indicators; sch->curr_status.scsw.count = ccw.count - sizeof(indicators); ret = 0; @@ -348,10 +348,10 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) ret = -EINVAL; break; } - indicators = ldq_phys(ccw.cda); - if (!indicators) { + if (!ccw.cda) { ret = -EFAULT; } else { + indicators = ldq_phys(ccw.cda); dev->indicators2 = indicators; sch->curr_status.scsw.count = ccw.count - sizeof(indicators); ret = 0; diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c index 48d12f4..446f723 100644 --- a/hw/scsi/vmw_pvscsi.c +++ b/hw/scsi/vmw_pvscsi.c @@ -389,7 +389,7 @@ pvscsi_process_completion_queue(void *opaque) QTAILQ_REMOVE(&s->completion_queue, pvscsi_req, next); pvscsi_cmp_ring_put(s, &pvscsi_req->cmp); g_free(pvscsi_req); - has_completed++; + has_completed = true; } if (has_completed) { diff --git a/hw/xen/xen_pt_config_init.c b/hw/xen/xen_pt_config_init.c index 01872db..8ccc2e4 100644 --- a/hw/xen/xen_pt_config_init.c +++ b/hw/xen/xen_pt_config_init.c @@ -1777,12 +1777,12 @@ static int xen_pt_config_reg_init(XenPCIPassthroughState *s, rc = reg->init(s, reg_entry->reg, reg_grp->base_offset + reg->offset, &data); if (rc < 0) { - free(reg_entry); + g_free(reg_entry); return rc; } if (data == XEN_PT_INVALID_REG) { /* free unused BAR register entry */ - free(reg_entry); + g_free(reg_entry); return 0; } /* set register value */ diff --git a/include/block/block.h b/include/block/block.h index dc5b388..2307f67 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -424,6 +424,9 @@ typedef enum { BLKDBG_CLUSTER_ALLOC_BYTES, BLKDBG_CLUSTER_FREE, + BLKDBG_FLUSH_TO_OS, + BLKDBG_FLUSH_TO_DISK, + BLKDBG_EVENT_MAX, } BlkDebugEvent; diff --git a/include/block/qapi.h b/include/block/qapi.h index e6e568d..0496cc9 100644 --- a/include/block/qapi.h +++ b/include/block/qapi.h @@ -29,11 +29,15 @@ #include "block/block.h" #include "block/snapshot.h" -void bdrv_collect_snapshots(BlockDriverState *bs , ImageInfo *info); -void bdrv_collect_image_info(BlockDriverState *bs, - ImageInfo *info, - const char *filename); -BlockInfo *bdrv_query_info(BlockDriverState *s); +int bdrv_query_snapshot_info_list(BlockDriverState *bs, + SnapshotInfoList **p_list, + Error **errp); +void bdrv_query_image_info(BlockDriverState *bs, + ImageInfo **p_info, + Error **errp); +void bdrv_query_info(BlockDriverState *bs, + BlockInfo **p_info, + Error **errp); BlockStats *bdrv_query_stats(const BlockDriverState *bs); void bdrv_snapshot_dump(fprintf_function func_fprintf, void *f, diff --git a/include/elf.h b/include/elf.h index a21ea53..cf0d3e2 100644 --- a/include/elf.h +++ b/include/elf.h @@ -129,6 +129,8 @@ typedef int64_t Elf64_Sxword; #define EM_XTENSA 94 /* Tensilica Xtensa */ +#define EM_AARCH64 183 + /* This is the info that is needed to parse the dynamic section of the file */ #define DT_NULL 0 #define DT_NEEDED 1 @@ -616,6 +618,133 @@ typedef struct { /* Keep this the last entry. */ #define R_ARM_NUM 256 +/* ARM Aarch64 relocation types */ +#define R_AARCH64_NONE 256 /* also accepts R_ARM_NONE (0) */ +/* static data relocations */ +#define R_AARCH64_ABS64 257 +#define R_AARCH64_ABS32 258 +#define R_AARCH64_ABS16 259 +#define R_AARCH64_PREL64 260 +#define R_AARCH64_PREL32 261 +#define R_AARCH64_PREL16 262 +/* static aarch64 group relocations */ +/* group relocs to create unsigned data value or address inline */ +#define R_AARCH64_MOVW_UABS_G0 263 +#define R_AARCH64_MOVW_UABS_G0_NC 264 +#define R_AARCH64_MOVW_UABS_G1 265 +#define R_AARCH64_MOVW_UABS_G1_NC 266 +#define R_AARCH64_MOVW_UABS_G2 267 +#define R_AARCH64_MOVW_UABS_G2_NC 268 +#define R_AARCH64_MOVW_UABS_G3 269 +/* group relocs to create signed data or offset value inline */ +#define R_AARCH64_MOVW_SABS_G0 270 +#define R_AARCH64_MOVW_SABS_G1 271 +#define R_AARCH64_MOVW_SABS_G2 272 +/* relocs to generate 19, 21, and 33 bit PC-relative addresses */ +#define R_AARCH64_LD_PREL_LO19 273 +#define R_AARCH64_ADR_PREL_LO21 274 +#define R_AARCH64_ADR_PREL_PG_HI21 275 +#define R_AARCH64_ADR_PREL_PG_HI21_NC 276 +#define R_AARCH64_ADD_ABS_LO12_NC 277 +#define R_AARCH64_LDST8_ABS_LO12_NC 278 +#define R_AARCH64_LDST16_ABS_LO12_NC 284 +#define R_AARCH64_LDST32_ABS_LO12_NC 285 +#define R_AARCH64_LDST64_ABS_LO12_NC 286 +#define R_AARCH64_LDST128_ABS_LO12_NC 299 +/* relocs for control-flow - all offsets as multiple of 4 */ +#define R_AARCH64_TSTBR14 279 +#define R_AARCH64_CONDBR19 280 +#define R_AARCH64_JUMP26 282 +#define R_AARCH64_CALL26 283 +/* group relocs to create pc-relative offset inline */ +#define R_AARCH64_MOVW_PREL_G0 287 +#define R_AARCH64_MOVW_PREL_G0_NC 288 +#define R_AARCH64_MOVW_PREL_G1 289 +#define R_AARCH64_MOVW_PREL_G1_NC 290 +#define R_AARCH64_MOVW_PREL_G2 291 +#define R_AARCH64_MOVW_PREL_G2_NC 292 +#define R_AARCH64_MOVW_PREL_G3 293 +/* group relocs to create a GOT-relative offset inline */ +#define R_AARCH64_MOVW_GOTOFF_G0 300 +#define R_AARCH64_MOVW_GOTOFF_G0_NC 301 +#define R_AARCH64_MOVW_GOTOFF_G1 302 +#define R_AARCH64_MOVW_GOTOFF_G1_NC 303 +#define R_AARCH64_MOVW_GOTOFF_G2 304 +#define R_AARCH64_MOVW_GOTOFF_G2_NC 305 +#define R_AARCH64_MOVW_GOTOFF_G3 306 +/* GOT-relative data relocs */ +#define R_AARCH64_GOTREL64 307 +#define R_AARCH64_GOTREL32 308 +/* GOT-relative instr relocs */ +#define R_AARCH64_GOT_LD_PREL19 309 +#define R_AARCH64_LD64_GOTOFF_LO15 310 +#define R_AARCH64_ADR_GOT_PAGE 311 +#define R_AARCH64_LD64_GOT_LO12_NC 312 +#define R_AARCH64_LD64_GOTPAGE_LO15 313 +/* General Dynamic TLS relocations */ +#define R_AARCH64_TLSGD_ADR_PREL21 512 +#define R_AARCH64_TLSGD_ADR_PAGE21 513 +#define R_AARCH64_TLSGD_ADD_LO12_NC 514 +#define R_AARCH64_TLSGD_MOVW_G1 515 +#define R_AARCH64_TLSGD_MOVW_G0_NC 516 +/* Local Dynamic TLS relocations */ +#define R_AARCH64_TLSLD_ADR_PREL21 517 +#define R_AARCH64_TLSLD_ADR_PAGE21 518 +#define R_AARCH64_TLSLD_ADD_LO12_NC 519 +#define R_AARCH64_TLSLD_MOVW_G1 520 +#define R_AARCH64_TLSLD_MOVW_G0_NC 521 +#define R_AARCH64_TLSLD_LD_PREL19 522 +#define R_AARCH64_TLSLD_MOVW_DTPREL_G2 523 +#define R_AARCH64_TLSLD_MOVW_DTPREL_G1 524 +#define R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC 525 +#define R_AARCH64_TLSLD_MOVW_DTPREL_G0 526 +#define R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC 527 +#define R_AARCH64_TLSLD_ADD_DTPREL_HI12 528 +#define R_AARCH64_TLSLD_ADD_DTPREL_LO12 529 +#define R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC 530 +#define R_AARCH64_TLSLD_LDST8_DTPREL_LO12 531 +#define R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC 532 +#define R_AARCH64_TLSLD_LDST16_DTPREL_LO12 533 +#define R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC 534 +#define R_AARCH64_TLSLD_LDST32_DTPREL_LO12 535 +#define R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC 536 +#define R_AARCH64_TLSLD_LDST64_DTPREL_LO12 537 +#define R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC 538 +/* initial exec TLS relocations */ +#define R_AARCH64_TLSIE_MOVW_GOTTPREL_G1 539 +#define R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC 540 +#define R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 541 +#define R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC 542 +#define R_AARCH64_TLSIE_LD_GOTTPREL_PREL19 543 +/* local exec TLS relocations */ +#define R_AARCH64_TLSLE_MOVW_TPREL_G2 544 +#define R_AARCH64_TLSLE_MOVW_TPREL_G1 545 +#define R_AARCH64_TLSLE_MOVW_TPREL_G1_NC 546 +#define R_AARCH64_TLSLE_MOVW_TPREL_G0 547 +#define R_AARCH64_TLSLE_MOVW_TPREL_G0_NC 548 +#define R_AARCH64_TLSLE_ADD_TPREL_HI12 549 +#define R_AARCH64_TLSLE_ADD_TPREL_LO12 550 +#define R_AARCH64_TLSLE_ADD_TPREL_LO12_NC 551 +#define R_AARCH64_TLSLE_LDST8_TPREL_LO12 552 +#define R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC 553 +#define R_AARCH64_TLSLE_LDST16_TPREL_LO12 554 +#define R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC 555 +#define R_AARCH64_TLSLE_LDST32_TPREL_LO12 556 +#define R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC 557 +#define R_AARCH64_TLSLE_LDST64_TPREL_LO12 558 +#define R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC 559 +/* Dynamic Relocations */ +#define R_AARCH64_COPY 1024 +#define R_AARCH64_GLOB_DAT 1025 +#define R_AARCH64_JUMP_SLOT 1026 +#define R_AARCH64_RELATIVE 1027 +#define R_AARCH64_TLS_DTPREL64 1028 +#define R_AARCH64_TLS_DTPMOD64 1029 +#define R_AARCH64_TLS_TPREL64 1030 +#define R_AARCH64_TLS_DTPREL32 1031 +#define R_AARCH64_TLS_DTPMOD32 1032 +#define R_AARCH64_TLS_TPREL32 1033 + /* s390 relocations defined by the ABIs */ #define R_390_NONE 0 /* No reloc. */ #define R_390_8 1 /* Direct 8 bit. */ diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h index d8c64e9..2e5a9ba 100644 --- a/include/exec/cpu-defs.h +++ b/include/exec/cpu-defs.h @@ -99,7 +99,7 @@ typedef struct CPUTLBEntry { sizeof(uintptr_t))]; } CPUTLBEntry; -extern int CPUTLBEntry_wrong_size[sizeof(CPUTLBEntry) == (1 << CPU_TLB_ENTRY_BITS) ? 1 : -1]; +QEMU_BUILD_BUG_ON(sizeof(CPUTLBEntry) != (1 << CPU_TLB_ENTRY_BITS)); #define CPU_COMMON_TLB \ /* The meaning of the MMU modes is defined in the target code. */ \ diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 17fde25..b2162a4 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -128,7 +128,7 @@ static inline void tlb_flush(CPUArchState *env, int flush_global) #if defined(__arm__) || defined(_ARCH_PPC) \ || defined(__x86_64__) || defined(__i386__) \ - || defined(__sparc__) \ + || defined(__sparc__) || defined(__aarch64__) \ || defined(CONFIG_TCG_INTERPRETER) #define USE_DIRECT_JUMP #endif @@ -230,6 +230,9 @@ static inline void tb_set_jmp_target1(uintptr_t jmp_addr, uintptr_t addr) *(uint32_t *)jmp_addr = addr - (jmp_addr + 4); /* no need to flush icache explicitly */ } +#elif defined(__aarch64__) +void aarch64_tb_set_jmp_target(uintptr_t jmp_addr, uintptr_t addr); +#define tb_set_jmp_target1 aarch64_tb_set_jmp_target #elif defined(__arm__) static inline void tb_set_jmp_target1(uintptr_t jmp_addr, uintptr_t addr) { diff --git a/include/hw/char/serial.h b/include/hw/char/serial.h index c15354a..85f58ac 100644 --- a/include/hw/char/serial.h +++ b/include/hw/char/serial.h @@ -28,17 +28,10 @@ #include "hw/hw.h" #include "sysemu/sysemu.h" #include "exec/memory.h" +#include "qemu/fifo8.h" #define UART_FIFO_LENGTH 16 /* 16550A Fifo Length */ -typedef struct SerialFIFO { - uint8_t data[UART_FIFO_LENGTH]; - uint8_t count; - uint8_t itl; /* Interrupt Trigger Level */ - uint8_t tail; - uint8_t head; -} SerialFIFO; - struct SerialState { uint16_t divider; uint8_t rbr; /* receive register */ @@ -67,8 +60,10 @@ struct SerialState { /* Time when the last byte was successfully sent out of the tsr */ uint64_t last_xmit_ts; - SerialFIFO recv_fifo; - SerialFIFO xmit_fifo; + Fifo8 recv_fifo; + Fifo8 xmit_fifo; + /* Interrupt trigger level for recv_fifo */ + uint8_t recv_fifo_itl; struct QEMUTimer *fifo_timeout_timer; int timeout_ipending; /* timeout interrupt pending state */ diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 5d883eb..7f04967 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -189,7 +189,35 @@ int pvpanic_init(ISABus *bus); int e820_add_entry(uint64_t, uint64_t, uint32_t); +#define PC_COMPAT_1_5 \ + {\ + .driver = "Conroe-" TYPE_X86_CPU,\ + .property = "model",\ + .value = stringify(2),\ + },{\ + .driver = "Conroe-" TYPE_X86_CPU,\ + .property = "level",\ + .value = stringify(2),\ + },{\ + .driver = "Penryn-" TYPE_X86_CPU,\ + .property = "model",\ + .value = stringify(2),\ + },{\ + .driver = "Penryn-" TYPE_X86_CPU,\ + .property = "level",\ + .value = stringify(2),\ + },{\ + .driver = "Nehalem-" TYPE_X86_CPU,\ + .property = "model",\ + .value = stringify(2),\ + },{\ + .driver = "Nehalem-" TYPE_X86_CPU,\ + .property = "level",\ + .value = stringify(2),\ + } + #define PC_COMPAT_1_4 \ + PC_COMPAT_1_5, \ {\ .driver = "scsi-hd",\ .property = "discard_granularity",\ diff --git a/include/hw/i386/smbios.h b/include/hw/i386/smbios.h index 94e3641..9babeaf 100644 --- a/include/hw/i386/smbios.h +++ b/include/hw/i386/smbios.h @@ -14,7 +14,7 @@ */ int smbios_entry_add(const char *t); -void smbios_add_field(int type, int offset, int len, void *data); +void smbios_add_field(int type, int offset, const void *data, size_t len); uint8_t *smbios_get_table(size_t *length); /* diff --git a/include/qemu-common.h b/include/qemu-common.h index cb82ef3..3c91375 100644 --- a/include/qemu-common.h +++ b/include/qemu-common.h @@ -42,19 +42,6 @@ #include <signal.h> #include "glib-compat.h" -#if defined(__GLIBC__) -# include <pty.h> -#elif defined CONFIG_BSD -# include <termios.h> -# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) -# include <libutil.h> -# else -# include <util.h> -# endif -#elif defined CONFIG_SOLARIS -# include <stropts.h> -#endif - #ifdef _WIN32 #include "sysemu/os-win32.h" #endif @@ -174,6 +161,7 @@ char *pstrcat(char *buf, int buf_size, const char *s); int strstart(const char *str, const char *val, const char **ptr); int stristart(const char *str, const char *val, const char **ptr); int qemu_strnlen(const char *s, int max_len); +char *qemu_strsep(char **input, const char *delim); time_t mktimegm(struct tm *tm); int qemu_fls(int i); int qemu_fdatasync(int fd); @@ -191,6 +179,8 @@ int parse_uint_full(const char *s, unsigned long long *value, int base); * A-Z, as strtosz() will use qemu_toupper() on the given argument * prior to comparison. */ +#define STRTOSZ_DEFSUFFIX_EB 'E' +#define STRTOSZ_DEFSUFFIX_PB 'P' #define STRTOSZ_DEFSUFFIX_TB 'T' #define STRTOSZ_DEFSUFFIX_GB 'G' #define STRTOSZ_DEFSUFFIX_MB 'M' @@ -232,6 +222,8 @@ ssize_t qemu_recv_full(int fd, void *buf, size_t count, int flags) #ifndef _WIN32 int qemu_pipe(int pipefd[2]); +/* like openpty() but also makes it raw; return master fd */ +int qemu_openpty_raw(int *aslave, char *pty_name); #endif #ifdef _WIN32 diff --git a/include/qemu-io.h b/include/qemu-io.h new file mode 100644 index 0000000..a418b46 --- /dev/null +++ b/include/qemu-io.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2000-2005 Silicon Graphics, Inc. + * All Rights Reserved. + * + * 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. + * + * This program is distributed in the hope that it would 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef QEMU_IO_H +#define QEMU_IO_H + +#include "qemu-common.h" + +#define CMD_FLAG_GLOBAL ((int)0x80000000) /* don't iterate "args" */ + +typedef int (*cfunc_t)(BlockDriverState *bs, int argc, char **argv); +typedef void (*helpfunc_t)(void); + +typedef struct cmdinfo { + const char* name; + const char* altname; + cfunc_t cfunc; + int argmin; + int argmax; + int canpush; + int flags; + const char *args; + const char *oneline; + helpfunc_t help; +} cmdinfo_t; + +bool qemuio_command(BlockDriverState *bs, const char *cmd); + +void qemuio_add_command(const cmdinfo_t *ci); +int qemuio_command_usage(const cmdinfo_t *ci); + +#endif /* QEMU_IO_H */ diff --git a/include/qemu/error-report.h b/include/qemu/error-report.h index c902cc1..14c1719 100644 --- a/include/qemu/error-report.h +++ b/include/qemu/error-report.h @@ -14,6 +14,7 @@ #define QEMU_ERROR_H #include <stdarg.h> +#include "qemu/compiler.h" typedef struct Location { /* all members are private to qemu-error.c */ diff --git a/include/qemu/log.h b/include/qemu/log.h index 6b0db02..fd76f91 100644 --- a/include/qemu/log.h +++ b/include/qemu/log.h @@ -2,6 +2,9 @@ #define QEMU_LOG_H #include <stdarg.h> +#include <stdbool.h> +#include <stdio.h> +#include "qemu/compiler.h" #ifdef NEED_CPU_H #include "disas/disas.h" #endif diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h index afe4ec7..698fc03 100644 --- a/include/qemu/typedefs.h +++ b/include/qemu/typedefs.h @@ -22,6 +22,8 @@ typedef struct AddressSpace AddressSpace; typedef struct MemoryRegion MemoryRegion; typedef struct MemoryRegionSection MemoryRegionSection; +typedef struct MemoryMappingList MemoryMappingList; + typedef struct NICInfo NICInfo; typedef struct HCIInfo HCIInfo; typedef struct AudioState AudioState; diff --git a/include/qom/cpu.h b/include/qom/cpu.h index 7cd9442..a5bb515 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -23,6 +23,7 @@ #include <signal.h> #include "hw/qdev-core.h" #include "qemu/thread.h" +#include "qemu/typedefs.h" typedef int (*WriteCoreDumpFunction)(void *buf, size_t size, void *opaque); @@ -48,6 +49,8 @@ typedef struct CPUState CPUState; * @reset: Callback to reset the #CPUState to its initial state. * @do_interrupt: Callback for interrupt handling. * @get_arch_id: Callback for getting architecture-dependent CPU ID. + * @get_paging_enabled: Callback for inquiring whether paging is enabled. + * @get_memory_mapping: Callback for obtaining the memory mappings. * @vmsd: State description for migration. * * Represents a CPU family or model. @@ -62,6 +65,9 @@ typedef struct CPUClass { void (*reset)(CPUState *cpu); void (*do_interrupt)(CPUState *cpu); int64_t (*get_arch_id)(CPUState *cpu); + bool (*get_paging_enabled)(const CPUState *cpu); + void (*get_memory_mapping)(CPUState *cpu, MemoryMappingList *list, + Error **errp); const struct VMStateDescription *vmsd; int (*write_elf64_note)(WriteCoreDumpFunction f, CPUState *cpu, @@ -138,6 +144,23 @@ struct CPUState { }; /** + * cpu_paging_enabled: + * @cpu: The CPU whose state is to be inspected. + * + * Returns: %true if paging is enabled, %false otherwise. + */ +bool cpu_paging_enabled(const CPUState *cpu); + +/** + * cpu_get_memory_mapping: + * @cpu: The CPU whose memory mappings are to be obtained. + * @list: Where to write the memory mappings to. + * @errp: Pointer for reporting an #Error. + */ +void cpu_get_memory_mapping(CPUState *cpu, MemoryMappingList *list, + Error **errp); + +/** * cpu_write_elf64_note: * @f: pointer to a function that writes memory to a file * @cpu: The CPU whose memory is to be dumped diff --git a/include/sysemu/char.h b/include/sysemu/char.h index 5e42c90..066c216 100644 --- a/include/sysemu/char.h +++ b/include/sysemu/char.h @@ -70,12 +70,12 @@ struct CharDriverState { void (*chr_set_echo)(struct CharDriverState *chr, bool echo); void (*chr_set_fe_open)(struct CharDriverState *chr, int fe_open); void *opaque; - int idle_tag; char *label; char *filename; int be_open; int fe_open; int explicit_fe_open; + int explicit_be_open; int avail_connections; QemuOpts *opts; QTAILQ_ENTRY(CharDriverState) next; diff --git a/include/sysemu/memory_mapping.h b/include/sysemu/memory_mapping.h index 1256125..6dfb68d 100644 --- a/include/sysemu/memory_mapping.h +++ b/include/sysemu/memory_mapping.h @@ -15,6 +15,7 @@ #define MEMORY_MAPPING_H #include "qemu/queue.h" +#include "qemu/typedefs.h" /* The physical and virtual address in the memory mapping are contiguous. */ typedef struct MemoryMapping { @@ -24,14 +25,11 @@ typedef struct MemoryMapping { QTAILQ_ENTRY(MemoryMapping) next; } MemoryMapping; -typedef struct MemoryMappingList { +struct MemoryMappingList { unsigned int num; MemoryMapping *last_mapping; QTAILQ_HEAD(, MemoryMapping) head; -} MemoryMappingList; - -int cpu_get_memory_mapping(MemoryMappingList *list, CPUArchState *env); -bool cpu_paging_enabled(CPUArchState *env); +}; /* * add or merge the memory region [phys_addr, phys_addr + length) into the @@ -47,13 +45,7 @@ void memory_mapping_list_free(MemoryMappingList *list); void memory_mapping_list_init(MemoryMappingList *list); -/* - * Return value: - * 0: success - * -1: failed - * -2: unsupported - */ -int qemu_get_guest_memory_mapping(MemoryMappingList *list); +void qemu_get_guest_memory_mapping(MemoryMappingList *list, Error **errp); /* get guest's memory mapping without do paging(virtual address is 0). */ void qemu_get_guest_simple_memory_mapping(MemoryMappingList *list); diff --git a/include/ui/console.h b/include/ui/console.h index 4307b5f..f1d79f9 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -339,6 +339,6 @@ int index_from_keycode(int code); /* gtk.c */ void early_gtk_display_init(void); -void gtk_display_init(DisplayState *ds); +void gtk_display_init(DisplayState *ds, bool full_screen); #endif diff --git a/libcacard/vscclient.c b/libcacard/vscclient.c index ac23647..5180d29 100644 --- a/libcacard/vscclient.c +++ b/libcacard/vscclient.c @@ -618,18 +618,22 @@ connect_to_qemu( if (ret != 0) { /* Error */ fprintf(stderr, "getaddrinfo failed\n"); - return -1; + goto cleanup_socket; } if (connect(sock, server->ai_addr, server->ai_addrlen) < 0) { /* Error */ fprintf(stderr, "Could not connect\n"); - return -1; + goto cleanup_socket; } if (verbose) { printf("Connected (sizeof Header=%zd)!\n", sizeof(VSCMsgHeader)); } return sock; + +cleanup_socket: + closesocket(sock); + return -1; } int @@ -759,5 +763,6 @@ main( g_io_channel_unref(channel_socket); g_byte_array_unref(socket_to_send); + closesocket(sock); return 0; } diff --git a/linux-headers/asm-arm/kvm.h b/linux-headers/asm-arm/kvm.h index 023bfeb..c1ee007 100644 --- a/linux-headers/asm-arm/kvm.h +++ b/linux-headers/asm-arm/kvm.h @@ -53,12 +53,12 @@ #define KVM_ARM_FIQ_spsr fiq_regs[7] struct kvm_regs { - struct pt_regs usr_regs;/* R0_usr - R14_usr, PC, CPSR */ - __u32 svc_regs[3]; /* SP_svc, LR_svc, SPSR_svc */ - __u32 abt_regs[3]; /* SP_abt, LR_abt, SPSR_abt */ - __u32 und_regs[3]; /* SP_und, LR_und, SPSR_und */ - __u32 irq_regs[3]; /* SP_irq, LR_irq, SPSR_irq */ - __u32 fiq_regs[8]; /* R8_fiq - R14_fiq, SPSR_fiq */ + struct pt_regs usr_regs; /* R0_usr - R14_usr, PC, CPSR */ + unsigned long svc_regs[3]; /* SP_svc, LR_svc, SPSR_svc */ + unsigned long abt_regs[3]; /* SP_abt, LR_abt, SPSR_abt */ + unsigned long und_regs[3]; /* SP_und, LR_und, SPSR_und */ + unsigned long irq_regs[3]; /* SP_irq, LR_irq, SPSR_irq */ + unsigned long fiq_regs[8]; /* R8_fiq - R14_fiq, SPSR_fiq */ }; /* Supported Processor Types */ diff --git a/linux-headers/asm-mips/kvm.h b/linux-headers/asm-mips/kvm.h new file mode 100644 index 0000000..3f424f5 --- /dev/null +++ b/linux-headers/asm-mips/kvm.h @@ -0,0 +1,138 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. + * Copyright (C) 2013 Cavium, Inc. + * Authors: Sanjay Lal <sanjayl@kymasys.com> + */ + +#ifndef __LINUX_KVM_MIPS_H +#define __LINUX_KVM_MIPS_H + +#include <linux/types.h> + +/* + * KVM MIPS specific structures and definitions. + * + * Some parts derived from the x86 version of this file. + */ + +/* + * for KVM_GET_REGS and KVM_SET_REGS + * + * If Config[AT] is zero (32-bit CPU), the register contents are + * stored in the lower 32-bits of the struct kvm_regs fields and sign + * extended to 64-bits. + */ +struct kvm_regs { + /* out (KVM_GET_REGS) / in (KVM_SET_REGS) */ + __u64 gpr[32]; + __u64 hi; + __u64 lo; + __u64 pc; +}; + +/* + * for KVM_GET_FPU and KVM_SET_FPU + * + * If Status[FR] is zero (32-bit FPU), the upper 32-bits of the FPRs + * are zero filled. + */ +struct kvm_fpu { + __u64 fpr[32]; + __u32 fir; + __u32 fccr; + __u32 fexr; + __u32 fenr; + __u32 fcsr; + __u32 pad; +}; + + +/* + * For MIPS, we use KVM_SET_ONE_REG and KVM_GET_ONE_REG to access CP0 + * registers. The id field is broken down as follows: + * + * bits[2..0] - Register 'sel' index. + * bits[7..3] - Register 'rd' index. + * bits[15..8] - Must be zero. + * bits[63..16] - 1 -> CP0 registers. + * + * Other sets registers may be added in the future. Each set would + * have its own identifier in bits[63..16]. + * + * The addr field of struct kvm_one_reg must point to an aligned + * 64-bit wide location. For registers that are narrower than + * 64-bits, the value is stored in the low order bits of the location, + * and sign extended to 64-bits. + * + * The registers defined in struct kvm_regs are also accessible, the + * id values for these are below. + */ + +#define KVM_REG_MIPS_R0 0 +#define KVM_REG_MIPS_R1 1 +#define KVM_REG_MIPS_R2 2 +#define KVM_REG_MIPS_R3 3 +#define KVM_REG_MIPS_R4 4 +#define KVM_REG_MIPS_R5 5 +#define KVM_REG_MIPS_R6 6 +#define KVM_REG_MIPS_R7 7 +#define KVM_REG_MIPS_R8 8 +#define KVM_REG_MIPS_R9 9 +#define KVM_REG_MIPS_R10 10 +#define KVM_REG_MIPS_R11 11 +#define KVM_REG_MIPS_R12 12 +#define KVM_REG_MIPS_R13 13 +#define KVM_REG_MIPS_R14 14 +#define KVM_REG_MIPS_R15 15 +#define KVM_REG_MIPS_R16 16 +#define KVM_REG_MIPS_R17 17 +#define KVM_REG_MIPS_R18 18 +#define KVM_REG_MIPS_R19 19 +#define KVM_REG_MIPS_R20 20 +#define KVM_REG_MIPS_R21 21 +#define KVM_REG_MIPS_R22 22 +#define KVM_REG_MIPS_R23 23 +#define KVM_REG_MIPS_R24 24 +#define KVM_REG_MIPS_R25 25 +#define KVM_REG_MIPS_R26 26 +#define KVM_REG_MIPS_R27 27 +#define KVM_REG_MIPS_R28 28 +#define KVM_REG_MIPS_R29 29 +#define KVM_REG_MIPS_R30 30 +#define KVM_REG_MIPS_R31 31 + +#define KVM_REG_MIPS_HI 32 +#define KVM_REG_MIPS_LO 33 +#define KVM_REG_MIPS_PC 34 + +/* + * KVM MIPS specific structures and definitions + * + */ +struct kvm_debug_exit_arch { + __u64 epc; +}; + +/* for KVM_SET_GUEST_DEBUG */ +struct kvm_guest_debug_arch { +}; + +/* definition of registers in kvm_run */ +struct kvm_sync_regs { +}; + +/* dummy definition */ +struct kvm_sregs { +}; + +struct kvm_mips_interrupt { + /* in */ + __u32 cpu; + __u32 irq; +}; + +#endif /* __LINUX_KVM_MIPS_H */ diff --git a/linux-headers/asm-mips/kvm_para.h b/linux-headers/asm-mips/kvm_para.h new file mode 100644 index 0000000..14fab8f --- /dev/null +++ b/linux-headers/asm-mips/kvm_para.h @@ -0,0 +1 @@ +#include <asm-generic/kvm_para.h> diff --git a/linux-headers/asm-powerpc/kvm.h b/linux-headers/asm-powerpc/kvm.h index ef072b1..0fb1a6e 100644 --- a/linux-headers/asm-powerpc/kvm.h +++ b/linux-headers/asm-powerpc/kvm.h @@ -25,6 +25,8 @@ /* Select powerpc specific features in <linux/kvm.h> */ #define __KVM_HAVE_SPAPR_TCE #define __KVM_HAVE_PPC_SMT +#define __KVM_HAVE_IRQCHIP +#define __KVM_HAVE_IRQ_LINE struct kvm_regs { __u64 pc; @@ -272,8 +274,31 @@ struct kvm_debug_exit_arch { /* for KVM_SET_GUEST_DEBUG */ struct kvm_guest_debug_arch { + struct { + /* H/W breakpoint/watchpoint address */ + __u64 addr; + /* + * Type denotes h/w breakpoint, read watchpoint, write + * watchpoint or watchpoint (both read and write). + */ +#define KVMPPC_DEBUG_NONE 0x0 +#define KVMPPC_DEBUG_BREAKPOINT (1UL << 1) +#define KVMPPC_DEBUG_WATCH_WRITE (1UL << 2) +#define KVMPPC_DEBUG_WATCH_READ (1UL << 3) + __u32 type; + __u32 reserved; + } bp[16]; }; +/* Debug related defines */ +/* + * kvm_guest_debug->control is a 32 bit field. The lower 16 bits are generic + * and upper 16 bits are architecture specific. Architecture specific defines + * that ioctl is for setting hardware breakpoint or software breakpoint. + */ +#define KVM_GUESTDBG_USE_SW_BP 0x00010000 +#define KVM_GUESTDBG_USE_HW_BP 0x00020000 + /* definition of registers in kvm_run */ struct kvm_sync_regs { }; @@ -299,6 +324,12 @@ struct kvm_allocate_rma { __u64 rma_size; }; +/* for KVM_CAP_PPC_RTAS */ +struct kvm_rtas_token_args { + char name[120]; + __u64 token; /* Use a token of 0 to undefine a mapping */ +}; + struct kvm_book3e_206_tlb_entry { __u32 mas8; __u32 mas1; @@ -359,6 +390,26 @@ struct kvm_get_htab_header { __u16 n_invalid; }; +/* Per-vcpu XICS interrupt controller state */ +#define KVM_REG_PPC_ICP_STATE (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x8c) + +#define KVM_REG_PPC_ICP_CPPR_SHIFT 56 /* current proc priority */ +#define KVM_REG_PPC_ICP_CPPR_MASK 0xff +#define KVM_REG_PPC_ICP_XISR_SHIFT 32 /* interrupt status field */ +#define KVM_REG_PPC_ICP_XISR_MASK 0xffffff +#define KVM_REG_PPC_ICP_MFRR_SHIFT 24 /* pending IPI priority */ +#define KVM_REG_PPC_ICP_MFRR_MASK 0xff +#define KVM_REG_PPC_ICP_PPRI_SHIFT 16 /* pending irq priority */ +#define KVM_REG_PPC_ICP_PPRI_MASK 0xff + +/* Device control API: PPC-specific devices */ +#define KVM_DEV_MPIC_GRP_MISC 1 +#define KVM_DEV_MPIC_BASE_ADDR 0 /* 64-bit */ + +#define KVM_DEV_MPIC_GRP_REGISTER 2 /* 32-bit */ +#define KVM_DEV_MPIC_GRP_IRQ_ACTIVE 3 /* 32-bit */ + +/* One-Reg API: PPC-specific registers */ #define KVM_REG_PPC_HIOR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x1) #define KVM_REG_PPC_IAC1 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x2) #define KVM_REG_PPC_IAC2 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x3) @@ -422,4 +473,42 @@ struct kvm_get_htab_header { #define KVM_REG_PPC_CLEAR_TSR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x88) #define KVM_REG_PPC_TCR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x89) #define KVM_REG_PPC_TSR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x8a) + +/* Debugging: Special instruction for software breakpoint */ +#define KVM_REG_PPC_DEBUG_INST (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x8b) + +/* MMU registers */ +#define KVM_REG_PPC_MAS0 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x8c) +#define KVM_REG_PPC_MAS1 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x8d) +#define KVM_REG_PPC_MAS2 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x8e) +#define KVM_REG_PPC_MAS7_3 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x8f) +#define KVM_REG_PPC_MAS4 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x90) +#define KVM_REG_PPC_MAS6 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x91) +#define KVM_REG_PPC_MMUCFG (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x92) +/* + * TLBnCFG fields TLBnCFG_N_ENTRY and TLBnCFG_ASSOC can be changed only using + * KVM_CAP_SW_TLB ioctl + */ +#define KVM_REG_PPC_TLB0CFG (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x93) +#define KVM_REG_PPC_TLB1CFG (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x94) +#define KVM_REG_PPC_TLB2CFG (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x95) +#define KVM_REG_PPC_TLB3CFG (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x96) +#define KVM_REG_PPC_TLB0PS (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x97) +#define KVM_REG_PPC_TLB1PS (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x98) +#define KVM_REG_PPC_TLB2PS (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x99) +#define KVM_REG_PPC_TLB3PS (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x9a) +#define KVM_REG_PPC_EPTCFG (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x9b) + +/* PPC64 eXternal Interrupt Controller Specification */ +#define KVM_DEV_XICS_GRP_SOURCES 1 /* 64-bit source attributes */ + +/* Layout of 64-bit source attribute values */ +#define KVM_XICS_DESTINATION_SHIFT 0 +#define KVM_XICS_DESTINATION_MASK 0xffffffffULL +#define KVM_XICS_PRIORITY_SHIFT 32 +#define KVM_XICS_PRIORITY_MASK 0xff +#define KVM_XICS_LEVEL_SENSITIVE (1ULL << 40) +#define KVM_XICS_MASKED (1ULL << 41) +#define KVM_XICS_PENDING (1ULL << 42) + #endif /* __LINUX_KVM_POWERPC_H */ diff --git a/linux-headers/asm-x86/kvm.h b/linux-headers/asm-x86/kvm.h index a65ec29..5d9a303 100644 --- a/linux-headers/asm-x86/kvm.h +++ b/linux-headers/asm-x86/kvm.h @@ -29,7 +29,6 @@ #define __KVM_HAVE_PIT #define __KVM_HAVE_IOAPIC #define __KVM_HAVE_IRQ_LINE -#define __KVM_HAVE_DEVICE_ASSIGNMENT #define __KVM_HAVE_MSI #define __KVM_HAVE_USER_NMI #define __KVM_HAVE_GUEST_DEBUG diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index eb02d8a..c614070 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -561,9 +561,7 @@ struct kvm_ppc_smmu_info { #define KVM_CAP_MP_STATE 14 #define KVM_CAP_COALESCED_MMIO 15 #define KVM_CAP_SYNC_MMU 16 /* Changes to host mmap are reflected in guest */ -#ifdef __KVM_HAVE_DEVICE_ASSIGNMENT #define KVM_CAP_DEVICE_ASSIGNMENT 17 -#endif #define KVM_CAP_IOMMU 18 #ifdef __KVM_HAVE_MSI #define KVM_CAP_DEVICE_MSI 20 @@ -579,13 +577,9 @@ struct kvm_ppc_smmu_info { #ifdef __KVM_HAVE_PIT #define KVM_CAP_REINJECT_CONTROL 24 #endif -#ifdef __KVM_HAVE_IOAPIC #define KVM_CAP_IRQ_ROUTING 25 -#endif #define KVM_CAP_IRQ_INJECT_STATUS 26 -#ifdef __KVM_HAVE_DEVICE_ASSIGNMENT #define KVM_CAP_DEVICE_DEASSIGNMENT 27 -#endif #ifdef __KVM_HAVE_MSIX #define KVM_CAP_DEVICE_MSIX 28 #endif @@ -668,6 +662,10 @@ struct kvm_ppc_smmu_info { #define KVM_CAP_PPC_EPR 86 #define KVM_CAP_ARM_PSCI 87 #define KVM_CAP_ARM_SET_DEVICE_ADDR 88 +#define KVM_CAP_DEVICE_CTRL 89 +#define KVM_CAP_IRQ_MPIC 90 +#define KVM_CAP_PPC_RTAS 91 +#define KVM_CAP_IRQ_XICS 92 #ifdef KVM_CAP_IRQ_ROUTING @@ -821,6 +819,28 @@ struct kvm_arm_device_addr { }; /* + * Device control API, available with KVM_CAP_DEVICE_CTRL + */ +#define KVM_CREATE_DEVICE_TEST 1 + +struct kvm_create_device { + __u32 type; /* in: KVM_DEV_TYPE_xxx */ + __u32 fd; /* out: device handle */ + __u32 flags; /* in: KVM_CREATE_DEVICE_xxx */ +}; + +struct kvm_device_attr { + __u32 flags; /* no flags currently defined */ + __u32 group; /* device-defined */ + __u64 attr; /* group-defined */ + __u64 addr; /* userspace address of attr data */ +}; + +#define KVM_DEV_TYPE_FSL_MPIC_20 1 +#define KVM_DEV_TYPE_FSL_MPIC_42 2 +#define KVM_DEV_TYPE_XICS 3 + +/* * ioctls for VM fds */ #define KVM_SET_MEMORY_REGION _IOW(KVMIO, 0x40, struct kvm_memory_region) @@ -907,6 +927,16 @@ struct kvm_s390_ucas_mapping { #define KVM_PPC_GET_HTAB_FD _IOW(KVMIO, 0xaa, struct kvm_get_htab_fd) /* Available with KVM_CAP_ARM_SET_DEVICE_ADDR */ #define KVM_ARM_SET_DEVICE_ADDR _IOW(KVMIO, 0xab, struct kvm_arm_device_addr) +/* Available with KVM_CAP_PPC_RTAS */ +#define KVM_PPC_RTAS_DEFINE_TOKEN _IOW(KVMIO, 0xac, struct kvm_rtas_token_args) + +/* ioctl for vm fd */ +#define KVM_CREATE_DEVICE _IOWR(KVMIO, 0xe0, struct kvm_create_device) + +/* ioctls for fds returned by KVM_CREATE_DEVICE */ +#define KVM_SET_DEVICE_ATTR _IOW(KVMIO, 0xe1, struct kvm_device_attr) +#define KVM_GET_DEVICE_ATTR _IOW(KVMIO, 0xe2, struct kvm_device_attr) +#define KVM_HAS_DEVICE_ATTR _IOW(KVMIO, 0xe3, struct kvm_device_attr) /* * ioctls for vcpu fds diff --git a/linux-headers/linux/vfio.h b/linux-headers/linux/vfio.h index e094121..7ec1864 100644 --- a/linux-headers/linux/vfio.h +++ b/linux-headers/linux/vfio.h @@ -319,6 +319,7 @@ enum { VFIO_PCI_INTX_IRQ_INDEX, VFIO_PCI_MSI_IRQ_INDEX, VFIO_PCI_MSIX_IRQ_INDEX, + VFIO_PCI_ERR_IRQ_INDEX, VFIO_PCI_NUM_IRQS }; diff --git a/linux-headers/linux/vhost.h b/linux-headers/linux/vhost.h index 165a484..c656f61 100644 --- a/linux-headers/linux/vhost.h +++ b/linux-headers/linux/vhost.h @@ -127,4 +127,32 @@ struct vhost_memory { /* vhost-net should add virtio_net_hdr for RX, and strip for TX packets. */ #define VHOST_NET_F_VIRTIO_NET_HDR 27 +/* VHOST_SCSI specific definitions */ + +/* + * Used by QEMU userspace to ensure a consistent vhost-scsi ABI. + * + * ABI Rev 0: July 2012 version starting point for v3.6-rc merge candidate + + * RFC-v2 vhost-scsi userspace. Add GET_ABI_VERSION ioctl usage + * ABI Rev 1: January 2013. Ignore vhost_tpgt filed in struct vhost_scsi_target. + * All the targets under vhost_wwpn can be seen and used by guset. + */ + +#define VHOST_SCSI_ABI_VERSION 1 + +struct vhost_scsi_target { + int abi_version; + char vhost_wwpn[224]; /* TRANSPORT_IQN_LEN */ + unsigned short vhost_tpgt; + unsigned short reserved; +}; + +#define VHOST_SCSI_SET_ENDPOINT _IOW(VHOST_VIRTIO, 0x40, struct vhost_scsi_target) +#define VHOST_SCSI_CLEAR_ENDPOINT _IOW(VHOST_VIRTIO, 0x41, struct vhost_scsi_target) +/* Changing this breaks userspace. */ +#define VHOST_SCSI_GET_ABI_VERSION _IOW(VHOST_VIRTIO, 0x42, int) +/* Set and get the events missed flag */ +#define VHOST_SCSI_SET_EVENTS_MISSED _IOW(VHOST_VIRTIO, 0x43, __u32) +#define VHOST_SCSI_GET_EVENTS_MISSED _IOW(VHOST_VIRTIO, 0x44, __u32) + #endif diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 0099d64..cdd0c28 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -181,29 +181,14 @@ static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \ #define __NR_sys_uname __NR_uname -#define __NR_sys_faccessat __NR_faccessat -#define __NR_sys_fchmodat __NR_fchmodat -#define __NR_sys_fchownat __NR_fchownat -#define __NR_sys_fstatat64 __NR_fstatat64 -#define __NR_sys_futimesat __NR_futimesat #define __NR_sys_getcwd1 __NR_getcwd #define __NR_sys_getdents __NR_getdents #define __NR_sys_getdents64 __NR_getdents64 #define __NR_sys_getpriority __NR_getpriority -#define __NR_sys_linkat __NR_linkat -#define __NR_sys_mkdirat __NR_mkdirat -#define __NR_sys_mknodat __NR_mknodat -#define __NR_sys_newfstatat __NR_newfstatat -#define __NR_sys_openat __NR_openat -#define __NR_sys_readlinkat __NR_readlinkat -#define __NR_sys_renameat __NR_renameat #define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo -#define __NR_sys_symlinkat __NR_symlinkat #define __NR_sys_syslog __NR_syslog #define __NR_sys_tgkill __NR_tgkill #define __NR_sys_tkill __NR_tkill -#define __NR_sys_unlinkat __NR_unlinkat -#define __NR_sys_utimensat __NR_utimensat #define __NR_sys_futex __NR_futex #define __NR_sys_inotify_init __NR_inotify_init #define __NR_sys_inotify_add_watch __NR_inotify_add_watch @@ -223,8 +208,11 @@ static int gettid(void) { return -ENOSYS; } #endif +#ifdef __NR_getdents _syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count); -#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64) +#endif +#if !defined(__NR_getdents) || \ + (defined(TARGET_NR_getdents64) && defined(__NR_getdents64)) _syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count); #endif #if defined(TARGET_NR__llseek) && defined(__NR_llseek) @@ -336,72 +324,6 @@ static int sys_getcwd1(char *buf, size_t size) return strlen(buf)+1; } -#ifdef CONFIG_ATFILE -/* - * Host system seems to have atfile syscall stubs available. We - * now enable them one by one as specified by target syscall_nr.h. - */ - -#ifdef TARGET_NR_faccessat -static int sys_faccessat(int dirfd, const char *pathname, int mode) -{ - return (faccessat(dirfd, pathname, mode, 0)); -} -#endif -#ifdef TARGET_NR_fchmodat -static int sys_fchmodat(int dirfd, const char *pathname, mode_t mode) -{ - return (fchmodat(dirfd, pathname, mode, 0)); -} -#endif -#if defined(TARGET_NR_fchownat) -static int sys_fchownat(int dirfd, const char *pathname, uid_t owner, - gid_t group, int flags) -{ - return (fchownat(dirfd, pathname, owner, group, flags)); -} -#endif -#ifdef __NR_fstatat64 -static int sys_fstatat64(int dirfd, const char *pathname, struct stat *buf, - int flags) -{ - return (fstatat(dirfd, pathname, buf, flags)); -} -#endif -#ifdef __NR_newfstatat -static int sys_newfstatat(int dirfd, const char *pathname, struct stat *buf, - int flags) -{ - return (fstatat(dirfd, pathname, buf, flags)); -} -#endif -#ifdef TARGET_NR_futimesat -static int sys_futimesat(int dirfd, const char *pathname, - const struct timeval times[2]) -{ - return (futimesat(dirfd, pathname, times)); -} -#endif -#ifdef TARGET_NR_linkat -static int sys_linkat(int olddirfd, const char *oldpath, - int newdirfd, const char *newpath, int flags) -{ - return (linkat(olddirfd, oldpath, newdirfd, newpath, flags)); -} -#endif -#ifdef TARGET_NR_mkdirat -static int sys_mkdirat(int dirfd, const char *pathname, mode_t mode) -{ - return (mkdirat(dirfd, pathname, mode)); -} -#endif -#ifdef TARGET_NR_mknodat -static int sys_mknodat(int dirfd, const char *pathname, mode_t mode, - dev_t dev) -{ - return (mknodat(dirfd, pathname, mode, dev)); -} -#endif #ifdef TARGET_NR_openat static int sys_openat(int dirfd, const char *pathname, int flags, mode_t mode) { @@ -415,91 +337,6 @@ static int sys_openat(int dirfd, const char *pathname, int flags, mode_t mode) return (openat(dirfd, pathname, flags)); } #endif -#ifdef TARGET_NR_readlinkat -static int sys_readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz) -{ - return (readlinkat(dirfd, pathname, buf, bufsiz)); -} -#endif -#ifdef TARGET_NR_renameat -static int sys_renameat(int olddirfd, const char *oldpath, - int newdirfd, const char *newpath) -{ - return (renameat(olddirfd, oldpath, newdirfd, newpath)); -} -#endif -#ifdef TARGET_NR_symlinkat -static int sys_symlinkat(const char *oldpath, int newdirfd, const char *newpath) -{ - return (symlinkat(oldpath, newdirfd, newpath)); -} -#endif -#ifdef TARGET_NR_unlinkat -static int sys_unlinkat(int dirfd, const char *pathname, int flags) -{ - return (unlinkat(dirfd, pathname, flags)); -} -#endif -#else /* !CONFIG_ATFILE */ - -/* - * Try direct syscalls instead - */ -#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat) -_syscall3(int,sys_faccessat,int,dirfd,const char *,pathname,int,mode) -#endif -#if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat) -_syscall3(int,sys_fchmodat,int,dirfd,const char *,pathname, mode_t,mode) -#endif -#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat) -_syscall5(int,sys_fchownat,int,dirfd,const char *,pathname, - uid_t,owner,gid_t,group,int,flags) -#endif -#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat)) && \ - defined(__NR_fstatat64) -_syscall4(int,sys_fstatat64,int,dirfd,const char *,pathname, - struct stat *,buf,int,flags) -#endif -#if defined(TARGET_NR_futimesat) && defined(__NR_futimesat) -_syscall3(int,sys_futimesat,int,dirfd,const char *,pathname, - const struct timeval *,times) -#endif -#if (defined(TARGET_NR_newfstatat) || defined(TARGET_NR_fstatat64) ) && \ - defined(__NR_newfstatat) -_syscall4(int,sys_newfstatat,int,dirfd,const char *,pathname, - struct stat *,buf,int,flags) -#endif -#if defined(TARGET_NR_linkat) && defined(__NR_linkat) -_syscall5(int,sys_linkat,int,olddirfd,const char *,oldpath, - int,newdirfd,const char *,newpath,int,flags) -#endif -#if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat) -_syscall3(int,sys_mkdirat,int,dirfd,const char *,pathname,mode_t,mode) -#endif -#if defined(TARGET_NR_mknodat) && defined(__NR_mknodat) -_syscall4(int,sys_mknodat,int,dirfd,const char *,pathname, - mode_t,mode,dev_t,dev) -#endif -#if defined(TARGET_NR_openat) && defined(__NR_openat) -_syscall4(int,sys_openat,int,dirfd,const char *,pathname,int,flags,mode_t,mode) -#endif -#if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat) -_syscall4(int,sys_readlinkat,int,dirfd,const char *,pathname, - char *,buf,size_t,bufsize) -#endif -#if defined(TARGET_NR_renameat) && defined(__NR_renameat) -_syscall4(int,sys_renameat,int,olddirfd,const char *,oldpath, - int,newdirfd,const char *,newpath) -#endif -#if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat) -_syscall3(int,sys_symlinkat,const char *,oldpath, - int,newdirfd,const char *,newpath) -#endif -#if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat) -_syscall3(int,sys_unlinkat,int,dirfd,const char *,pathname,int,flags) -#endif - -#endif /* CONFIG_ATFILE */ #ifdef CONFIG_UTIMENSAT static int sys_utimensat(int dirfd, const char *pathname, @@ -5342,7 +5179,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, unlock_user(p, arg1, 0); } break; -#if defined(TARGET_NR_linkat) && defined(__NR_linkat) +#if defined(TARGET_NR_linkat) case TARGET_NR_linkat: { void * p2 = NULL; @@ -5353,7 +5190,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, if (!p || !p2) ret = -TARGET_EFAULT; else - ret = get_errno(sys_linkat(arg1, p, arg3, p2, arg5)); + ret = get_errno(linkat(arg1, p, arg3, p2, arg5)); unlock_user(p, arg2, 0); unlock_user(p2, arg4, 0); } @@ -5365,11 +5202,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(unlink(p)); unlock_user(p, arg1, 0); break; -#if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat) +#if defined(TARGET_NR_unlinkat) case TARGET_NR_unlinkat: if (!(p = lock_user_string(arg2))) goto efault; - ret = get_errno(sys_unlinkat(arg1, p, arg3)); + ret = get_errno(unlinkat(arg1, p, arg3)); unlock_user(p, arg2, 0); break; #endif @@ -5487,11 +5324,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(mknod(p, arg2, arg3)); unlock_user(p, arg1, 0); break; -#if defined(TARGET_NR_mknodat) && defined(__NR_mknodat) +#if defined(TARGET_NR_mknodat) case TARGET_NR_mknodat: if (!(p = lock_user_string(arg2))) goto efault; - ret = get_errno(sys_mknodat(arg1, p, arg3, arg4)); + ret = get_errno(mknodat(arg1, p, arg3, arg4)); unlock_user(p, arg2, 0); break; #endif @@ -5622,7 +5459,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, unlock_user(p, arg1, 0); } break; -#if defined(TARGET_NR_futimesat) && defined(__NR_futimesat) +#if defined(TARGET_NR_futimesat) case TARGET_NR_futimesat: { struct timeval *tvp, tv[2]; @@ -5637,7 +5474,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } if (!(p = lock_user_string(arg2))) goto efault; - ret = get_errno(sys_futimesat(arg1, path(p), tvp)); + ret = get_errno(futimesat(arg1, path(p), tvp)); unlock_user(p, arg2, 0); } break; @@ -5660,7 +5497,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_faccessat: if (!(p = lock_user_string(arg2))) goto efault; - ret = get_errno(sys_faccessat(arg1, p, arg3)); + ret = get_errno(faccessat(arg1, p, arg3, 0)); unlock_user(p, arg2, 0); break; #endif @@ -5693,7 +5530,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, unlock_user(p, arg1, 0); } break; -#if defined(TARGET_NR_renameat) && defined(__NR_renameat) +#if defined(TARGET_NR_renameat) case TARGET_NR_renameat: { void *p2; @@ -5702,7 +5539,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, if (!p || !p2) ret = -TARGET_EFAULT; else - ret = get_errno(sys_renameat(arg1, p, arg3, p2)); + ret = get_errno(renameat(arg1, p, arg3, p2)); unlock_user(p2, arg4, 0); unlock_user(p, arg2, 0); } @@ -5714,11 +5551,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(mkdir(p, arg2)); unlock_user(p, arg1, 0); break; -#if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat) +#if defined(TARGET_NR_mkdirat) case TARGET_NR_mkdirat: if (!(p = lock_user_string(arg2))) goto efault; - ret = get_errno(sys_mkdirat(arg1, p, arg3)); + ret = get_errno(mkdirat(arg1, p, arg3)); unlock_user(p, arg2, 0); break; #endif @@ -6404,7 +6241,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, unlock_user(p, arg1, 0); } break; -#if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat) +#if defined(TARGET_NR_symlinkat) case TARGET_NR_symlinkat: { void *p2; @@ -6413,7 +6250,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, if (!p || !p2) ret = -TARGET_EFAULT; else - ret = get_errno(sys_symlinkat(p, arg2, p2)); + ret = get_errno(symlinkat(p, arg2, p2)); unlock_user(p2, arg3, 0); unlock_user(p, arg1, 0); } @@ -6444,7 +6281,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, unlock_user(p, arg1, 0); } break; -#if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat) +#if defined(TARGET_NR_readlinkat) case TARGET_NR_readlinkat: { void *p2; @@ -6453,7 +6290,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, if (!p || !p2) ret = -TARGET_EFAULT; else - ret = get_errno(sys_readlinkat(arg1, path(p), p2, arg4)); + ret = get_errno(readlinkat(arg1, path(p), p2, arg4)); unlock_user(p2, arg3, ret); unlock_user(p, arg2, 0); } @@ -6588,11 +6425,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_fchmod: ret = get_errno(fchmod(arg1, arg2)); break; -#if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat) +#if defined(TARGET_NR_fchmodat) case TARGET_NR_fchmodat: if (!(p = lock_user_string(arg2))) goto efault; - ret = get_errno(sys_fchmodat(arg1, p, arg3)); + ret = get_errno(fchmodat(arg1, p, arg3, 0)); unlock_user(p, arg2, 0); break; #endif @@ -7123,6 +6960,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #endif case TARGET_NR_getdents: +#ifdef __NR_getdents #if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64 { struct target_dirent *target_dirp; @@ -7195,6 +7033,61 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, unlock_user(dirp, arg2, ret); } #endif +#else + /* Implement getdents in terms of getdents64 */ + { + struct linux_dirent64 *dirp; + abi_long count = arg3; + + dirp = lock_user(VERIFY_WRITE, arg2, count, 0); + if (!dirp) { + goto efault; + } + ret = get_errno(sys_getdents64(arg1, dirp, count)); + if (!is_error(ret)) { + /* Convert the dirent64 structs to target dirent. We do this + * in-place, since we can guarantee that a target_dirent is no + * larger than a dirent64; however this means we have to be + * careful to read everything before writing in the new format. + */ + struct linux_dirent64 *de; + struct target_dirent *tde; + int len = ret; + int tlen = 0; + + de = dirp; + tde = (struct target_dirent *)dirp; + while (len > 0) { + int namelen, treclen; + int reclen = de->d_reclen; + uint64_t ino = de->d_ino; + int64_t off = de->d_off; + uint8_t type = de->d_type; + + namelen = strlen(de->d_name); + treclen = offsetof(struct target_dirent, d_name) + + namelen + 2; + treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long)); + + memmove(tde->d_name, de->d_name, namelen + 1); + tde->d_ino = tswapal(ino); + tde->d_off = tswapal(off); + tde->d_reclen = tswap16(treclen); + /* The target_dirent type is in what was formerly a padding + * byte at the end of the structure: + */ + *(((char *)tde) + treclen - 1) = type; + + de = (struct linux_dirent64 *)((char *)de + reclen); + tde = (struct target_dirent *)((char *)tde + treclen); + len -= reclen; + tlen += treclen; + } + ret = tlen; + } + unlock_user(dirp, arg2, ret); + } +#endif break; #if defined(TARGET_NR_getdents64) && defined(__NR_getdents64) case TARGET_NR_getdents64: @@ -7680,8 +7573,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = host_to_target_stat64(cpu_env, arg2, &st); break; #endif -#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat)) && \ - (defined(__NR_fstatat64) || defined(__NR_newfstatat)) +#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat)) #ifdef TARGET_NR_fstatat64 case TARGET_NR_fstatat64: #endif @@ -7690,11 +7582,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif if (!(p = lock_user_string(arg2))) goto efault; -#ifdef __NR_fstatat64 - ret = get_errno(sys_fstatat64(arg1, path(p), &st, arg4)); -#else - ret = get_errno(sys_newfstatat(arg1, path(p), &st, arg4)); -#endif + ret = get_errno(fstatat(arg1, path(p), &st, arg4)); if (!is_error(ret)) ret = host_to_target_stat64(cpu_env, arg3, &st); break; @@ -7776,11 +7664,12 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_fchown: ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3))); break; -#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat) +#if defined(TARGET_NR_fchownat) case TARGET_NR_fchownat: if (!(p = lock_user_string(arg2))) goto efault; - ret = get_errno(sys_fchownat(arg1, p, low2highuid(arg3), low2highgid(arg4), arg5)); + ret = get_errno(fchownat(arg1, p, low2highuid(arg3), + low2highgid(arg4), arg5)); unlock_user(p, arg2, 0); break; #endif diff --git a/main-loop.c b/main-loop.c index cf36645..a44fff6 100644 --- a/main-loop.c +++ b/main-loop.c @@ -24,7 +24,8 @@ #include "qemu-common.h" #include "qemu/timer.h" -#include "slirp/slirp.h" +#include "qemu/sockets.h" // struct in_addr needed for libslirp.h +#include "slirp/libslirp.h" #include "qemu/main-loop.h" #include "block/aio.h" diff --git a/memory_mapping-stub.c b/memory_mapping-stub.c deleted file mode 100644 index 24d5d67..0000000 --- a/memory_mapping-stub.c +++ /dev/null @@ -1,33 +0,0 @@ -/* - * QEMU memory mapping - * - * Copyright Fujitsu, Corp. 2011, 2012 - * - * Authors: - * Wen Congyang <wency@cn.fujitsu.com> - * - * 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 "cpu.h" -#include "exec/cpu-all.h" -#include "sysemu/memory_mapping.h" - -int qemu_get_guest_memory_mapping(MemoryMappingList *list) -{ - return -2; -} - -int cpu_get_memory_mapping(MemoryMappingList *list, - CPUArchState *env) -{ - return -1; -} - -bool cpu_paging_enabled(CPUArchState *env) -{ - return true; -} - diff --git a/memory_mapping.c b/memory_mapping.c index ff45b3a..5634f81 100644 --- a/memory_mapping.c +++ b/memory_mapping.c @@ -170,7 +170,7 @@ static CPUArchState *find_paging_enabled_cpu(CPUArchState *start_cpu) CPUArchState *env; for (env = start_cpu; env != NULL; env = env->next_cpu) { - if (cpu_paging_enabled(env)) { + if (cpu_paging_enabled(ENV_GET_CPU(env))) { return env; } } @@ -178,22 +178,23 @@ static CPUArchState *find_paging_enabled_cpu(CPUArchState *start_cpu) return NULL; } -int qemu_get_guest_memory_mapping(MemoryMappingList *list) +void qemu_get_guest_memory_mapping(MemoryMappingList *list, Error **errp) { CPUArchState *env, *first_paging_enabled_cpu; RAMBlock *block; ram_addr_t offset, length; - int ret; first_paging_enabled_cpu = find_paging_enabled_cpu(first_cpu); if (first_paging_enabled_cpu) { for (env = first_paging_enabled_cpu; env != NULL; env = env->next_cpu) { - ret = cpu_get_memory_mapping(list, env); - if (ret < 0) { - return -1; + Error *err = NULL; + cpu_get_memory_mapping(ENV_GET_CPU(env), list, &err); + if (err) { + error_propagate(errp, err); + return; } } - return 0; + return; } /* @@ -205,8 +206,6 @@ int qemu_get_guest_memory_mapping(MemoryMappingList *list) length = block->length; create_new_memory_mapping(list, offset, offset, length); } - - return 0; } void qemu_get_guest_simple_memory_mapping(MemoryMappingList *list) @@ -93,10 +93,10 @@ * 'M' Non-negative target long (32 or 64 bit), in user mode the * value is multiplied by 2^20 (think Mebibyte) * 'o' octets (aka bytes) - * user mode accepts an optional T, t, G, g, M, m, K, k - * suffix, which multiplies the value by 2^40 for - * suffixes T and t, 2^30 for suffixes G and g, 2^20 for - * M and m, 2^10 for K and k + * user mode accepts an optional E, e, P, p, T, t, G, g, M, m, + * K, k suffix, which multiplies the value by 2^60 for suffixes E + * and e, 2^50 for suffixes P and p, 2^40 for suffixes T and t, + * 2^30 for suffixes G and g, 2^20 for M and m, 2^10 for K and k * 'T' double * user mode accepts an optional ms, us, ns suffix, * which divides the value by 1e3, 1e6, 1e9, respectively @@ -2013,7 +2013,6 @@ static void do_acl_remove(Monitor *mon, const QDict *qdict) static void do_inject_mce(Monitor *mon, const QDict *qdict) { X86CPU *cpu; - CPUX86State *cenv; CPUState *cs; int cpu_index = qdict_get_int(qdict, "cpu_index"); int bank = qdict_get_int(qdict, "bank"); @@ -2026,14 +2025,11 @@ static void do_inject_mce(Monitor *mon, const QDict *qdict) if (qdict_get_try_bool(qdict, "broadcast", 0)) { flags |= MCE_INJECT_BROADCAST; } - for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) { - cpu = x86_env_get_cpu(cenv); - cs = CPU(cpu); - if (cs->cpu_index == cpu_index) { - cpu_x86_inject_mce(mon, cpu, bank, status, mcg_status, addr, misc, - flags); - break; - } + cs = qemu_get_cpu(cpu_index); + if (cs != NULL) { + cpu = X86_CPU(cs); + cpu_x86_inject_mce(mon, cpu, bank, status, mcg_status, addr, misc, + flags); } } #endif @@ -2472,9 +2468,10 @@ static mon_cmd_t info_cmds[] = { }, { .name = "block", - .args_type = "", - .params = "", - .help = "show the block devices", + .args_type = "verbose:-v,device:B?", + .params = "[-v] [device]", + .help = "show info of one block device or all block devices " + "(and details of images with -v option)", .mhandler.cmd = hmp_info_block, }, { @@ -698,9 +698,10 @@ int net_init_tap(const NetClientOptions *opts, const char *name, if (tap->has_fd) { if (tap->has_ifname || tap->has_script || tap->has_downscript || tap->has_vnet_hdr || tap->has_helper || tap->has_queues || - tap->has_fds) { + tap->has_fds || tap->has_vhostfds) { error_report("ifname=, script=, downscript=, vnet_hdr=, " - "helper=, queues=, and fds= are invalid with fd="); + "helper=, queues=, fds=, and vhostfds= " + "are invalid with fd="); return -1; } @@ -725,9 +726,10 @@ int net_init_tap(const NetClientOptions *opts, const char *name, if (tap->has_ifname || tap->has_script || tap->has_downscript || tap->has_vnet_hdr || tap->has_helper || tap->has_queues || - tap->has_fd) { + tap->has_vhostfd) { error_report("ifname=, script=, downscript=, vnet_hdr=, " - "helper=, queues=, and fd= are invalid with fds="); + "helper=, queues=, and vhostfd= " + "are invalid with fds="); return -1; } @@ -765,9 +767,9 @@ int net_init_tap(const NetClientOptions *opts, const char *name, } } else if (tap->has_helper) { if (tap->has_ifname || tap->has_script || tap->has_downscript || - tap->has_vnet_hdr || tap->has_queues || tap->has_fds) { + tap->has_vnet_hdr || tap->has_queues || tap->has_vhostfds) { error_report("ifname=, script=, downscript=, and vnet_hdr= " - "queues=, and fds= are invalid with helper="); + "queues=, and vhostfds= are invalid with helper="); return -1; } @@ -785,6 +787,10 @@ int net_init_tap(const NetClientOptions *opts, const char *name, return -1; } } else { + if (tap->has_vhostfds) { + error_report("vhostfds= is invalid if fds= wasn't specified"); + return -1; + } script = tap->has_script ? tap->script : DEFAULT_NETWORK_SCRIPT; downscript = tap->has_downscript ? tap->downscript : DEFAULT_NETWORK_DOWN_SCRIPT; diff --git a/pc-bios/qemu_logo_no_text.svg b/pc-bios/qemu_logo_no_text.svg new file mode 100644 index 0000000..24ca23a --- /dev/null +++ b/pc-bios/qemu_logo_no_text.svg @@ -0,0 +1,976 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="111.71874" + height="111.12498" + id="svg2" + version="1.1" + inkscape:version="0.48.2 r9819" + sodipodi:docname="qemu_logo_no_text.svg"> + <defs + id="defs4"> + <linearGradient + id="linearGradient4686"> + <stop + style="stop-color:#000000;stop-opacity:1;" + offset="0" + id="stop4688" /> + <stop + id="stop3956" + offset="0.75" + style="stop-color:#000000;stop-opacity:0.87843138;" /> + <stop + style="stop-color:#ffffff;stop-opacity:0.43921569;" + offset="0.75" + id="stop3958" /> + <stop + id="stop3960" + offset="0.88" + style="stop-color:#181818;stop-opacity:1;" /> + <stop + style="stop-color:#242424;stop-opacity:1;" + offset="0.88" + id="stop3962" /> + <stop + style="stop-color:#000000;stop-opacity:1;" + offset="1" + id="stop4690" /> + </linearGradient> + <linearGradient + id="linearGradient4467"> + <stop + style="stop-color:#000000;stop-opacity:1;" + offset="0" + id="stop4469" /> + <stop + style="stop-color:#000000;stop-opacity:0.8974359;" + offset="1" + id="stop4471" /> + </linearGradient> + <linearGradient + id="linearGradient4431"> + <stop + style="stop-color:#ffffff;stop-opacity:1;" + offset="0" + id="stop4433" /> + <stop + style="stop-color:#ffffff;stop-opacity:0;" + offset="1" + id="stop4435" /> + </linearGradient> + <linearGradient + id="linearGradient4466"> + <stop + style="stop-color:#ffffff;stop-opacity:1;" + offset="0" + id="stop4468" /> + <stop + style="stop-color:#ffffff;stop-opacity:0;" + offset="1" + id="stop4470" /> + </linearGradient> + <linearGradient + id="linearGradient4321"> + <stop + style="stop-color:#ff6702;stop-opacity:1;" + offset="0" + id="stop4323" /> + <stop + style="stop-color:#ff9a55;stop-opacity:1;" + offset="1" + id="stop4325" /> + </linearGradient> + <linearGradient + id="linearGradient4283"> + <stop + style="stop-color:#000000;stop-opacity:1;" + offset="0" + id="stop4285" /> + <stop + style="stop-color:#000000;stop-opacity:0;" + offset="1" + id="stop4287" /> + </linearGradient> + <linearGradient + id="linearGradient4251"> + <stop + style="stop-color:#000000;stop-opacity:1;" + offset="0" + id="stop4253" /> + <stop + style="stop-color:#000000;stop-opacity:0;" + offset="1" + id="stop4255" /> + </linearGradient> + <linearGradient + id="linearGradient4007"> + <stop + style="stop-color:#ff6600;stop-opacity:1;" + offset="0" + id="stop4009" /> + <stop + style="stop-color:#ff9148;stop-opacity:1;" + offset="1" + id="stop4011" /> + </linearGradient> + <linearGradient + id="linearGradient3999"> + <stop + style="stop-color:#fff7f2;stop-opacity:1;" + offset="0" + id="stop4001" /> + <stop + style="stop-color:#ffffff;stop-opacity:0;" + offset="1" + id="stop4003" /> + </linearGradient> + <linearGradient + id="linearGradient3890"> + <stop + style="stop-color:#ffffff;stop-opacity:1;" + offset="0" + id="stop3892" /> + <stop + style="stop-color:#ffffff;stop-opacity:0;" + offset="1" + id="stop3894" /> + </linearGradient> + <linearGradient + id="linearGradient3880"> + <stop + style="stop-color:#eb7400;stop-opacity:1;" + offset="0" + id="stop3882" /> + <stop + style="stop-color:#f7b06a;stop-opacity:1;" + offset="1" + id="stop3884" /> + </linearGradient> + <linearGradient + id="linearGradient4011"> + <stop + style="stop-color:#042dc8;stop-opacity:1;" + offset="0" + id="stop4013" /> + <stop + style="stop-color:#4260d5;stop-opacity:1;" + offset="1" + id="stop4015" /> + </linearGradient> + <linearGradient + id="linearGradient3879"> + <stop + style="stop-color:#ffffff;stop-opacity:0.90598291;" + offset="0" + id="stop3881" /> + <stop + style="stop-color:#ffffff;stop-opacity:0;" + offset="1" + id="stop3883" /> + </linearGradient> + <linearGradient + id="linearGradient3869"> + <stop + style="stop-color:#c95000;stop-opacity:1;" + offset="0" + id="stop3871" /> + <stop + style="stop-color:#ff9e5e;stop-opacity:1;" + offset="1" + id="stop3873" /> + </linearGradient> + <linearGradient + id="linearGradient3861"> + <stop + style="stop-color:#f06000;stop-opacity:1;" + offset="0" + id="stop3863" /> + <stop + style="stop-color:#ffccaa;stop-opacity:1;" + offset="1" + id="stop3865" /> + </linearGradient> + <linearGradient + id="linearGradient3826"> + <stop + style="stop-color:#ff6600;stop-opacity:1;" + offset="0" + id="stop3828" /> + <stop + style="stop-color:#ff893b;stop-opacity:1;" + offset="1" + id="stop3830" /> + </linearGradient> + <linearGradient + id="linearGradient3879-6"> + <stop + style="stop-color:#ffffff;stop-opacity:0.90598291;" + offset="0" + id="stop3881-4" /> + <stop + style="stop-color:#ffffff;stop-opacity:0;" + offset="1" + id="stop3883-7" /> + </linearGradient> + <linearGradient + id="linearGradient3869-5"> + <stop + style="stop-color:#c95000;stop-opacity:1;" + offset="0" + id="stop3871-9" /> + <stop + style="stop-color:#ff9e5e;stop-opacity:1;" + offset="1" + id="stop3873-4" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3879-4" + id="linearGradient3885-6" + x1="76.025352" + y1="124.8497" + x2="75.874107" + y2="143.03978" + gradientUnits="userSpaceOnUse" /> + <linearGradient + id="linearGradient3879-4"> + <stop + style="stop-color:#ffffff;stop-opacity:0.93162394;" + offset="0" + id="stop3881-6" /> + <stop + style="stop-color:#ffffff;stop-opacity:0;" + offset="1" + id="stop3883-74" /> + </linearGradient> + <linearGradient + id="linearGradient3869-2"> + <stop + style="stop-color:#c95000;stop-opacity:1;" + offset="0" + id="stop3871-99" /> + <stop + style="stop-color:#ff9e5e;stop-opacity:1;" + offset="1" + id="stop3873-6" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient4011" + id="radialGradient4017" + cx="66.639" + cy="93.096375" + fx="66.639" + fy="93.096375" + r="11.515625" + gradientTransform="matrix(0.23244854,1.600893,-1.0124495,0.14700695,145.40424,-26.300303)" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3879-4-7" + id="linearGradient3885-6-2" + x1="76.025352" + y1="124.8497" + x2="75.874107" + y2="143.03978" + gradientUnits="userSpaceOnUse" /> + <linearGradient + id="linearGradient3879-4-7"> + <stop + style="stop-color:#ffffff;stop-opacity:0.93162394;" + offset="0" + id="stop3881-6-7" /> + <stop + style="stop-color:#ffffff;stop-opacity:0;" + offset="1" + id="stop3883-74-6" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient4011-5" + id="radialGradient4017-7" + cx="66.639" + cy="93.096375" + fx="66.639" + fy="93.096375" + r="11.515625" + gradientTransform="matrix(0.99779178,6.8718773,-4.3459674,0.6310314,452.75975,-225.98471)" + gradientUnits="userSpaceOnUse" /> + <linearGradient + id="linearGradient4011-5"> + <stop + style="stop-color:#042dc8;stop-opacity:1;" + offset="0" + id="stop4013-1" /> + <stop + style="stop-color:#4260d5;stop-opacity:1;" + offset="1" + id="stop4015-3" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3879-4-75" + id="linearGradient3885-6-8" + x1="76.025352" + y1="124.8497" + x2="75.874107" + y2="143.03978" + gradientUnits="userSpaceOnUse" /> + <linearGradient + id="linearGradient3879-4-75"> + <stop + style="stop-color:#ffffff;stop-opacity:0.93162394;" + offset="0" + id="stop3881-6-1" /> + <stop + style="stop-color:#ffffff;stop-opacity:0;" + offset="1" + id="stop3883-74-4" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient4011-0" + id="radialGradient4017-5" + cx="66.639" + cy="93.096375" + fx="66.639" + fy="93.096375" + r="11.515625" + gradientTransform="matrix(0.23244854,1.600893,-1.0124495,0.14700695,146.34996,53.681728)" + gradientUnits="userSpaceOnUse" /> + <linearGradient + id="linearGradient4011-0"> + <stop + style="stop-color:#042dc8;stop-opacity:1;" + offset="0" + id="stop4013-4" /> + <stop + style="stop-color:#4260d5;stop-opacity:1;" + offset="1" + id="stop4015-0" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4011-0" + id="linearGradient4117" + x1="107.03001" + y1="189.72537" + x2="107.18476" + y2="173.47537" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3879-4-7-2" + id="linearGradient3885-6-2-8" + x1="76.025352" + y1="124.8497" + x2="75.874107" + y2="143.03978" + gradientUnits="userSpaceOnUse" /> + <linearGradient + id="linearGradient3879-4-7-2"> + <stop + style="stop-color:#ffffff;stop-opacity:0.93162394;" + offset="0" + id="stop3881-6-7-9" /> + <stop + style="stop-color:#ffffff;stop-opacity:0;" + offset="1" + id="stop3883-74-6-9" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient4011-5-1" + id="radialGradient4017-7-9" + cx="66.639" + cy="93.096375" + fx="66.639" + fy="93.096375" + r="11.515625" + gradientTransform="matrix(0.99779178,6.8718773,-4.3459674,0.6310314,448.94742,-406.99277)" + gradientUnits="userSpaceOnUse" /> + <linearGradient + id="linearGradient4011-5-1"> + <stop + style="stop-color:#042dc8;stop-opacity:1;" + offset="0" + id="stop4013-1-9" /> + <stop + style="stop-color:#4260d5;stop-opacity:1;" + offset="1" + id="stop4015-3-8" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3879-4-7-2-7" + id="linearGradient3885-6-2-8-0" + x1="76.025352" + y1="124.8497" + x2="75.874107" + y2="143.03978" + gradientUnits="userSpaceOnUse" /> + <linearGradient + id="linearGradient3879-4-7-2-7"> + <stop + style="stop-color:#ffffff;stop-opacity:0.93162394;" + offset="0" + id="stop3881-6-7-9-3" /> + <stop + style="stop-color:#ffffff;stop-opacity:0;" + offset="1" + id="stop3883-74-6-9-6" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient4011-5-1-5" + id="radialGradient4017-7-9-5" + cx="66.639" + cy="93.096375" + fx="66.639" + fy="93.096375" + r="11.515625" + gradientTransform="matrix(0.55965334,3.8543806,-2.4376181,0.3539404,454.75182,-145.44353)" + gradientUnits="userSpaceOnUse" /> + <linearGradient + id="linearGradient4011-5-1-5"> + <stop + style="stop-color:#042dc8;stop-opacity:1;" + offset="0" + id="stop4013-1-9-6" /> + <stop + style="stop-color:#4260d5;stop-opacity:1;" + offset="1" + id="stop4015-3-8-9" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3879-4-7-2-4" + id="linearGradient3885-6-2-8-4" + x1="76.025352" + y1="124.8497" + x2="75.874107" + y2="143.03978" + gradientUnits="userSpaceOnUse" /> + <linearGradient + id="linearGradient3879-4-7-2-4"> + <stop + style="stop-color:#ffffff;stop-opacity:0.93162394;" + offset="0" + id="stop3881-6-7-9-9" /> + <stop + style="stop-color:#ffffff;stop-opacity:0;" + offset="1" + id="stop3883-74-6-9-3" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient4011-5-1-7" + id="radialGradient4017-7-9-7" + cx="66.639" + cy="93.096375" + fx="66.639" + fy="93.096375" + r="11.515625" + gradientTransform="matrix(0.26837158,1.8482981,-1.1689154,0.16972569,466.57614,26.180822)" + gradientUnits="userSpaceOnUse" /> + <linearGradient + id="linearGradient4011-5-1-7"> + <stop + style="stop-color:#042dc8;stop-opacity:1;" + offset="0" + id="stop4013-1-9-1" /> + <stop + style="stop-color:#4260d5;stop-opacity:1;" + offset="1" + id="stop4015-3-8-5" /> + </linearGradient> + <linearGradient + id="linearGradient3879-4-7-2-0"> + <stop + style="stop-color:#ffffff;stop-opacity:0.93162394;" + offset="0" + id="stop3881-6-7-9-7" /> + <stop + style="stop-color:#ffffff;stop-opacity:0;" + offset="1" + id="stop3883-74-6-9-8" /> + </linearGradient> + <linearGradient + id="linearGradient4011-5-1-55"> + <stop + style="stop-color:#000a30;stop-opacity:1;" + offset="0" + id="stop4013-1-9-8" /> + <stop + style="stop-color:#4260d5;stop-opacity:1;" + offset="1" + id="stop4015-3-8-3" /> + </linearGradient> + <linearGradient + id="linearGradient3890-9"> + <stop + style="stop-color:#ffffff;stop-opacity:1;" + offset="0" + id="stop3892-0" /> + <stop + style="stop-color:#ffffff;stop-opacity:0;" + offset="1" + id="stop3894-9" /> + </linearGradient> + <linearGradient + id="linearGradient3880-4"> + <stop + style="stop-color:#eb7400;stop-opacity:1;" + offset="0" + id="stop3882-5" /> + <stop + style="stop-color:#f7b06a;stop-opacity:1;" + offset="1" + id="stop3884-1" /> + </linearGradient> + <linearGradient + id="linearGradient3999-7"> + <stop + style="stop-color:#fff7f2;stop-opacity:1;" + offset="0" + id="stop4001-9" /> + <stop + style="stop-color:#ffffff;stop-opacity:0;" + offset="1" + id="stop4003-4" /> + </linearGradient> + <linearGradient + id="linearGradient4007-9"> + <stop + style="stop-color:#ff6600;stop-opacity:1;" + offset="0" + id="stop4009-1" /> + <stop + style="stop-color:#ff9148;stop-opacity:1;" + offset="1" + id="stop4011-9" /> + </linearGradient> + <linearGradient + id="linearGradient4007-9-5"> + <stop + style="stop-color:#ff6600;stop-opacity:1;" + offset="0" + id="stop4009-1-9" /> + <stop + style="stop-color:#ff9148;stop-opacity:1;" + offset="1" + id="stop4011-9-5" /> + </linearGradient> + <linearGradient + id="linearGradient3999-7-1"> + <stop + style="stop-color:#fff7f2;stop-opacity:1;" + offset="0" + id="stop4001-9-1" /> + <stop + style="stop-color:#ffffff;stop-opacity:0;" + offset="1" + id="stop4003-4-4" /> + </linearGradient> + <linearGradient + id="linearGradient4007-9-5-3"> + <stop + style="stop-color:#ff6600;stop-opacity:1;" + offset="0" + id="stop4009-1-9-3" /> + <stop + style="stop-color:#ff9148;stop-opacity:1;" + offset="1" + id="stop4011-9-5-9" /> + </linearGradient> + <linearGradient + id="linearGradient3999-7-1-4"> + <stop + style="stop-color:#fff7f2;stop-opacity:1;" + offset="0" + id="stop4001-9-1-4" /> + <stop + style="stop-color:#ffffff;stop-opacity:0;" + offset="1" + id="stop4003-4-4-4" /> + </linearGradient> + <linearGradient + id="linearGradient3879-4-7-2-3"> + <stop + style="stop-color:#ffffff;stop-opacity:0.93162394;" + offset="0" + id="stop3881-6-7-9-1" /> + <stop + style="stop-color:#ffffff;stop-opacity:0;" + offset="1" + id="stop3883-74-6-9-87" /> + </linearGradient> + <linearGradient + id="linearGradient4011-5-1-1"> + <stop + style="stop-color:#fde8a1;stop-opacity:1;" + offset="0" + id="stop4013-1-9-63" /> + <stop + style="stop-color:#2947b9;stop-opacity:1;" + offset="1" + id="stop4015-3-8-8" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4466" + id="linearGradient4472" + x1="161.7561" + y1="540.72662" + x2="161.7561" + y2="579.80206" + gradientUnits="userSpaceOnUse" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient4321" + id="radialGradient4474" + cx="130.8242" + cy="575.27838" + fx="130.8242" + fy="575.27838" + r="49.498173" + gradientTransform="matrix(0.95670828,0.96684666,-0.72623533,0.71862001,423.45109,35.05138)" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4466-5" + id="linearGradient4472-9" + x1="161.7561" + y1="540.72662" + x2="161.7561" + y2="579.80206" + gradientUnits="userSpaceOnUse" /> + <linearGradient + id="linearGradient4466-5"> + <stop + style="stop-color:#ffffff;stop-opacity:1;" + offset="0" + id="stop4468-2" /> + <stop + style="stop-color:#ffffff;stop-opacity:0;" + offset="1" + id="stop4470-3" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient4321-0" + id="radialGradient4474-6" + cx="130.8242" + cy="575.27838" + fx="130.8242" + fy="575.27838" + r="49.498173" + gradientTransform="matrix(0.95670828,0.96684666,-0.72623533,0.71862001,442.64399,170.9169)" + gradientUnits="userSpaceOnUse" /> + <linearGradient + id="linearGradient4321-0"> + <stop + style="stop-color:#ff6702;stop-opacity:1;" + offset="0" + id="stop4323-3" /> + <stop + style="stop-color:#ff9a55;stop-opacity:1;" + offset="1" + id="stop4325-1" /> + </linearGradient> + <linearGradient + id="linearGradient4466-5-5"> + <stop + style="stop-color:#ffffff;stop-opacity:1;" + offset="0" + id="stop4468-2-9" /> + <stop + style="stop-color:#ffffff;stop-opacity:0;" + offset="1" + id="stop4470-3-4" /> + </linearGradient> + <linearGradient + id="linearGradient4321-0-0"> + <stop + style="stop-color:#ff6702;stop-opacity:1;" + offset="0" + id="stop4323-3-9" /> + <stop + style="stop-color:#ff9a55;stop-opacity:1;" + offset="1" + id="stop4325-1-1" /> + </linearGradient> + <linearGradient + id="linearGradient4466-5-9"> + <stop + style="stop-color:#ffffff;stop-opacity:1;" + offset="0" + id="stop4468-2-7" /> + <stop + style="stop-color:#ffffff;stop-opacity:0;" + offset="1" + id="stop4470-3-7" /> + </linearGradient> + <linearGradient + id="linearGradient4321-0-7"> + <stop + style="stop-color:#ff6702;stop-opacity:1;" + offset="0" + id="stop4323-3-3" /> + <stop + style="stop-color:#ff9a55;stop-opacity:1;" + offset="1" + id="stop4325-1-6" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4431" + id="linearGradient4437" + x1="142.81854" + y1="831.52283" + x2="142.81854" + y2="878.90735" + gradientUnits="userSpaceOnUse" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient4467" + id="radialGradient4475" + cx="116.51958" + cy="98.282051" + fx="116.51958" + fy="98.282051" + r="55.859375" + gradientTransform="matrix(0.97442557,1.5088911,-0.83559154,0.53961599,79.641615,-130.28522)" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4431-3" + id="linearGradient4437-6" + x1="142.81854" + y1="831.52283" + x2="142.81854" + y2="878.90735" + gradientUnits="userSpaceOnUse" /> + <linearGradient + id="linearGradient4431-3"> + <stop + style="stop-color:#ffffff;stop-opacity:1;" + offset="0" + id="stop4433-0" /> + <stop + style="stop-color:#ffffff;stop-opacity:0;" + offset="1" + id="stop4435-2" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient4467-7" + id="radialGradient4475-0" + cx="116.51958" + cy="98.282051" + fx="116.51958" + fy="98.282051" + r="55.859375" + gradientTransform="matrix(0.97442557,1.5088911,-0.83559154,0.53961599,225.10358,63.664066)" + gradientUnits="userSpaceOnUse" /> + <linearGradient + id="linearGradient4467-7"> + <stop + style="stop-color:#000000;stop-opacity:1;" + offset="0" + id="stop4469-4" /> + <stop + style="stop-color:#000000;stop-opacity:0.8974359;" + offset="1" + id="stop4471-7" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient4467" + id="radialGradient3262" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.97442557,1.5088911,-0.83559154,0.53961599,59.641615,-150.28522)" + cx="116.51958" + cy="98.282051" + fx="116.51958" + fy="98.282051" + r="55.859375" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4431" + id="linearGradient3264" + gradientUnits="userSpaceOnUse" + x1="142.81854" + y1="831.52283" + x2="142.81854" + y2="878.90735" /> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="5.6" + inkscape:cx="31.144191" + inkscape:cy="38.335716" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showgrid="false" + showguides="false" + inkscape:guide-bbox="true" + inkscape:window-width="1920" + inkscape:window-height="1056" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" + fit-margin-top="0" + fit-margin-right="0" + fit-margin-bottom="0" + fit-margin-left="0"> + <sodipodi:guide + orientation="0,1" + position="72.563745,37.346999" + id="guide2989" /> + <sodipodi:guide + orientation="0,1" + position="74.584055,7.2949693" + id="guide2991" /> + <sodipodi:guide + orientation="1,0" + position="71.048515,20.426949" + id="guide2993" /> + <sodipodi:guide + orientation="1,0" + position="97.817565,20.174409" + id="guide2995" /> + <sodipodi:guide + orientation="1,0" + position="71.048515,20.426949" + id="guide3017" /> + <inkscape:grid + type="xygrid" + id="grid3019" + empspacing="5" + visible="true" + enabled="true" + snapvisiblegridlinesonly="true" /> + <sodipodi:guide + orientation="1,0" + position="105.6589,-12.377861" + id="guide3021" /> + <sodipodi:guide + orientation="1,0" + position="126.6589,-16.377861" + id="guide3023" /> + <sodipodi:guide + orientation="0,1" + position="110.6589,-3.3778607" + id="guide3025" /> + <sodipodi:guide + orientation="0,1" + position="110.6589,-27.377861" + id="guide3027" /> + <sodipodi:guide + orientation="0,1" + position="19.658895,-35.37786" + id="guide3810" /> + <sodipodi:guide + orientation="0,1" + position="21.658895,-70.377861" + id="guide3814" /> + <sodipodi:guide + orientation="0,1" + position="2.301752,-9.4850007" + id="guide3856" /> + <sodipodi:guide + orientation="0,1" + position="26.601806,-9.4850007" + id="guide3887" /> + <sodipodi:guide + orientation="0,1" + position="44.658283,37.346999" + id="guide4019" /> + <sodipodi:guide + orientation="0,1" + position="126.6589,-27.377861" + id="guide4481" /> + <sodipodi:guide + orientation="0,1" + position="159.08747,-213.94929" + id="guide4483" /> + </sodipodi:namedview> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(-42.341105,-35.859333)"> + <path + inkscape:connector-curvature="0" + style="fill:url(#radialGradient3262);fill-opacity:1;stroke:none" + d="m 98.2161,35.859333 c -30.850815,0 -55.874995,24.87043 -55.874995,55.562497 0,30.69207 25.02418,55.56249 55.874995,55.56249 10.09496,0 19.54625,-2.6525 27.71875,-7.3125 l 2.90625,7.3125 2.40625,0 20,0 0.125,0 -8.8125,-21.78124 c 7.21537,-9.3622 11.5,-21.07236 11.5,-33.78125 0,-30.692067 -24.99293,-55.562497 -55.84375,-55.562497 z" + id="path3834-7-7-2-5-5-0-5-4" /> + <path + sodipodi:type="arc" + style="fill:url(#linearGradient3264);fill-opacity:1;stroke:none" + id="path3661" + sodipodi:cx="142.5" + sodipodi:cy="856.29077" + sodipodi:rx="35.357143" + sodipodi:ry="24.642857" + d="m 177.85714,856.29077 c 0,13.60988 -15.82993,24.64286 -35.35714,24.64286 -19.52721,0 -35.35714,-11.03298 -35.35714,-24.64286 0,-13.60987 15.82993,-24.64286 35.35714,-24.64286 19.52721,0 35.35714,11.03299 35.35714,24.64286 z" + transform="matrix(1.0465082,0,0,1.2920463,-51.641235,-1036.8612)" /> + <path + sodipodi:type="arc" + style="fill:#000000;fill-opacity:1;stroke:none" + id="path4442" + sodipodi:cx="115.66247" + sodipodi:cy="856.39258" + sodipodi:rx="6.5659914" + sodipodi:ry="6.5659914" + d="m 122.22846,856.39258 c 0,3.6263 -2.9397,6.56599 -6.56599,6.56599 -3.6263,0 -6.56599,-2.93969 -6.56599,-6.56599 0,-3.6263 2.93969,-6.56599 6.56599,-6.56599 3.62629,0 6.56599,2.93969 6.56599,6.56599 z" + transform="translate(-12.329975,-797.60351)" /> + <rect + style="fill:#000000;fill-opacity:1;stroke:none" + id="rect4444" + width="37.643608" + height="5.5005069" + x="101.55376" + y="48.297417" + transform="matrix(0.98974903,0.14281759,-0.18972639,0.981837,0,0)" /> + <rect + style="fill:#000000;fill-opacity:1;stroke:none" + id="rect4446" + width="6.5659914" + height="2.9041886" + x="124.92451" + y="69.016899" /> + <path + style="fill:#ff6600;fill-opacity:1" + d="m 83.38797,45.010543 c -0.057,2.18531 -3.865755,0.28296 -4.031245,2.78125 -4.22387,-1.88052 0.32884,2.87188 -0.0937,3.3125 l -0.0312,0 -0.3125,-0.0312 c -0.20386,-0.0728 -0.49977,-0.19904 -0.9375,-0.46875 -2.9499,2.35025 -3.02157,7.23369 -6.0625,9.9375 -1.99467,4.30504 -2.47977,8.98337 -3.9375,13.46875 -0.71796,4.30292 -1.34881,8.597857 -0.28125,12.906247 0.32053,3.50159 -0.68919,8.25865 2.5,10.71875 4.72728,3.88304 8.65575,8.79543 12.624995,13.46875 6.21914,7.65333 11.72948,15.86251 16.59375,24.4375 0.32431,-2.11756 1.10954,4.26459 2.53125,4.6875 -0.49161,-3.19231 -1.13213,-8.26328 -1.4375,-12.1875 -1.5814,-10.2909 -6.65305,-19.64903 -8.5625,-29.84375 -0.0587,-0.43037 -0.12809,-0.87203 -0.1875,-1.3125 l 0,-1.28125 -0.15625,0 c -0.62551,-5.04297 -0.8504,-10.46546 2.8125,-14.40625 3.73968,-3.772097 9.30633,-4.722447 13.8125,-7.343747 1.00194,-0.59119 2.04921,-1.07174 3.125,-1.40625 0.009,-0.003 0.0228,0.003 0.0312,0 3.11701,-0.96341 6.44862,-0.93323 9.6875,-0.40625 0.0479,0.008 0.10841,0.0233 0.15625,0.0312 0.29455,0.0493 0.61389,0.099 0.90625,0.15625 2.37136,0.21133 7.14463,1.13687 8,-0.5 -3.27225,-2.78631 -7.98526,-2.59211 -11.96875,-3.6875 -0.63059,-0.11469 -1.41182,-0.24041 -2.1875,-0.3125 l -3.90625,-0.875 -0.96875,-0.25 0,0.0312 -13.96875,-2.71875 c -0.22212,-0.20226 -0.46434,-0.40933 -0.6875,-0.5625 l 13.625,1.6875 0,-0.0625 c 0.48011,0.10699 0.95576,0.19361 1.4375,0.25 l 0,0.0312 9.625,1.78125 c 1.66103,0.61952 3.4322,1.08374 5.09375,1.1875 2.74263,0.39907 6.22526,4.49092 7.125,4.6875 -0.44096,-4.307 -4.7422,-6.23586 -8.3125,-7.5 -4.1712,-2.02803 -10.4023,-1.95417 -11.0625,-7.5625 -0.1756,-0.39076 -0.34902,-0.78118 -0.5625,-1.15625 l -1.625,-2.15625 0.0625,-0.0312 c -2.21724,-2.61691 -5.34011,-4.52196 -8.65625,-5.25 -3.2914,-1.13611 -6.98773,-2.2671 -10.46875,-2.71875 -1.18132,3.47826 -2.5031,-2.75561 -5.34375,-0.90625 -2.48996,0.29488 -2.14614,0.95256 -4,-0.625 z m 17.90625,10.15625 c 0.90187,-0.0238 1.93277,0.14208 2.96875,0.5 2.76259,0.95447 4.56151,2.96523 4.03125,4.5 -0.53026,1.53477 -3.20616,1.98572 -5.96875,1.03125 -2.76259,-0.95447 -4.5615,-2.93398 -4.03125,-4.46875 0.33141,-0.95923 1.49689,-1.52281 3,-1.5625 z" + id="path3499-9-7" + inkscape:connector-curvature="0" /> + </g> +</svg> diff --git a/qapi-schema.json b/qapi-schema.json index ef1f657..5ad6894 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -236,6 +236,8 @@ # # @snapshots: #optional list of VM snapshots # +# @backing-image: #optional info of the backing image (since 1.6) +# # Since: 1.3 # ## @@ -245,7 +247,8 @@ '*actual-size': 'int', 'virtual-size': 'int', '*cluster-size': 'int', '*encrypted': 'bool', '*backing-filename': 'str', '*full-backing-filename': 'str', - '*backing-filename-format': 'str', '*snapshots': ['SnapshotInfo'] } } + '*backing-filename-format': 'str', '*snapshots': ['SnapshotInfo'], + '*backing-image': 'ImageInfo' } } ## # @ImageCheck: @@ -756,6 +759,8 @@ # # @iops_wr: write I/O operations per second is specified # +# @image: the info of image used (since: 1.6) +# # Since: 0.14.0 # # Notes: This interface is only found in @BlockInfo. @@ -765,7 +770,8 @@ '*backing_file': 'str', 'backing_file_depth': 'int', 'encrypted': 'bool', 'encryption_key_missing': 'bool', 'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int', - 'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int'} } + 'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int', + 'image': 'ImageInfo' } } ## # @BlockDeviceIoStatus: diff --git a/qemu-char.c b/qemu-char.c index d04b429..2c3cfe6 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -76,8 +76,6 @@ #include <netinet/ip_icmp.h> // must come after ip.h #include <netinet/udp.h> #include <netinet/tcp.h> -#include <net/if.h> -#include <syslog.h> #endif #endif #endif @@ -110,19 +108,9 @@ void qemu_chr_be_event(CharDriverState *s, int event) s->chr_event(s->handler_opaque, event); } -static gboolean qemu_chr_be_generic_open_bh(gpointer opaque) -{ - CharDriverState *s = opaque; - qemu_chr_be_event(s, CHR_EVENT_OPENED); - s->idle_tag = 0; - return FALSE; -} - void qemu_chr_be_generic_open(CharDriverState *s) { - if (s->idle_tag == 0) { - s->idle_tag = g_idle_add(qemu_chr_be_generic_open_bh, s); - } + qemu_chr_be_event(s, CHR_EVENT_OPENED); } int qemu_chr_fe_write(CharDriverState *s, const uint8_t *buf, int len) @@ -247,6 +235,7 @@ static CharDriverState *qemu_chr_open_null(void) chr = g_malloc0(sizeof(CharDriverState)); chr->chr_write = null_chr_write; + chr->explicit_be_open = true; return chr; } @@ -504,9 +493,6 @@ static CharDriverState *qemu_chr_open_mux(CharDriverState *drv) /* Frontend guest-open / -close notification is not support with muxes */ chr->chr_set_fe_open = NULL; - /* Muxes are always open on creation */ - qemu_chr_be_generic_open(chr); - return chr; } @@ -883,8 +869,6 @@ static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out) chr->chr_update_read_handler = fd_chr_update_read_handler; chr->chr_close = fd_chr_close; - qemu_chr_be_generic_open(chr); - return chr; } @@ -980,63 +964,6 @@ static CharDriverState *qemu_chr_open_stdio(ChardevStdio *opts) return chr; } -#ifdef __sun__ -/* Once Solaris has openpty(), this is going to be removed. */ -static int openpty(int *amaster, int *aslave, char *name, - struct termios *termp, struct winsize *winp) -{ - const char *slave; - int mfd = -1, sfd = -1; - - *amaster = *aslave = -1; - - mfd = open("/dev/ptmx", O_RDWR | O_NOCTTY); - if (mfd < 0) - goto err; - - if (grantpt(mfd) == -1 || unlockpt(mfd) == -1) - goto err; - - if ((slave = ptsname(mfd)) == NULL) - goto err; - - if ((sfd = open(slave, O_RDONLY | O_NOCTTY)) == -1) - goto err; - - if (ioctl(sfd, I_PUSH, "ptem") == -1 || - (termp != NULL && tcgetattr(sfd, termp) < 0)) - goto err; - - if (amaster) - *amaster = mfd; - if (aslave) - *aslave = sfd; - if (winp) - ioctl(sfd, TIOCSWINSZ, winp); - - return 0; - -err: - if (sfd != -1) - close(sfd); - close(mfd); - return -1; -} - -static void cfmakeraw (struct termios *termios_p) -{ - termios_p->c_iflag &= - ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON); - termios_p->c_oflag &= ~OPOST; - termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); - termios_p->c_cflag &= ~(CSIZE|PARENB); - termios_p->c_cflag |= CS8; - - termios_p->c_cc[VMIN] = 0; - termios_p->c_cc[VTIME] = 0; -} -#endif - #if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \ || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \ || defined(__GLIBC__) @@ -1208,34 +1135,24 @@ static CharDriverState *qemu_chr_open_pty(const char *id, { CharDriverState *chr; PtyCharDriver *s; - struct termios tty; int master_fd, slave_fd; -#if defined(__OpenBSD__) || defined(__DragonFly__) char pty_name[PATH_MAX]; -#define q_ptsname(x) pty_name -#else - char *pty_name = NULL; -#define q_ptsname(x) ptsname(x) -#endif - if (openpty(&master_fd, &slave_fd, pty_name, NULL, NULL) < 0) { + master_fd = qemu_openpty_raw(&slave_fd, pty_name); + if (master_fd < 0) { return NULL; } - /* Set raw attributes on the pty. */ - tcgetattr(slave_fd, &tty); - cfmakeraw(&tty); - tcsetattr(slave_fd, TCSAFLUSH, &tty); close(slave_fd); chr = g_malloc0(sizeof(CharDriverState)); - chr->filename = g_strdup_printf("pty:%s", q_ptsname(master_fd)); - ret->pty = g_strdup(q_ptsname(master_fd)); + chr->filename = g_strdup_printf("pty:%s", pty_name); + ret->pty = g_strdup(pty_name); ret->has_pty = true; fprintf(stderr, "char device redirected to %s (label %s)\n", - q_ptsname(master_fd), id); + pty_name, id); s = g_malloc0(sizeof(PtyCharDriver)); chr->opaque = s; @@ -1243,6 +1160,7 @@ static CharDriverState *qemu_chr_open_pty(const char *id, chr->chr_update_read_handler = pty_chr_update_read_handler; chr->chr_close = pty_chr_close; chr->chr_add_watch = pty_chr_add_watch; + chr->explicit_be_open = true; s->fd = io_channel_from_fd(master_fd); s->timer_tag = 0; @@ -1595,8 +1513,6 @@ static CharDriverState *qemu_chr_open_pp_fd(int fd) chr->chr_close = pp_close; chr->opaque = drv; - qemu_chr_be_generic_open(chr); - return chr; } #endif /* __linux__ */ @@ -1650,6 +1566,7 @@ static CharDriverState *qemu_chr_open_pp_fd(int fd) chr->opaque = (void *)(intptr_t)fd; chr->chr_write = null_chr_write; chr->chr_ioctl = pp_ioctl; + chr->explicit_be_open = true; return chr; } #endif @@ -1880,7 +1797,6 @@ static CharDriverState *qemu_chr_open_win_path(const char *filename) g_free(chr); return NULL; } - qemu_chr_be_generic_open(chr); return chr; } @@ -1980,7 +1896,6 @@ static CharDriverState *qemu_chr_open_pipe(ChardevHostdev *opts) g_free(chr); return NULL; } - qemu_chr_be_generic_open(chr); return chr; } @@ -1994,7 +1909,6 @@ static CharDriverState *qemu_chr_open_win_file(HANDLE fd_out) s->hcom = fd_out; chr->opaque = s; chr->chr_write = win_chr_write; - qemu_chr_be_generic_open(chr); return chr; } @@ -2329,6 +2243,8 @@ static CharDriverState *qemu_chr_open_udp_fd(int fd) chr->chr_write = udp_chr_write; chr->chr_update_read_handler = udp_chr_update_read_handler; chr->chr_close = udp_chr_close; + /* be isn't opened until we get a connection */ + chr->explicit_be_open = true; return chr; } @@ -2731,6 +2647,8 @@ static CharDriverState *qemu_chr_open_socket_fd(int fd, bool do_nodelay, chr->get_msgfd = tcp_get_msgfd; chr->chr_add_client = tcp_chr_add_client; chr->chr_add_watch = tcp_chr_add_watch; + /* be isn't opened until we get a connection */ + chr->explicit_be_open = true; if (is_listen) { s->listen_fd = fd; @@ -3325,6 +3243,12 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts, if (!chr->filename) chr->filename = g_strdup(qemu_opt_get(opts, "backend")); chr->init = init; + /* if we didn't create the chardev via qmp_chardev_add, we + * need to send the OPENED event here + */ + if (!chr->explicit_be_open) { + qemu_chr_be_event(chr, CHR_EVENT_OPENED); + } QTAILQ_INSERT_TAIL(&chardevs, chr, next); if (qemu_opt_get_bool(opts, "mux", 0)) { @@ -3804,6 +3728,9 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, if (!chr->filename) { chr->filename = g_strdup(ChardevBackendKind_lookup[backend->kind]); } + if (!chr->explicit_be_open) { + qemu_chr_be_event(chr, CHR_EVENT_OPENED); + } QTAILQ_INSERT_TAIL(&chardevs, chr, next); return ret; } else { @@ -85,8 +85,9 @@ static void help(void) " options are: 'none', 'writeback' (default, except for convert), 'writethrough',\n" " 'directsync' and 'unsafe' (default for convert)\n" " 'size' is the disk image size in bytes. Optional suffixes\n" - " 'k' or 'K' (kilobyte, 1024), 'M' (megabyte, 1024k), 'G' (gigabyte, 1024M)\n" - " and T (terabyte, 1024G) are supported. 'b' is ignored.\n" + " 'k' or 'K' (kilobyte, 1024), 'M' (megabyte, 1024k), 'G' (gigabyte, 1024M),\n" + " 'T' (terabyte, 1024G), 'P' (petabyte, 1024T) and 'E' (exabyte, 1024P) are\n" + " supported. 'b' is ignored.\n" " 'output_filename' is the destination disk image filename\n" " 'output_fmt' is the destination format\n" " 'options' is a comma separated list of format specific options in a\n" @@ -387,8 +388,9 @@ static int img_create(int argc, char **argv) error_report("Image size must be less than 8 EiB!"); } else { error_report("Invalid image size specified! You may use k, M, " - "G or T suffixes for "); - error_report("kilobytes, megabytes, gigabytes and terabytes."); + "G, T, P or E suffixes for "); + error_report("kilobytes, megabytes, gigabytes, terabytes, " + "petabytes and exabytes."); } return 1; } @@ -1642,6 +1644,7 @@ static ImageInfoList *collect_image_info_list(const char *filename, ImageInfoList *head = NULL; ImageInfoList **last = &head; GHashTable *filenames; + Error *err = NULL; filenames = g_hash_table_new_full(g_str_hash, str_equal_func, NULL, NULL); @@ -1663,9 +1666,12 @@ static ImageInfoList *collect_image_info_list(const char *filename, goto err; } - info = g_new0(ImageInfo, 1); - bdrv_collect_image_info(bs, info, filename); - bdrv_collect_snapshots(bs, info); + bdrv_query_image_info(bs, &info, &err); + if (error_is_set(&err)) { + error_report("%s", error_get_pretty(err)); + error_free(err); + goto err; + } elem = g_new0(ImageInfoList, 1); elem->value = info; diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c new file mode 100644 index 0000000..ffbcf31 --- /dev/null +++ b/qemu-io-cmds.c @@ -0,0 +1,2118 @@ +/* + * Command line utility to exercise the QEMU I/O path. + * + * Copyright (C) 2009 Red Hat, Inc. + * Copyright (c) 2003-2005 Silicon Graphics, 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. + */ + +#include "qemu-io.h" +#include "block/block_int.h" + +#define CMD_NOFILE_OK 0x01 + +int qemuio_misalign; + +static cmdinfo_t *cmdtab; +static int ncmds; + +static int compare_cmdname(const void *a, const void *b) +{ + return strcmp(((const cmdinfo_t *)a)->name, + ((const cmdinfo_t *)b)->name); +} + +void qemuio_add_command(const cmdinfo_t *ci) +{ + cmdtab = g_realloc(cmdtab, ++ncmds * sizeof(*cmdtab)); + cmdtab[ncmds - 1] = *ci; + qsort(cmdtab, ncmds, sizeof(*cmdtab), compare_cmdname); +} + +int qemuio_command_usage(const cmdinfo_t *ci) +{ + printf("%s %s -- %s\n", ci->name, ci->args, ci->oneline); + return 0; +} + +static int init_check_command(BlockDriverState *bs, const cmdinfo_t *ct) +{ + if (ct->flags & CMD_FLAG_GLOBAL) { + return 1; + } + if (!(ct->flags & CMD_NOFILE_OK) && !bs) { + fprintf(stderr, "no file open, try 'help open'\n"); + return 0; + } + return 1; +} + +static int command(BlockDriverState *bs, const cmdinfo_t *ct, int argc, + char **argv) +{ + char *cmd = argv[0]; + + if (!init_check_command(bs, ct)) { + return 0; + } + + if (argc - 1 < ct->argmin || (ct->argmax != -1 && argc - 1 > ct->argmax)) { + if (ct->argmax == -1) { + fprintf(stderr, + "bad argument count %d to %s, expected at least %d arguments\n", + argc-1, cmd, ct->argmin); + } else if (ct->argmin == ct->argmax) { + fprintf(stderr, + "bad argument count %d to %s, expected %d arguments\n", + argc-1, cmd, ct->argmin); + } else { + fprintf(stderr, + "bad argument count %d to %s, expected between %d and %d arguments\n", + argc-1, cmd, ct->argmin, ct->argmax); + } + return 0; + } + optind = 0; + return ct->cfunc(bs, argc, argv); +} + +static const cmdinfo_t *find_command(const char *cmd) +{ + cmdinfo_t *ct; + + for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) { + if (strcmp(ct->name, cmd) == 0 || + (ct->altname && strcmp(ct->altname, cmd) == 0)) + { + return (const cmdinfo_t *)ct; + } + } + return NULL; +} + +static char **breakline(char *input, int *count) +{ + int c = 0; + char *p; + char **rval = g_malloc0(sizeof(char *)); + char **tmp; + + while (rval && (p = qemu_strsep(&input, " ")) != NULL) { + if (!*p) { + continue; + } + c++; + tmp = g_realloc(rval, sizeof(*rval) * (c + 1)); + if (!tmp) { + g_free(rval); + rval = NULL; + c = 0; + break; + } else { + rval = tmp; + } + rval[c - 1] = p; + rval[c] = NULL; + } + *count = c; + return rval; +} + +static int64_t cvtnum(const char *s) +{ + char *end; + return strtosz_suffix(s, &end, STRTOSZ_DEFSUFFIX_B); +} + +#define EXABYTES(x) ((long long)(x) << 60) +#define PETABYTES(x) ((long long)(x) << 50) +#define TERABYTES(x) ((long long)(x) << 40) +#define GIGABYTES(x) ((long long)(x) << 30) +#define MEGABYTES(x) ((long long)(x) << 20) +#define KILOBYTES(x) ((long long)(x) << 10) + +#define TO_EXABYTES(x) ((x) / EXABYTES(1)) +#define TO_PETABYTES(x) ((x) / PETABYTES(1)) +#define TO_TERABYTES(x) ((x) / TERABYTES(1)) +#define TO_GIGABYTES(x) ((x) / GIGABYTES(1)) +#define TO_MEGABYTES(x) ((x) / MEGABYTES(1)) +#define TO_KILOBYTES(x) ((x) / KILOBYTES(1)) + +static void cvtstr(double value, char *str, size_t size) +{ + char *trim; + const char *suffix; + + if (value >= EXABYTES(1)) { + suffix = " EiB"; + snprintf(str, size - 4, "%.3f", TO_EXABYTES(value)); + } else if (value >= PETABYTES(1)) { + suffix = " PiB"; + snprintf(str, size - 4, "%.3f", TO_PETABYTES(value)); + } else if (value >= TERABYTES(1)) { + suffix = " TiB"; + snprintf(str, size - 4, "%.3f", TO_TERABYTES(value)); + } else if (value >= GIGABYTES(1)) { + suffix = " GiB"; + snprintf(str, size - 4, "%.3f", TO_GIGABYTES(value)); + } else if (value >= MEGABYTES(1)) { + suffix = " MiB"; + snprintf(str, size - 4, "%.3f", TO_MEGABYTES(value)); + } else if (value >= KILOBYTES(1)) { + suffix = " KiB"; + snprintf(str, size - 4, "%.3f", TO_KILOBYTES(value)); + } else { + suffix = " bytes"; + snprintf(str, size - 6, "%f", value); + } + + trim = strstr(str, ".000"); + if (trim) { + strcpy(trim, suffix); + } else { + strcat(str, suffix); + } +} + + + +static struct timeval tsub(struct timeval t1, struct timeval t2) +{ + t1.tv_usec -= t2.tv_usec; + if (t1.tv_usec < 0) { + t1.tv_usec += 1000000; + t1.tv_sec--; + } + t1.tv_sec -= t2.tv_sec; + return t1; +} + +static double tdiv(double value, struct timeval tv) +{ + return value / ((double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0)); +} + +#define HOURS(sec) ((sec) / (60 * 60)) +#define MINUTES(sec) (((sec) % (60 * 60)) / 60) +#define SECONDS(sec) ((sec) % 60) + +enum { + DEFAULT_TIME = 0x0, + TERSE_FIXED_TIME = 0x1, + VERBOSE_FIXED_TIME = 0x2, +}; + +static void timestr(struct timeval *tv, char *ts, size_t size, int format) +{ + double usec = (double)tv->tv_usec / 1000000.0; + + if (format & TERSE_FIXED_TIME) { + if (!HOURS(tv->tv_sec)) { + snprintf(ts, size, "%u:%02u.%02u", + (unsigned int) MINUTES(tv->tv_sec), + (unsigned int) SECONDS(tv->tv_sec), + (unsigned int) (usec * 100)); + return; + } + format |= VERBOSE_FIXED_TIME; /* fallback if hours needed */ + } + + if ((format & VERBOSE_FIXED_TIME) || tv->tv_sec) { + snprintf(ts, size, "%u:%02u:%02u.%02u", + (unsigned int) HOURS(tv->tv_sec), + (unsigned int) MINUTES(tv->tv_sec), + (unsigned int) SECONDS(tv->tv_sec), + (unsigned int) (usec * 100)); + } else { + snprintf(ts, size, "0.%04u sec", (unsigned int) (usec * 10000)); + } +} + +/* + * Parse the pattern argument to various sub-commands. + * + * Because the pattern is used as an argument to memset it must evaluate + * to an unsigned integer that fits into a single byte. + */ +static int parse_pattern(const char *arg) +{ + char *endptr = NULL; + long pattern; + + pattern = strtol(arg, &endptr, 0); + if (pattern < 0 || pattern > UCHAR_MAX || *endptr != '\0') { + printf("%s is not a valid pattern byte\n", arg); + return -1; + } + + return pattern; +} + +/* + * Memory allocation helpers. + * + * Make sure memory is aligned by default, or purposefully misaligned if + * that is specified on the command line. + */ + +#define MISALIGN_OFFSET 16 +static void *qemu_io_alloc(BlockDriverState *bs, size_t len, int pattern) +{ + void *buf; + + if (qemuio_misalign) { + len += MISALIGN_OFFSET; + } + buf = qemu_blockalign(bs, len); + memset(buf, pattern, len); + if (qemuio_misalign) { + buf += MISALIGN_OFFSET; + } + return buf; +} + +static void qemu_io_free(void *p) +{ + if (qemuio_misalign) { + p -= MISALIGN_OFFSET; + } + qemu_vfree(p); +} + +static void dump_buffer(const void *buffer, int64_t offset, int len) +{ + int i, j; + const uint8_t *p; + + for (i = 0, p = buffer; i < len; i += 16) { + const uint8_t *s = p; + + printf("%08" PRIx64 ": ", offset + i); + for (j = 0; j < 16 && i + j < len; j++, p++) { + printf("%02x ", *p); + } + printf(" "); + for (j = 0; j < 16 && i + j < len; j++, s++) { + if (isalnum(*s)) { + printf("%c", *s); + } else { + printf("."); + } + } + printf("\n"); + } +} + +static void print_report(const char *op, struct timeval *t, int64_t offset, + int count, int total, int cnt, int Cflag) +{ + char s1[64], s2[64], ts[64]; + + timestr(t, ts, sizeof(ts), Cflag ? VERBOSE_FIXED_TIME : 0); + if (!Cflag) { + cvtstr((double)total, s1, sizeof(s1)); + cvtstr(tdiv((double)total, *t), s2, sizeof(s2)); + printf("%s %d/%d bytes at offset %" PRId64 "\n", + op, total, count, offset); + printf("%s, %d ops; %s (%s/sec and %.4f ops/sec)\n", + s1, cnt, ts, s2, tdiv((double)cnt, *t)); + } else {/* bytes,ops,time,bytes/sec,ops/sec */ + printf("%d,%d,%s,%.3f,%.3f\n", + total, cnt, ts, + tdiv((double)total, *t), + tdiv((double)cnt, *t)); + } +} + +/* + * Parse multiple length statements for vectored I/O, and construct an I/O + * vector matching it. + */ +static void * +create_iovec(BlockDriverState *bs, QEMUIOVector *qiov, char **argv, int nr_iov, + int pattern) +{ + size_t *sizes = g_new0(size_t, nr_iov); + size_t count = 0; + void *buf = NULL; + void *p; + int i; + + for (i = 0; i < nr_iov; i++) { + char *arg = argv[i]; + int64_t len; + + len = cvtnum(arg); + if (len < 0) { + printf("non-numeric length argument -- %s\n", arg); + goto fail; + } + + /* should be SIZE_T_MAX, but that doesn't exist */ + if (len > INT_MAX) { + printf("too large length argument -- %s\n", arg); + goto fail; + } + + if (len & 0x1ff) { + printf("length argument %" PRId64 + " is not sector aligned\n", len); + goto fail; + } + + sizes[i] = len; + count += len; + } + + qemu_iovec_init(qiov, nr_iov); + + buf = p = qemu_io_alloc(bs, count, pattern); + + for (i = 0; i < nr_iov; i++) { + qemu_iovec_add(qiov, p, sizes[i]); + p += sizes[i]; + } + +fail: + g_free(sizes); + return buf; +} + +static int do_read(BlockDriverState *bs, char *buf, int64_t offset, int count, + int *total) +{ + int ret; + + ret = bdrv_read(bs, offset >> 9, (uint8_t *)buf, count >> 9); + if (ret < 0) { + return ret; + } + *total = count; + return 1; +} + +static int do_write(BlockDriverState *bs, char *buf, int64_t offset, int count, + int *total) +{ + int ret; + + ret = bdrv_write(bs, offset >> 9, (uint8_t *)buf, count >> 9); + if (ret < 0) { + return ret; + } + *total = count; + return 1; +} + +static int do_pread(BlockDriverState *bs, char *buf, int64_t offset, int count, + int *total) +{ + *total = bdrv_pread(bs, offset, (uint8_t *)buf, count); + if (*total < 0) { + return *total; + } + return 1; +} + +static int do_pwrite(BlockDriverState *bs, char *buf, int64_t offset, int count, + int *total) +{ + *total = bdrv_pwrite(bs, offset, (uint8_t *)buf, count); + if (*total < 0) { + return *total; + } + return 1; +} + +typedef struct { + BlockDriverState *bs; + int64_t offset; + int count; + int *total; + int ret; + bool done; +} CoWriteZeroes; + +static void coroutine_fn co_write_zeroes_entry(void *opaque) +{ + CoWriteZeroes *data = opaque; + + data->ret = bdrv_co_write_zeroes(data->bs, data->offset / BDRV_SECTOR_SIZE, + data->count / BDRV_SECTOR_SIZE); + data->done = true; + if (data->ret < 0) { + *data->total = data->ret; + return; + } + + *data->total = data->count; +} + +static int do_co_write_zeroes(BlockDriverState *bs, int64_t offset, int count, + int *total) +{ + Coroutine *co; + CoWriteZeroes data = { + .bs = bs, + .offset = offset, + .count = count, + .total = total, + .done = false, + }; + + co = qemu_coroutine_create(co_write_zeroes_entry); + qemu_coroutine_enter(co, &data); + while (!data.done) { + qemu_aio_wait(); + } + if (data.ret < 0) { + return data.ret; + } else { + return 1; + } +} + +static int do_write_compressed(BlockDriverState *bs, char *buf, int64_t offset, + int count, int *total) +{ + int ret; + + ret = bdrv_write_compressed(bs, offset >> 9, (uint8_t *)buf, count >> 9); + if (ret < 0) { + return ret; + } + *total = count; + return 1; +} + +static int do_load_vmstate(BlockDriverState *bs, char *buf, int64_t offset, + int count, int *total) +{ + *total = bdrv_load_vmstate(bs, (uint8_t *)buf, offset, count); + if (*total < 0) { + return *total; + } + return 1; +} + +static int do_save_vmstate(BlockDriverState *bs, char *buf, int64_t offset, + int count, int *total) +{ + *total = bdrv_save_vmstate(bs, (uint8_t *)buf, offset, count); + if (*total < 0) { + return *total; + } + return 1; +} + +#define NOT_DONE 0x7fffffff +static void aio_rw_done(void *opaque, int ret) +{ + *(int *)opaque = ret; +} + +static int do_aio_readv(BlockDriverState *bs, QEMUIOVector *qiov, + int64_t offset, int *total) +{ + int async_ret = NOT_DONE; + + bdrv_aio_readv(bs, offset >> 9, qiov, qiov->size >> 9, + aio_rw_done, &async_ret); + while (async_ret == NOT_DONE) { + main_loop_wait(false); + } + + *total = qiov->size; + return async_ret < 0 ? async_ret : 1; +} + +static int do_aio_writev(BlockDriverState *bs, QEMUIOVector *qiov, + int64_t offset, int *total) +{ + int async_ret = NOT_DONE; + + bdrv_aio_writev(bs, offset >> 9, qiov, qiov->size >> 9, + aio_rw_done, &async_ret); + while (async_ret == NOT_DONE) { + main_loop_wait(false); + } + + *total = qiov->size; + return async_ret < 0 ? async_ret : 1; +} + +struct multiwrite_async_ret { + int num_done; + int error; +}; + +static void multiwrite_cb(void *opaque, int ret) +{ + struct multiwrite_async_ret *async_ret = opaque; + + async_ret->num_done++; + if (ret < 0) { + async_ret->error = ret; + } +} + +static int do_aio_multiwrite(BlockDriverState *bs, BlockRequest* reqs, + int num_reqs, int *total) +{ + int i, ret; + struct multiwrite_async_ret async_ret = { + .num_done = 0, + .error = 0, + }; + + *total = 0; + for (i = 0; i < num_reqs; i++) { + reqs[i].cb = multiwrite_cb; + reqs[i].opaque = &async_ret; + *total += reqs[i].qiov->size; + } + + ret = bdrv_aio_multiwrite(bs, reqs, num_reqs); + if (ret < 0) { + return ret; + } + + while (async_ret.num_done < num_reqs) { + main_loop_wait(false); + } + + return async_ret.error < 0 ? async_ret.error : 1; +} + +static void read_help(void) +{ + printf( +"\n" +" reads a range of bytes from the given offset\n" +"\n" +" Example:\n" +" 'read -v 512 1k' - dumps 1 kilobyte read from 512 bytes into the file\n" +"\n" +" Reads a segment of the currently open file, optionally dumping it to the\n" +" standard output stream (with -v option) for subsequent inspection.\n" +" -b, -- read from the VM state rather than the virtual disk\n" +" -C, -- report statistics in a machine parsable format\n" +" -l, -- length for pattern verification (only with -P)\n" +" -p, -- use bdrv_pread to read the file\n" +" -P, -- use a pattern to verify read data\n" +" -q, -- quiet mode, do not show I/O statistics\n" +" -s, -- start offset for pattern verification (only with -P)\n" +" -v, -- dump buffer to standard output\n" +"\n"); +} + +static int read_f(BlockDriverState *bs, int argc, char **argv); + +static const cmdinfo_t read_cmd = { + .name = "read", + .altname = "r", + .cfunc = read_f, + .argmin = 2, + .argmax = -1, + .args = "[-abCpqv] [-P pattern [-s off] [-l len]] off len", + .oneline = "reads a number of bytes at a specified offset", + .help = read_help, +}; + +static int read_f(BlockDriverState *bs, int argc, char **argv) +{ + struct timeval t1, t2; + int Cflag = 0, pflag = 0, qflag = 0, vflag = 0; + int Pflag = 0, sflag = 0, lflag = 0, bflag = 0; + int c, cnt; + char *buf; + int64_t offset; + int count; + /* Some compilers get confused and warn if this is not initialized. */ + int total = 0; + int pattern = 0, pattern_offset = 0, pattern_count = 0; + + while ((c = getopt(argc, argv, "bCl:pP:qs:v")) != EOF) { + switch (c) { + case 'b': + bflag = 1; + break; + case 'C': + Cflag = 1; + break; + case 'l': + lflag = 1; + pattern_count = cvtnum(optarg); + if (pattern_count < 0) { + printf("non-numeric length argument -- %s\n", optarg); + return 0; + } + break; + case 'p': + pflag = 1; + break; + case 'P': + Pflag = 1; + pattern = parse_pattern(optarg); + if (pattern < 0) { + return 0; + } + break; + case 'q': + qflag = 1; + break; + case 's': + sflag = 1; + pattern_offset = cvtnum(optarg); + if (pattern_offset < 0) { + printf("non-numeric length argument -- %s\n", optarg); + return 0; + } + break; + case 'v': + vflag = 1; + break; + default: + return qemuio_command_usage(&read_cmd); + } + } + + if (optind != argc - 2) { + return qemuio_command_usage(&read_cmd); + } + + if (bflag && pflag) { + printf("-b and -p cannot be specified at the same time\n"); + return 0; + } + + offset = cvtnum(argv[optind]); + if (offset < 0) { + printf("non-numeric length argument -- %s\n", argv[optind]); + return 0; + } + + optind++; + count = cvtnum(argv[optind]); + if (count < 0) { + printf("non-numeric length argument -- %s\n", argv[optind]); + return 0; + } + + if (!Pflag && (lflag || sflag)) { + return qemuio_command_usage(&read_cmd); + } + + if (!lflag) { + pattern_count = count - pattern_offset; + } + + if ((pattern_count < 0) || (pattern_count + pattern_offset > count)) { + printf("pattern verification range exceeds end of read data\n"); + return 0; + } + + if (!pflag) { + if (offset & 0x1ff) { + printf("offset %" PRId64 " is not sector aligned\n", + offset); + return 0; + } + if (count & 0x1ff) { + printf("count %d is not sector aligned\n", + count); + return 0; + } + } + + buf = qemu_io_alloc(bs, count, 0xab); + + gettimeofday(&t1, NULL); + if (pflag) { + cnt = do_pread(bs, buf, offset, count, &total); + } else if (bflag) { + cnt = do_load_vmstate(bs, buf, offset, count, &total); + } else { + cnt = do_read(bs, buf, offset, count, &total); + } + gettimeofday(&t2, NULL); + + if (cnt < 0) { + printf("read failed: %s\n", strerror(-cnt)); + goto out; + } + + if (Pflag) { + void *cmp_buf = g_malloc(pattern_count); + memset(cmp_buf, pattern, pattern_count); + if (memcmp(buf + pattern_offset, cmp_buf, pattern_count)) { + printf("Pattern verification failed at offset %" + PRId64 ", %d bytes\n", + offset + pattern_offset, pattern_count); + } + g_free(cmp_buf); + } + + if (qflag) { + goto out; + } + + if (vflag) { + dump_buffer(buf, offset, count); + } + + /* Finally, report back -- -C gives a parsable format */ + t2 = tsub(t2, t1); + print_report("read", &t2, offset, count, total, cnt, Cflag); + +out: + qemu_io_free(buf); + + return 0; +} + +static void readv_help(void) +{ + printf( +"\n" +" reads a range of bytes from the given offset into multiple buffers\n" +"\n" +" Example:\n" +" 'readv -v 512 1k 1k ' - dumps 2 kilobytes read from 512 bytes into the file\n" +"\n" +" Reads a segment of the currently open file, optionally dumping it to the\n" +" standard output stream (with -v option) for subsequent inspection.\n" +" Uses multiple iovec buffers if more than one byte range is specified.\n" +" -C, -- report statistics in a machine parsable format\n" +" -P, -- use a pattern to verify read data\n" +" -v, -- dump buffer to standard output\n" +" -q, -- quiet mode, do not show I/O statistics\n" +"\n"); +} + +static int readv_f(BlockDriverState *bs, int argc, char **argv); + +static const cmdinfo_t readv_cmd = { + .name = "readv", + .cfunc = readv_f, + .argmin = 2, + .argmax = -1, + .args = "[-Cqv] [-P pattern ] off len [len..]", + .oneline = "reads a number of bytes at a specified offset", + .help = readv_help, +}; + +static int readv_f(BlockDriverState *bs, int argc, char **argv) +{ + struct timeval t1, t2; + int Cflag = 0, qflag = 0, vflag = 0; + int c, cnt; + char *buf; + int64_t offset; + /* Some compilers get confused and warn if this is not initialized. */ + int total = 0; + int nr_iov; + QEMUIOVector qiov; + int pattern = 0; + int Pflag = 0; + + while ((c = getopt(argc, argv, "CP:qv")) != EOF) { + switch (c) { + case 'C': + Cflag = 1; + break; + case 'P': + Pflag = 1; + pattern = parse_pattern(optarg); + if (pattern < 0) { + return 0; + } + break; + case 'q': + qflag = 1; + break; + case 'v': + vflag = 1; + break; + default: + return qemuio_command_usage(&readv_cmd); + } + } + + if (optind > argc - 2) { + return qemuio_command_usage(&readv_cmd); + } + + + offset = cvtnum(argv[optind]); + if (offset < 0) { + printf("non-numeric length argument -- %s\n", argv[optind]); + return 0; + } + optind++; + + if (offset & 0x1ff) { + printf("offset %" PRId64 " is not sector aligned\n", + offset); + return 0; + } + + nr_iov = argc - optind; + buf = create_iovec(bs, &qiov, &argv[optind], nr_iov, 0xab); + if (buf == NULL) { + return 0; + } + + gettimeofday(&t1, NULL); + cnt = do_aio_readv(bs, &qiov, offset, &total); + gettimeofday(&t2, NULL); + + if (cnt < 0) { + printf("readv failed: %s\n", strerror(-cnt)); + goto out; + } + + if (Pflag) { + void *cmp_buf = g_malloc(qiov.size); + memset(cmp_buf, pattern, qiov.size); + if (memcmp(buf, cmp_buf, qiov.size)) { + printf("Pattern verification failed at offset %" + PRId64 ", %zd bytes\n", offset, qiov.size); + } + g_free(cmp_buf); + } + + if (qflag) { + goto out; + } + + if (vflag) { + dump_buffer(buf, offset, qiov.size); + } + + /* Finally, report back -- -C gives a parsable format */ + t2 = tsub(t2, t1); + print_report("read", &t2, offset, qiov.size, total, cnt, Cflag); + +out: + qemu_iovec_destroy(&qiov); + qemu_io_free(buf); + return 0; +} + +static void write_help(void) +{ + printf( +"\n" +" writes a range of bytes from the given offset\n" +"\n" +" Example:\n" +" 'write 512 1k' - writes 1 kilobyte at 512 bytes into the open file\n" +"\n" +" Writes into a segment of the currently open file, using a buffer\n" +" filled with a set pattern (0xcdcdcdcd).\n" +" -b, -- write to the VM state rather than the virtual disk\n" +" -c, -- write compressed data with bdrv_write_compressed\n" +" -p, -- use bdrv_pwrite to write the file\n" +" -P, -- use different pattern to fill file\n" +" -C, -- report statistics in a machine parsable format\n" +" -q, -- quiet mode, do not show I/O statistics\n" +" -z, -- write zeroes using bdrv_co_write_zeroes\n" +"\n"); +} + +static int write_f(BlockDriverState *bs, int argc, char **argv); + +static const cmdinfo_t write_cmd = { + .name = "write", + .altname = "w", + .cfunc = write_f, + .argmin = 2, + .argmax = -1, + .args = "[-bcCpqz] [-P pattern ] off len", + .oneline = "writes a number of bytes at a specified offset", + .help = write_help, +}; + +static int write_f(BlockDriverState *bs, int argc, char **argv) +{ + struct timeval t1, t2; + int Cflag = 0, pflag = 0, qflag = 0, bflag = 0, Pflag = 0, zflag = 0; + int cflag = 0; + int c, cnt; + char *buf = NULL; + int64_t offset; + int count; + /* Some compilers get confused and warn if this is not initialized. */ + int total = 0; + int pattern = 0xcd; + + while ((c = getopt(argc, argv, "bcCpP:qz")) != EOF) { + switch (c) { + case 'b': + bflag = 1; + break; + case 'c': + cflag = 1; + break; + case 'C': + Cflag = 1; + break; + case 'p': + pflag = 1; + break; + case 'P': + Pflag = 1; + pattern = parse_pattern(optarg); + if (pattern < 0) { + return 0; + } + break; + case 'q': + qflag = 1; + break; + case 'z': + zflag = 1; + break; + default: + return qemuio_command_usage(&write_cmd); + } + } + + if (optind != argc - 2) { + return qemuio_command_usage(&write_cmd); + } + + if (bflag + pflag + zflag > 1) { + printf("-b, -p, or -z cannot be specified at the same time\n"); + return 0; + } + + if (zflag && Pflag) { + printf("-z and -P cannot be specified at the same time\n"); + return 0; + } + + offset = cvtnum(argv[optind]); + if (offset < 0) { + printf("non-numeric length argument -- %s\n", argv[optind]); + return 0; + } + + optind++; + count = cvtnum(argv[optind]); + if (count < 0) { + printf("non-numeric length argument -- %s\n", argv[optind]); + return 0; + } + + if (!pflag) { + if (offset & 0x1ff) { + printf("offset %" PRId64 " is not sector aligned\n", + offset); + return 0; + } + + if (count & 0x1ff) { + printf("count %d is not sector aligned\n", + count); + return 0; + } + } + + if (!zflag) { + buf = qemu_io_alloc(bs, count, pattern); + } + + gettimeofday(&t1, NULL); + if (pflag) { + cnt = do_pwrite(bs, buf, offset, count, &total); + } else if (bflag) { + cnt = do_save_vmstate(bs, buf, offset, count, &total); + } else if (zflag) { + cnt = do_co_write_zeroes(bs, offset, count, &total); + } else if (cflag) { + cnt = do_write_compressed(bs, buf, offset, count, &total); + } else { + cnt = do_write(bs, buf, offset, count, &total); + } + gettimeofday(&t2, NULL); + + if (cnt < 0) { + printf("write failed: %s\n", strerror(-cnt)); + goto out; + } + + if (qflag) { + goto out; + } + + /* Finally, report back -- -C gives a parsable format */ + t2 = tsub(t2, t1); + print_report("wrote", &t2, offset, count, total, cnt, Cflag); + +out: + if (!zflag) { + qemu_io_free(buf); + } + + return 0; +} + +static void +writev_help(void) +{ + printf( +"\n" +" writes a range of bytes from the given offset source from multiple buffers\n" +"\n" +" Example:\n" +" 'write 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n" +"\n" +" Writes into a segment of the currently open file, using a buffer\n" +" filled with a set pattern (0xcdcdcdcd).\n" +" -P, -- use different pattern to fill file\n" +" -C, -- report statistics in a machine parsable format\n" +" -q, -- quiet mode, do not show I/O statistics\n" +"\n"); +} + +static int writev_f(BlockDriverState *bs, int argc, char **argv); + +static const cmdinfo_t writev_cmd = { + .name = "writev", + .cfunc = writev_f, + .argmin = 2, + .argmax = -1, + .args = "[-Cq] [-P pattern ] off len [len..]", + .oneline = "writes a number of bytes at a specified offset", + .help = writev_help, +}; + +static int writev_f(BlockDriverState *bs, int argc, char **argv) +{ + struct timeval t1, t2; + int Cflag = 0, qflag = 0; + int c, cnt; + char *buf; + int64_t offset; + /* Some compilers get confused and warn if this is not initialized. */ + int total = 0; + int nr_iov; + int pattern = 0xcd; + QEMUIOVector qiov; + + while ((c = getopt(argc, argv, "CqP:")) != EOF) { + switch (c) { + case 'C': + Cflag = 1; + break; + case 'q': + qflag = 1; + break; + case 'P': + pattern = parse_pattern(optarg); + if (pattern < 0) { + return 0; + } + break; + default: + return qemuio_command_usage(&writev_cmd); + } + } + + if (optind > argc - 2) { + return qemuio_command_usage(&writev_cmd); + } + + offset = cvtnum(argv[optind]); + if (offset < 0) { + printf("non-numeric length argument -- %s\n", argv[optind]); + return 0; + } + optind++; + + if (offset & 0x1ff) { + printf("offset %" PRId64 " is not sector aligned\n", + offset); + return 0; + } + + nr_iov = argc - optind; + buf = create_iovec(bs, &qiov, &argv[optind], nr_iov, pattern); + if (buf == NULL) { + return 0; + } + + gettimeofday(&t1, NULL); + cnt = do_aio_writev(bs, &qiov, offset, &total); + gettimeofday(&t2, NULL); + + if (cnt < 0) { + printf("writev failed: %s\n", strerror(-cnt)); + goto out; + } + + if (qflag) { + goto out; + } + + /* Finally, report back -- -C gives a parsable format */ + t2 = tsub(t2, t1); + print_report("wrote", &t2, offset, qiov.size, total, cnt, Cflag); +out: + qemu_iovec_destroy(&qiov); + qemu_io_free(buf); + return 0; +} + +static void multiwrite_help(void) +{ + printf( +"\n" +" writes a range of bytes from the given offset source from multiple buffers,\n" +" in a batch of requests that may be merged by qemu\n" +"\n" +" Example:\n" +" 'multiwrite 512 1k 1k ; 4k 1k'\n" +" writes 2 kB at 512 bytes and 1 kB at 4 kB into the open file\n" +"\n" +" Writes into a segment of the currently open file, using a buffer\n" +" filled with a set pattern (0xcdcdcdcd). The pattern byte is increased\n" +" by one for each request contained in the multiwrite command.\n" +" -P, -- use different pattern to fill file\n" +" -C, -- report statistics in a machine parsable format\n" +" -q, -- quiet mode, do not show I/O statistics\n" +"\n"); +} + +static int multiwrite_f(BlockDriverState *bs, int argc, char **argv); + +static const cmdinfo_t multiwrite_cmd = { + .name = "multiwrite", + .cfunc = multiwrite_f, + .argmin = 2, + .argmax = -1, + .args = "[-Cq] [-P pattern ] off len [len..] [; off len [len..]..]", + .oneline = "issues multiple write requests at once", + .help = multiwrite_help, +}; + +static int multiwrite_f(BlockDriverState *bs, int argc, char **argv) +{ + struct timeval t1, t2; + int Cflag = 0, qflag = 0; + int c, cnt; + char **buf; + int64_t offset, first_offset = 0; + /* Some compilers get confused and warn if this is not initialized. */ + int total = 0; + int nr_iov; + int nr_reqs; + int pattern = 0xcd; + QEMUIOVector *qiovs; + int i; + BlockRequest *reqs; + + while ((c = getopt(argc, argv, "CqP:")) != EOF) { + switch (c) { + case 'C': + Cflag = 1; + break; + case 'q': + qflag = 1; + break; + case 'P': + pattern = parse_pattern(optarg); + if (pattern < 0) { + return 0; + } + break; + default: + return qemuio_command_usage(&writev_cmd); + } + } + + if (optind > argc - 2) { + return qemuio_command_usage(&writev_cmd); + } + + nr_reqs = 1; + for (i = optind; i < argc; i++) { + if (!strcmp(argv[i], ";")) { + nr_reqs++; + } + } + + reqs = g_malloc0(nr_reqs * sizeof(*reqs)); + buf = g_malloc0(nr_reqs * sizeof(*buf)); + qiovs = g_malloc(nr_reqs * sizeof(*qiovs)); + + for (i = 0; i < nr_reqs && optind < argc; i++) { + int j; + + /* Read the offset of the request */ + offset = cvtnum(argv[optind]); + if (offset < 0) { + printf("non-numeric offset argument -- %s\n", argv[optind]); + goto out; + } + optind++; + + if (offset & 0x1ff) { + printf("offset %lld is not sector aligned\n", + (long long)offset); + goto out; + } + + if (i == 0) { + first_offset = offset; + } + + /* Read lengths for qiov entries */ + for (j = optind; j < argc; j++) { + if (!strcmp(argv[j], ";")) { + break; + } + } + + nr_iov = j - optind; + + /* Build request */ + buf[i] = create_iovec(bs, &qiovs[i], &argv[optind], nr_iov, pattern); + if (buf[i] == NULL) { + goto out; + } + + reqs[i].qiov = &qiovs[i]; + reqs[i].sector = offset >> 9; + reqs[i].nb_sectors = reqs[i].qiov->size >> 9; + + optind = j + 1; + + pattern++; + } + + /* If there were empty requests at the end, ignore them */ + nr_reqs = i; + + gettimeofday(&t1, NULL); + cnt = do_aio_multiwrite(bs, reqs, nr_reqs, &total); + gettimeofday(&t2, NULL); + + if (cnt < 0) { + printf("aio_multiwrite failed: %s\n", strerror(-cnt)); + goto out; + } + + if (qflag) { + goto out; + } + + /* Finally, report back -- -C gives a parsable format */ + t2 = tsub(t2, t1); + print_report("wrote", &t2, first_offset, total, total, cnt, Cflag); +out: + for (i = 0; i < nr_reqs; i++) { + qemu_io_free(buf[i]); + if (reqs[i].qiov != NULL) { + qemu_iovec_destroy(&qiovs[i]); + } + } + g_free(buf); + g_free(reqs); + g_free(qiovs); + return 0; +} + +struct aio_ctx { + QEMUIOVector qiov; + int64_t offset; + char *buf; + int qflag; + int vflag; + int Cflag; + int Pflag; + int pattern; + struct timeval t1; +}; + +static void aio_write_done(void *opaque, int ret) +{ + struct aio_ctx *ctx = opaque; + struct timeval t2; + + gettimeofday(&t2, NULL); + + + if (ret < 0) { + printf("aio_write failed: %s\n", strerror(-ret)); + goto out; + } + + if (ctx->qflag) { + goto out; + } + + /* Finally, report back -- -C gives a parsable format */ + t2 = tsub(t2, ctx->t1); + print_report("wrote", &t2, ctx->offset, ctx->qiov.size, + ctx->qiov.size, 1, ctx->Cflag); +out: + qemu_io_free(ctx->buf); + qemu_iovec_destroy(&ctx->qiov); + g_free(ctx); +} + +static void aio_read_done(void *opaque, int ret) +{ + struct aio_ctx *ctx = opaque; + struct timeval t2; + + gettimeofday(&t2, NULL); + + if (ret < 0) { + printf("readv failed: %s\n", strerror(-ret)); + goto out; + } + + if (ctx->Pflag) { + void *cmp_buf = g_malloc(ctx->qiov.size); + + memset(cmp_buf, ctx->pattern, ctx->qiov.size); + if (memcmp(ctx->buf, cmp_buf, ctx->qiov.size)) { + printf("Pattern verification failed at offset %" + PRId64 ", %zd bytes\n", ctx->offset, ctx->qiov.size); + } + g_free(cmp_buf); + } + + if (ctx->qflag) { + goto out; + } + + if (ctx->vflag) { + dump_buffer(ctx->buf, ctx->offset, ctx->qiov.size); + } + + /* Finally, report back -- -C gives a parsable format */ + t2 = tsub(t2, ctx->t1); + print_report("read", &t2, ctx->offset, ctx->qiov.size, + ctx->qiov.size, 1, ctx->Cflag); +out: + qemu_io_free(ctx->buf); + qemu_iovec_destroy(&ctx->qiov); + g_free(ctx); +} + +static void aio_read_help(void) +{ + printf( +"\n" +" asynchronously reads a range of bytes from the given offset\n" +"\n" +" Example:\n" +" 'aio_read -v 512 1k 1k ' - dumps 2 kilobytes read from 512 bytes into the file\n" +"\n" +" Reads a segment of the currently open file, optionally dumping it to the\n" +" standard output stream (with -v option) for subsequent inspection.\n" +" The read is performed asynchronously and the aio_flush command must be\n" +" used to ensure all outstanding aio requests have been completed.\n" +" -C, -- report statistics in a machine parsable format\n" +" -P, -- use a pattern to verify read data\n" +" -v, -- dump buffer to standard output\n" +" -q, -- quiet mode, do not show I/O statistics\n" +"\n"); +} + +static int aio_read_f(BlockDriverState *bs, int argc, char **argv); + +static const cmdinfo_t aio_read_cmd = { + .name = "aio_read", + .cfunc = aio_read_f, + .argmin = 2, + .argmax = -1, + .args = "[-Cqv] [-P pattern ] off len [len..]", + .oneline = "asynchronously reads a number of bytes", + .help = aio_read_help, +}; + +static int aio_read_f(BlockDriverState *bs, int argc, char **argv) +{ + int nr_iov, c; + struct aio_ctx *ctx = g_new0(struct aio_ctx, 1); + + while ((c = getopt(argc, argv, "CP:qv")) != EOF) { + switch (c) { + case 'C': + ctx->Cflag = 1; + break; + case 'P': + ctx->Pflag = 1; + ctx->pattern = parse_pattern(optarg); + if (ctx->pattern < 0) { + g_free(ctx); + return 0; + } + break; + case 'q': + ctx->qflag = 1; + break; + case 'v': + ctx->vflag = 1; + break; + default: + g_free(ctx); + return qemuio_command_usage(&aio_read_cmd); + } + } + + if (optind > argc - 2) { + g_free(ctx); + return qemuio_command_usage(&aio_read_cmd); + } + + ctx->offset = cvtnum(argv[optind]); + if (ctx->offset < 0) { + printf("non-numeric length argument -- %s\n", argv[optind]); + g_free(ctx); + return 0; + } + optind++; + + if (ctx->offset & 0x1ff) { + printf("offset %" PRId64 " is not sector aligned\n", + ctx->offset); + g_free(ctx); + return 0; + } + + nr_iov = argc - optind; + ctx->buf = create_iovec(bs, &ctx->qiov, &argv[optind], nr_iov, 0xab); + if (ctx->buf == NULL) { + g_free(ctx); + return 0; + } + + gettimeofday(&ctx->t1, NULL); + bdrv_aio_readv(bs, ctx->offset >> 9, &ctx->qiov, + ctx->qiov.size >> 9, aio_read_done, ctx); + return 0; +} + +static void aio_write_help(void) +{ + printf( +"\n" +" asynchronously writes a range of bytes from the given offset source\n" +" from multiple buffers\n" +"\n" +" Example:\n" +" 'aio_write 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n" +"\n" +" Writes into a segment of the currently open file, using a buffer\n" +" filled with a set pattern (0xcdcdcdcd).\n" +" The write is performed asynchronously and the aio_flush command must be\n" +" used to ensure all outstanding aio requests have been completed.\n" +" -P, -- use different pattern to fill file\n" +" -C, -- report statistics in a machine parsable format\n" +" -q, -- quiet mode, do not show I/O statistics\n" +"\n"); +} + +static int aio_write_f(BlockDriverState *bs, int argc, char **argv); + +static const cmdinfo_t aio_write_cmd = { + .name = "aio_write", + .cfunc = aio_write_f, + .argmin = 2, + .argmax = -1, + .args = "[-Cq] [-P pattern ] off len [len..]", + .oneline = "asynchronously writes a number of bytes", + .help = aio_write_help, +}; + +static int aio_write_f(BlockDriverState *bs, int argc, char **argv) +{ + int nr_iov, c; + int pattern = 0xcd; + struct aio_ctx *ctx = g_new0(struct aio_ctx, 1); + + while ((c = getopt(argc, argv, "CqP:")) != EOF) { + switch (c) { + case 'C': + ctx->Cflag = 1; + break; + case 'q': + ctx->qflag = 1; + break; + case 'P': + pattern = parse_pattern(optarg); + if (pattern < 0) { + g_free(ctx); + return 0; + } + break; + default: + g_free(ctx); + return qemuio_command_usage(&aio_write_cmd); + } + } + + if (optind > argc - 2) { + g_free(ctx); + return qemuio_command_usage(&aio_write_cmd); + } + + ctx->offset = cvtnum(argv[optind]); + if (ctx->offset < 0) { + printf("non-numeric length argument -- %s\n", argv[optind]); + g_free(ctx); + return 0; + } + optind++; + + if (ctx->offset & 0x1ff) { + printf("offset %" PRId64 " is not sector aligned\n", + ctx->offset); + g_free(ctx); + return 0; + } + + nr_iov = argc - optind; + ctx->buf = create_iovec(bs, &ctx->qiov, &argv[optind], nr_iov, pattern); + if (ctx->buf == NULL) { + g_free(ctx); + return 0; + } + + gettimeofday(&ctx->t1, NULL); + bdrv_aio_writev(bs, ctx->offset >> 9, &ctx->qiov, + ctx->qiov.size >> 9, aio_write_done, ctx); + return 0; +} + +static int aio_flush_f(BlockDriverState *bs, int argc, char **argv) +{ + bdrv_drain_all(); + return 0; +} + +static const cmdinfo_t aio_flush_cmd = { + .name = "aio_flush", + .cfunc = aio_flush_f, + .oneline = "completes all outstanding aio requests" +}; + +static int flush_f(BlockDriverState *bs, int argc, char **argv) +{ + bdrv_flush(bs); + return 0; +} + +static const cmdinfo_t flush_cmd = { + .name = "flush", + .altname = "f", + .cfunc = flush_f, + .oneline = "flush all in-core file state to disk", +}; + +static int truncate_f(BlockDriverState *bs, int argc, char **argv) +{ + int64_t offset; + int ret; + + offset = cvtnum(argv[1]); + if (offset < 0) { + printf("non-numeric truncate argument -- %s\n", argv[1]); + return 0; + } + + ret = bdrv_truncate(bs, offset); + if (ret < 0) { + printf("truncate: %s\n", strerror(-ret)); + return 0; + } + + return 0; +} + +static const cmdinfo_t truncate_cmd = { + .name = "truncate", + .altname = "t", + .cfunc = truncate_f, + .argmin = 1, + .argmax = 1, + .args = "off", + .oneline = "truncates the current file at the given offset", +}; + +static int length_f(BlockDriverState *bs, int argc, char **argv) +{ + int64_t size; + char s1[64]; + + size = bdrv_getlength(bs); + if (size < 0) { + printf("getlength: %s\n", strerror(-size)); + return 0; + } + + cvtstr(size, s1, sizeof(s1)); + printf("%s\n", s1); + return 0; +} + + +static const cmdinfo_t length_cmd = { + .name = "length", + .altname = "l", + .cfunc = length_f, + .oneline = "gets the length of the current file", +}; + + +static int info_f(BlockDriverState *bs, int argc, char **argv) +{ + BlockDriverInfo bdi; + char s1[64], s2[64]; + int ret; + + if (bs->drv && bs->drv->format_name) { + printf("format name: %s\n", bs->drv->format_name); + } + if (bs->drv && bs->drv->protocol_name) { + printf("format name: %s\n", bs->drv->protocol_name); + } + + ret = bdrv_get_info(bs, &bdi); + if (ret) { + return 0; + } + + cvtstr(bdi.cluster_size, s1, sizeof(s1)); + cvtstr(bdi.vm_state_offset, s2, sizeof(s2)); + + printf("cluster size: %s\n", s1); + printf("vm state offset: %s\n", s2); + + return 0; +} + + + +static const cmdinfo_t info_cmd = { + .name = "info", + .altname = "i", + .cfunc = info_f, + .oneline = "prints information about the current file", +}; + +static void discard_help(void) +{ + printf( +"\n" +" discards a range of bytes from the given offset\n" +"\n" +" Example:\n" +" 'discard 512 1k' - discards 1 kilobyte from 512 bytes into the file\n" +"\n" +" Discards a segment of the currently open file.\n" +" -C, -- report statistics in a machine parsable format\n" +" -q, -- quiet mode, do not show I/O statistics\n" +"\n"); +} + +static int discard_f(BlockDriverState *bs, int argc, char **argv); + +static const cmdinfo_t discard_cmd = { + .name = "discard", + .altname = "d", + .cfunc = discard_f, + .argmin = 2, + .argmax = -1, + .args = "[-Cq] off len", + .oneline = "discards a number of bytes at a specified offset", + .help = discard_help, +}; + +static int discard_f(BlockDriverState *bs, int argc, char **argv) +{ + struct timeval t1, t2; + int Cflag = 0, qflag = 0; + int c, ret; + int64_t offset; + int count; + + while ((c = getopt(argc, argv, "Cq")) != EOF) { + switch (c) { + case 'C': + Cflag = 1; + break; + case 'q': + qflag = 1; + break; + default: + return qemuio_command_usage(&discard_cmd); + } + } + + if (optind != argc - 2) { + return qemuio_command_usage(&discard_cmd); + } + + offset = cvtnum(argv[optind]); + if (offset < 0) { + printf("non-numeric length argument -- %s\n", argv[optind]); + return 0; + } + + optind++; + count = cvtnum(argv[optind]); + if (count < 0) { + printf("non-numeric length argument -- %s\n", argv[optind]); + return 0; + } + + gettimeofday(&t1, NULL); + ret = bdrv_discard(bs, offset >> BDRV_SECTOR_BITS, + count >> BDRV_SECTOR_BITS); + gettimeofday(&t2, NULL); + + if (ret < 0) { + printf("discard failed: %s\n", strerror(-ret)); + goto out; + } + + /* Finally, report back -- -C gives a parsable format */ + if (!qflag) { + t2 = tsub(t2, t1); + print_report("discard", &t2, offset, count, count, 1, Cflag); + } + +out: + return 0; +} + +static int alloc_f(BlockDriverState *bs, int argc, char **argv) +{ + int64_t offset, sector_num; + int nb_sectors, remaining; + char s1[64]; + int num, sum_alloc; + int ret; + + offset = cvtnum(argv[1]); + if (offset < 0) { + printf("non-numeric offset argument -- %s\n", argv[1]); + return 0; + } else if (offset & 0x1ff) { + printf("offset %" PRId64 " is not sector aligned\n", + offset); + return 0; + } + + if (argc == 3) { + nb_sectors = cvtnum(argv[2]); + if (nb_sectors < 0) { + printf("non-numeric length argument -- %s\n", argv[2]); + return 0; + } + } else { + nb_sectors = 1; + } + + remaining = nb_sectors; + sum_alloc = 0; + sector_num = offset >> 9; + while (remaining) { + ret = bdrv_is_allocated(bs, sector_num, remaining, &num); + sector_num += num; + remaining -= num; + if (ret) { + sum_alloc += num; + } + if (num == 0) { + nb_sectors -= remaining; + remaining = 0; + } + } + + cvtstr(offset, s1, sizeof(s1)); + + printf("%d/%d sectors allocated at offset %s\n", + sum_alloc, nb_sectors, s1); + return 0; +} + +static const cmdinfo_t alloc_cmd = { + .name = "alloc", + .altname = "a", + .argmin = 1, + .argmax = 2, + .cfunc = alloc_f, + .args = "off [sectors]", + .oneline = "checks if a sector is present in the file", +}; + + +static int map_is_allocated(BlockDriverState *bs, int64_t sector_num, + int64_t nb_sectors, int64_t *pnum) +{ + int num, num_checked; + int ret, firstret; + + num_checked = MIN(nb_sectors, INT_MAX); + ret = bdrv_is_allocated(bs, sector_num, num_checked, &num); + if (ret < 0) { + return ret; + } + + firstret = ret; + *pnum = num; + + while (nb_sectors > 0 && ret == firstret) { + sector_num += num; + nb_sectors -= num; + + num_checked = MIN(nb_sectors, INT_MAX); + ret = bdrv_is_allocated(bs, sector_num, num_checked, &num); + if (ret == firstret) { + *pnum += num; + } else { + break; + } + } + + return firstret; +} + +static int map_f(BlockDriverState *bs, int argc, char **argv) +{ + int64_t offset; + int64_t nb_sectors; + char s1[64]; + int64_t num; + int ret; + const char *retstr; + + offset = 0; + nb_sectors = bs->total_sectors; + + do { + ret = map_is_allocated(bs, offset, nb_sectors, &num); + if (ret < 0) { + error_report("Failed to get allocation status: %s", strerror(-ret)); + return 0; + } + + retstr = ret ? " allocated" : "not allocated"; + cvtstr(offset << 9ULL, s1, sizeof(s1)); + printf("[% 24" PRId64 "] % 8" PRId64 "/% 8" PRId64 " sectors %s " + "at offset %s (%d)\n", + offset << 9ULL, num, nb_sectors, retstr, s1, ret); + + offset += num; + nb_sectors -= num; + } while (offset < bs->total_sectors); + + return 0; +} + +static const cmdinfo_t map_cmd = { + .name = "map", + .argmin = 0, + .argmax = 0, + .cfunc = map_f, + .args = "", + .oneline = "prints the allocated areas of a file", +}; + +static int break_f(BlockDriverState *bs, int argc, char **argv) +{ + int ret; + + ret = bdrv_debug_breakpoint(bs, argv[1], argv[2]); + if (ret < 0) { + printf("Could not set breakpoint: %s\n", strerror(-ret)); + } + + return 0; +} + +static const cmdinfo_t break_cmd = { + .name = "break", + .argmin = 2, + .argmax = 2, + .cfunc = break_f, + .args = "event tag", + .oneline = "sets a breakpoint on event and tags the stopped " + "request as tag", +}; + +static int resume_f(BlockDriverState *bs, int argc, char **argv) +{ + int ret; + + ret = bdrv_debug_resume(bs, argv[1]); + if (ret < 0) { + printf("Could not resume request: %s\n", strerror(-ret)); + } + + return 0; +} + +static const cmdinfo_t resume_cmd = { + .name = "resume", + .argmin = 1, + .argmax = 1, + .cfunc = resume_f, + .args = "tag", + .oneline = "resumes the request tagged as tag", +}; + +static int wait_break_f(BlockDriverState *bs, int argc, char **argv) +{ + while (!bdrv_debug_is_suspended(bs, argv[1])) { + qemu_aio_wait(); + } + + return 0; +} + +static const cmdinfo_t wait_break_cmd = { + .name = "wait_break", + .argmin = 1, + .argmax = 1, + .cfunc = wait_break_f, + .args = "tag", + .oneline = "waits for the suspension of a request", +}; + +static int abort_f(BlockDriverState *bs, int argc, char **argv) +{ + abort(); +} + +static const cmdinfo_t abort_cmd = { + .name = "abort", + .cfunc = abort_f, + .flags = CMD_NOFILE_OK, + .oneline = "simulate a program crash using abort(3)", +}; + +static void help_oneline(const char *cmd, const cmdinfo_t *ct) +{ + if (cmd) { + printf("%s ", cmd); + } else { + printf("%s ", ct->name); + if (ct->altname) { + printf("(or %s) ", ct->altname); + } + } + + if (ct->args) { + printf("%s ", ct->args); + } + printf("-- %s\n", ct->oneline); +} + +static void help_onecmd(const char *cmd, const cmdinfo_t *ct) +{ + help_oneline(cmd, ct); + if (ct->help) { + ct->help(); + } +} + +static void help_all(void) +{ + const cmdinfo_t *ct; + + for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) { + help_oneline(ct->name, ct); + } + printf("\nUse 'help commandname' for extended help.\n"); +} + +static int help_f(BlockDriverState *bs, int argc, char **argv) +{ + const cmdinfo_t *ct; + + if (argc == 1) { + help_all(); + return 0; + } + + ct = find_command(argv[1]); + if (ct == NULL) { + printf("command %s not found\n", argv[1]); + return 0; + } + + help_onecmd(argv[1], ct); + return 0; +} + +static const cmdinfo_t help_cmd = { + .name = "help", + .altname = "?", + .cfunc = help_f, + .argmin = 0, + .argmax = 1, + .flags = CMD_FLAG_GLOBAL, + .args = "[command]", + .oneline = "help for one or all commands", +}; + +bool qemuio_command(BlockDriverState *bs, const char *cmd) +{ + char *input; + const cmdinfo_t *ct; + char **v; + int c; + bool done = false; + + input = g_strdup(cmd); + v = breakline(input, &c); + if (c) { + ct = find_command(v[0]); + if (ct) { + done = command(bs, ct, c, v); + } else { + fprintf(stderr, "command \"%s\" not found\n", v[0]); + } + } + g_free(input); + g_free(v); + + return done; +} + +static void __attribute((constructor)) init_qemuio_commands(void) +{ + /* initialize commands */ + qemuio_add_command(&help_cmd); + qemuio_add_command(&read_cmd); + qemuio_add_command(&readv_cmd); + qemuio_add_command(&write_cmd); + qemuio_add_command(&writev_cmd); + qemuio_add_command(&multiwrite_cmd); + qemuio_add_command(&aio_read_cmd); + qemuio_add_command(&aio_write_cmd); + qemuio_add_command(&aio_flush_cmd); + qemuio_add_command(&flush_cmd); + qemuio_add_command(&truncate_cmd); + qemuio_add_command(&length_cmd); + qemuio_add_command(&info_cmd); + qemuio_add_command(&discard_cmd); + qemuio_add_command(&alloc_cmd); + qemuio_add_command(&map_cmd); + qemuio_add_command(&break_cmd); + qemuio_add_command(&resume_cmd); + qemuio_add_command(&wait_break_cmd); + qemuio_add_command(&abort_cmd); +} @@ -14,1776 +14,26 @@ #include <getopt.h> #include <libgen.h> -#include "qemu-common.h" +#include "qemu-io.h" #include "qemu/main-loop.h" #include "block/block_int.h" -#include "cmd.h" #include "trace/control.h" -#define VERSION "0.0.1" - #define CMD_NOFILE_OK 0x01 char *progname; -static BlockDriverState *bs; - -static int misalign; - -/* - * Parse the pattern argument to various sub-commands. - * - * Because the pattern is used as an argument to memset it must evaluate - * to an unsigned integer that fits into a single byte. - */ -static int parse_pattern(const char *arg) -{ - char *endptr = NULL; - long pattern; - - pattern = strtol(arg, &endptr, 0); - if (pattern < 0 || pattern > UCHAR_MAX || *endptr != '\0') { - printf("%s is not a valid pattern byte\n", arg); - return -1; - } - - return pattern; -} - -/* - * Memory allocation helpers. - * - * Make sure memory is aligned by default, or purposefully misaligned if - * that is specified on the command line. - */ - -#define MISALIGN_OFFSET 16 -static void *qemu_io_alloc(size_t len, int pattern) -{ - void *buf; - - if (misalign) { - len += MISALIGN_OFFSET; - } - buf = qemu_blockalign(bs, len); - memset(buf, pattern, len); - if (misalign) { - buf += MISALIGN_OFFSET; - } - return buf; -} - -static void qemu_io_free(void *p) -{ - if (misalign) { - p -= MISALIGN_OFFSET; - } - qemu_vfree(p); -} - -static void dump_buffer(const void *buffer, int64_t offset, int len) -{ - int i, j; - const uint8_t *p; - - for (i = 0, p = buffer; i < len; i += 16) { - const uint8_t *s = p; - - printf("%08" PRIx64 ": ", offset + i); - for (j = 0; j < 16 && i + j < len; j++, p++) { - printf("%02x ", *p); - } - printf(" "); - for (j = 0; j < 16 && i + j < len; j++, s++) { - if (isalnum(*s)) { - printf("%c", *s); - } else { - printf("."); - } - } - printf("\n"); - } -} - -static void print_report(const char *op, struct timeval *t, int64_t offset, - int count, int total, int cnt, int Cflag) -{ - char s1[64], s2[64], ts[64]; - - timestr(t, ts, sizeof(ts), Cflag ? VERBOSE_FIXED_TIME : 0); - if (!Cflag) { - cvtstr((double)total, s1, sizeof(s1)); - cvtstr(tdiv((double)total, *t), s2, sizeof(s2)); - printf("%s %d/%d bytes at offset %" PRId64 "\n", - op, total, count, offset); - printf("%s, %d ops; %s (%s/sec and %.4f ops/sec)\n", - s1, cnt, ts, s2, tdiv((double)cnt, *t)); - } else {/* bytes,ops,time,bytes/sec,ops/sec */ - printf("%d,%d,%s,%.3f,%.3f\n", - total, cnt, ts, - tdiv((double)total, *t), - tdiv((double)cnt, *t)); - } -} - -/* - * Parse multiple length statements for vectored I/O, and construct an I/O - * vector matching it. - */ -static void * -create_iovec(QEMUIOVector *qiov, char **argv, int nr_iov, int pattern) -{ - size_t *sizes = g_new0(size_t, nr_iov); - size_t count = 0; - void *buf = NULL; - void *p; - int i; - - for (i = 0; i < nr_iov; i++) { - char *arg = argv[i]; - int64_t len; - - len = cvtnum(arg); - if (len < 0) { - printf("non-numeric length argument -- %s\n", arg); - goto fail; - } - - /* should be SIZE_T_MAX, but that doesn't exist */ - if (len > INT_MAX) { - printf("too large length argument -- %s\n", arg); - goto fail; - } - - if (len & 0x1ff) { - printf("length argument %" PRId64 - " is not sector aligned\n", len); - goto fail; - } - - sizes[i] = len; - count += len; - } - - qemu_iovec_init(qiov, nr_iov); - - buf = p = qemu_io_alloc(count, pattern); - - for (i = 0; i < nr_iov; i++) { - qemu_iovec_add(qiov, p, sizes[i]); - p += sizes[i]; - } - -fail: - g_free(sizes); - return buf; -} - -static int do_read(char *buf, int64_t offset, int count, int *total) -{ - int ret; - - ret = bdrv_read(bs, offset >> 9, (uint8_t *)buf, count >> 9); - if (ret < 0) { - return ret; - } - *total = count; - return 1; -} - -static int do_write(char *buf, int64_t offset, int count, int *total) -{ - int ret; - - ret = bdrv_write(bs, offset >> 9, (uint8_t *)buf, count >> 9); - if (ret < 0) { - return ret; - } - *total = count; - return 1; -} - -static int do_pread(char *buf, int64_t offset, int count, int *total) -{ - *total = bdrv_pread(bs, offset, (uint8_t *)buf, count); - if (*total < 0) { - return *total; - } - return 1; -} - -static int do_pwrite(char *buf, int64_t offset, int count, int *total) -{ - *total = bdrv_pwrite(bs, offset, (uint8_t *)buf, count); - if (*total < 0) { - return *total; - } - return 1; -} - -typedef struct { - int64_t offset; - int count; - int *total; - int ret; - bool done; -} CoWriteZeroes; - -static void coroutine_fn co_write_zeroes_entry(void *opaque) -{ - CoWriteZeroes *data = opaque; - - data->ret = bdrv_co_write_zeroes(bs, data->offset / BDRV_SECTOR_SIZE, - data->count / BDRV_SECTOR_SIZE); - data->done = true; - if (data->ret < 0) { - *data->total = data->ret; - return; - } - - *data->total = data->count; -} - -static int do_co_write_zeroes(int64_t offset, int count, int *total) -{ - Coroutine *co; - CoWriteZeroes data = { - .offset = offset, - .count = count, - .total = total, - .done = false, - }; - - co = qemu_coroutine_create(co_write_zeroes_entry); - qemu_coroutine_enter(co, &data); - while (!data.done) { - qemu_aio_wait(); - } - if (data.ret < 0) { - return data.ret; - } else { - return 1; - } -} - -static int do_write_compressed(char *buf, int64_t offset, int count, int *total) -{ - int ret; - - ret = bdrv_write_compressed(bs, offset >> 9, (uint8_t *)buf, count >> 9); - if (ret < 0) { - return ret; - } - *total = count; - return 1; -} - -static int do_load_vmstate(char *buf, int64_t offset, int count, int *total) -{ - *total = bdrv_load_vmstate(bs, (uint8_t *)buf, offset, count); - if (*total < 0) { - return *total; - } - return 1; -} - -static int do_save_vmstate(char *buf, int64_t offset, int count, int *total) -{ - *total = bdrv_save_vmstate(bs, (uint8_t *)buf, offset, count); - if (*total < 0) { - return *total; - } - return 1; -} - -#define NOT_DONE 0x7fffffff -static void aio_rw_done(void *opaque, int ret) -{ - *(int *)opaque = ret; -} - -static int do_aio_readv(QEMUIOVector *qiov, int64_t offset, int *total) -{ - int async_ret = NOT_DONE; - - bdrv_aio_readv(bs, offset >> 9, qiov, qiov->size >> 9, - aio_rw_done, &async_ret); - while (async_ret == NOT_DONE) { - main_loop_wait(false); - } - - *total = qiov->size; - return async_ret < 0 ? async_ret : 1; -} - -static int do_aio_writev(QEMUIOVector *qiov, int64_t offset, int *total) -{ - int async_ret = NOT_DONE; - - bdrv_aio_writev(bs, offset >> 9, qiov, qiov->size >> 9, - aio_rw_done, &async_ret); - while (async_ret == NOT_DONE) { - main_loop_wait(false); - } - - *total = qiov->size; - return async_ret < 0 ? async_ret : 1; -} - -struct multiwrite_async_ret { - int num_done; - int error; -}; - -static void multiwrite_cb(void *opaque, int ret) -{ - struct multiwrite_async_ret *async_ret = opaque; - - async_ret->num_done++; - if (ret < 0) { - async_ret->error = ret; - } -} - -static int do_aio_multiwrite(BlockRequest* reqs, int num_reqs, int *total) -{ - int i, ret; - struct multiwrite_async_ret async_ret = { - .num_done = 0, - .error = 0, - }; - *total = 0; - for (i = 0; i < num_reqs; i++) { - reqs[i].cb = multiwrite_cb; - reqs[i].opaque = &async_ret; - *total += reqs[i].qiov->size; - } - - ret = bdrv_aio_multiwrite(bs, reqs, num_reqs); - if (ret < 0) { - return ret; - } - - while (async_ret.num_done < num_reqs) { - main_loop_wait(false); - } - - return async_ret.error < 0 ? async_ret.error : 1; -} - -static void read_help(void) -{ - printf( -"\n" -" reads a range of bytes from the given offset\n" -"\n" -" Example:\n" -" 'read -v 512 1k' - dumps 1 kilobyte read from 512 bytes into the file\n" -"\n" -" Reads a segment of the currently open file, optionally dumping it to the\n" -" standard output stream (with -v option) for subsequent inspection.\n" -" -b, -- read from the VM state rather than the virtual disk\n" -" -C, -- report statistics in a machine parsable format\n" -" -l, -- length for pattern verification (only with -P)\n" -" -p, -- use bdrv_pread to read the file\n" -" -P, -- use a pattern to verify read data\n" -" -q, -- quiet mode, do not show I/O statistics\n" -" -s, -- start offset for pattern verification (only with -P)\n" -" -v, -- dump buffer to standard output\n" -"\n"); -} - -static int read_f(int argc, char **argv); +BlockDriverState *qemuio_bs; +extern int qemuio_misalign; -static const cmdinfo_t read_cmd = { - .name = "read", - .altname = "r", - .cfunc = read_f, - .argmin = 2, - .argmax = -1, - .args = "[-abCpqv] [-P pattern [-s off] [-l len]] off len", - .oneline = "reads a number of bytes at a specified offset", - .help = read_help, -}; +/* qemu-io commands passed using -c */ +static int ncmdline; +static char **cmdline; -static int read_f(int argc, char **argv) -{ - struct timeval t1, t2; - int Cflag = 0, pflag = 0, qflag = 0, vflag = 0; - int Pflag = 0, sflag = 0, lflag = 0, bflag = 0; - int c, cnt; - char *buf; - int64_t offset; - int count; - /* Some compilers get confused and warn if this is not initialized. */ - int total = 0; - int pattern = 0, pattern_offset = 0, pattern_count = 0; - - while ((c = getopt(argc, argv, "bCl:pP:qs:v")) != EOF) { - switch (c) { - case 'b': - bflag = 1; - break; - case 'C': - Cflag = 1; - break; - case 'l': - lflag = 1; - pattern_count = cvtnum(optarg); - if (pattern_count < 0) { - printf("non-numeric length argument -- %s\n", optarg); - return 0; - } - break; - case 'p': - pflag = 1; - break; - case 'P': - Pflag = 1; - pattern = parse_pattern(optarg); - if (pattern < 0) { - return 0; - } - break; - case 'q': - qflag = 1; - break; - case 's': - sflag = 1; - pattern_offset = cvtnum(optarg); - if (pattern_offset < 0) { - printf("non-numeric length argument -- %s\n", optarg); - return 0; - } - break; - case 'v': - vflag = 1; - break; - default: - return command_usage(&read_cmd); - } - } - - if (optind != argc - 2) { - return command_usage(&read_cmd); - } - - if (bflag && pflag) { - printf("-b and -p cannot be specified at the same time\n"); - return 0; - } - - offset = cvtnum(argv[optind]); - if (offset < 0) { - printf("non-numeric length argument -- %s\n", argv[optind]); - return 0; - } - - optind++; - count = cvtnum(argv[optind]); - if (count < 0) { - printf("non-numeric length argument -- %s\n", argv[optind]); - return 0; - } - - if (!Pflag && (lflag || sflag)) { - return command_usage(&read_cmd); - } - - if (!lflag) { - pattern_count = count - pattern_offset; - } - - if ((pattern_count < 0) || (pattern_count + pattern_offset > count)) { - printf("pattern verification range exceeds end of read data\n"); - return 0; - } - - if (!pflag) { - if (offset & 0x1ff) { - printf("offset %" PRId64 " is not sector aligned\n", - offset); - return 0; - } - if (count & 0x1ff) { - printf("count %d is not sector aligned\n", - count); - return 0; - } - } - - buf = qemu_io_alloc(count, 0xab); - - gettimeofday(&t1, NULL); - if (pflag) { - cnt = do_pread(buf, offset, count, &total); - } else if (bflag) { - cnt = do_load_vmstate(buf, offset, count, &total); - } else { - cnt = do_read(buf, offset, count, &total); - } - gettimeofday(&t2, NULL); - - if (cnt < 0) { - printf("read failed: %s\n", strerror(-cnt)); - goto out; - } - - if (Pflag) { - void *cmp_buf = g_malloc(pattern_count); - memset(cmp_buf, pattern, pattern_count); - if (memcmp(buf + pattern_offset, cmp_buf, pattern_count)) { - printf("Pattern verification failed at offset %" - PRId64 ", %d bytes\n", - offset + pattern_offset, pattern_count); - } - g_free(cmp_buf); - } - - if (qflag) { - goto out; - } - - if (vflag) { - dump_buffer(buf, offset, count); - } - - /* Finally, report back -- -C gives a parsable format */ - t2 = tsub(t2, t1); - print_report("read", &t2, offset, count, total, cnt, Cflag); - -out: - qemu_io_free(buf); - - return 0; -} - -static void readv_help(void) -{ - printf( -"\n" -" reads a range of bytes from the given offset into multiple buffers\n" -"\n" -" Example:\n" -" 'readv -v 512 1k 1k ' - dumps 2 kilobytes read from 512 bytes into the file\n" -"\n" -" Reads a segment of the currently open file, optionally dumping it to the\n" -" standard output stream (with -v option) for subsequent inspection.\n" -" Uses multiple iovec buffers if more than one byte range is specified.\n" -" -C, -- report statistics in a machine parsable format\n" -" -P, -- use a pattern to verify read data\n" -" -v, -- dump buffer to standard output\n" -" -q, -- quiet mode, do not show I/O statistics\n" -"\n"); -} - -static int readv_f(int argc, char **argv); - -static const cmdinfo_t readv_cmd = { - .name = "readv", - .cfunc = readv_f, - .argmin = 2, - .argmax = -1, - .args = "[-Cqv] [-P pattern ] off len [len..]", - .oneline = "reads a number of bytes at a specified offset", - .help = readv_help, -}; - -static int readv_f(int argc, char **argv) -{ - struct timeval t1, t2; - int Cflag = 0, qflag = 0, vflag = 0; - int c, cnt; - char *buf; - int64_t offset; - /* Some compilers get confused and warn if this is not initialized. */ - int total = 0; - int nr_iov; - QEMUIOVector qiov; - int pattern = 0; - int Pflag = 0; - - while ((c = getopt(argc, argv, "CP:qv")) != EOF) { - switch (c) { - case 'C': - Cflag = 1; - break; - case 'P': - Pflag = 1; - pattern = parse_pattern(optarg); - if (pattern < 0) { - return 0; - } - break; - case 'q': - qflag = 1; - break; - case 'v': - vflag = 1; - break; - default: - return command_usage(&readv_cmd); - } - } - - if (optind > argc - 2) { - return command_usage(&readv_cmd); - } - - - offset = cvtnum(argv[optind]); - if (offset < 0) { - printf("non-numeric length argument -- %s\n", argv[optind]); - return 0; - } - optind++; - - if (offset & 0x1ff) { - printf("offset %" PRId64 " is not sector aligned\n", - offset); - return 0; - } - - nr_iov = argc - optind; - buf = create_iovec(&qiov, &argv[optind], nr_iov, 0xab); - if (buf == NULL) { - return 0; - } - - gettimeofday(&t1, NULL); - cnt = do_aio_readv(&qiov, offset, &total); - gettimeofday(&t2, NULL); - - if (cnt < 0) { - printf("readv failed: %s\n", strerror(-cnt)); - goto out; - } - - if (Pflag) { - void *cmp_buf = g_malloc(qiov.size); - memset(cmp_buf, pattern, qiov.size); - if (memcmp(buf, cmp_buf, qiov.size)) { - printf("Pattern verification failed at offset %" - PRId64 ", %zd bytes\n", offset, qiov.size); - } - g_free(cmp_buf); - } - - if (qflag) { - goto out; - } - - if (vflag) { - dump_buffer(buf, offset, qiov.size); - } - - /* Finally, report back -- -C gives a parsable format */ - t2 = tsub(t2, t1); - print_report("read", &t2, offset, qiov.size, total, cnt, Cflag); - -out: - qemu_iovec_destroy(&qiov); - qemu_io_free(buf); - return 0; -} - -static void write_help(void) -{ - printf( -"\n" -" writes a range of bytes from the given offset\n" -"\n" -" Example:\n" -" 'write 512 1k' - writes 1 kilobyte at 512 bytes into the open file\n" -"\n" -" Writes into a segment of the currently open file, using a buffer\n" -" filled with a set pattern (0xcdcdcdcd).\n" -" -b, -- write to the VM state rather than the virtual disk\n" -" -c, -- write compressed data with bdrv_write_compressed\n" -" -p, -- use bdrv_pwrite to write the file\n" -" -P, -- use different pattern to fill file\n" -" -C, -- report statistics in a machine parsable format\n" -" -q, -- quiet mode, do not show I/O statistics\n" -" -z, -- write zeroes using bdrv_co_write_zeroes\n" -"\n"); -} - -static int write_f(int argc, char **argv); - -static const cmdinfo_t write_cmd = { - .name = "write", - .altname = "w", - .cfunc = write_f, - .argmin = 2, - .argmax = -1, - .args = "[-bcCpqz] [-P pattern ] off len", - .oneline = "writes a number of bytes at a specified offset", - .help = write_help, -}; - -static int write_f(int argc, char **argv) -{ - struct timeval t1, t2; - int Cflag = 0, pflag = 0, qflag = 0, bflag = 0, Pflag = 0, zflag = 0; - int cflag = 0; - int c, cnt; - char *buf = NULL; - int64_t offset; - int count; - /* Some compilers get confused and warn if this is not initialized. */ - int total = 0; - int pattern = 0xcd; - - while ((c = getopt(argc, argv, "bcCpP:qz")) != EOF) { - switch (c) { - case 'b': - bflag = 1; - break; - case 'c': - cflag = 1; - break; - case 'C': - Cflag = 1; - break; - case 'p': - pflag = 1; - break; - case 'P': - Pflag = 1; - pattern = parse_pattern(optarg); - if (pattern < 0) { - return 0; - } - break; - case 'q': - qflag = 1; - break; - case 'z': - zflag = 1; - break; - default: - return command_usage(&write_cmd); - } - } - - if (optind != argc - 2) { - return command_usage(&write_cmd); - } - - if (bflag + pflag + zflag > 1) { - printf("-b, -p, or -z cannot be specified at the same time\n"); - return 0; - } - - if (zflag && Pflag) { - printf("-z and -P cannot be specified at the same time\n"); - return 0; - } - - offset = cvtnum(argv[optind]); - if (offset < 0) { - printf("non-numeric length argument -- %s\n", argv[optind]); - return 0; - } - - optind++; - count = cvtnum(argv[optind]); - if (count < 0) { - printf("non-numeric length argument -- %s\n", argv[optind]); - return 0; - } - - if (!pflag) { - if (offset & 0x1ff) { - printf("offset %" PRId64 " is not sector aligned\n", - offset); - return 0; - } - - if (count & 0x1ff) { - printf("count %d is not sector aligned\n", - count); - return 0; - } - } - - if (!zflag) { - buf = qemu_io_alloc(count, pattern); - } - - gettimeofday(&t1, NULL); - if (pflag) { - cnt = do_pwrite(buf, offset, count, &total); - } else if (bflag) { - cnt = do_save_vmstate(buf, offset, count, &total); - } else if (zflag) { - cnt = do_co_write_zeroes(offset, count, &total); - } else if (cflag) { - cnt = do_write_compressed(buf, offset, count, &total); - } else { - cnt = do_write(buf, offset, count, &total); - } - gettimeofday(&t2, NULL); - - if (cnt < 0) { - printf("write failed: %s\n", strerror(-cnt)); - goto out; - } - - if (qflag) { - goto out; - } - - /* Finally, report back -- -C gives a parsable format */ - t2 = tsub(t2, t1); - print_report("wrote", &t2, offset, count, total, cnt, Cflag); - -out: - if (!zflag) { - qemu_io_free(buf); - } - - return 0; -} - -static void -writev_help(void) -{ - printf( -"\n" -" writes a range of bytes from the given offset source from multiple buffers\n" -"\n" -" Example:\n" -" 'write 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n" -"\n" -" Writes into a segment of the currently open file, using a buffer\n" -" filled with a set pattern (0xcdcdcdcd).\n" -" -P, -- use different pattern to fill file\n" -" -C, -- report statistics in a machine parsable format\n" -" -q, -- quiet mode, do not show I/O statistics\n" -"\n"); -} - -static int writev_f(int argc, char **argv); - -static const cmdinfo_t writev_cmd = { - .name = "writev", - .cfunc = writev_f, - .argmin = 2, - .argmax = -1, - .args = "[-Cq] [-P pattern ] off len [len..]", - .oneline = "writes a number of bytes at a specified offset", - .help = writev_help, -}; - -static int writev_f(int argc, char **argv) -{ - struct timeval t1, t2; - int Cflag = 0, qflag = 0; - int c, cnt; - char *buf; - int64_t offset; - /* Some compilers get confused and warn if this is not initialized. */ - int total = 0; - int nr_iov; - int pattern = 0xcd; - QEMUIOVector qiov; - - while ((c = getopt(argc, argv, "CqP:")) != EOF) { - switch (c) { - case 'C': - Cflag = 1; - break; - case 'q': - qflag = 1; - break; - case 'P': - pattern = parse_pattern(optarg); - if (pattern < 0) { - return 0; - } - break; - default: - return command_usage(&writev_cmd); - } - } - - if (optind > argc - 2) { - return command_usage(&writev_cmd); - } - - offset = cvtnum(argv[optind]); - if (offset < 0) { - printf("non-numeric length argument -- %s\n", argv[optind]); - return 0; - } - optind++; - - if (offset & 0x1ff) { - printf("offset %" PRId64 " is not sector aligned\n", - offset); - return 0; - } - - nr_iov = argc - optind; - buf = create_iovec(&qiov, &argv[optind], nr_iov, pattern); - if (buf == NULL) { - return 0; - } - - gettimeofday(&t1, NULL); - cnt = do_aio_writev(&qiov, offset, &total); - gettimeofday(&t2, NULL); - - if (cnt < 0) { - printf("writev failed: %s\n", strerror(-cnt)); - goto out; - } - - if (qflag) { - goto out; - } - - /* Finally, report back -- -C gives a parsable format */ - t2 = tsub(t2, t1); - print_report("wrote", &t2, offset, qiov.size, total, cnt, Cflag); -out: - qemu_iovec_destroy(&qiov); - qemu_io_free(buf); - return 0; -} - -static void multiwrite_help(void) -{ - printf( -"\n" -" writes a range of bytes from the given offset source from multiple buffers,\n" -" in a batch of requests that may be merged by qemu\n" -"\n" -" Example:\n" -" 'multiwrite 512 1k 1k ; 4k 1k'\n" -" writes 2 kB at 512 bytes and 1 kB at 4 kB into the open file\n" -"\n" -" Writes into a segment of the currently open file, using a buffer\n" -" filled with a set pattern (0xcdcdcdcd). The pattern byte is increased\n" -" by one for each request contained in the multiwrite command.\n" -" -P, -- use different pattern to fill file\n" -" -C, -- report statistics in a machine parsable format\n" -" -q, -- quiet mode, do not show I/O statistics\n" -"\n"); -} - -static int multiwrite_f(int argc, char **argv); - -static const cmdinfo_t multiwrite_cmd = { - .name = "multiwrite", - .cfunc = multiwrite_f, - .argmin = 2, - .argmax = -1, - .args = "[-Cq] [-P pattern ] off len [len..] [; off len [len..]..]", - .oneline = "issues multiple write requests at once", - .help = multiwrite_help, -}; - -static int multiwrite_f(int argc, char **argv) -{ - struct timeval t1, t2; - int Cflag = 0, qflag = 0; - int c, cnt; - char **buf; - int64_t offset, first_offset = 0; - /* Some compilers get confused and warn if this is not initialized. */ - int total = 0; - int nr_iov; - int nr_reqs; - int pattern = 0xcd; - QEMUIOVector *qiovs; - int i; - BlockRequest *reqs; - - while ((c = getopt(argc, argv, "CqP:")) != EOF) { - switch (c) { - case 'C': - Cflag = 1; - break; - case 'q': - qflag = 1; - break; - case 'P': - pattern = parse_pattern(optarg); - if (pattern < 0) { - return 0; - } - break; - default: - return command_usage(&writev_cmd); - } - } - - if (optind > argc - 2) { - return command_usage(&writev_cmd); - } - - nr_reqs = 1; - for (i = optind; i < argc; i++) { - if (!strcmp(argv[i], ";")) { - nr_reqs++; - } - } - - reqs = g_malloc0(nr_reqs * sizeof(*reqs)); - buf = g_malloc0(nr_reqs * sizeof(*buf)); - qiovs = g_malloc(nr_reqs * sizeof(*qiovs)); - - for (i = 0; i < nr_reqs && optind < argc; i++) { - int j; - - /* Read the offset of the request */ - offset = cvtnum(argv[optind]); - if (offset < 0) { - printf("non-numeric offset argument -- %s\n", argv[optind]); - goto out; - } - optind++; - - if (offset & 0x1ff) { - printf("offset %lld is not sector aligned\n", - (long long)offset); - goto out; - } - - if (i == 0) { - first_offset = offset; - } - - /* Read lengths for qiov entries */ - for (j = optind; j < argc; j++) { - if (!strcmp(argv[j], ";")) { - break; - } - } - - nr_iov = j - optind; - - /* Build request */ - buf[i] = create_iovec(&qiovs[i], &argv[optind], nr_iov, pattern); - if (buf[i] == NULL) { - goto out; - } - - reqs[i].qiov = &qiovs[i]; - reqs[i].sector = offset >> 9; - reqs[i].nb_sectors = reqs[i].qiov->size >> 9; - - optind = j + 1; - - pattern++; - } - - /* If there were empty requests at the end, ignore them */ - nr_reqs = i; - - gettimeofday(&t1, NULL); - cnt = do_aio_multiwrite(reqs, nr_reqs, &total); - gettimeofday(&t2, NULL); - - if (cnt < 0) { - printf("aio_multiwrite failed: %s\n", strerror(-cnt)); - goto out; - } - - if (qflag) { - goto out; - } - - /* Finally, report back -- -C gives a parsable format */ - t2 = tsub(t2, t1); - print_report("wrote", &t2, first_offset, total, total, cnt, Cflag); -out: - for (i = 0; i < nr_reqs; i++) { - qemu_io_free(buf[i]); - if (reqs[i].qiov != NULL) { - qemu_iovec_destroy(&qiovs[i]); - } - } - g_free(buf); - g_free(reqs); - g_free(qiovs); - return 0; -} - -struct aio_ctx { - QEMUIOVector qiov; - int64_t offset; - char *buf; - int qflag; - int vflag; - int Cflag; - int Pflag; - int pattern; - struct timeval t1; -}; - -static void aio_write_done(void *opaque, int ret) -{ - struct aio_ctx *ctx = opaque; - struct timeval t2; - - gettimeofday(&t2, NULL); - - - if (ret < 0) { - printf("aio_write failed: %s\n", strerror(-ret)); - goto out; - } - - if (ctx->qflag) { - goto out; - } - - /* Finally, report back -- -C gives a parsable format */ - t2 = tsub(t2, ctx->t1); - print_report("wrote", &t2, ctx->offset, ctx->qiov.size, - ctx->qiov.size, 1, ctx->Cflag); -out: - qemu_io_free(ctx->buf); - qemu_iovec_destroy(&ctx->qiov); - g_free(ctx); -} - -static void aio_read_done(void *opaque, int ret) -{ - struct aio_ctx *ctx = opaque; - struct timeval t2; - - gettimeofday(&t2, NULL); - - if (ret < 0) { - printf("readv failed: %s\n", strerror(-ret)); - goto out; - } - - if (ctx->Pflag) { - void *cmp_buf = g_malloc(ctx->qiov.size); - - memset(cmp_buf, ctx->pattern, ctx->qiov.size); - if (memcmp(ctx->buf, cmp_buf, ctx->qiov.size)) { - printf("Pattern verification failed at offset %" - PRId64 ", %zd bytes\n", ctx->offset, ctx->qiov.size); - } - g_free(cmp_buf); - } - - if (ctx->qflag) { - goto out; - } - - if (ctx->vflag) { - dump_buffer(ctx->buf, ctx->offset, ctx->qiov.size); - } - - /* Finally, report back -- -C gives a parsable format */ - t2 = tsub(t2, ctx->t1); - print_report("read", &t2, ctx->offset, ctx->qiov.size, - ctx->qiov.size, 1, ctx->Cflag); -out: - qemu_io_free(ctx->buf); - qemu_iovec_destroy(&ctx->qiov); - g_free(ctx); -} - -static void aio_read_help(void) -{ - printf( -"\n" -" asynchronously reads a range of bytes from the given offset\n" -"\n" -" Example:\n" -" 'aio_read -v 512 1k 1k ' - dumps 2 kilobytes read from 512 bytes into the file\n" -"\n" -" Reads a segment of the currently open file, optionally dumping it to the\n" -" standard output stream (with -v option) for subsequent inspection.\n" -" The read is performed asynchronously and the aio_flush command must be\n" -" used to ensure all outstanding aio requests have been completed.\n" -" -C, -- report statistics in a machine parsable format\n" -" -P, -- use a pattern to verify read data\n" -" -v, -- dump buffer to standard output\n" -" -q, -- quiet mode, do not show I/O statistics\n" -"\n"); -} - -static int aio_read_f(int argc, char **argv); - -static const cmdinfo_t aio_read_cmd = { - .name = "aio_read", - .cfunc = aio_read_f, - .argmin = 2, - .argmax = -1, - .args = "[-Cqv] [-P pattern ] off len [len..]", - .oneline = "asynchronously reads a number of bytes", - .help = aio_read_help, -}; - -static int aio_read_f(int argc, char **argv) -{ - int nr_iov, c; - struct aio_ctx *ctx = g_new0(struct aio_ctx, 1); - - while ((c = getopt(argc, argv, "CP:qv")) != EOF) { - switch (c) { - case 'C': - ctx->Cflag = 1; - break; - case 'P': - ctx->Pflag = 1; - ctx->pattern = parse_pattern(optarg); - if (ctx->pattern < 0) { - g_free(ctx); - return 0; - } - break; - case 'q': - ctx->qflag = 1; - break; - case 'v': - ctx->vflag = 1; - break; - default: - g_free(ctx); - return command_usage(&aio_read_cmd); - } - } - - if (optind > argc - 2) { - g_free(ctx); - return command_usage(&aio_read_cmd); - } - - ctx->offset = cvtnum(argv[optind]); - if (ctx->offset < 0) { - printf("non-numeric length argument -- %s\n", argv[optind]); - g_free(ctx); - return 0; - } - optind++; - - if (ctx->offset & 0x1ff) { - printf("offset %" PRId64 " is not sector aligned\n", - ctx->offset); - g_free(ctx); - return 0; - } - - nr_iov = argc - optind; - ctx->buf = create_iovec(&ctx->qiov, &argv[optind], nr_iov, 0xab); - if (ctx->buf == NULL) { - g_free(ctx); - return 0; - } - - gettimeofday(&ctx->t1, NULL); - bdrv_aio_readv(bs, ctx->offset >> 9, &ctx->qiov, - ctx->qiov.size >> 9, aio_read_done, ctx); - return 0; -} - -static void aio_write_help(void) -{ - printf( -"\n" -" asynchronously writes a range of bytes from the given offset source\n" -" from multiple buffers\n" -"\n" -" Example:\n" -" 'aio_write 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n" -"\n" -" Writes into a segment of the currently open file, using a buffer\n" -" filled with a set pattern (0xcdcdcdcd).\n" -" The write is performed asynchronously and the aio_flush command must be\n" -" used to ensure all outstanding aio requests have been completed.\n" -" -P, -- use different pattern to fill file\n" -" -C, -- report statistics in a machine parsable format\n" -" -q, -- quiet mode, do not show I/O statistics\n" -"\n"); -} - -static int aio_write_f(int argc, char **argv); - -static const cmdinfo_t aio_write_cmd = { - .name = "aio_write", - .cfunc = aio_write_f, - .argmin = 2, - .argmax = -1, - .args = "[-Cq] [-P pattern ] off len [len..]", - .oneline = "asynchronously writes a number of bytes", - .help = aio_write_help, -}; - -static int aio_write_f(int argc, char **argv) -{ - int nr_iov, c; - int pattern = 0xcd; - struct aio_ctx *ctx = g_new0(struct aio_ctx, 1); - - while ((c = getopt(argc, argv, "CqP:")) != EOF) { - switch (c) { - case 'C': - ctx->Cflag = 1; - break; - case 'q': - ctx->qflag = 1; - break; - case 'P': - pattern = parse_pattern(optarg); - if (pattern < 0) { - g_free(ctx); - return 0; - } - break; - default: - g_free(ctx); - return command_usage(&aio_write_cmd); - } - } - - if (optind > argc - 2) { - g_free(ctx); - return command_usage(&aio_write_cmd); - } - - ctx->offset = cvtnum(argv[optind]); - if (ctx->offset < 0) { - printf("non-numeric length argument -- %s\n", argv[optind]); - g_free(ctx); - return 0; - } - optind++; - - if (ctx->offset & 0x1ff) { - printf("offset %" PRId64 " is not sector aligned\n", - ctx->offset); - g_free(ctx); - return 0; - } - - nr_iov = argc - optind; - ctx->buf = create_iovec(&ctx->qiov, &argv[optind], nr_iov, pattern); - if (ctx->buf == NULL) { - g_free(ctx); - return 0; - } - - gettimeofday(&ctx->t1, NULL); - bdrv_aio_writev(bs, ctx->offset >> 9, &ctx->qiov, - ctx->qiov.size >> 9, aio_write_done, ctx); - return 0; -} - -static int aio_flush_f(int argc, char **argv) -{ - bdrv_drain_all(); - return 0; -} - -static const cmdinfo_t aio_flush_cmd = { - .name = "aio_flush", - .cfunc = aio_flush_f, - .oneline = "completes all outstanding aio requests" -}; - -static int flush_f(int argc, char **argv) -{ - bdrv_flush(bs); - return 0; -} - -static const cmdinfo_t flush_cmd = { - .name = "flush", - .altname = "f", - .cfunc = flush_f, - .oneline = "flush all in-core file state to disk", -}; - -static int truncate_f(int argc, char **argv) -{ - int64_t offset; - int ret; - - offset = cvtnum(argv[1]); - if (offset < 0) { - printf("non-numeric truncate argument -- %s\n", argv[1]); - return 0; - } - - ret = bdrv_truncate(bs, offset); - if (ret < 0) { - printf("truncate: %s\n", strerror(-ret)); - return 0; - } - - return 0; -} - -static const cmdinfo_t truncate_cmd = { - .name = "truncate", - .altname = "t", - .cfunc = truncate_f, - .argmin = 1, - .argmax = 1, - .args = "off", - .oneline = "truncates the current file at the given offset", -}; - -static int length_f(int argc, char **argv) -{ - int64_t size; - char s1[64]; - - size = bdrv_getlength(bs); - if (size < 0) { - printf("getlength: %s\n", strerror(-size)); - return 0; - } - - cvtstr(size, s1, sizeof(s1)); - printf("%s\n", s1); - return 0; -} - - -static const cmdinfo_t length_cmd = { - .name = "length", - .altname = "l", - .cfunc = length_f, - .oneline = "gets the length of the current file", -}; - - -static int info_f(int argc, char **argv) -{ - BlockDriverInfo bdi; - char s1[64], s2[64]; - int ret; - - if (bs->drv && bs->drv->format_name) { - printf("format name: %s\n", bs->drv->format_name); - } - if (bs->drv && bs->drv->protocol_name) { - printf("format name: %s\n", bs->drv->protocol_name); - } - - ret = bdrv_get_info(bs, &bdi); - if (ret) { - return 0; - } - - cvtstr(bdi.cluster_size, s1, sizeof(s1)); - cvtstr(bdi.vm_state_offset, s2, sizeof(s2)); - - printf("cluster size: %s\n", s1); - printf("vm state offset: %s\n", s2); - - return 0; -} - - - -static const cmdinfo_t info_cmd = { - .name = "info", - .altname = "i", - .cfunc = info_f, - .oneline = "prints information about the current file", -}; - -static void discard_help(void) -{ - printf( -"\n" -" discards a range of bytes from the given offset\n" -"\n" -" Example:\n" -" 'discard 512 1k' - discards 1 kilobyte from 512 bytes into the file\n" -"\n" -" Discards a segment of the currently open file.\n" -" -C, -- report statistics in a machine parsable format\n" -" -q, -- quiet mode, do not show I/O statistics\n" -"\n"); -} - -static int discard_f(int argc, char **argv); - -static const cmdinfo_t discard_cmd = { - .name = "discard", - .altname = "d", - .cfunc = discard_f, - .argmin = 2, - .argmax = -1, - .args = "[-Cq] off len", - .oneline = "discards a number of bytes at a specified offset", - .help = discard_help, -}; - -static int discard_f(int argc, char **argv) -{ - struct timeval t1, t2; - int Cflag = 0, qflag = 0; - int c, ret; - int64_t offset; - int count; - - while ((c = getopt(argc, argv, "Cq")) != EOF) { - switch (c) { - case 'C': - Cflag = 1; - break; - case 'q': - qflag = 1; - break; - default: - return command_usage(&discard_cmd); - } - } - - if (optind != argc - 2) { - return command_usage(&discard_cmd); - } - - offset = cvtnum(argv[optind]); - if (offset < 0) { - printf("non-numeric length argument -- %s\n", argv[optind]); - return 0; - } - - optind++; - count = cvtnum(argv[optind]); - if (count < 0) { - printf("non-numeric length argument -- %s\n", argv[optind]); - return 0; - } - - gettimeofday(&t1, NULL); - ret = bdrv_discard(bs, offset >> BDRV_SECTOR_BITS, - count >> BDRV_SECTOR_BITS); - gettimeofday(&t2, NULL); - - if (ret < 0) { - printf("discard failed: %s\n", strerror(-ret)); - goto out; - } - - /* Finally, report back -- -C gives a parsable format */ - if (!qflag) { - t2 = tsub(t2, t1); - print_report("discard", &t2, offset, count, count, 1, Cflag); - } - -out: - return 0; -} - -static int alloc_f(int argc, char **argv) -{ - int64_t offset, sector_num; - int nb_sectors, remaining; - char s1[64]; - int num, sum_alloc; - int ret; - - offset = cvtnum(argv[1]); - if (offset & 0x1ff) { - printf("offset %" PRId64 " is not sector aligned\n", - offset); - return 0; - } - - if (argc == 3) { - nb_sectors = cvtnum(argv[2]); - } else { - nb_sectors = 1; - } - - remaining = nb_sectors; - sum_alloc = 0; - sector_num = offset >> 9; - while (remaining) { - ret = bdrv_is_allocated(bs, sector_num, remaining, &num); - sector_num += num; - remaining -= num; - if (ret) { - sum_alloc += num; - } - if (num == 0) { - nb_sectors -= remaining; - remaining = 0; - } - } - - cvtstr(offset, s1, sizeof(s1)); - - printf("%d/%d sectors allocated at offset %s\n", - sum_alloc, nb_sectors, s1); - return 0; -} - -static const cmdinfo_t alloc_cmd = { - .name = "alloc", - .altname = "a", - .argmin = 1, - .argmax = 2, - .cfunc = alloc_f, - .args = "off [sectors]", - .oneline = "checks if a sector is present in the file", -}; - - -static int map_is_allocated(int64_t sector_num, int64_t nb_sectors, int64_t *pnum) -{ - int num, num_checked; - int ret, firstret; - - num_checked = MIN(nb_sectors, INT_MAX); - ret = bdrv_is_allocated(bs, sector_num, num_checked, &num); - if (ret < 0) { - return ret; - } - - firstret = ret; - *pnum = num; - - while (nb_sectors > 0 && ret == firstret) { - sector_num += num; - nb_sectors -= num; - - num_checked = MIN(nb_sectors, INT_MAX); - ret = bdrv_is_allocated(bs, sector_num, num_checked, &num); - if (ret == firstret) { - *pnum += num; - } else { - break; - } - } - - return firstret; -} - -static int map_f(int argc, char **argv) -{ - int64_t offset; - int64_t nb_sectors; - char s1[64]; - int64_t num; - int ret; - const char *retstr; - - offset = 0; - nb_sectors = bs->total_sectors; - - do { - ret = map_is_allocated(offset, nb_sectors, &num); - if (ret < 0) { - error_report("Failed to get allocation status: %s", strerror(-ret)); - return 0; - } - - retstr = ret ? " allocated" : "not allocated"; - cvtstr(offset << 9ULL, s1, sizeof(s1)); - printf("[% 24" PRId64 "] % 8" PRId64 "/% 8" PRId64 " sectors %s " - "at offset %s (%d)\n", - offset << 9ULL, num, nb_sectors, retstr, s1, ret); - - offset += num; - nb_sectors -= num; - } while (offset < bs->total_sectors); - - return 0; -} - -static const cmdinfo_t map_cmd = { - .name = "map", - .argmin = 0, - .argmax = 0, - .cfunc = map_f, - .args = "", - .oneline = "prints the allocated areas of a file", -}; - -static int break_f(int argc, char **argv) -{ - int ret; - - ret = bdrv_debug_breakpoint(bs, argv[1], argv[2]); - if (ret < 0) { - printf("Could not set breakpoint: %s\n", strerror(-ret)); - } - - return 0; -} - -static const cmdinfo_t break_cmd = { - .name = "break", - .argmin = 2, - .argmax = 2, - .cfunc = break_f, - .args = "event tag", - .oneline = "sets a breakpoint on event and tags the stopped " - "request as tag", -}; - -static int resume_f(int argc, char **argv) -{ - int ret; - - ret = bdrv_debug_resume(bs, argv[1]); - if (ret < 0) { - printf("Could not resume request: %s\n", strerror(-ret)); - } - - return 0; -} - -static const cmdinfo_t resume_cmd = { - .name = "resume", - .argmin = 1, - .argmax = 1, - .cfunc = resume_f, - .args = "tag", - .oneline = "resumes the request tagged as tag", -}; - -static int wait_break_f(int argc, char **argv) -{ - while (!bdrv_debug_is_suspended(bs, argv[1])) { - qemu_aio_wait(); - } - - return 0; -} - -static const cmdinfo_t wait_break_cmd = { - .name = "wait_break", - .argmin = 1, - .argmax = 1, - .cfunc = wait_break_f, - .args = "tag", - .oneline = "waits for the suspension of a request", -}; - -static int abort_f(int argc, char **argv) -{ - abort(); -} - -static const cmdinfo_t abort_cmd = { - .name = "abort", - .cfunc = abort_f, - .flags = CMD_NOFILE_OK, - .oneline = "simulate a program crash using abort(3)", -}; - -static int close_f(int argc, char **argv) +static int close_f(BlockDriverState *bs, int argc, char **argv) { bdrv_delete(bs); - bs = NULL; + qemuio_bs = NULL; return 0; } @@ -1796,23 +46,23 @@ static const cmdinfo_t close_cmd = { static int openfile(char *name, int flags, int growable) { - if (bs) { + if (qemuio_bs) { fprintf(stderr, "file open already, try 'help close'\n"); return 1; } if (growable) { - if (bdrv_file_open(&bs, name, NULL, flags)) { + if (bdrv_file_open(&qemuio_bs, name, NULL, flags)) { fprintf(stderr, "%s: can't open device %s\n", progname, name); return 1; } } else { - bs = bdrv_new("hda"); + qemuio_bs = bdrv_new("hda"); - if (bdrv_open(bs, name, NULL, flags, NULL) < 0) { + if (bdrv_open(qemuio_bs, name, NULL, flags, NULL) < 0) { fprintf(stderr, "%s: can't open device %s\n", progname, name); - bdrv_delete(bs); - bs = NULL; + bdrv_delete(qemuio_bs); + qemuio_bs = NULL; return 1; } } @@ -1837,7 +87,7 @@ static void open_help(void) "\n"); } -static int open_f(int argc, char **argv); +static int open_f(BlockDriverState *bs, int argc, char **argv); static const cmdinfo_t open_cmd = { .name = "open", @@ -1851,7 +101,7 @@ static const cmdinfo_t open_cmd = { .help = open_help, }; -static int open_f(int argc, char **argv) +static int open_f(BlockDriverState *bs, int argc, char **argv) { int flags = 0; int readonly = 0; @@ -1873,7 +123,7 @@ static int open_f(int argc, char **argv) growable = 1; break; default: - return command_usage(&open_cmd); + return qemuio_command_usage(&open_cmd); } } @@ -1882,33 +132,27 @@ static int open_f(int argc, char **argv) } if (optind != argc - 1) { - return command_usage(&open_cmd); + return qemuio_command_usage(&open_cmd); } return openfile(argv[optind], flags, growable); } -static int init_args_command(int index) -{ - /* only one device allowed so far */ - if (index >= 1) { - return 0; - } - return ++index; -} - -static int init_check_command(const cmdinfo_t *ct) +static int quit_f(BlockDriverState *bs, int argc, char **argv) { - if (ct->flags & CMD_FLAG_GLOBAL) { - return 1; - } - if (!(ct->flags & CMD_NOFILE_OK) && !bs) { - fprintf(stderr, "no file open, try 'help open'\n"); - return 0; - } return 1; } +static const cmdinfo_t quit_cmd = { + .name = "quit", + .altname = "q", + .cfunc = quit_f, + .argmin = -1, + .argmax = -1, + .flags = CMD_FLAG_GLOBAL, + .oneline = "exit the program", +}; + static void usage(const char *name) { printf( @@ -1931,6 +175,141 @@ static void usage(const char *name) } +#if defined(ENABLE_READLINE) +# include <readline/history.h> +# include <readline/readline.h> +#elif defined(ENABLE_EDITLINE) +# include <histedit.h> +#endif + +static char *get_prompt(void) +{ + static char prompt[FILENAME_MAX + 2 /*"> "*/ + 1 /*"\0"*/ ]; + + if (!prompt[0]) { + snprintf(prompt, sizeof(prompt), "%s> ", progname); + } + + return prompt; +} + +#if defined(ENABLE_READLINE) +static char *fetchline(void) +{ + char *line = readline(get_prompt()); + if (line && *line) { + add_history(line); + } + return line; +} +#elif defined(ENABLE_EDITLINE) +static char *el_get_prompt(EditLine *e) +{ + return get_prompt(); +} + +static char *fetchline(void) +{ + static EditLine *el; + static History *hist; + HistEvent hevent; + char *line; + int count; + + if (!el) { + hist = history_init(); + history(hist, &hevent, H_SETSIZE, 100); + el = el_init(progname, stdin, stdout, stderr); + el_source(el, NULL); + el_set(el, EL_SIGNAL, 1); + el_set(el, EL_PROMPT, el_get_prompt); + el_set(el, EL_HIST, history, (const char *)hist); + } + line = strdup(el_gets(el, &count)); + if (line) { + if (count > 0) { + line[count-1] = '\0'; + } + if (*line) { + history(hist, &hevent, H_ENTER, line); + } + } + return line; +} +#else +# define MAXREADLINESZ 1024 +static char *fetchline(void) +{ + char *p, *line = g_malloc(MAXREADLINESZ); + + if (!fgets(line, MAXREADLINESZ, stdin)) { + g_free(line); + return NULL; + } + + p = line + strlen(line); + if (p != line && p[-1] == '\n') { + p[-1] = '\0'; + } + + return line; +} +#endif + +static void prep_fetchline(void *opaque) +{ + int *fetchable = opaque; + + qemu_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL); + *fetchable= 1; +} + +static void command_loop(void) +{ + int i, done = 0, fetchable = 0, prompted = 0; + char *input; + + for (i = 0; !done && i < ncmdline; i++) { + done = qemuio_command(qemuio_bs, cmdline[i]); + } + if (cmdline) { + g_free(cmdline); + return; + } + + while (!done) { + if (!prompted) { + printf("%s", get_prompt()); + fflush(stdout); + qemu_set_fd_handler(STDIN_FILENO, prep_fetchline, NULL, &fetchable); + prompted = 1; + } + + main_loop_wait(false); + + if (!fetchable) { + continue; + } + + input = fetchline(); + if (input == NULL) { + break; + } + done = qemuio_command(qemuio_bs, input); + g_free(input); + + prompted = 0; + fetchable = 0; + } + qemu_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL); +} + +static void add_user_command(char *optarg) +{ + cmdline = g_realloc(cmdline, ++ncmdline * sizeof(char *)); + cmdline[ncmdline-1] = optarg; +} + int main(int argc, char **argv) { int readonly = 0; @@ -1979,7 +358,7 @@ int main(int argc, char **argv) readonly = 1; break; case 'm': - misalign = 1; + qemuio_misalign = 1; break; case 'g': growable = 1; @@ -1999,7 +378,7 @@ int main(int argc, char **argv) } break; case 'V': - printf("%s version %s\n", progname, VERSION); + printf("%s version %s\n", progname, QEMU_VERSION); exit(0); case 'h': usage(progname); @@ -2019,32 +398,9 @@ int main(int argc, char **argv) bdrv_init(); /* initialize commands */ - quit_init(); - help_init(); - add_command(&open_cmd); - add_command(&close_cmd); - add_command(&read_cmd); - add_command(&readv_cmd); - add_command(&write_cmd); - add_command(&writev_cmd); - add_command(&multiwrite_cmd); - add_command(&aio_read_cmd); - add_command(&aio_write_cmd); - add_command(&aio_flush_cmd); - add_command(&flush_cmd); - add_command(&truncate_cmd); - add_command(&length_cmd); - add_command(&info_cmd); - add_command(&discard_cmd); - add_command(&alloc_cmd); - add_command(&map_cmd); - add_command(&break_cmd); - add_command(&resume_cmd); - add_command(&wait_break_cmd); - add_command(&abort_cmd); - - add_args_command(init_args_command); - add_check_command(init_check_command); + qemuio_add_command(&quit_cmd); + qemuio_add_command(&open_cmd); + qemuio_add_command(&close_cmd); /* open the device */ if (!readonly) { @@ -2061,8 +417,8 @@ int main(int argc, char **argv) */ bdrv_drain_all(); - if (bs) { - bdrv_delete(bs); + if (qemuio_bs) { + bdrv_delete(qemuio_bs); } return 0; } diff --git a/qmp-commands.hx b/qmp-commands.hx index ffd130e..8cea5e5 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -1704,6 +1704,47 @@ Each json-object contain the following: - "iops": limit total I/O operations per second (json-int) - "iops_rd": limit read operations per second (json-int) - "iops_wr": limit write operations per second (json-int) + - "image": the detail of the image, it is a json-object containing + the following: + - "filename": image file name (json-string) + - "format": image format (json-string) + - "virtual-size": image capacity in bytes (json-int) + - "dirty-flag": true if image is not cleanly closed, not present + means clean (json-bool, optional) + - "actual-size": actual size on disk in bytes of the image, not + present when image does not support thin + provision (json-int, optional) + - "cluster-size": size of a cluster in bytes, not present if image + format does not support it (json-int, optional) + - "encrypted": true if the image is encrypted, not present means + false or the image format does not support + encryption (json-bool, optional) + - "backing_file": backing file name, not present means no backing + file is used or the image format does not + support backing file chain + (json-string, optional) + - "full-backing-filename": full path of the backing file, not + present if it equals backing_file or no + backing file is used + (json-string, optional) + - "backing-filename-format": the format of the backing file, not + present means unknown or no backing + file (json-string, optional) + - "snapshots": the internal snapshot info, it is an optional list + of json-object containing the following: + - "id": unique snapshot id (json-string) + - "name": snapshot name (json-string) + - "vm-state-size": size of the VM state in bytes (json-int) + - "date-sec": UTC date of the snapshot in seconds (json-int) + - "date-nsec": fractional part in nanoseconds to be used with + date-sec(json-int) + - "vm-clock-sec": VM clock relative to boot in seconds + (json-int) + - "vm-clock-nsec": fractional part in nanoseconds to be used + with vm-clock-sec (json-int) + - "backing-image": the detail of the backing image, it is an + optional json-object only present when a + backing image present for this image - "io-status": I/O operation status, only present if the device supports it and the VM is configured to stop on errors. It's always reset @@ -1724,14 +1765,38 @@ Example: "ro":false, "drv":"qcow2", "encrypted":false, - "file":"disks/test.img", - "backing_file_depth":0, + "file":"disks/test.qcow2", + "backing_file_depth":1, "bps":1000000, "bps_rd":0, "bps_wr":0, "iops":1000000, "iops_rd":0, "iops_wr":0, + "image":{ + "filename":"disks/test.qcow2", + "format":"qcow2", + "virtual-size":2048000, + "backing_file":"base.qcow2", + "full-backing-filename":"disks/base.qcow2", + "backing-filename-format:"qcow2", + "snapshots":[ + { + "id": "1", + "name": "snapshot1", + "vm-state-size": 0, + "date-sec": 10000200, + "date-nsec": 12, + "vm-clock-sec": 206, + "vm-clock-nsec": 30 + } + ], + "backing-image":{ + "filename":"disks/base.qcow2", + "format":"qcow2", + "virtual-size":2048000 + } + } }, "type":"unknown" }, @@ -50,6 +50,33 @@ bool cpu_exists(int64_t id) return data.found; } +bool cpu_paging_enabled(const CPUState *cpu) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + + return cc->get_paging_enabled(cpu); +} + +static bool cpu_common_get_paging_enabled(const CPUState *cpu) +{ + return false; +} + +void cpu_get_memory_mapping(CPUState *cpu, MemoryMappingList *list, + Error **errp) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + + return cc->get_memory_mapping(cpu, list, errp); +} + +static void cpu_common_get_memory_mapping(CPUState *cpu, + MemoryMappingList *list, + Error **errp) +{ + error_setg(errp, "Obtaining memory mappings is unsupported on this CPU."); +} + /* CPU hot-plug notifiers */ static NotifierList cpu_added_notifiers = NOTIFIER_LIST_INITIALIZER(cpu_add_notifiers); @@ -176,6 +203,8 @@ static void cpu_class_init(ObjectClass *klass, void *data) k->class_by_name = cpu_common_class_by_name; k->reset = cpu_common_reset; k->get_arch_id = cpu_common_get_arch_id; + k->get_paging_enabled = cpu_common_get_paging_enabled; + k->get_memory_mapping = cpu_common_get_memory_mapping; k->write_elf32_qemunote = cpu_common_write_elf32_qemunote; k->write_elf32_note = cpu_common_write_elf32_note; k->write_elf64_qemunote = cpu_common_write_elf64_qemunote; diff --git a/spice-qemu-char.c b/spice-qemu-char.c index f10970c..6d147a7 100644 --- a/spice-qemu-char.c +++ b/spice-qemu-char.c @@ -255,6 +255,7 @@ static CharDriverState *chr_open(const char *subtype) chr->chr_add_watch = spice_chr_add_watch; chr->chr_close = spice_chr_close; chr->chr_set_fe_open = spice_chr_set_fe_open; + chr->explicit_be_open = true; QLIST_INSERT_HEAD(&spice_chars, s, next); diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs index 03dff20..9b701b4 100644 --- a/stubs/Makefile.objs +++ b/stubs/Makefile.objs @@ -2,6 +2,7 @@ stub-obj-y += arch-query-cpu-def.o stub-obj-y += clock-warp.o stub-obj-y += cpu-get-clock.o stub-obj-y += cpu-get-icount.o +stub-obj-y += dump.o stub-obj-y += fdset-add-fd.o stub-obj-y += fdset-find-fd.o stub-obj-y += fdset-get-fd.o diff --git a/dump-stub.c b/stubs/dump.c index b3f42cb..43c9a3f 100644 --- a/dump-stub.c +++ b/stubs/dump.c @@ -16,14 +16,6 @@ #include "qapi/qmp/qerror.h" #include "qmp-commands.h" -/* we need this function in hmp.c */ -void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin, - int64_t begin, bool has_length, int64_t length, - Error **errp) -{ - error_set(errp, QERR_UNSUPPORTED); -} - int cpu_get_dump_info(ArchDumpInfo *info) { return -1; diff --git a/target-arm/kvm.c b/target-arm/kvm.c index b7bdc03..27dcab9 100644 --- a/target-arm/kvm.c +++ b/target-arm/kvm.c @@ -491,3 +491,7 @@ void kvm_arch_remove_all_hw_breakpoints(void) { qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__); } + +void kvm_arch_init_irq_routing(KVMState *s) +{ +} diff --git a/target-arm/translate.c b/target-arm/translate.c index b3f26d6..2a18ffe 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -6752,7 +6752,7 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) tcg_gen_qemu_ld32u(tmp, addr, 0); tcg_gen_addi_i32(addr, addr, 4); tmp2 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32u(tmp, addr, 0); + tcg_gen_qemu_ld32u(tmp2, addr, 0); if (insn & (1 << 21)) { /* Base writeback. */ switch (i) { diff --git a/target-i386/arch_memory_mapping.c b/target-i386/arch_memory_mapping.c index 5096fbd..2566a04 100644 --- a/target-i386/arch_memory_mapping.c +++ b/target-i386/arch_memory_mapping.c @@ -239,11 +239,15 @@ static void walk_pml4e(MemoryMappingList *list, } #endif -int cpu_get_memory_mapping(MemoryMappingList *list, CPUArchState *env) +void x86_cpu_get_memory_mapping(CPUState *cs, MemoryMappingList *list, + Error **errp) { - if (!cpu_paging_enabled(env)) { + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; + + if (!cpu_paging_enabled(cs)) { /* paging is disabled */ - return 0; + return; } if (env->cr[4] & CR4_PAE_MASK) { @@ -269,11 +273,5 @@ int cpu_get_memory_mapping(MemoryMappingList *list, CPUArchState *env) pse = !!(env->cr[4] & CR4_PSE_MASK); walk_pde2(list, pde_addr, env->a20_mask, pse); } - - return 0; } -bool cpu_paging_enabled(CPUArchState *env) -{ - return env->cr[0] & CR0_PG_MASK; -} diff --git a/target-i386/cpu-qom.h b/target-i386/cpu-qom.h index 849cedf..e0ac072 100644 --- a/target-i386/cpu-qom.h +++ b/target-i386/cpu-qom.h @@ -98,4 +98,7 @@ int x86_cpu_write_elf64_qemunote(WriteCoreDumpFunction f, CPUState *cpu, int x86_cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cpu, void *opaque); +void x86_cpu_get_memory_mapping(CPUState *cpu, MemoryMappingList *list, + Error **errp); + #endif diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 1a501d9..a7154af 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -221,7 +221,7 @@ X86RegisterInfo32 x86_reg_info_32[CPU_NB_REGS32] = { const char *get_register_name_32(unsigned int reg) { - if (reg > CPU_NB_REGS32) { + if (reg >= CPU_NB_REGS32) { return NULL; } return x86_reg_info_32[reg].name; @@ -669,10 +669,10 @@ static x86_def_t builtin_x86_defs[] = { }, { .name = "Conroe", - .level = 2, + .level = 4, .vendor = CPUID_VENDOR_INTEL, .family = 6, - .model = 2, + .model = 15, .stepping = 3, .features[FEAT_1_EDX] = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | @@ -691,10 +691,10 @@ static x86_def_t builtin_x86_defs[] = { }, { .name = "Penryn", - .level = 2, + .level = 4, .vendor = CPUID_VENDOR_INTEL, .family = 6, - .model = 2, + .model = 23, .stepping = 3, .features[FEAT_1_EDX] = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | @@ -714,10 +714,10 @@ static x86_def_t builtin_x86_defs[] = { }, { .name = "Nehalem", - .level = 2, + .level = 4, .vendor = CPUID_VENDOR_INTEL, .family = 6, - .model = 2, + .model = 26, .stepping = 3, .features[FEAT_1_EDX] = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | @@ -2505,6 +2505,13 @@ static int64_t x86_cpu_get_arch_id(CPUState *cs) return env->cpuid_apic_id; } +static bool x86_cpu_get_paging_enabled(const CPUState *cs) +{ + X86CPU *cpu = X86_CPU(cs); + + return cpu->env.cr[0] & CR0_PG_MASK; +} + static void x86_cpu_common_class_init(ObjectClass *oc, void *data) { X86CPUClass *xcc = X86_CPU_CLASS(oc); @@ -2519,15 +2526,16 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data) cc->reset = x86_cpu_reset; cc->do_interrupt = x86_cpu_do_interrupt; + cc->get_arch_id = x86_cpu_get_arch_id; + cc->get_paging_enabled = x86_cpu_get_paging_enabled; #ifndef CONFIG_USER_ONLY + cc->get_memory_mapping = x86_cpu_get_memory_mapping; cc->write_elf64_note = x86_cpu_write_elf64_note; cc->write_elf64_qemunote = x86_cpu_write_elf64_qemunote; cc->write_elf32_note = x86_cpu_write_elf32_note; cc->write_elf32_qemunote = x86_cpu_write_elf32_qemunote; #endif cpu_class_set_vmsd(cc, &vmstate_x86_cpu); - - cc->get_arch_id = x86_cpu_get_arch_id; } static const TypeInfo x86_cpu_type_info = { diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 3ab2946..2bbc3b8 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -1797,3 +1797,7 @@ int kvm_arch_on_sigbus(int code, void *addr) { return 1; } + +void kvm_arch_init_irq_routing(KVMState *s) +{ +} diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 862fb12..4d9ac4a 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -928,3 +928,7 @@ void kvm_s390_enable_css_support(S390CPU *cpu) r = kvm_vcpu_ioctl(CPU(cpu), KVM_ENABLE_CAP, &cap); assert(r == 0); } + +void kvm_arch_init_irq_routing(KVMState *s) +{ +} diff --git a/target-sparc/cpu.c b/target-sparc/cpu.c index 290b580..13bb7bb 100644 --- a/target-sparc/cpu.c +++ b/target-sparc/cpu.c @@ -614,7 +614,7 @@ static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model) return 0; error: - free(s); + g_free(s); return -1; } diff --git a/tcg/aarch64/tcg-target.c b/tcg/aarch64/tcg-target.c new file mode 100644 index 0000000..562a549 --- /dev/null +++ b/tcg/aarch64/tcg-target.c @@ -0,0 +1,1404 @@ +/* + * Initial TCG Implementation for aarch64 + * + * Copyright (c) 2013 Huawei Technologies Duesseldorf GmbH + * Written by Claudio Fontana + * + * 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 for details. + */ + +#include "qemu/bitops.h" + +#ifndef NDEBUG +static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { + "%x0", "%x1", "%x2", "%x3", "%x4", "%x5", "%x6", "%x7", + "%x8", "%x9", "%x10", "%x11", "%x12", "%x13", "%x14", "%x15", + "%x16", "%x17", "%x18", "%x19", "%x20", "%x21", "%x22", "%x23", + "%x24", "%x25", "%x26", "%x27", "%x28", + "%fp", /* frame pointer */ + "%lr", /* link register */ + "%sp", /* stack pointer */ +}; +#endif /* NDEBUG */ + +#ifdef TARGET_WORDS_BIGENDIAN + #define TCG_LDST_BSWAP 1 +#else + #define TCG_LDST_BSWAP 0 +#endif + +static const int tcg_target_reg_alloc_order[] = { + TCG_REG_X20, TCG_REG_X21, TCG_REG_X22, TCG_REG_X23, + TCG_REG_X24, TCG_REG_X25, TCG_REG_X26, TCG_REG_X27, + TCG_REG_X28, /* we will reserve this for GUEST_BASE if configured */ + + TCG_REG_X9, TCG_REG_X10, TCG_REG_X11, TCG_REG_X12, + TCG_REG_X13, TCG_REG_X14, TCG_REG_X15, + TCG_REG_X16, TCG_REG_X17, + + TCG_REG_X18, TCG_REG_X19, /* will not use these, see tcg_target_init */ + + TCG_REG_X0, TCG_REG_X1, TCG_REG_X2, TCG_REG_X3, + TCG_REG_X4, TCG_REG_X5, TCG_REG_X6, TCG_REG_X7, + + TCG_REG_X8, /* will not use, see tcg_target_init */ +}; + +static const int tcg_target_call_iarg_regs[8] = { + TCG_REG_X0, TCG_REG_X1, TCG_REG_X2, TCG_REG_X3, + TCG_REG_X4, TCG_REG_X5, TCG_REG_X6, TCG_REG_X7 +}; +static const int tcg_target_call_oarg_regs[1] = { + TCG_REG_X0 +}; + +#define TCG_REG_TMP TCG_REG_X8 + +#ifndef CONFIG_SOFTMMU +# if defined(CONFIG_USE_GUEST_BASE) +# define TCG_REG_GUEST_BASE TCG_REG_X28 +# else +# define TCG_REG_GUEST_BASE TCG_REG_XZR +# endif +#endif + +static inline void reloc_pc26(void *code_ptr, tcg_target_long target) +{ + tcg_target_long offset; uint32_t insn; + offset = (target - (tcg_target_long)code_ptr) / 4; + /* read instruction, mask away previous PC_REL26 parameter contents, + set the proper offset, then write back the instruction. */ + insn = *(uint32_t *)code_ptr; + insn = deposit32(insn, 0, 26, offset); + *(uint32_t *)code_ptr = insn; +} + +static inline void reloc_pc19(void *code_ptr, tcg_target_long target) +{ + tcg_target_long offset; uint32_t insn; + offset = (target - (tcg_target_long)code_ptr) / 4; + /* read instruction, mask away previous PC_REL19 parameter contents, + set the proper offset, then write back the instruction. */ + insn = *(uint32_t *)code_ptr; + insn = deposit32(insn, 5, 19, offset); + *(uint32_t *)code_ptr = insn; +} + +static inline void patch_reloc(uint8_t *code_ptr, int type, + tcg_target_long value, tcg_target_long addend) +{ + value += addend; + + switch (type) { + case R_AARCH64_JUMP26: + case R_AARCH64_CALL26: + reloc_pc26(code_ptr, value); + break; + case R_AARCH64_CONDBR19: + reloc_pc19(code_ptr, value); + break; + + default: + tcg_abort(); + } +} + +/* parse target specific constraints */ +static int target_parse_constraint(TCGArgConstraint *ct, + const char **pct_str) +{ + const char *ct_str = *pct_str; + + switch (ct_str[0]) { + case 'r': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, (1ULL << TCG_TARGET_NB_REGS) - 1); + break; + case 'l': /* qemu_ld / qemu_st address, data_reg */ + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, (1ULL << TCG_TARGET_NB_REGS) - 1); +#ifdef CONFIG_SOFTMMU + /* x0 and x1 will be overwritten when reading the tlb entry, + and x2, and x3 for helper args, better to avoid using them. */ + tcg_regset_reset_reg(ct->u.regs, TCG_REG_X0); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_X1); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_X2); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_X3); +#endif + break; + default: + return -1; + } + + ct_str++; + *pct_str = ct_str; + return 0; +} + +static inline int tcg_target_const_match(tcg_target_long val, + const TCGArgConstraint *arg_ct) +{ + int ct = arg_ct->ct; + + if (ct & TCG_CT_CONST) { + return 1; + } + + return 0; +} + +enum aarch64_cond_code { + COND_EQ = 0x0, + COND_NE = 0x1, + COND_CS = 0x2, /* Unsigned greater or equal */ + COND_HS = COND_CS, /* ALIAS greater or equal */ + COND_CC = 0x3, /* Unsigned less than */ + COND_LO = COND_CC, /* ALIAS Lower */ + COND_MI = 0x4, /* Negative */ + COND_PL = 0x5, /* Zero or greater */ + COND_VS = 0x6, /* Overflow */ + COND_VC = 0x7, /* No overflow */ + COND_HI = 0x8, /* Unsigned greater than */ + COND_LS = 0x9, /* Unsigned less or equal */ + COND_GE = 0xa, + COND_LT = 0xb, + COND_GT = 0xc, + COND_LE = 0xd, + COND_AL = 0xe, + COND_NV = 0xf, /* behaves like COND_AL here */ +}; + +static const enum aarch64_cond_code tcg_cond_to_aarch64[] = { + [TCG_COND_EQ] = COND_EQ, + [TCG_COND_NE] = COND_NE, + [TCG_COND_LT] = COND_LT, + [TCG_COND_GE] = COND_GE, + [TCG_COND_LE] = COND_LE, + [TCG_COND_GT] = COND_GT, + /* unsigned */ + [TCG_COND_LTU] = COND_LO, + [TCG_COND_GTU] = COND_HI, + [TCG_COND_GEU] = COND_HS, + [TCG_COND_LEU] = COND_LS, +}; + +/* opcodes for LDR / STR instructions with base + simm9 addressing */ +enum aarch64_ldst_op_data { /* size of the data moved */ + LDST_8 = 0x38, + LDST_16 = 0x78, + LDST_32 = 0xb8, + LDST_64 = 0xf8, +}; +enum aarch64_ldst_op_type { /* type of operation */ + LDST_ST = 0x0, /* store */ + LDST_LD = 0x4, /* load */ + LDST_LD_S_X = 0x8, /* load and sign-extend into Xt */ + LDST_LD_S_W = 0xc, /* load and sign-extend into Wt */ +}; + +enum aarch64_arith_opc { + ARITH_AND = 0x0a, + ARITH_ADD = 0x0b, + ARITH_OR = 0x2a, + ARITH_ADDS = 0x2b, + ARITH_XOR = 0x4a, + ARITH_SUB = 0x4b, + ARITH_ANDS = 0x6a, + ARITH_SUBS = 0x6b, +}; + +enum aarch64_srr_opc { + SRR_SHL = 0x0, + SRR_SHR = 0x4, + SRR_SAR = 0x8, + SRR_ROR = 0xc +}; + +static inline enum aarch64_ldst_op_data +aarch64_ldst_get_data(TCGOpcode tcg_op) +{ + switch (tcg_op) { + case INDEX_op_ld8u_i32: + case INDEX_op_ld8s_i32: + case INDEX_op_ld8u_i64: + case INDEX_op_ld8s_i64: + case INDEX_op_st8_i32: + case INDEX_op_st8_i64: + return LDST_8; + + case INDEX_op_ld16u_i32: + case INDEX_op_ld16s_i32: + case INDEX_op_ld16u_i64: + case INDEX_op_ld16s_i64: + case INDEX_op_st16_i32: + case INDEX_op_st16_i64: + return LDST_16; + + case INDEX_op_ld_i32: + case INDEX_op_st_i32: + case INDEX_op_ld32u_i64: + case INDEX_op_ld32s_i64: + case INDEX_op_st32_i64: + return LDST_32; + + case INDEX_op_ld_i64: + case INDEX_op_st_i64: + return LDST_64; + + default: + tcg_abort(); + } +} + +static inline enum aarch64_ldst_op_type +aarch64_ldst_get_type(TCGOpcode tcg_op) +{ + switch (tcg_op) { + case INDEX_op_st8_i32: + case INDEX_op_st16_i32: + case INDEX_op_st8_i64: + case INDEX_op_st16_i64: + case INDEX_op_st_i32: + case INDEX_op_st32_i64: + case INDEX_op_st_i64: + return LDST_ST; + + case INDEX_op_ld8u_i32: + case INDEX_op_ld16u_i32: + case INDEX_op_ld8u_i64: + case INDEX_op_ld16u_i64: + case INDEX_op_ld_i32: + case INDEX_op_ld32u_i64: + case INDEX_op_ld_i64: + return LDST_LD; + + case INDEX_op_ld8s_i32: + case INDEX_op_ld16s_i32: + return LDST_LD_S_W; + + case INDEX_op_ld8s_i64: + case INDEX_op_ld16s_i64: + case INDEX_op_ld32s_i64: + return LDST_LD_S_X; + + default: + tcg_abort(); + } +} + +static inline uint32_t tcg_in32(TCGContext *s) +{ + uint32_t v = *(uint32_t *)s->code_ptr; + return v; +} + +static inline void tcg_out_ldst_9(TCGContext *s, + enum aarch64_ldst_op_data op_data, + enum aarch64_ldst_op_type op_type, + TCGReg rd, TCGReg rn, tcg_target_long offset) +{ + /* use LDUR with BASE register with 9bit signed unscaled offset */ + unsigned int mod, off; + + if (offset < 0) { + off = (256 + offset); + mod = 0x1; + } else { + off = offset; + mod = 0x0; + } + + mod |= op_type; + tcg_out32(s, op_data << 24 | mod << 20 | off << 12 | rn << 5 | rd); +} + +static inline void tcg_out_movr(TCGContext *s, int ext, TCGReg rd, TCGReg src) +{ + /* register to register move using MOV (shifted register with no shift) */ + /* using MOV 0x2a0003e0 | (shift).. */ + unsigned int base = ext ? 0xaa0003e0 : 0x2a0003e0; + tcg_out32(s, base | src << 16 | rd); +} + +static inline void tcg_out_movi_aux(TCGContext *s, + TCGReg rd, uint64_t value) +{ + uint32_t half, base, shift, movk = 0; + /* construct halfwords of the immediate with MOVZ/MOVK with LSL */ + /* using MOVZ 0x52800000 | extended reg.. */ + base = (value > 0xffffffff) ? 0xd2800000 : 0x52800000; + /* count trailing zeros in 16 bit steps, mapping 64 to 0. Emit the + first MOVZ with the half-word immediate skipping the zeros, with a shift + (LSL) equal to this number. Then morph all next instructions into MOVKs. + Zero the processed half-word in the value, continue until empty. + We build the final result 16bits at a time with up to 4 instructions, + but do not emit instructions for 16bit zero holes. */ + do { + shift = ctz64(value) & (63 & -16); + half = (value >> shift) & 0xffff; + tcg_out32(s, base | movk | shift << 17 | half << 5 | rd); + movk = 0x20000000; /* morph next MOVZs into MOVKs */ + value &= ~(0xffffUL << shift); + } while (value); +} + +static inline void tcg_out_movi(TCGContext *s, TCGType type, + TCGReg rd, tcg_target_long value) +{ + if (type == TCG_TYPE_I64) { + tcg_out_movi_aux(s, rd, value); + } else { + tcg_out_movi_aux(s, rd, value & 0xffffffff); + } +} + +static inline void tcg_out_ldst_r(TCGContext *s, + enum aarch64_ldst_op_data op_data, + enum aarch64_ldst_op_type op_type, + TCGReg rd, TCGReg base, TCGReg regoff) +{ + /* load from memory to register using base + 64bit register offset */ + /* using f.e. STR Wt, [Xn, Xm] 0xb8600800|(regoff << 16)|(base << 5)|rd */ + /* the 0x6000 is for the "no extend field" */ + tcg_out32(s, 0x00206800 + | op_data << 24 | op_type << 20 | regoff << 16 | base << 5 | rd); +} + +/* solve the whole ldst problem */ +static inline void tcg_out_ldst(TCGContext *s, enum aarch64_ldst_op_data data, + enum aarch64_ldst_op_type type, + TCGReg rd, TCGReg rn, tcg_target_long offset) +{ + if (offset >= -256 && offset < 256) { + tcg_out_ldst_9(s, data, type, rd, rn, offset); + } else { + tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, offset); + tcg_out_ldst_r(s, data, type, rd, rn, TCG_REG_TMP); + } +} + +/* mov alias implemented with add immediate, useful to move to/from SP */ +static inline void tcg_out_movr_sp(TCGContext *s, int ext, TCGReg rd, TCGReg rn) +{ + /* using ADD 0x11000000 | (ext) | rn << 5 | rd */ + unsigned int base = ext ? 0x91000000 : 0x11000000; + tcg_out32(s, base | rn << 5 | rd); +} + +static inline void tcg_out_mov(TCGContext *s, + TCGType type, TCGReg ret, TCGReg arg) +{ + if (ret != arg) { + tcg_out_movr(s, type == TCG_TYPE_I64, ret, arg); + } +} + +static inline void tcg_out_ld(TCGContext *s, TCGType type, TCGReg arg, + TCGReg arg1, tcg_target_long arg2) +{ + tcg_out_ldst(s, (type == TCG_TYPE_I64) ? LDST_64 : LDST_32, LDST_LD, + arg, arg1, arg2); +} + +static inline void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, + TCGReg arg1, tcg_target_long arg2) +{ + tcg_out_ldst(s, (type == TCG_TYPE_I64) ? LDST_64 : LDST_32, LDST_ST, + arg, arg1, arg2); +} + +static inline void tcg_out_arith(TCGContext *s, enum aarch64_arith_opc opc, + int ext, TCGReg rd, TCGReg rn, TCGReg rm, + int shift_imm) +{ + /* Using shifted register arithmetic operations */ + /* if extended register operation (64bit) just OR with 0x80 << 24 */ + unsigned int shift, base = ext ? (0x80 | opc) << 24 : opc << 24; + if (shift_imm == 0) { + shift = 0; + } else if (shift_imm > 0) { + shift = shift_imm << 10 | 1 << 22; + } else /* (shift_imm < 0) */ { + shift = (-shift_imm) << 10; + } + tcg_out32(s, base | rm << 16 | shift | rn << 5 | rd); +} + +static inline void tcg_out_mul(TCGContext *s, int ext, + TCGReg rd, TCGReg rn, TCGReg rm) +{ + /* Using MADD 0x1b000000 with Ra = wzr alias MUL 0x1b007c00 */ + unsigned int base = ext ? 0x9b007c00 : 0x1b007c00; + tcg_out32(s, base | rm << 16 | rn << 5 | rd); +} + +static inline void tcg_out_shiftrot_reg(TCGContext *s, + enum aarch64_srr_opc opc, int ext, + TCGReg rd, TCGReg rn, TCGReg rm) +{ + /* using 2-source data processing instructions 0x1ac02000 */ + unsigned int base = ext ? 0x9ac02000 : 0x1ac02000; + tcg_out32(s, base | rm << 16 | opc << 8 | rn << 5 | rd); +} + +static inline void tcg_out_ubfm(TCGContext *s, int ext, TCGReg rd, TCGReg rn, + unsigned int a, unsigned int b) +{ + /* Using UBFM 0x53000000 Wd, Wn, a, b */ + unsigned int base = ext ? 0xd3400000 : 0x53000000; + tcg_out32(s, base | a << 16 | b << 10 | rn << 5 | rd); +} + +static inline void tcg_out_sbfm(TCGContext *s, int ext, TCGReg rd, TCGReg rn, + unsigned int a, unsigned int b) +{ + /* Using SBFM 0x13000000 Wd, Wn, a, b */ + unsigned int base = ext ? 0x93400000 : 0x13000000; + tcg_out32(s, base | a << 16 | b << 10 | rn << 5 | rd); +} + +static inline void tcg_out_extr(TCGContext *s, int ext, TCGReg rd, + TCGReg rn, TCGReg rm, unsigned int a) +{ + /* Using EXTR 0x13800000 Wd, Wn, Wm, a */ + unsigned int base = ext ? 0x93c00000 : 0x13800000; + tcg_out32(s, base | rm << 16 | a << 10 | rn << 5 | rd); +} + +static inline void tcg_out_shl(TCGContext *s, int ext, + TCGReg rd, TCGReg rn, unsigned int m) +{ + int bits, max; + bits = ext ? 64 : 32; + max = bits - 1; + tcg_out_ubfm(s, ext, rd, rn, bits - (m & max), max - (m & max)); +} + +static inline void tcg_out_shr(TCGContext *s, int ext, + TCGReg rd, TCGReg rn, unsigned int m) +{ + int max = ext ? 63 : 31; + tcg_out_ubfm(s, ext, rd, rn, m & max, max); +} + +static inline void tcg_out_sar(TCGContext *s, int ext, + TCGReg rd, TCGReg rn, unsigned int m) +{ + int max = ext ? 63 : 31; + tcg_out_sbfm(s, ext, rd, rn, m & max, max); +} + +static inline void tcg_out_rotr(TCGContext *s, int ext, + TCGReg rd, TCGReg rn, unsigned int m) +{ + int max = ext ? 63 : 31; + tcg_out_extr(s, ext, rd, rn, rn, m & max); +} + +static inline void tcg_out_rotl(TCGContext *s, int ext, + TCGReg rd, TCGReg rn, unsigned int m) +{ + int bits, max; + bits = ext ? 64 : 32; + max = bits - 1; + tcg_out_extr(s, ext, rd, rn, rn, bits - (m & max)); +} + +static inline void tcg_out_cmp(TCGContext *s, int ext, TCGReg rn, TCGReg rm, + int shift_imm) +{ + /* Using CMP alias SUBS wzr, Wn, Wm */ + tcg_out_arith(s, ARITH_SUBS, ext, TCG_REG_XZR, rn, rm, shift_imm); +} + +static inline void tcg_out_cset(TCGContext *s, int ext, TCGReg rd, TCGCond c) +{ + /* Using CSET alias of CSINC 0x1a800400 Xd, XZR, XZR, invert(cond) */ + unsigned int base = ext ? 0x9a9f07e0 : 0x1a9f07e0; + tcg_out32(s, base | tcg_cond_to_aarch64[tcg_invert_cond(c)] << 12 | rd); +} + +static inline void tcg_out_goto(TCGContext *s, tcg_target_long target) +{ + tcg_target_long offset; + offset = (target - (tcg_target_long)s->code_ptr) / 4; + + if (offset < -0x02000000 || offset >= 0x02000000) { + /* out of 26bit range */ + tcg_abort(); + } + + tcg_out32(s, 0x14000000 | (offset & 0x03ffffff)); +} + +static inline void tcg_out_goto_noaddr(TCGContext *s) +{ + /* We pay attention here to not modify the branch target by + reading from the buffer. This ensure that caches and memory are + kept coherent during retranslation. + Mask away possible garbage in the high bits for the first translation, + while keeping the offset bits for retranslation. */ + uint32_t insn; + insn = (tcg_in32(s) & 0x03ffffff) | 0x14000000; + tcg_out32(s, insn); +} + +static inline void tcg_out_goto_cond_noaddr(TCGContext *s, TCGCond c) +{ + /* see comments in tcg_out_goto_noaddr */ + uint32_t insn; + insn = tcg_in32(s) & (0x07ffff << 5); + insn |= 0x54000000 | tcg_cond_to_aarch64[c]; + tcg_out32(s, insn); +} + +static inline void tcg_out_goto_cond(TCGContext *s, TCGCond c, + tcg_target_long target) +{ + tcg_target_long offset; + offset = (target - (tcg_target_long)s->code_ptr) / 4; + + if (offset < -0x40000 || offset >= 0x40000) { + /* out of 19bit range */ + tcg_abort(); + } + + offset &= 0x7ffff; + tcg_out32(s, 0x54000000 | tcg_cond_to_aarch64[c] | offset << 5); +} + +static inline void tcg_out_callr(TCGContext *s, TCGReg reg) +{ + tcg_out32(s, 0xd63f0000 | reg << 5); +} + +static inline void tcg_out_gotor(TCGContext *s, TCGReg reg) +{ + tcg_out32(s, 0xd61f0000 | reg << 5); +} + +static inline void tcg_out_call(TCGContext *s, tcg_target_long target) +{ + tcg_target_long offset; + + offset = (target - (tcg_target_long)s->code_ptr) / 4; + + if (offset < -0x02000000 || offset >= 0x02000000) { /* out of 26bit rng */ + tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, target); + tcg_out_callr(s, TCG_REG_TMP); + } else { + tcg_out32(s, 0x94000000 | (offset & 0x03ffffff)); + } +} + +/* encode a logical immediate, mapping user parameter + M=set bits pattern length to S=M-1 */ +static inline unsigned int +aarch64_limm(unsigned int m, unsigned int r) +{ + assert(m > 0); + return r << 16 | (m - 1) << 10; +} + +/* test a register against an immediate bit pattern made of + M set bits rotated right by R. + Examples: + to test a 32/64 reg against 0x00000007, pass M = 3, R = 0. + to test a 32/64 reg against 0x000000ff, pass M = 8, R = 0. + to test a 32bit reg against 0xff000000, pass M = 8, R = 8. + to test a 32bit reg against 0xff0000ff, pass M = 16, R = 8. + */ +static inline void tcg_out_tst(TCGContext *s, int ext, TCGReg rn, + unsigned int m, unsigned int r) +{ + /* using TST alias of ANDS XZR, Xn,#bimm64 0x7200001f */ + unsigned int base = ext ? 0xf240001f : 0x7200001f; + tcg_out32(s, base | aarch64_limm(m, r) | rn << 5); +} + +/* and a register with a bit pattern, similarly to TST, no flags change */ +static inline void tcg_out_andi(TCGContext *s, int ext, TCGReg rd, TCGReg rn, + unsigned int m, unsigned int r) +{ + /* using AND 0x12000000 */ + unsigned int base = ext ? 0x92400000 : 0x12000000; + tcg_out32(s, base | aarch64_limm(m, r) | rn << 5 | rd); +} + +static inline void tcg_out_ret(TCGContext *s) +{ + /* emit RET { LR } */ + tcg_out32(s, 0xd65f03c0); +} + +void aarch64_tb_set_jmp_target(uintptr_t jmp_addr, uintptr_t addr) +{ + tcg_target_long target, offset; + target = (tcg_target_long)addr; + offset = (target - (tcg_target_long)jmp_addr) / 4; + + if (offset < -0x02000000 || offset >= 0x02000000) { + /* out of 26bit range */ + tcg_abort(); + } + + patch_reloc((uint8_t *)jmp_addr, R_AARCH64_JUMP26, target, 0); + flush_icache_range(jmp_addr, jmp_addr + 4); +} + +static inline void tcg_out_goto_label(TCGContext *s, int label_index) +{ + TCGLabel *l = &s->labels[label_index]; + + if (!l->has_value) { + tcg_out_reloc(s, s->code_ptr, R_AARCH64_JUMP26, label_index, 0); + tcg_out_goto_noaddr(s); + } else { + tcg_out_goto(s, l->u.value); + } +} + +static inline void tcg_out_goto_label_cond(TCGContext *s, + TCGCond c, int label_index) +{ + TCGLabel *l = &s->labels[label_index]; + + if (!l->has_value) { + tcg_out_reloc(s, s->code_ptr, R_AARCH64_CONDBR19, label_index, 0); + tcg_out_goto_cond_noaddr(s, c); + } else { + tcg_out_goto_cond(s, c, l->u.value); + } +} + +static inline void tcg_out_rev(TCGContext *s, int ext, TCGReg rd, TCGReg rm) +{ + /* using REV 0x5ac00800 */ + unsigned int base = ext ? 0xdac00c00 : 0x5ac00800; + tcg_out32(s, base | rm << 5 | rd); +} + +static inline void tcg_out_rev16(TCGContext *s, int ext, TCGReg rd, TCGReg rm) +{ + /* using REV16 0x5ac00400 */ + unsigned int base = ext ? 0xdac00400 : 0x5ac00400; + tcg_out32(s, base | rm << 5 | rd); +} + +static inline void tcg_out_sxt(TCGContext *s, int ext, int s_bits, + TCGReg rd, TCGReg rn) +{ + /* using ALIASes SXTB 0x13001c00, SXTH 0x13003c00, SXTW 0x93407c00 + of SBFM Xd, Xn, #0, #7|15|31 */ + int bits = 8 * (1 << s_bits) - 1; + tcg_out_sbfm(s, ext, rd, rn, 0, bits); +} + +static inline void tcg_out_uxt(TCGContext *s, int s_bits, + TCGReg rd, TCGReg rn) +{ + /* using ALIASes UXTB 0x53001c00, UXTH 0x53003c00 + of UBFM Wd, Wn, #0, #7|15 */ + int bits = 8 * (1 << s_bits) - 1; + tcg_out_ubfm(s, 0, rd, rn, 0, bits); +} + +#ifdef CONFIG_SOFTMMU +#include "exec/softmmu_defs.h" + +/* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr, + int mmu_idx) */ +static const void * const qemu_ld_helpers[4] = { + helper_ldb_mmu, + helper_ldw_mmu, + helper_ldl_mmu, + helper_ldq_mmu, +}; + +/* helper signature: helper_st_mmu(CPUState *env, target_ulong addr, + uintxx_t val, int mmu_idx) */ +static const void * const qemu_st_helpers[4] = { + helper_stb_mmu, + helper_stw_mmu, + helper_stl_mmu, + helper_stq_mmu, +}; + +#else /* !CONFIG_SOFTMMU */ + +static void tcg_out_qemu_ld_direct(TCGContext *s, int opc, TCGReg data_r, + TCGReg addr_r, TCGReg off_r) +{ + switch (opc) { + case 0: + tcg_out_ldst_r(s, LDST_8, LDST_LD, data_r, addr_r, off_r); + break; + case 0 | 4: + tcg_out_ldst_r(s, LDST_8, LDST_LD_S_X, data_r, addr_r, off_r); + break; + case 1: + tcg_out_ldst_r(s, LDST_16, LDST_LD, data_r, addr_r, off_r); + if (TCG_LDST_BSWAP) { + tcg_out_rev16(s, 0, data_r, data_r); + } + break; + case 1 | 4: + if (TCG_LDST_BSWAP) { + tcg_out_ldst_r(s, LDST_16, LDST_LD, data_r, addr_r, off_r); + tcg_out_rev16(s, 0, data_r, data_r); + tcg_out_sxt(s, 1, 1, data_r, data_r); + } else { + tcg_out_ldst_r(s, LDST_16, LDST_LD_S_X, data_r, addr_r, off_r); + } + break; + case 2: + tcg_out_ldst_r(s, LDST_32, LDST_LD, data_r, addr_r, off_r); + if (TCG_LDST_BSWAP) { + tcg_out_rev(s, 0, data_r, data_r); + } + break; + case 2 | 4: + if (TCG_LDST_BSWAP) { + tcg_out_ldst_r(s, LDST_32, LDST_LD, data_r, addr_r, off_r); + tcg_out_rev(s, 0, data_r, data_r); + tcg_out_sxt(s, 1, 2, data_r, data_r); + } else { + tcg_out_ldst_r(s, LDST_32, LDST_LD_S_X, data_r, addr_r, off_r); + } + break; + case 3: + tcg_out_ldst_r(s, LDST_64, LDST_LD, data_r, addr_r, off_r); + if (TCG_LDST_BSWAP) { + tcg_out_rev(s, 1, data_r, data_r); + } + break; + default: + tcg_abort(); + } +} + +static void tcg_out_qemu_st_direct(TCGContext *s, int opc, TCGReg data_r, + TCGReg addr_r, TCGReg off_r) +{ + switch (opc) { + case 0: + tcg_out_ldst_r(s, LDST_8, LDST_ST, data_r, addr_r, off_r); + break; + case 1: + if (TCG_LDST_BSWAP) { + tcg_out_rev16(s, 0, TCG_REG_TMP, data_r); + tcg_out_ldst_r(s, LDST_16, LDST_ST, TCG_REG_TMP, addr_r, off_r); + } else { + tcg_out_ldst_r(s, LDST_16, LDST_ST, data_r, addr_r, off_r); + } + break; + case 2: + if (TCG_LDST_BSWAP) { + tcg_out_rev(s, 0, TCG_REG_TMP, data_r); + tcg_out_ldst_r(s, LDST_32, LDST_ST, TCG_REG_TMP, addr_r, off_r); + } else { + tcg_out_ldst_r(s, LDST_32, LDST_ST, data_r, addr_r, off_r); + } + break; + case 3: + if (TCG_LDST_BSWAP) { + tcg_out_rev(s, 1, TCG_REG_TMP, data_r); + tcg_out_ldst_r(s, LDST_64, LDST_ST, TCG_REG_TMP, addr_r, off_r); + } else { + tcg_out_ldst_r(s, LDST_64, LDST_ST, data_r, addr_r, off_r); + } + break; + default: + tcg_abort(); + } +} +#endif /* CONFIG_SOFTMMU */ + +static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc) +{ + TCGReg addr_reg, data_reg; +#ifdef CONFIG_SOFTMMU + int mem_index, s_bits; +#endif + data_reg = args[0]; + addr_reg = args[1]; + +#ifdef CONFIG_SOFTMMU + mem_index = args[2]; + s_bits = opc & 3; + + /* TODO: insert TLB lookup here */ + + /* all arguments passed via registers */ + tcg_out_movr(s, 1, TCG_REG_X0, TCG_AREG0); + tcg_out_movr(s, (TARGET_LONG_BITS == 64), TCG_REG_X1, addr_reg); + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_X2, mem_index); + tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, + (tcg_target_long)qemu_ld_helpers[s_bits]); + tcg_out_callr(s, TCG_REG_TMP); + + if (opc & 0x04) { /* sign extend */ + tcg_out_sxt(s, 1, s_bits, data_reg, TCG_REG_X0); + } else { + tcg_out_movr(s, 1, data_reg, TCG_REG_X0); + } + +#else /* !CONFIG_SOFTMMU */ + tcg_out_qemu_ld_direct(s, opc, data_reg, addr_reg, + GUEST_BASE ? TCG_REG_GUEST_BASE : TCG_REG_XZR); +#endif /* CONFIG_SOFTMMU */ +} + +static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc) +{ + TCGReg addr_reg, data_reg; +#ifdef CONFIG_SOFTMMU + int mem_index, s_bits; +#endif + data_reg = args[0]; + addr_reg = args[1]; + +#ifdef CONFIG_SOFTMMU + mem_index = args[2]; + s_bits = opc & 3; + + /* TODO: insert TLB lookup here */ + + /* all arguments passed via registers */ + tcg_out_movr(s, 1, TCG_REG_X0, TCG_AREG0); + tcg_out_movr(s, (TARGET_LONG_BITS == 64), TCG_REG_X1, addr_reg); + tcg_out_movr(s, 1, TCG_REG_X2, data_reg); + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_X3, mem_index); + tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, + (tcg_target_long)qemu_st_helpers[s_bits]); + tcg_out_callr(s, TCG_REG_TMP); + +#else /* !CONFIG_SOFTMMU */ + tcg_out_qemu_st_direct(s, opc, data_reg, addr_reg, + GUEST_BASE ? TCG_REG_GUEST_BASE : TCG_REG_XZR); +#endif /* CONFIG_SOFTMMU */ +} + +static uint8_t *tb_ret_addr; + +/* callee stack use example: + stp x29, x30, [sp,#-32]! + mov x29, sp + stp x1, x2, [sp,#16] + ... + ldp x1, x2, [sp,#16] + ldp x29, x30, [sp],#32 + ret +*/ + +/* push r1 and r2, and alloc stack space for a total of + alloc_n elements (1 element=16 bytes, must be between 1 and 31. */ +static inline void tcg_out_push_pair(TCGContext *s, TCGReg addr, + TCGReg r1, TCGReg r2, int alloc_n) +{ + /* using indexed scaled simm7 STP 0x28800000 | (ext) | 0x01000000 (pre-idx) + | alloc_n * (-1) << 16 | r2 << 10 | addr << 5 | r1 */ + assert(alloc_n > 0 && alloc_n < 0x20); + alloc_n = (-alloc_n) & 0x3f; + tcg_out32(s, 0xa9800000 | alloc_n << 16 | r2 << 10 | addr << 5 | r1); +} + +/* dealloc stack space for a total of alloc_n elements and pop r1, r2. */ +static inline void tcg_out_pop_pair(TCGContext *s, TCGReg addr, + TCGReg r1, TCGReg r2, int alloc_n) +{ + /* using indexed scaled simm7 LDP 0x28c00000 | (ext) | nothing (post-idx) + | alloc_n << 16 | r2 << 10 | addr << 5 | r1 */ + assert(alloc_n > 0 && alloc_n < 0x20); + tcg_out32(s, 0xa8c00000 | alloc_n << 16 | r2 << 10 | addr << 5 | r1); +} + +static inline void tcg_out_store_pair(TCGContext *s, TCGReg addr, + TCGReg r1, TCGReg r2, int idx) +{ + /* using register pair offset simm7 STP 0x29000000 | (ext) + | idx << 16 | r2 << 10 | addr << 5 | r1 */ + assert(idx > 0 && idx < 0x20); + tcg_out32(s, 0xa9000000 | idx << 16 | r2 << 10 | addr << 5 | r1); +} + +static inline void tcg_out_load_pair(TCGContext *s, TCGReg addr, + TCGReg r1, TCGReg r2, int idx) +{ + /* using register pair offset simm7 LDP 0x29400000 | (ext) + | idx << 16 | r2 << 10 | addr << 5 | r1 */ + assert(idx > 0 && idx < 0x20); + tcg_out32(s, 0xa9400000 | idx << 16 | r2 << 10 | addr << 5 | r1); +} + +static void tcg_out_op(TCGContext *s, TCGOpcode opc, + const TCGArg *args, const int *const_args) +{ + /* ext will be set in the switch below, which will fall through to the + common code. It triggers the use of extended regs where appropriate. */ + int ext = 0; + + switch (opc) { + case INDEX_op_exit_tb: + tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_X0, args[0]); + tcg_out_goto(s, (tcg_target_long)tb_ret_addr); + break; + + case INDEX_op_goto_tb: +#ifndef USE_DIRECT_JUMP +#error "USE_DIRECT_JUMP required for aarch64" +#endif + assert(s->tb_jmp_offset != NULL); /* consistency for USE_DIRECT_JUMP */ + s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; + /* actual branch destination will be patched by + aarch64_tb_set_jmp_target later, beware retranslation. */ + tcg_out_goto_noaddr(s); + s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf; + break; + + case INDEX_op_call: + if (const_args[0]) { + tcg_out_call(s, args[0]); + } else { + tcg_out_callr(s, args[0]); + } + break; + + case INDEX_op_br: + tcg_out_goto_label(s, args[0]); + break; + + case INDEX_op_ld_i32: + case INDEX_op_ld_i64: + case INDEX_op_st_i32: + case INDEX_op_st_i64: + case INDEX_op_ld8u_i32: + case INDEX_op_ld8s_i32: + case INDEX_op_ld16u_i32: + case INDEX_op_ld16s_i32: + case INDEX_op_ld8u_i64: + case INDEX_op_ld8s_i64: + case INDEX_op_ld16u_i64: + case INDEX_op_ld16s_i64: + case INDEX_op_ld32u_i64: + case INDEX_op_ld32s_i64: + case INDEX_op_st8_i32: + case INDEX_op_st8_i64: + case INDEX_op_st16_i32: + case INDEX_op_st16_i64: + case INDEX_op_st32_i64: + tcg_out_ldst(s, aarch64_ldst_get_data(opc), aarch64_ldst_get_type(opc), + args[0], args[1], args[2]); + break; + + case INDEX_op_mov_i64: + ext = 1; /* fall through */ + case INDEX_op_mov_i32: + tcg_out_movr(s, ext, args[0], args[1]); + break; + + case INDEX_op_movi_i64: + tcg_out_movi(s, TCG_TYPE_I64, args[0], args[1]); + break; + case INDEX_op_movi_i32: + tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]); + break; + + case INDEX_op_add_i64: + ext = 1; /* fall through */ + case INDEX_op_add_i32: + tcg_out_arith(s, ARITH_ADD, ext, args[0], args[1], args[2], 0); + break; + + case INDEX_op_sub_i64: + ext = 1; /* fall through */ + case INDEX_op_sub_i32: + tcg_out_arith(s, ARITH_SUB, ext, args[0], args[1], args[2], 0); + break; + + case INDEX_op_and_i64: + ext = 1; /* fall through */ + case INDEX_op_and_i32: + tcg_out_arith(s, ARITH_AND, ext, args[0], args[1], args[2], 0); + break; + + case INDEX_op_or_i64: + ext = 1; /* fall through */ + case INDEX_op_or_i32: + tcg_out_arith(s, ARITH_OR, ext, args[0], args[1], args[2], 0); + break; + + case INDEX_op_xor_i64: + ext = 1; /* fall through */ + case INDEX_op_xor_i32: + tcg_out_arith(s, ARITH_XOR, ext, args[0], args[1], args[2], 0); + break; + + case INDEX_op_mul_i64: + ext = 1; /* fall through */ + case INDEX_op_mul_i32: + tcg_out_mul(s, ext, args[0], args[1], args[2]); + break; + + case INDEX_op_shl_i64: + ext = 1; /* fall through */ + case INDEX_op_shl_i32: + if (const_args[2]) { /* LSL / UBFM Wd, Wn, (32 - m) */ + tcg_out_shl(s, ext, args[0], args[1], args[2]); + } else { /* LSL / LSLV */ + tcg_out_shiftrot_reg(s, SRR_SHL, ext, args[0], args[1], args[2]); + } + break; + + case INDEX_op_shr_i64: + ext = 1; /* fall through */ + case INDEX_op_shr_i32: + if (const_args[2]) { /* LSR / UBFM Wd, Wn, m, 31 */ + tcg_out_shr(s, ext, args[0], args[1], args[2]); + } else { /* LSR / LSRV */ + tcg_out_shiftrot_reg(s, SRR_SHR, ext, args[0], args[1], args[2]); + } + break; + + case INDEX_op_sar_i64: + ext = 1; /* fall through */ + case INDEX_op_sar_i32: + if (const_args[2]) { /* ASR / SBFM Wd, Wn, m, 31 */ + tcg_out_sar(s, ext, args[0], args[1], args[2]); + } else { /* ASR / ASRV */ + tcg_out_shiftrot_reg(s, SRR_SAR, ext, args[0], args[1], args[2]); + } + break; + + case INDEX_op_rotr_i64: + ext = 1; /* fall through */ + case INDEX_op_rotr_i32: + if (const_args[2]) { /* ROR / EXTR Wd, Wm, Wm, m */ + tcg_out_rotr(s, ext, args[0], args[1], args[2]); + } else { /* ROR / RORV */ + tcg_out_shiftrot_reg(s, SRR_ROR, ext, args[0], args[1], args[2]); + } + break; + + case INDEX_op_rotl_i64: + ext = 1; /* fall through */ + case INDEX_op_rotl_i32: /* same as rotate right by (32 - m) */ + if (const_args[2]) { /* ROR / EXTR Wd, Wm, Wm, 32 - m */ + tcg_out_rotl(s, ext, args[0], args[1], args[2]); + } else { + tcg_out_arith(s, ARITH_SUB, 0, + TCG_REG_TMP, TCG_REG_XZR, args[2], 0); + tcg_out_shiftrot_reg(s, SRR_ROR, ext, + args[0], args[1], TCG_REG_TMP); + } + break; + + case INDEX_op_brcond_i64: + ext = 1; /* fall through */ + case INDEX_op_brcond_i32: /* CMP 0, 1, cond(2), label 3 */ + tcg_out_cmp(s, ext, args[0], args[1], 0); + tcg_out_goto_label_cond(s, args[2], args[3]); + break; + + case INDEX_op_setcond_i64: + ext = 1; /* fall through */ + case INDEX_op_setcond_i32: + tcg_out_cmp(s, ext, args[1], args[2], 0); + tcg_out_cset(s, 0, args[0], args[3]); + break; + + case INDEX_op_qemu_ld8u: + tcg_out_qemu_ld(s, args, 0 | 0); + break; + case INDEX_op_qemu_ld8s: + tcg_out_qemu_ld(s, args, 4 | 0); + break; + case INDEX_op_qemu_ld16u: + tcg_out_qemu_ld(s, args, 0 | 1); + break; + case INDEX_op_qemu_ld16s: + tcg_out_qemu_ld(s, args, 4 | 1); + break; + case INDEX_op_qemu_ld32u: + tcg_out_qemu_ld(s, args, 0 | 2); + break; + case INDEX_op_qemu_ld32s: + tcg_out_qemu_ld(s, args, 4 | 2); + break; + case INDEX_op_qemu_ld32: + tcg_out_qemu_ld(s, args, 0 | 2); + break; + case INDEX_op_qemu_ld64: + tcg_out_qemu_ld(s, args, 0 | 3); + break; + case INDEX_op_qemu_st8: + tcg_out_qemu_st(s, args, 0); + break; + case INDEX_op_qemu_st16: + tcg_out_qemu_st(s, args, 1); + break; + case INDEX_op_qemu_st32: + tcg_out_qemu_st(s, args, 2); + break; + case INDEX_op_qemu_st64: + tcg_out_qemu_st(s, args, 3); + break; + + case INDEX_op_bswap64_i64: + ext = 1; /* fall through */ + case INDEX_op_bswap32_i64: + case INDEX_op_bswap32_i32: + tcg_out_rev(s, ext, args[0], args[1]); + break; + case INDEX_op_bswap16_i64: + case INDEX_op_bswap16_i32: + tcg_out_rev16(s, 0, args[0], args[1]); + break; + + case INDEX_op_ext8s_i64: + ext = 1; /* fall through */ + case INDEX_op_ext8s_i32: + tcg_out_sxt(s, ext, 0, args[0], args[1]); + break; + case INDEX_op_ext16s_i64: + ext = 1; /* fall through */ + case INDEX_op_ext16s_i32: + tcg_out_sxt(s, ext, 1, args[0], args[1]); + break; + case INDEX_op_ext32s_i64: + tcg_out_sxt(s, 1, 2, args[0], args[1]); + break; + case INDEX_op_ext8u_i64: + case INDEX_op_ext8u_i32: + tcg_out_uxt(s, 0, args[0], args[1]); + break; + case INDEX_op_ext16u_i64: + case INDEX_op_ext16u_i32: + tcg_out_uxt(s, 1, args[0], args[1]); + break; + case INDEX_op_ext32u_i64: + tcg_out_movr(s, 0, args[0], args[1]); + break; + + default: + tcg_abort(); /* opcode not implemented */ + } +} + +static const TCGTargetOpDef aarch64_op_defs[] = { + { INDEX_op_exit_tb, { } }, + { INDEX_op_goto_tb, { } }, + { INDEX_op_call, { "ri" } }, + { INDEX_op_br, { } }, + + { INDEX_op_mov_i32, { "r", "r" } }, + { INDEX_op_mov_i64, { "r", "r" } }, + + { INDEX_op_movi_i32, { "r" } }, + { INDEX_op_movi_i64, { "r" } }, + + { INDEX_op_ld8u_i32, { "r", "r" } }, + { INDEX_op_ld8s_i32, { "r", "r" } }, + { INDEX_op_ld16u_i32, { "r", "r" } }, + { INDEX_op_ld16s_i32, { "r", "r" } }, + { INDEX_op_ld_i32, { "r", "r" } }, + { INDEX_op_ld8u_i64, { "r", "r" } }, + { INDEX_op_ld8s_i64, { "r", "r" } }, + { INDEX_op_ld16u_i64, { "r", "r" } }, + { INDEX_op_ld16s_i64, { "r", "r" } }, + { INDEX_op_ld32u_i64, { "r", "r" } }, + { INDEX_op_ld32s_i64, { "r", "r" } }, + { INDEX_op_ld_i64, { "r", "r" } }, + + { INDEX_op_st8_i32, { "r", "r" } }, + { INDEX_op_st16_i32, { "r", "r" } }, + { INDEX_op_st_i32, { "r", "r" } }, + { INDEX_op_st8_i64, { "r", "r" } }, + { INDEX_op_st16_i64, { "r", "r" } }, + { INDEX_op_st32_i64, { "r", "r" } }, + { INDEX_op_st_i64, { "r", "r" } }, + + { INDEX_op_add_i32, { "r", "r", "r" } }, + { INDEX_op_add_i64, { "r", "r", "r" } }, + { INDEX_op_sub_i32, { "r", "r", "r" } }, + { INDEX_op_sub_i64, { "r", "r", "r" } }, + { INDEX_op_mul_i32, { "r", "r", "r" } }, + { INDEX_op_mul_i64, { "r", "r", "r" } }, + { INDEX_op_and_i32, { "r", "r", "r" } }, + { INDEX_op_and_i64, { "r", "r", "r" } }, + { INDEX_op_or_i32, { "r", "r", "r" } }, + { INDEX_op_or_i64, { "r", "r", "r" } }, + { INDEX_op_xor_i32, { "r", "r", "r" } }, + { INDEX_op_xor_i64, { "r", "r", "r" } }, + + { INDEX_op_shl_i32, { "r", "r", "ri" } }, + { INDEX_op_shr_i32, { "r", "r", "ri" } }, + { INDEX_op_sar_i32, { "r", "r", "ri" } }, + { INDEX_op_rotl_i32, { "r", "r", "ri" } }, + { INDEX_op_rotr_i32, { "r", "r", "ri" } }, + { INDEX_op_shl_i64, { "r", "r", "ri" } }, + { INDEX_op_shr_i64, { "r", "r", "ri" } }, + { INDEX_op_sar_i64, { "r", "r", "ri" } }, + { INDEX_op_rotl_i64, { "r", "r", "ri" } }, + { INDEX_op_rotr_i64, { "r", "r", "ri" } }, + + { INDEX_op_brcond_i32, { "r", "r" } }, + { INDEX_op_setcond_i32, { "r", "r", "r" } }, + { INDEX_op_brcond_i64, { "r", "r" } }, + { INDEX_op_setcond_i64, { "r", "r", "r" } }, + + { INDEX_op_qemu_ld8u, { "r", "l" } }, + { INDEX_op_qemu_ld8s, { "r", "l" } }, + { INDEX_op_qemu_ld16u, { "r", "l" } }, + { INDEX_op_qemu_ld16s, { "r", "l" } }, + { INDEX_op_qemu_ld32u, { "r", "l" } }, + { INDEX_op_qemu_ld32s, { "r", "l" } }, + + { INDEX_op_qemu_ld32, { "r", "l" } }, + { INDEX_op_qemu_ld64, { "r", "l" } }, + + { INDEX_op_qemu_st8, { "l", "l" } }, + { INDEX_op_qemu_st16, { "l", "l" } }, + { INDEX_op_qemu_st32, { "l", "l" } }, + { INDEX_op_qemu_st64, { "l", "l" } }, + + { INDEX_op_bswap16_i32, { "r", "r" } }, + { INDEX_op_bswap32_i32, { "r", "r" } }, + { INDEX_op_bswap16_i64, { "r", "r" } }, + { INDEX_op_bswap32_i64, { "r", "r" } }, + { INDEX_op_bswap64_i64, { "r", "r" } }, + + { INDEX_op_ext8s_i32, { "r", "r" } }, + { INDEX_op_ext16s_i32, { "r", "r" } }, + { INDEX_op_ext8u_i32, { "r", "r" } }, + { INDEX_op_ext16u_i32, { "r", "r" } }, + + { INDEX_op_ext8s_i64, { "r", "r" } }, + { INDEX_op_ext16s_i64, { "r", "r" } }, + { INDEX_op_ext32s_i64, { "r", "r" } }, + { INDEX_op_ext8u_i64, { "r", "r" } }, + { INDEX_op_ext16u_i64, { "r", "r" } }, + { INDEX_op_ext32u_i64, { "r", "r" } }, + + { -1 }, +}; + +static void tcg_target_init(TCGContext *s) +{ +#if !defined(CONFIG_USER_ONLY) + /* fail safe */ + if ((1ULL << CPU_TLB_ENTRY_BITS) != sizeof(CPUTLBEntry)) { + tcg_abort(); + } +#endif + tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff); + tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I64], 0, 0xffffffff); + + tcg_regset_set32(tcg_target_call_clobber_regs, 0, + (1 << TCG_REG_X0) | (1 << TCG_REG_X1) | + (1 << TCG_REG_X2) | (1 << TCG_REG_X3) | + (1 << TCG_REG_X4) | (1 << TCG_REG_X5) | + (1 << TCG_REG_X6) | (1 << TCG_REG_X7) | + (1 << TCG_REG_X8) | (1 << TCG_REG_X9) | + (1 << TCG_REG_X10) | (1 << TCG_REG_X11) | + (1 << TCG_REG_X12) | (1 << TCG_REG_X13) | + (1 << TCG_REG_X14) | (1 << TCG_REG_X15) | + (1 << TCG_REG_X16) | (1 << TCG_REG_X17) | + (1 << TCG_REG_X18)); + + tcg_regset_clear(s->reserved_regs); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_SP); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_FP); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_TMP); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_X18); /* platform register */ + + tcg_add_target_add_op_defs(aarch64_op_defs); +} + +static inline void tcg_out_addi(TCGContext *s, int ext, + TCGReg rd, TCGReg rn, unsigned int aimm) +{ + /* add immediate aimm unsigned 12bit value (we use LSL 0 - no shift) */ + /* using ADD 0x11000000 | (ext) | (aimm << 10) | (rn << 5) | rd */ + unsigned int base = ext ? 0x91000000 : 0x11000000; + assert(aimm <= 0xfff); + tcg_out32(s, base | (aimm << 10) | (rn << 5) | rd); +} + +static inline void tcg_out_subi(TCGContext *s, int ext, + TCGReg rd, TCGReg rn, unsigned int aimm) +{ + /* sub immediate aimm unsigned 12bit value (we use LSL 0 - no shift) */ + /* using SUB 0x51000000 | (ext) | (aimm << 10) | (rn << 5) | rd */ + unsigned int base = ext ? 0xd1000000 : 0x51000000; + assert(aimm <= 0xfff); + tcg_out32(s, base | (aimm << 10) | (rn << 5) | rd); +} + +static void tcg_target_qemu_prologue(TCGContext *s) +{ + /* NB: frame sizes are in 16 byte stack units! */ + int frame_size_callee_saved, frame_size_tcg_locals; + TCGReg r; + + /* save pairs (FP, LR) and (X19, X20) .. (X27, X28) */ + frame_size_callee_saved = (1) + (TCG_REG_X28 - TCG_REG_X19) / 2 + 1; + + /* frame size requirement for TCG local variables */ + frame_size_tcg_locals = TCG_STATIC_CALL_ARGS_SIZE + + CPU_TEMP_BUF_NLONGS * sizeof(long) + + (TCG_TARGET_STACK_ALIGN - 1); + frame_size_tcg_locals &= ~(TCG_TARGET_STACK_ALIGN - 1); + frame_size_tcg_locals /= TCG_TARGET_STACK_ALIGN; + + /* push (FP, LR) and update sp */ + tcg_out_push_pair(s, TCG_REG_SP, + TCG_REG_FP, TCG_REG_LR, frame_size_callee_saved); + + /* FP -> callee_saved */ + tcg_out_movr_sp(s, 1, TCG_REG_FP, TCG_REG_SP); + + /* store callee-preserved regs x19..x28 using FP -> callee_saved */ + for (r = TCG_REG_X19; r <= TCG_REG_X27; r += 2) { + int idx = (r - TCG_REG_X19) / 2 + 1; + tcg_out_store_pair(s, TCG_REG_FP, r, r + 1, idx); + } + + /* make stack space for TCG locals */ + tcg_out_subi(s, 1, TCG_REG_SP, TCG_REG_SP, + frame_size_tcg_locals * TCG_TARGET_STACK_ALIGN); + /* inform TCG about how to find TCG locals with register, offset, size */ + tcg_set_frame(s, TCG_REG_SP, TCG_STATIC_CALL_ARGS_SIZE, + CPU_TEMP_BUF_NLONGS * sizeof(long)); + +#if defined(CONFIG_USE_GUEST_BASE) + if (GUEST_BASE) { + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_GUEST_BASE, GUEST_BASE); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_GUEST_BASE); + } +#endif + + tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]); + tcg_out_gotor(s, tcg_target_call_iarg_regs[1]); + + tb_ret_addr = s->code_ptr; + + /* remove TCG locals stack space */ + tcg_out_addi(s, 1, TCG_REG_SP, TCG_REG_SP, + frame_size_tcg_locals * TCG_TARGET_STACK_ALIGN); + + /* restore registers x19..x28. + FP must be preserved, so it still points to callee_saved area */ + for (r = TCG_REG_X19; r <= TCG_REG_X27; r += 2) { + int idx = (r - TCG_REG_X19) / 2 + 1; + tcg_out_load_pair(s, TCG_REG_FP, r, r + 1, idx); + } + + /* pop (FP, LR), restore SP to previous frame, return */ + tcg_out_pop_pair(s, TCG_REG_SP, + TCG_REG_FP, TCG_REG_LR, frame_size_callee_saved); + tcg_out_ret(s); +} diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h new file mode 100644 index 0000000..97e4a5b --- /dev/null +++ b/tcg/aarch64/tcg-target.h @@ -0,0 +1,99 @@ +/* + * Initial TCG Implementation for aarch64 + * + * Copyright (c) 2013 Huawei Technologies Duesseldorf GmbH + * Written by Claudio Fontana + * + * 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 for details. + */ + +#ifndef TCG_TARGET_AARCH64 +#define TCG_TARGET_AARCH64 1 + +#undef TCG_TARGET_WORDS_BIGENDIAN +#undef TCG_TARGET_STACK_GROWSUP + +typedef enum { + TCG_REG_X0, TCG_REG_X1, TCG_REG_X2, TCG_REG_X3, TCG_REG_X4, + TCG_REG_X5, TCG_REG_X6, TCG_REG_X7, TCG_REG_X8, TCG_REG_X9, + TCG_REG_X10, TCG_REG_X11, TCG_REG_X12, TCG_REG_X13, TCG_REG_X14, + TCG_REG_X15, TCG_REG_X16, TCG_REG_X17, TCG_REG_X18, TCG_REG_X19, + TCG_REG_X20, TCG_REG_X21, TCG_REG_X22, TCG_REG_X23, TCG_REG_X24, + TCG_REG_X25, TCG_REG_X26, TCG_REG_X27, TCG_REG_X28, + TCG_REG_FP, /* frame pointer */ + TCG_REG_LR, /* link register */ + TCG_REG_SP, /* stack pointer or zero register */ + TCG_REG_XZR = TCG_REG_SP /* same register number */ + /* program counter is not directly accessible! */ +} TCGReg; + +#define TCG_TARGET_NB_REGS 32 + +/* used for function call generation */ +#define TCG_REG_CALL_STACK TCG_REG_SP +#define TCG_TARGET_STACK_ALIGN 16 +#define TCG_TARGET_CALL_ALIGN_ARGS 1 +#define TCG_TARGET_CALL_STACK_OFFSET 0 + +/* optional instructions */ +#define TCG_TARGET_HAS_div_i32 0 +#define TCG_TARGET_HAS_ext8s_i32 1 +#define TCG_TARGET_HAS_ext16s_i32 1 +#define TCG_TARGET_HAS_ext8u_i32 1 +#define TCG_TARGET_HAS_ext16u_i32 1 +#define TCG_TARGET_HAS_bswap16_i32 1 +#define TCG_TARGET_HAS_bswap32_i32 1 +#define TCG_TARGET_HAS_not_i32 0 +#define TCG_TARGET_HAS_neg_i32 0 +#define TCG_TARGET_HAS_rot_i32 1 +#define TCG_TARGET_HAS_andc_i32 0 +#define TCG_TARGET_HAS_orc_i32 0 +#define TCG_TARGET_HAS_eqv_i32 0 +#define TCG_TARGET_HAS_nand_i32 0 +#define TCG_TARGET_HAS_nor_i32 0 +#define TCG_TARGET_HAS_deposit_i32 0 +#define TCG_TARGET_HAS_movcond_i32 0 +#define TCG_TARGET_HAS_add2_i32 0 +#define TCG_TARGET_HAS_sub2_i32 0 +#define TCG_TARGET_HAS_mulu2_i32 0 +#define TCG_TARGET_HAS_muls2_i32 0 + +#define TCG_TARGET_HAS_div_i64 0 +#define TCG_TARGET_HAS_ext8s_i64 1 +#define TCG_TARGET_HAS_ext16s_i64 1 +#define TCG_TARGET_HAS_ext32s_i64 1 +#define TCG_TARGET_HAS_ext8u_i64 1 +#define TCG_TARGET_HAS_ext16u_i64 1 +#define TCG_TARGET_HAS_ext32u_i64 1 +#define TCG_TARGET_HAS_bswap16_i64 1 +#define TCG_TARGET_HAS_bswap32_i64 1 +#define TCG_TARGET_HAS_bswap64_i64 1 +#define TCG_TARGET_HAS_not_i64 0 +#define TCG_TARGET_HAS_neg_i64 0 +#define TCG_TARGET_HAS_rot_i64 1 +#define TCG_TARGET_HAS_andc_i64 0 +#define TCG_TARGET_HAS_orc_i64 0 +#define TCG_TARGET_HAS_eqv_i64 0 +#define TCG_TARGET_HAS_nand_i64 0 +#define TCG_TARGET_HAS_nor_i64 0 +#define TCG_TARGET_HAS_deposit_i64 0 +#define TCG_TARGET_HAS_movcond_i64 0 +#define TCG_TARGET_HAS_add2_i64 0 +#define TCG_TARGET_HAS_sub2_i64 0 +#define TCG_TARGET_HAS_mulu2_i64 0 +#define TCG_TARGET_HAS_muls2_i64 0 + +enum { + TCG_AREG0 = TCG_REG_X19, +}; + +static inline void flush_icache_range(tcg_target_ulong start, + tcg_target_ulong stop) +{ + __builtin___clear_cache((char *)start, (char *)stop); +} + +#endif /* TCG_TARGET_AARCH64 */ diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.c index 3d43412..6be736b 100644 --- a/tcg/arm/tcg-target.c +++ b/tcg/arm/tcg-target.c @@ -2053,12 +2053,6 @@ static const TCGTargetOpDef arm_op_defs[] = { static void tcg_target_init(TCGContext *s) { -#if !defined(CONFIG_USER_ONLY) - /* fail safe */ - if ((1 << CPU_TLB_ENTRY_BITS) != sizeof(CPUTLBEntry)) - tcg_abort(); -#endif - tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffff); tcg_regset_set32(tcg_target_call_clobber_regs, 0, (1 << TCG_REG_R0) | diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c index 9eec06c..9e95477 100644 --- a/tcg/i386/tcg-target.c +++ b/tcg/i386/tcg-target.c @@ -2283,12 +2283,6 @@ static void tcg_target_init(TCGContext *s) } #endif -#if !defined(CONFIG_USER_ONLY) - /* fail safe */ - if ((1 << CPU_TLB_ENTRY_BITS) != sizeof(CPUTLBEntry)) - tcg_abort(); -#endif - if (TCG_TARGET_REG_BITS == 64) { tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffff); tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I64], 0, 0xffff); diff --git a/tcg/s390/tcg-target.c b/tcg/s390/tcg-target.c index 7d6f777..f229f1c 100644 --- a/tcg/s390/tcg-target.c +++ b/tcg/s390/tcg-target.c @@ -2324,13 +2324,6 @@ static void query_facilities(void) static void tcg_target_init(TCGContext *s) { -#if !defined(CONFIG_USER_ONLY) - /* fail safe */ - if ((1 << CPU_TLB_ENTRY_BITS) != sizeof(CPUTLBEntry)) { - tcg_abort(); - } -#endif - query_facilities(); tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffff); diff --git a/tests/ide-test.c b/tests/ide-test.c index 365e995..7e2eb94 100644 --- a/tests/ide-test.c +++ b/tests/ide-test.c @@ -64,6 +64,7 @@ enum { }; enum { + DEV = 0x10, LBA = 0x40, }; @@ -76,6 +77,7 @@ enum { enum { CMD_READ_DMA = 0xc8, CMD_WRITE_DMA = 0xca, + CMD_FLUSH_CACHE = 0xe7, CMD_IDENTIFY = 0xec, CMDF_ABORT = 0x100, @@ -394,7 +396,7 @@ static void test_identify(void) /* Read in the IDENTIFY buffer and check registers */ data = inb(IDE_BASE + reg_device); - g_assert_cmpint(data & 0x10, ==, 0); + g_assert_cmpint(data & DEV, ==, 0); for (i = 0; i < 256; i++) { data = inb(IDE_BASE + reg_status); @@ -423,6 +425,46 @@ static void test_identify(void) ide_test_quit(); } +static void test_flush(void) +{ + uint8_t data; + + ide_test_start( + "-vnc none " + "-drive file=blkdebug::%s,if=ide,cache=writeback", + tmp_path); + + /* Delay the completion of the flush request until we explicitly do it */ + qmp("{'execute':'human-monitor-command', 'arguments': { " + "'command-line': 'qemu-io ide0-hd0 \"break flush_to_os A\"'} }"); + + /* FLUSH CACHE command on device 0*/ + outb(IDE_BASE + reg_device, 0); + outb(IDE_BASE + reg_command, CMD_FLUSH_CACHE); + + /* Check status while request is in flight*/ + data = inb(IDE_BASE + reg_status); + assert_bit_set(data, BSY | DRDY); + assert_bit_clear(data, DF | ERR | DRQ); + + /* Complete the command */ + qmp("{'execute':'human-monitor-command', 'arguments': { " + "'command-line': 'qemu-io ide0-hd0 \"resume A\"'} }"); + + /* Check registers */ + data = inb(IDE_BASE + reg_device); + g_assert_cmpint(data & DEV, ==, 0); + + do { + data = inb(IDE_BASE + reg_status); + } while (data & BSY); + + assert_bit_set(data, DRDY); + assert_bit_clear(data, BSY | DF | ERR | DRQ); + + ide_test_quit(); +} + int main(int argc, char **argv) { const char *arch = qtest_get_arch(); @@ -453,6 +495,8 @@ int main(int argc, char **argv) qtest_add_func("/ide/bmdma/long_prdt", test_bmdma_long_prdt); qtest_add_func("/ide/bmdma/teardown", test_bmdma_teardown); + qtest_add_func("/ide/flush", test_flush); + ret = g_test_run(); /* Cleanup */ diff --git a/tests/qemu-iotests/049.out b/tests/qemu-iotests/049.out index 72db13f..d2f0efe 100644 --- a/tests/qemu-iotests/049.out +++ b/tests/qemu-iotests/049.out @@ -108,15 +108,15 @@ qemu-img: Formatting or formatting option not supported for file format 'qcow2' Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=-1024 encryption=off cluster_size=65536 lazy_refcounts=off qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- 1kilobyte -qemu-img: Invalid image size specified! You may use k, M, G or T suffixes for -qemu-img: kilobytes, megabytes, gigabytes and terabytes. +qemu-img: Invalid image size specified! You may use k, M, G, T, P or E suffixes for +qemu-img: kilobytes, megabytes, gigabytes, terabytes, petabytes and exabytes. qemu-img create -f qcow2 -o size=1kilobyte TEST_DIR/t.qcow2 Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- foobar -qemu-img: Invalid image size specified! You may use k, M, G or T suffixes for -qemu-img: kilobytes, megabytes, gigabytes and terabytes. +qemu-img: Invalid image size specified! You may use k, M, G, T, P or E suffixes for +qemu-img: kilobytes, megabytes, gigabytes, terabytes, petabytes and exabytes. qemu-img create -f qcow2 -o size=foobar TEST_DIR/t.qcow2 qemu-img: Parameter 'size' expects a size diff --git a/translate-all.c b/translate-all.c index 40b8f3d..df7c697 100644 --- a/translate-all.c +++ b/translate-all.c @@ -460,6 +460,8 @@ static inline PageDesc *page_find(tb_page_addr_t index) # define MAX_CODE_GEN_BUFFER_SIZE (2ul * 1024 * 1024 * 1024) #elif defined(__sparc__) # define MAX_CODE_GEN_BUFFER_SIZE (2ul * 1024 * 1024 * 1024) +#elif defined(__aarch64__) +# define MAX_CODE_GEN_BUFFER_SIZE (128ul * 1024 * 1024) #elif defined(__arm__) # define MAX_CODE_GEN_BUFFER_SIZE (16u * 1024 * 1024) #elif defined(__s390x__) diff --git a/ui/console.c b/ui/console.c index b30853f..28bba6d 100644 --- a/ui/console.c +++ b/ui/console.c @@ -1788,6 +1788,10 @@ static CharDriverState *text_console_init(ChardevVC *vc) s->chr = chr; chr->opaque = s; chr->chr_set_echo = text_console_set_echo; + /* console/chardev init sometimes completes elsewhere in a 2nd + * stage, so defer OPENED events until they are fully initialized + */ + chr->explicit_be_open = true; if (display_state) { text_console_do_init(chr, display_state); @@ -1119,6 +1119,8 @@ static CharDriverState *gd_vc_handler(ChardevVC *unused) chr = g_malloc0(sizeof(*chr)); chr->chr_write = gd_vc_chr_write; + /* defer OPENED events until our vc is fully initialized */ + chr->explicit_be_open = true; vcs[nb_vcs++] = chr; @@ -1158,8 +1160,7 @@ static GSList *gd_vc_init(GtkDisplayState *s, VirtualConsole *vc, int index, GSL GIOChannel *chan; GtkWidget *scrolled_window; GtkAdjustment *vadjustment; - int master_fd, slave_fd, ret; - struct termios tty; + int master_fd, slave_fd; snprintf(buffer, sizeof(buffer), "vc%d", index); snprintf(path, sizeof(path), "<QEMU>/View/VC%d", index); @@ -1179,13 +1180,8 @@ static GSList *gd_vc_init(GtkDisplayState *s, VirtualConsole *vc, int index, GSL vc->terminal = vte_terminal_new(); - ret = openpty(&master_fd, &slave_fd, NULL, NULL, NULL); - g_assert(ret != -1); - - /* Set raw attributes on the pty. */ - tcgetattr(slave_fd, &tty); - cfmakeraw(&tty); - tcsetattr(slave_fd, TCSAFLUSH, &tty); + master_fd = qemu_openpty_raw(&slave_fd, NULL); + g_assert(master_fd != -1); #if VTE_CHECK_VERSION(0, 26, 0) pty = vte_pty_new_foreign(master_fd, NULL); @@ -1433,7 +1429,7 @@ static const DisplayChangeListenerOps dcl_ops = { .dpy_cursor_define = gd_cursor_define, }; -void gtk_display_init(DisplayState *ds) +void gtk_display_init(DisplayState *ds, bool full_screen) { GtkDisplayState *s = g_malloc0(sizeof(*s)); char *filename; @@ -1469,7 +1465,7 @@ void gtk_display_init(DisplayState *ds) gtk_notebook_append_page(GTK_NOTEBOOK(s->notebook), s->drawing_area, gtk_label_new("VGA")); - filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "qemu-icon.bmp"); + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "qemu_logo_no_text.svg"); if (filename) { GError *error = NULL; GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(filename, &error); @@ -1509,6 +1505,10 @@ void gtk_display_init(DisplayState *ds) gtk_widget_show_all(s->window); + if (full_screen) { + gtk_menu_item_activate(GTK_MENU_ITEM(s->full_screen_item)); + } + register_displaychangelistener(&s->dcl); global_state = s; diff --git a/user-exec.c b/user-exec.c index 71bd6c5..fa7f1f1 100644 --- a/user-exec.c +++ b/user-exec.c @@ -448,6 +448,21 @@ int cpu_signal_handler(int host_signum, void *pinfo, &uc->uc_sigmask, puc); } +#elif defined(__aarch64__) + +int cpu_signal_handler(int host_signum, void *pinfo, + void *puc) +{ + siginfo_t *info = pinfo; + struct ucontext *uc = puc; + uint64_t pc; + int is_write = 0; /* XXX how to determine? */ + + pc = uc->uc_mcontext.pc; + return handle_cpu_signal(pc, (uint64_t)info->si_addr, + is_write, &uc->uc_sigmask, puc); +} + #elif defined(__mc68000) int cpu_signal_handler(int host_signum, void *pinfo, diff --git a/util/Makefile.objs b/util/Makefile.objs index 4a1bd4e..dc72ab0 100644 --- a/util/Makefile.objs +++ b/util/Makefile.objs @@ -1,6 +1,6 @@ util-obj-y = osdep.o cutils.o unicode.o qemu-timer-common.o util-obj-$(CONFIG_WIN32) += oslib-win32.o qemu-thread-win32.o event_notifier-win32.o -util-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-thread-posix.o event_notifier-posix.o +util-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-thread-posix.o event_notifier-posix.o qemu-openpty.o util-obj-y += envlist.o path.o host-utils.o cache-utils.o module.o util-obj-y += bitmap.o bitops.o hbitmap.o util-obj-y += fifo8.o diff --git a/util/cutils.c b/util/cutils.c index a165819..0116fcd 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -107,6 +107,27 @@ int qemu_strnlen(const char *s, int max_len) return i; } +char *qemu_strsep(char **input, const char *delim) +{ + char *result = *input; + if (result != NULL) { + char *p; + + for (p = result; *p != '\0'; p++) { + if (strchr(delim, *p)) { + break; + } + } + if (*p == '\0') { + *input = NULL; + } else { + *p = '\0'; + *input = p + 1; + } + } + return result; +} + time_t mktimegm(struct tm *tm) { time_t t; @@ -267,6 +288,10 @@ static int64_t suffix_mul(char suffix, int64_t unit) return unit * unit * unit; case STRTOSZ_DEFSUFFIX_TB: return unit * unit * unit * unit; + case STRTOSZ_DEFSUFFIX_PB: + return unit * unit * unit * unit * unit; + case STRTOSZ_DEFSUFFIX_EB: + return unit * unit * unit * unit * unit * unit; } return -1; } diff --git a/util/qemu-openpty.c b/util/qemu-openpty.c new file mode 100644 index 0000000..4febfe9 --- /dev/null +++ b/util/qemu-openpty.c @@ -0,0 +1,135 @@ +/* + * qemu-openpty.c + * + * Copyright (c) 2003-2008 Fabrice Bellard + * Copyright (c) 2010 Red Hat, Inc. + * + * Wrapper function qemu_openpty() implementation. + * + * 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. + */ + +/* + * This is not part of oslib-posix.c because this function + * uses openpty() which often in -lutil, and if we add this + * dependency to oslib-posix.o, every app will have to be + * linked with -lutil. + */ + +#include "config-host.h" +#include "qemu-common.h" + +#if defined(__GLIBC__) +# include <pty.h> +#elif defined CONFIG_BSD +# include <termios.h> +# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) +# include <libutil.h> +# else +# include <util.h> +# endif +#elif defined CONFIG_SOLARIS +# include <termios.h> +# include <stropts.h> +#endif + +#ifdef __sun__ +/* Once Solaris has openpty(), this is going to be removed. */ +static int openpty(int *amaster, int *aslave, char *name, + struct termios *termp, struct winsize *winp) +{ + const char *slave; + int mfd = -1, sfd = -1; + + *amaster = *aslave = -1; + + mfd = open("/dev/ptmx", O_RDWR | O_NOCTTY); + if (mfd < 0) + goto err; + + if (grantpt(mfd) == -1 || unlockpt(mfd) == -1) + goto err; + + if ((slave = ptsname(mfd)) == NULL) + goto err; + + if ((sfd = open(slave, O_RDONLY | O_NOCTTY)) == -1) + goto err; + + if (ioctl(sfd, I_PUSH, "ptem") == -1 || + (termp != NULL && tcgetattr(sfd, termp) < 0)) + goto err; + + if (amaster) + *amaster = mfd; + if (aslave) + *aslave = sfd; + if (winp) + ioctl(sfd, TIOCSWINSZ, winp); + + return 0; + +err: + if (sfd != -1) + close(sfd); + close(mfd); + return -1; +} + +static void cfmakeraw (struct termios *termios_p) +{ + termios_p->c_iflag &= + ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON); + termios_p->c_oflag &= ~OPOST; + termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); + termios_p->c_cflag &= ~(CSIZE|PARENB); + termios_p->c_cflag |= CS8; + + termios_p->c_cc[VMIN] = 0; + termios_p->c_cc[VTIME] = 0; +} +#endif + +int qemu_openpty_raw(int *aslave, char *pty_name) +{ + int amaster; + struct termios tty; +#if defined(__OpenBSD__) || defined(__DragonFly__) + char pty_buf[PATH_MAX]; +#define q_ptsname(x) pty_buf +#else + char *pty_buf = NULL; +#define q_ptsname(x) ptsname(x) +#endif + + if (openpty(&amaster, aslave, pty_buf, NULL, NULL) < 0) { + return -1; + } + + /* Set raw attributes on the pty. */ + tcgetattr(*aslave, &tty); + cfmakeraw(&tty); + tcsetattr(*aslave, TCSAFLUSH, &tty); + + if (pty_name) { + strcpy(pty_name, q_ptsname(amaster)); + } + + return amaster; +} @@ -610,6 +610,7 @@ static const RunStateTransition runstate_transitions_def[] = { { RUN_STATE_GUEST_PANICKED, RUN_STATE_PAUSED }, { RUN_STATE_GUEST_PANICKED, RUN_STATE_FINISH_MIGRATE }, + { RUN_STATE_GUEST_PANICKED, RUN_STATE_DEBUG }, { RUN_STATE_MAX, RUN_STATE_MAX }, }; @@ -3523,7 +3524,6 @@ int main(int argc, char **argv, char **envp) case QEMU_OPTION_full_screen: full_screen = 1; break; -#ifdef CONFIG_SDL case QEMU_OPTION_no_frame: no_frame = 1; break; @@ -3536,14 +3536,11 @@ int main(int argc, char **argv, char **envp) case QEMU_OPTION_no_quit: no_quit = 1; break; +#ifdef CONFIG_SDL case QEMU_OPTION_sdl: display_type = DT_SDL; break; #else - case QEMU_OPTION_no_frame: - case QEMU_OPTION_alt_grab: - case QEMU_OPTION_ctrl_grab: - case QEMU_OPTION_no_quit: case QEMU_OPTION_sdl: fprintf(stderr, "SDL support is disabled\n"); exit(1); @@ -4084,6 +4081,15 @@ int main(int argc, char **argv, char **envp) #endif } + if ((no_frame || alt_grab || ctrl_grab) && display_type != DT_SDL) { + fprintf(stderr, "-no-frame, -alt-grab and -ctrl-grab are only valid " + "for SDL, ignoring option\n"); + } + if (no_quit && (display_type != DT_GTK && display_type != DT_SDL)) { + fprintf(stderr, "-no-quit is only valid for GTK and SDL, " + "ignoring option\n"); + } + #if defined(CONFIG_GTK) if (display_type == DT_GTK) { early_gtk_display_init(); @@ -4347,7 +4353,7 @@ int main(int argc, char **argv, char **envp) #endif #if defined(CONFIG_GTK) case DT_GTK: - gtk_display_init(ds); + gtk_display_init(ds, full_screen); break; #endif default: @@ -389,7 +389,7 @@ static int xen_remove_from_physmap(XenIOState *state, if (state->log_for_dirtybit == physmap) { state->log_for_dirtybit = NULL; } - free(physmap); + g_free(physmap); return 0; } @@ -1030,7 +1030,7 @@ static void xen_read_physmap(XenIOState *state) xen_domid, entries[i]); value = xs_read(state->xenstore, 0, path, &len); if (value == NULL) { - free(physmap); + g_free(physmap); continue; } physmap->start_addr = strtoull(value, NULL, 16); @@ -1041,7 +1041,7 @@ static void xen_read_physmap(XenIOState *state) xen_domid, entries[i]); value = xs_read(state->xenstore, 0, path, &len); if (value == NULL) { - free(physmap); + g_free(physmap); continue; } physmap->size = strtoull(value, NULL, 16); @@ -1069,12 +1069,14 @@ int xen_hvm_init(void) state->xce_handle = xen_xc_evtchn_open(NULL, 0); if (state->xce_handle == XC_HANDLER_INITIAL_VALUE) { perror("xen: event channel open"); + g_free(state); return -errno; } state->xenstore = xs_daemon_open(); if (state->xenstore == NULL) { perror("xen: xenstore open"); + g_free(state); return -errno; } |