QEMU will now register all memory range (PIO and MMIO) in Xen. We distinct two phases in memory registered : - initialization - running
For all range registered during the initialization, QEMU will check with XenStore if it is authorized to use them. After the initialization, QEMU can register all range. Indeed, the new ranges will be for PCI Bar. Signed-off-by: Julien Grall <julien.gr...@citrix.com> --- exec.c | 9 ++++++ ioport.c | 17 ++++++++++++ xen-all.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+), 0 deletions(-) diff --git a/exec.c b/exec.c index 780f63f..42d8c56 100644 --- a/exec.c +++ b/exec.c @@ -3557,12 +3557,21 @@ static void core_commit(MemoryListener *listener) static void core_region_add(MemoryListener *listener, MemoryRegionSection *section) { + if (xen_enabled()) { + xen_map_iorange(section->offset_within_address_space, + section->size, 1); + } + cpu_register_physical_memory_log(section, section->readonly); } static void core_region_del(MemoryListener *listener, MemoryRegionSection *section) { + if (xen_enabled()) { + xen_unmap_iorange(section->offset_within_address_space, + section->size, 1); + } } static void core_region_nop(MemoryListener *listener, diff --git a/ioport.c b/ioport.c index 78a3b89..073ed75 100644 --- a/ioport.c +++ b/ioport.c @@ -28,6 +28,7 @@ #include "ioport.h" #include "trace.h" #include "memory.h" +#include "hw/xen.h" /***********************************************************/ /* IO Port */ @@ -155,6 +156,11 @@ int register_ioport_read(pio_addr_t start, int length, int size, i); ioport_opaque[i] = opaque; } + + if (xen_enabled()) { + xen_map_iorange(start, length, 0); + } + return 0; } @@ -175,7 +181,13 @@ int register_ioport_write(pio_addr_t start, int length, int size, i); ioport_opaque[i] = opaque; } + + if (xen_enabled()) { + xen_map_iorange(start, length, 0); + } + return 0; + } static uint32_t ioport_readb_thunk(void *opaque, uint32_t addr) @@ -260,6 +272,11 @@ void isa_unassign_ioport(pio_addr_t start, int length) ioport_destructor_table[start](ioport_opaque[start]); ioport_destructor_table[start] = NULL; } + + if (xen_enabled()) { + xen_unmap_iorange(start, length, 0); + } + for(i = start; i < start + length; i++) { ioport_read_table[0][i] = NULL; ioport_read_table[1][i] = NULL; diff --git a/xen-all.c b/xen-all.c index f007278..366bafe 100644 --- a/xen-all.c +++ b/xen-all.c @@ -124,6 +124,89 @@ void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len) } } +static void str_to_range(const char *str, uint64_t *begin, uint64_t *end) +{ + char *buf; + + /* We assume that range is valid */ + *begin = strtoll(str, &buf, 0); + if (buf[0] == '\0') { + *end = *begin; + return; + } + + str = buf + 1; + *end = strtoll(str, &buf, 0); +} + +static int check_range(uint64_t addr, uint64_t size, int is_mmio) +{ + struct xs_handle *xs = NULL; + char **dir; + char *str; + int rc = 1; + int i; + uint64_t begin; + uint64_t end; + char base[70]; + char path[70]; + unsigned int nb; + unsigned int len; + + xs = xs_open(0); + if (!xs) { + fprintf(stderr, "check_range: unable to open xenstore\n"); + return 1; + } + + snprintf(base, sizeof (base), "/local/domain/%u/image/dms/%u/%s", + xen_domid, xen_dmid, (is_mmio) ? "mmio" : "pio"); + dir = xs_directory(xs, XBT_NULL, base, &nb); + + if (dir) { + for (i = 0; i < nb; i++) { + snprintf(path, sizeof (path), "%s/%s", base, dir[i]); + str = xs_read(xs, XBT_NULL, path, &len); + str_to_range(str, &begin, &end); + free(str); + if (addr == begin && (addr + size - 1) == end) { + rc = 0; + break; + } + } + free(dir); + } + + return rc; +} + +void xen_map_iorange(uint64_t addr, uint64_t size, int is_mmio) +{ + static uint64_t previous_addr = ~0; + + /* Don't register multiple times the same ioport */ + if (!is_mmio) { + if (addr == previous_addr) + return; + previous_addr = addr; + } + + if (!is_running) { + if (check_range(addr, size, is_mmio)) { + return; + } + } + + xc_hvm_map_io_range_to_ioreq_server(xen_xc, xen_domid, serverid, is_mmio, + addr, addr + size - 1); +} + +void xen_unmap_iorange(uint64_t addr, uint64_t size, int is_mmio) +{ + xc_hvm_unmap_io_range_from_ioreq_server(xen_xc, xen_domid, serverid, is_mmio, + addr); +} + static void xen_suspend_notifier(Notifier *notifier, void *data) { xc_set_hvm_param(xen_xc, xen_domid, HVM_PARAM_ACPI_S_STATE, 3); -- Julien Grall