diff options
-rw-r--r-- | VERSION | 2 | ||||
-rw-r--r-- | blockdev.c | 12 | ||||
-rw-r--r-- | dump.c | 171 | ||||
-rw-r--r-- | hw/mips/mips_fulong2e.c | 4 | ||||
-rw-r--r-- | hw/mips/mips_jazz.c | 5 | ||||
-rw-r--r-- | hw/mips/mips_malta.c | 7 | ||||
-rw-r--r-- | hw/mips/mips_mipssim.c | 7 | ||||
-rw-r--r-- | hw/usb/hcd-xhci.c | 13 | ||||
-rw-r--r-- | hw/virtio/virtio-mmio.c | 3 | ||||
-rw-r--r-- | hw/virtio/virtio.c | 12 | ||||
-rw-r--r-- | include/sysemu/dump.h | 4 | ||||
-rw-r--r-- | include/sysemu/memory_mapping.h | 30 | ||||
-rw-r--r-- | memory_mapping.c | 123 | ||||
-rw-r--r-- | stubs/dump.c | 3 | ||||
-rw-r--r-- | target-i386/arch_dump.c | 10 | ||||
-rw-r--r-- | target-s390x/arch_dump.c | 3 | ||||
-rw-r--r-- | tcg/mips/tcg-target.c | 10 |
17 files changed, 308 insertions, 111 deletions
@@ -1 +1 @@ -1.5.91 +1.5.92 diff --git a/blockdev.c b/blockdev.c index 41b0a49344..e174b7d02d 100644 --- a/blockdev.c +++ b/blockdev.c @@ -340,6 +340,7 @@ static DriveInfo *blockdev_init(QemuOpts *all_opts, QDict *bs_opts; const char *id; bool has_driver_specific_opts; + BlockDriver *drv = NULL; translation = BIOS_ATA_TRANSLATION_AUTO; media = MEDIA_DISK; @@ -485,7 +486,11 @@ static DriveInfo *blockdev_init(QemuOpts *all_opts, return NULL; } - qdict_put(bs_opts, "driver", qstring_from_str(buf)); + drv = bdrv_find_whitelisted_format(buf, ro); + if (!drv) { + error_report("'%s' invalid format", buf); + return NULL; + } } /* disk I/O throttling */ @@ -700,12 +705,13 @@ static DriveInfo *blockdev_init(QemuOpts *all_opts, } QINCREF(bs_opts); - ret = bdrv_open(dinfo->bdrv, file, bs_opts, bdrv_flags, NULL); + ret = bdrv_open(dinfo->bdrv, file, bs_opts, bdrv_flags, drv); if (ret < 0) { if (ret == -EMEDIUMTYPE) { error_report("could not open disk image %s: not in %s format", - file ?: dinfo->id, qdict_get_str(bs_opts, "driver")); + file ?: dinfo->id, drv ? drv->format_name : + qdict_get_str(bs_opts, "driver")); } else { error_report("could not open disk image %s: %s", file ?: dinfo->id, strerror(-ret)); @@ -59,6 +59,7 @@ static uint64_t cpu_convert_to_target64(uint64_t val, int endian) } typedef struct DumpState { + GuestPhysBlockList guest_phys_blocks; ArchDumpInfo dump_info; MemoryMappingList list; uint16_t phdr_num; @@ -69,7 +70,7 @@ typedef struct DumpState { hwaddr memory_offset; int fd; - RAMBlock *block; + GuestPhysBlock *next_block; ram_addr_t start; bool has_filter; int64_t begin; @@ -81,6 +82,7 @@ static int dump_cleanup(DumpState *s) { int ret = 0; + guest_phys_blocks_free(&s->guest_phys_blocks); memory_mapping_list_free(&s->list); if (s->fd != -1) { close(s->fd); @@ -187,7 +189,8 @@ static int write_elf32_header(DumpState *s) } static int write_elf64_load(DumpState *s, MemoryMapping *memory_mapping, - int phdr_index, hwaddr offset) + int phdr_index, hwaddr offset, + hwaddr filesz) { Elf64_Phdr phdr; int ret; @@ -197,15 +200,12 @@ static int write_elf64_load(DumpState *s, MemoryMapping *memory_mapping, phdr.p_type = cpu_convert_to_target32(PT_LOAD, endian); phdr.p_offset = cpu_convert_to_target64(offset, endian); phdr.p_paddr = cpu_convert_to_target64(memory_mapping->phys_addr, endian); - if (offset == -1) { - /* When the memory is not stored into vmcore, offset will be -1 */ - phdr.p_filesz = 0; - } else { - phdr.p_filesz = cpu_convert_to_target64(memory_mapping->length, endian); - } + phdr.p_filesz = cpu_convert_to_target64(filesz, endian); phdr.p_memsz = cpu_convert_to_target64(memory_mapping->length, endian); phdr.p_vaddr = cpu_convert_to_target64(memory_mapping->virt_addr, endian); + assert(memory_mapping->length >= filesz); + ret = fd_write_vmcore(&phdr, sizeof(Elf64_Phdr), s); if (ret < 0) { dump_error(s, "dump: failed to write program header table.\n"); @@ -216,7 +216,8 @@ static int write_elf64_load(DumpState *s, MemoryMapping *memory_mapping, } static int write_elf32_load(DumpState *s, MemoryMapping *memory_mapping, - int phdr_index, hwaddr offset) + int phdr_index, hwaddr offset, + hwaddr filesz) { Elf32_Phdr phdr; int ret; @@ -226,15 +227,12 @@ static int write_elf32_load(DumpState *s, MemoryMapping *memory_mapping, phdr.p_type = cpu_convert_to_target32(PT_LOAD, endian); phdr.p_offset = cpu_convert_to_target32(offset, endian); phdr.p_paddr = cpu_convert_to_target32(memory_mapping->phys_addr, endian); - if (offset == -1) { - /* When the memory is not stored into vmcore, offset will be -1 */ - phdr.p_filesz = 0; - } else { - phdr.p_filesz = cpu_convert_to_target32(memory_mapping->length, endian); - } + phdr.p_filesz = cpu_convert_to_target32(filesz, endian); phdr.p_memsz = cpu_convert_to_target32(memory_mapping->length, endian); phdr.p_vaddr = cpu_convert_to_target32(memory_mapping->virt_addr, endian); + assert(memory_mapping->length >= filesz); + ret = fd_write_vmcore(&phdr, sizeof(Elf32_Phdr), s); if (ret < 0) { dump_error(s, "dump: failed to write program header table.\n"); @@ -393,14 +391,14 @@ static int write_data(DumpState *s, void *buf, int length) } /* write the memroy to vmcore. 1 page per I/O. */ -static int write_memory(DumpState *s, RAMBlock *block, ram_addr_t start, +static int write_memory(DumpState *s, GuestPhysBlock *block, ram_addr_t start, int64_t size) { int64_t i; int ret; for (i = 0; i < size / TARGET_PAGE_SIZE; i++) { - ret = write_data(s, block->host + start + i * TARGET_PAGE_SIZE, + ret = write_data(s, block->host_addr + start + i * TARGET_PAGE_SIZE, TARGET_PAGE_SIZE); if (ret < 0) { return ret; @@ -408,7 +406,7 @@ static int write_memory(DumpState *s, RAMBlock *block, ram_addr_t start, } if ((size % TARGET_PAGE_SIZE) != 0) { - ret = write_data(s, block->host + start + i * TARGET_PAGE_SIZE, + ret = write_data(s, block->host_addr + start + i * TARGET_PAGE_SIZE, size % TARGET_PAGE_SIZE); if (ret < 0) { return ret; @@ -418,57 +416,71 @@ static int write_memory(DumpState *s, RAMBlock *block, ram_addr_t start, return 0; } -/* get the memory's offset in the vmcore */ -static hwaddr get_offset(hwaddr phys_addr, - DumpState *s) +/* get the memory's offset and size in the vmcore */ +static void get_offset_range(hwaddr phys_addr, + ram_addr_t mapping_length, + DumpState *s, + hwaddr *p_offset, + hwaddr *p_filesz) { - RAMBlock *block; + GuestPhysBlock *block; hwaddr offset = s->memory_offset; int64_t size_in_block, start; + /* When the memory is not stored into vmcore, offset will be -1 */ + *p_offset = -1; + *p_filesz = 0; + if (s->has_filter) { if (phys_addr < s->begin || phys_addr >= s->begin + s->length) { - return -1; + return; } } - QTAILQ_FOREACH(block, &ram_list.blocks, next) { + QTAILQ_FOREACH(block, &s->guest_phys_blocks.head, next) { if (s->has_filter) { - if (block->offset >= s->begin + s->length || - block->offset + block->length <= s->begin) { + if (block->target_start >= s->begin + s->length || + block->target_end <= s->begin) { /* This block is out of the range */ continue; } - if (s->begin <= block->offset) { - start = block->offset; + if (s->begin <= block->target_start) { + start = block->target_start; } else { start = s->begin; } - size_in_block = block->length - (start - block->offset); - if (s->begin + s->length < block->offset + block->length) { - size_in_block -= block->offset + block->length - - (s->begin + s->length); + size_in_block = block->target_end - start; + if (s->begin + s->length < block->target_end) { + size_in_block -= block->target_end - (s->begin + s->length); } } else { - start = block->offset; - size_in_block = block->length; + start = block->target_start; + size_in_block = block->target_end - block->target_start; } if (phys_addr >= start && phys_addr < start + size_in_block) { - return phys_addr - start + offset; + *p_offset = phys_addr - start + offset; + + /* The offset range mapped from the vmcore file must not spill over + * the GuestPhysBlock, clamp it. The rest of the mapping will be + * zero-filled in memory at load time; see + * <http://refspecs.linuxbase.org/elf/gabi4+/ch5.pheader.html>. + */ + *p_filesz = phys_addr + mapping_length <= start + size_in_block ? + mapping_length : + size_in_block - (phys_addr - start); + return; } offset += size_in_block; } - - return -1; } static int write_elf_loads(DumpState *s) { - hwaddr offset; + hwaddr offset, filesz; MemoryMapping *memory_mapping; uint32_t phdr_index = 1; int ret; @@ -481,11 +493,15 @@ static int write_elf_loads(DumpState *s) } QTAILQ_FOREACH(memory_mapping, &s->list.head, next) { - offset = get_offset(memory_mapping->phys_addr, s); + get_offset_range(memory_mapping->phys_addr, + memory_mapping->length, + s, &offset, &filesz); if (s->dump_info.d_class == ELFCLASS64) { - ret = write_elf64_load(s, memory_mapping, phdr_index++, offset); + ret = write_elf64_load(s, memory_mapping, phdr_index++, offset, + filesz); } else { - ret = write_elf32_load(s, memory_mapping, phdr_index++, offset); + ret = write_elf32_load(s, memory_mapping, phdr_index++, offset, + filesz); } if (ret < 0) { @@ -596,7 +612,7 @@ static int dump_completed(DumpState *s) return 0; } -static int get_next_block(DumpState *s, RAMBlock *block) +static int get_next_block(DumpState *s, GuestPhysBlock *block) { while (1) { block = QTAILQ_NEXT(block, next); @@ -606,16 +622,16 @@ static int get_next_block(DumpState *s, RAMBlock *block) } s->start = 0; - s->block = block; + s->next_block = block; if (s->has_filter) { - if (block->offset >= s->begin + s->length || - block->offset + block->length <= s->begin) { + if (block->target_start >= s->begin + s->length || + block->target_end <= s->begin) { /* This block is out of the range */ continue; } - if (s->begin > block->offset) { - s->start = s->begin - block->offset; + if (s->begin > block->target_start) { + s->start = s->begin - block->target_start; } } @@ -626,18 +642,18 @@ static int get_next_block(DumpState *s, RAMBlock *block) /* write all memory to vmcore */ static int dump_iterate(DumpState *s) { - RAMBlock *block; + GuestPhysBlock *block; int64_t size; int ret; while (1) { - block = s->block; + block = s->next_block; - size = block->length; + size = block->target_end - block->target_start; if (s->has_filter) { size -= s->start; - if (s->begin + s->length < block->offset + block->length) { - size -= block->offset + block->length - (s->begin + s->length); + if (s->begin + s->length < block->target_end) { + size -= block->target_end - (s->begin + s->length); } } ret = write_memory(s, block, s->start, size); @@ -672,23 +688,23 @@ static int create_vmcore(DumpState *s) static ram_addr_t get_start_block(DumpState *s) { - RAMBlock *block; + GuestPhysBlock *block; if (!s->has_filter) { - s->block = QTAILQ_FIRST(&ram_list.blocks); + s->next_block = QTAILQ_FIRST(&s->guest_phys_blocks.head); return 0; } - QTAILQ_FOREACH(block, &ram_list.blocks, next) { - if (block->offset >= s->begin + s->length || - block->offset + block->length <= s->begin) { + QTAILQ_FOREACH(block, &s->guest_phys_blocks.head, next) { + if (block->target_start >= s->begin + s->length || + block->target_end <= s->begin) { /* This block is out of the range */ continue; } - s->block = block; - if (s->begin > block->offset) { - s->start = s->begin - block->offset; + s->next_block = block; + if (s->begin > block->target_start) { + s->start = s->begin - block->target_start; } else { s->start = 0; } @@ -713,32 +729,35 @@ static int dump_init(DumpState *s, int fd, bool paging, bool has_filter, s->resume = false; } + /* If we use KVM, we should synchronize the registers before we get dump + * info or physmap info. + */ + cpu_synchronize_all_states(); + nr_cpus = 0; + for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) { + nr_cpus++; + } + s->errp = errp; s->fd = fd; s->has_filter = has_filter; s->begin = begin; s->length = length; + + guest_phys_blocks_init(&s->guest_phys_blocks); + guest_phys_blocks_append(&s->guest_phys_blocks); + s->start = get_start_block(s); if (s->start == -1) { error_set(errp, QERR_INVALID_PARAMETER, "begin"); goto cleanup; } - /* - * get dump info: endian, class and architecture. + /* get dump info: endian, class and architecture. * If the target architecture is not supported, cpu_get_dump_info() will * return -1. - * - * If we use KVM, we should synchronize the registers before we get dump - * info. */ - cpu_synchronize_all_states(); - nr_cpus = 0; - for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) { - nr_cpus++; - } - - ret = cpu_get_dump_info(&s->dump_info); + ret = cpu_get_dump_info(&s->dump_info, &s->guest_phys_blocks); if (ret < 0) { error_set(errp, QERR_UNSUPPORTED); goto cleanup; @@ -754,13 +773,13 @@ 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, &err); + qemu_get_guest_memory_mapping(&s->list, &s->guest_phys_blocks, &err); if (err != NULL) { error_propagate(errp, err); goto cleanup; } } else { - qemu_get_guest_simple_memory_mapping(&s->list); + qemu_get_guest_simple_memory_mapping(&s->list, &s->guest_phys_blocks); } if (s->has_filter) { @@ -812,6 +831,8 @@ static int dump_init(DumpState *s, int fd, bool paging, bool has_filter, return 0; cleanup: + guest_phys_blocks_free(&s->guest_phys_blocks); + if (s->resume) { vm_start(); } @@ -859,7 +880,7 @@ void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin, return; } - s = g_malloc(sizeof(DumpState)); + s = g_malloc0(sizeof(DumpState)); ret = dump_init(s, fd, paging, has_begin, begin, length, errp); if (ret < 0) { diff --git a/hw/mips/mips_fulong2e.c b/hw/mips/mips_fulong2e.c index b13750d0d9..e8d5dd0980 100644 --- a/hw/mips/mips_fulong2e.c +++ b/hw/mips/mips_fulong2e.c @@ -44,6 +44,7 @@ #include "sysemu/blockdev.h" #include "exec/address-spaces.h" #include "sysemu/qtest.h" +#include "qemu/error-report.h" #define DEBUG_FULONG2E_INIT @@ -335,7 +336,8 @@ static void mips_fulong2e_init(QEMUMachineInitArgs *args) if ((bios_size < 0 || bios_size > BIOS_SIZE) && !kernel_filename && !qtest_enabled()) { - fprintf(stderr, "qemu: Warning, could not load MIPS bios '%s'\n", bios_name); + error_report("Could not load MIPS bios '%s'", bios_name); + exit(1); } } diff --git a/hw/mips/mips_jazz.c b/hw/mips/mips_jazz.c index 36677cc652..d748ded7eb 100644 --- a/hw/mips/mips_jazz.c +++ b/hw/mips/mips_jazz.c @@ -43,6 +43,7 @@ #include "hw/sysbus.h" #include "exec/address-spaces.h" #include "sysemu/qtest.h" +#include "qemu/error-report.h" enum jazz_model_e { @@ -178,8 +179,8 @@ static void mips_jazz_init(MemoryRegion *address_space, bios_size = -1; } if ((bios_size < 0 || bios_size > MAGNUM_BIOS_SIZE) && !qtest_enabled()) { - fprintf(stderr, "qemu: Warning, could not load MIPS bios '%s'\n", - bios_name); + error_report("Could not load MIPS bios '%s'", bios_name); + exit(1); } /* Init CPU internal devices */ diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c index f56f34f3e6..0f5de338fa 100644 --- a/hw/mips/mips_malta.c +++ b/hw/mips/mips_malta.c @@ -49,6 +49,7 @@ #include "hw/sysbus.h" /* SysBusDevice */ #include "qemu/host-utils.h" #include "sysemu/qtest.h" +#include "qemu/error-report.h" //#define DEBUG_BOARD_INIT @@ -1008,9 +1009,9 @@ void mips_malta_init(QEMUMachineInitArgs *args) } if ((bios_size < 0 || bios_size > BIOS_SIZE) && !kernel_filename && !qtest_enabled()) { - fprintf(stderr, - "qemu: Warning, could not load MIPS bios '%s', and no -kernel argument was specified\n", - bios_name); + error_report("Could not load MIPS bios '%s', and no " + "-kernel argument was specified", bios_name); + exit(1); } } /* In little endian mode the 32bit words in the bios are swapped, diff --git a/hw/mips/mips_mipssim.c b/hw/mips/mips_mipssim.c index fea1a15916..297f01e268 100644 --- a/hw/mips/mips_mipssim.c +++ b/hw/mips/mips_mipssim.c @@ -37,6 +37,7 @@ #include "elf.h" #include "hw/sysbus.h" #include "exec/address-spaces.h" +#include "qemu/error-report.h" static struct _loaderparams { int ram_size; @@ -191,9 +192,9 @@ mips_mipssim_init(QEMUMachineInitArgs *args) } if ((bios_size < 0 || bios_size > BIOS_SIZE) && !kernel_filename) { /* Bail out if we have neither a kernel image nor boot vector code. */ - fprintf(stderr, - "qemu: Warning, could not load MIPS bios '%s', and no -kernel argument was specified\n", - filename); + error_report("Could not load MIPS bios '%s', and no " + "-kernel argument was specified", filename); + exit(1); } else { /* We have a boot vector start address. */ env->active_tc.PC = (target_long)(int32_t)0xbfc00000; diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index ff5f68135c..58c88b8a6b 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -2672,7 +2672,7 @@ static void xhci_port_update(XHCIPort *port, int is_detach) xhci_port_notify(port, PORTSC_CSC); } -static void xhci_port_reset(XHCIPort *port) +static void xhci_port_reset(XHCIPort *port, bool warm_reset) { trace_usb_xhci_port_reset(port->portnr); @@ -2683,6 +2683,11 @@ static void xhci_port_reset(XHCIPort *port) usb_device_reset(port->uport->dev); switch (port->uport->dev->speed) { + case USB_SPEED_SUPER: + if (warm_reset) { + port->portsc |= PORTSC_WRC; + } + /* fall through */ case USB_SPEED_LOW: case USB_SPEED_FULL: case USB_SPEED_HIGH: @@ -2845,8 +2850,12 @@ static void xhci_port_write(void *ptr, hwaddr reg, switch (reg) { case 0x00: /* PORTSC */ /* write-1-to-start bits */ + if (val & PORTSC_WPR) { + xhci_port_reset(port, true); + break; + } if (val & PORTSC_PR) { - xhci_port_reset(port); + xhci_port_reset(port, false); break; } diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c index 88cf994b97..4bd29533f3 100644 --- a/hw/virtio/virtio-mmio.c +++ b/hw/virtio/virtio-mmio.c @@ -151,6 +151,9 @@ static uint64_t virtio_mmio_read(void *opaque, hwaddr offset, unsigned size) } return proxy->host_features; case VIRTIO_MMIO_QUEUENUMMAX: + if (!virtio_queue_get_num(vdev, vdev->queue_sel)) { + return 0; + } return VIRTQUEUE_MAX_SIZE; case VIRTIO_MMIO_QUEUEPFN: return virtio_queue_get_addr(vdev, vdev->queue_sel) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 706bdf4c46..f03c45dff5 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -673,10 +673,16 @@ hwaddr virtio_queue_get_addr(VirtIODevice *vdev, int n) void virtio_queue_set_num(VirtIODevice *vdev, int n, int num) { - if (num <= VIRTQUEUE_MAX_SIZE) { - vdev->vq[n].vring.num = num; - virtqueue_init(&vdev->vq[n]); + /* Don't allow guest to flip queue between existent and + * nonexistent states, or to set it to an invalid size. + */ + if (!!num != !!vdev->vq[n].vring.num || + num > VIRTQUEUE_MAX_SIZE || + num < 0) { + return; } + vdev->vq[n].vring.num = num; + virtqueue_init(&vdev->vq[n]); } int virtio_queue_get_num(VirtIODevice *vdev, int n) diff --git a/include/sysemu/dump.h b/include/sysemu/dump.h index b8c770f8d9..19fafb2cf9 100644 --- a/include/sysemu/dump.h +++ b/include/sysemu/dump.h @@ -20,7 +20,9 @@ typedef struct ArchDumpInfo { int d_class; /* ELFCLASS32 or ELFCLASS64 */ } ArchDumpInfo; -int cpu_get_dump_info(ArchDumpInfo *info); +struct GuestPhysBlockList; /* memory_mapping.h */ +int cpu_get_dump_info(ArchDumpInfo *info, + const struct GuestPhysBlockList *guest_phys_blocks); ssize_t cpu_get_note_size(int class, int machine, int nr_cpus); #endif diff --git a/include/sysemu/memory_mapping.h b/include/sysemu/memory_mapping.h index 6dfb68ddcd..a75d59a55d 100644 --- a/include/sysemu/memory_mapping.h +++ b/include/sysemu/memory_mapping.h @@ -17,6 +17,25 @@ #include "qemu/queue.h" #include "qemu/typedefs.h" +typedef struct GuestPhysBlock { + /* visible to guest, reflects PCI hole, etc */ + hwaddr target_start; + + /* implies size */ + hwaddr target_end; + + /* points into host memory */ + uint8_t *host_addr; + + QTAILQ_ENTRY(GuestPhysBlock) next; +} GuestPhysBlock; + +/* point-in-time snapshot of guest-visible physical mappings */ +typedef struct GuestPhysBlockList { + unsigned num; + QTAILQ_HEAD(GuestPhysBlockHead, GuestPhysBlock) head; +} GuestPhysBlockList; + /* The physical and virtual address in the memory mapping are contiguous. */ typedef struct MemoryMapping { hwaddr phys_addr; @@ -45,10 +64,17 @@ void memory_mapping_list_free(MemoryMappingList *list); void memory_mapping_list_init(MemoryMappingList *list); -void qemu_get_guest_memory_mapping(MemoryMappingList *list, Error **errp); +void guest_phys_blocks_free(GuestPhysBlockList *list); +void guest_phys_blocks_init(GuestPhysBlockList *list); +void guest_phys_blocks_append(GuestPhysBlockList *list); + +void qemu_get_guest_memory_mapping(MemoryMappingList *list, + const GuestPhysBlockList *guest_phys_blocks, + Error **errp); /* get guest's memory mapping without do paging(virtual address is 0). */ -void qemu_get_guest_simple_memory_mapping(MemoryMappingList *list); +void qemu_get_guest_simple_memory_mapping(MemoryMappingList *list, + const GuestPhysBlockList *guest_phys_blocks); void memory_mapping_filter(MemoryMappingList *list, int64_t begin, int64_t length); diff --git a/memory_mapping.c b/memory_mapping.c index 515a984e0d..eeeeb44026 100644 --- a/memory_mapping.c +++ b/memory_mapping.c @@ -11,9 +11,15 @@ * */ +#include <glib.h> + #include "cpu.h" #include "exec/cpu-all.h" #include "sysemu/memory_mapping.h" +#include "exec/memory.h" +#include "exec/address-spaces.h" + +//#define DEBUG_GUEST_PHYS_REGION_ADD static void memory_mapping_list_add_mapping_sorted(MemoryMappingList *list, MemoryMapping *mapping) @@ -165,6 +171,101 @@ void memory_mapping_list_init(MemoryMappingList *list) QTAILQ_INIT(&list->head); } +void guest_phys_blocks_free(GuestPhysBlockList *list) +{ + GuestPhysBlock *p, *q; + + QTAILQ_FOREACH_SAFE(p, &list->head, next, q) { + QTAILQ_REMOVE(&list->head, p, next); + g_free(p); + } + list->num = 0; +} + +void guest_phys_blocks_init(GuestPhysBlockList *list) +{ + list->num = 0; + QTAILQ_INIT(&list->head); +} + +typedef struct GuestPhysListener { + GuestPhysBlockList *list; + MemoryListener listener; +} GuestPhysListener; + +static void guest_phys_blocks_region_add(MemoryListener *listener, + MemoryRegionSection *section) +{ + GuestPhysListener *g; + uint64_t section_size; + hwaddr target_start, target_end; + uint8_t *host_addr; + GuestPhysBlock *predecessor; + + /* we only care about RAM */ + if (!memory_region_is_ram(section->mr)) { + return; + } + + g = container_of(listener, GuestPhysListener, listener); + section_size = int128_get64(section->size); + target_start = section->offset_within_address_space; + target_end = target_start + section_size; + host_addr = memory_region_get_ram_ptr(section->mr) + + section->offset_within_region; + predecessor = NULL; + + /* find continuity in guest physical address space */ + if (!QTAILQ_EMPTY(&g->list->head)) { + hwaddr predecessor_size; + + predecessor = QTAILQ_LAST(&g->list->head, GuestPhysBlockHead); + predecessor_size = predecessor->target_end - predecessor->target_start; + + /* the memory API guarantees monotonically increasing traversal */ + g_assert(predecessor->target_end <= target_start); + + /* we want continuity in both guest-physical and host-virtual memory */ + if (predecessor->target_end < target_start || + predecessor->host_addr + predecessor_size != host_addr) { + predecessor = NULL; + } + } + + if (predecessor == NULL) { + /* isolated mapping, allocate it and add it to the list */ + GuestPhysBlock *block = g_malloc0(sizeof *block); + + block->target_start = target_start; + block->target_end = target_end; + block->host_addr = host_addr; + + QTAILQ_INSERT_TAIL(&g->list->head, block, next); + ++g->list->num; + } else { + /* expand predecessor until @target_end; predecessor's start doesn't + * change + */ + predecessor->target_end = target_end; + } + +#ifdef DEBUG_GUEST_PHYS_REGION_ADD + fprintf(stderr, "%s: target_start=" TARGET_FMT_plx " target_end=" + TARGET_FMT_plx ": %s (count: %u)\n", __FUNCTION__, target_start, + target_end, predecessor ? "joined" : "added", g->list->num); +#endif +} + +void guest_phys_blocks_append(GuestPhysBlockList *list) +{ + GuestPhysListener g = { 0 }; + + g.list = list; + g.listener.region_add = &guest_phys_blocks_region_add; + memory_listener_register(&g.listener, &address_space_memory); + memory_listener_unregister(&g.listener); +} + static CPUState *find_paging_enabled_cpu(CPUState *start_cpu) { CPUState *cpu; @@ -178,10 +279,12 @@ static CPUState *find_paging_enabled_cpu(CPUState *start_cpu) return NULL; } -void qemu_get_guest_memory_mapping(MemoryMappingList *list, Error **errp) +void qemu_get_guest_memory_mapping(MemoryMappingList *list, + const GuestPhysBlockList *guest_phys_blocks, + Error **errp) { CPUState *cpu, *first_paging_enabled_cpu; - RAMBlock *block; + GuestPhysBlock *block; ram_addr_t offset, length; first_paging_enabled_cpu = find_paging_enabled_cpu(first_cpu); @@ -201,19 +304,21 @@ void qemu_get_guest_memory_mapping(MemoryMappingList *list, Error **errp) * If the guest doesn't use paging, the virtual address is equal to physical * address. */ - QTAILQ_FOREACH(block, &ram_list.blocks, next) { - offset = block->offset; - length = block->length; + QTAILQ_FOREACH(block, &guest_phys_blocks->head, next) { + offset = block->target_start; + length = block->target_end - block->target_start; create_new_memory_mapping(list, offset, offset, length); } } -void qemu_get_guest_simple_memory_mapping(MemoryMappingList *list) +void qemu_get_guest_simple_memory_mapping(MemoryMappingList *list, + const GuestPhysBlockList *guest_phys_blocks) { - RAMBlock *block; + GuestPhysBlock *block; - QTAILQ_FOREACH(block, &ram_list.blocks, next) { - create_new_memory_mapping(list, block->offset, 0, block->length); + QTAILQ_FOREACH(block, &guest_phys_blocks->head, next) { + create_new_memory_mapping(list, block->target_start, 0, + block->target_end - block->target_start); } } diff --git a/stubs/dump.c b/stubs/dump.c index 43c9a3fa02..370cd96eb2 100644 --- a/stubs/dump.c +++ b/stubs/dump.c @@ -16,7 +16,8 @@ #include "qapi/qmp/qerror.h" #include "qmp-commands.h" -int cpu_get_dump_info(ArchDumpInfo *info) +int cpu_get_dump_info(ArchDumpInfo *info, + const struct GuestPhysBlockList *guest_phys_blocks) { return -1; } diff --git a/target-i386/arch_dump.c b/target-i386/arch_dump.c index 10dc2284bf..0bbed239f8 100644 --- a/target-i386/arch_dump.c +++ b/target-i386/arch_dump.c @@ -15,6 +15,7 @@ #include "exec/cpu-all.h" #include "sysemu/dump.h" #include "elf.h" +#include "sysemu/memory_mapping.h" #ifdef TARGET_X86_64 typedef struct { @@ -389,10 +390,11 @@ int x86_cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cs, return cpu_write_qemu_note(f, &cpu->env, opaque, 0); } -int cpu_get_dump_info(ArchDumpInfo *info) +int cpu_get_dump_info(ArchDumpInfo *info, + const GuestPhysBlockList *guest_phys_blocks) { bool lma = false; - RAMBlock *block; + GuestPhysBlock *block; #ifdef TARGET_X86_64 X86CPU *first_x86_cpu = X86_CPU(first_cpu); @@ -412,8 +414,8 @@ int cpu_get_dump_info(ArchDumpInfo *info) } else { info->d_class = ELFCLASS32; - QTAILQ_FOREACH(block, &ram_list.blocks, next) { - if (block->offset + block->length > UINT_MAX) { + QTAILQ_FOREACH(block, &guest_phys_blocks->head, next) { + if (block->target_end > UINT_MAX) { /* The memory size is greater than 4G */ info->d_class = ELFCLASS64; break; diff --git a/target-s390x/arch_dump.c b/target-s390x/arch_dump.c index f3e5144cc1..9d36116242 100644 --- a/target-s390x/arch_dump.c +++ b/target-s390x/arch_dump.c @@ -176,7 +176,8 @@ int s390_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, return s390x_write_all_elf64_notes("CORE", f, cpu, cpuid, opaque); } -int cpu_get_dump_info(ArchDumpInfo *info) +int cpu_get_dump_info(ArchDumpInfo *info, + const struct GuestPhysBlockList *guest_phys_blocks) { info->d_machine = EM_S390; info->d_endian = ELFDATA2MSB; diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c index 373c3640f0..793532ec95 100644 --- a/tcg/mips/tcg-target.c +++ b/tcg/mips/tcg-target.c @@ -1617,19 +1617,29 @@ static const TCGTargetOpDef mips_op_defs[] = { { INDEX_op_shl_i32, { "r", "rZ", "ri" } }, { INDEX_op_shr_i32, { "r", "rZ", "ri" } }, { INDEX_op_sar_i32, { "r", "rZ", "ri" } }, +#if TCG_TARGET_HAS_rot_i32 { INDEX_op_rotr_i32, { "r", "rZ", "ri" } }, { INDEX_op_rotl_i32, { "r", "rZ", "ri" } }, +#endif +#if TCG_TARGET_HAS_bswap16_i32 { INDEX_op_bswap16_i32, { "r", "r" } }, +#endif +#if TCG_TARGET_HAS_bswap32_i32 { INDEX_op_bswap32_i32, { "r", "r" } }, +#endif { INDEX_op_ext8s_i32, { "r", "rZ" } }, { INDEX_op_ext16s_i32, { "r", "rZ" } }, +#if TCG_TARGET_HAS_deposit_i32 { INDEX_op_deposit_i32, { "r", "0", "rZ" } }, +#endif { INDEX_op_brcond_i32, { "rZ", "rZ" } }, +#if TCG_TARGET_HAS_movcond_i32 { INDEX_op_movcond_i32, { "r", "rZ", "rZ", "rZ", "0" } }, +#endif { INDEX_op_setcond_i32, { "r", "rZ", "rZ" } }, { INDEX_op_setcond2_i32, { "r", "rZ", "rZ", "rZ", "rZ" } }, |