Xen 2017/07/18

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJZbokoAAoJEIlPj0hw4a6QgloP/jc9tVFrPjTDezDyPmXR4ls8
 U/kvz5RCn2bu4y8h6U+FHK4BZ7DR1Ccd3Uq1qqDbnlyfcvJeISqqkN2RrnwUQEgV
 XMCEr+okQyiQV4H/MLvmUWtPHpHt3gSEBdoRdGHnkzA2dC/YsJ1F/khKgCh8wqWS
 GTeACabyDTb9L/QFdh//o7GtcI6qv/APGJ/rVVFrrVktp+lZuIZCGZ3hbJ8lopoI
 FSXuM7caVgIlNzP/6RmCoP91ibREPfbfL/yqgv0cW7kiOWVXWwriz6Mi/J2AzmCo
 jqgDqRzkLZPAl1WdZM7MosQIiY7ZlAGhpS9ArK5P4Kv7H6TYV7mkbiSap8SmjnZH
 NvSRLxgT3JjTE5evSodfaaQpjiX0KGaZX0JmpqXYPqOBSYal2lDUNFSokbeucp7w
 y3dBZGY0/9om+G34QzZNvPisYJ2F4Yr5DvCtue8hmkvLSw+z3251555wKQvc6TNx
 wob2h8b8h+YsfhvnSrN1R8w3OL69kGFlMz9PWEgB4opVacZqph/XsMKLARXCg+FD
 83kCuJnV/WAannHpvQA8k4HO6GiKGtrulh6vv1QOlCJQokcK1mZt7Atot+cPcGU2
 UTyhSaOv4sy07lPYzvv0B4MUHNObN/v/OoDygrf7WjCDKigH+RpsVruwAqFakoCB
 09+PtQ26X2Vup+YtW5bG
 =qPq6
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/sstabellini/tags/xen-20170718-tag' into staging

Xen 2017/07/18

# gpg: Signature made Tue 18 Jul 2017 23:18:16 BST
# gpg:                using RSA key 0x894F8F4870E1AE90
# gpg: Good signature from "Stefano Stabellini <stefano.stabellini@eu.citrix.com>"
# gpg:                 aka "Stefano Stabellini <sstabellini@kernel.org>"
# Primary key fingerprint: D04E 33AB A51F 67BA 07D3  0AEA 894F 8F48 70E1 AE90

* remotes/sstabellini/tags/xen-20170718-tag:
  xen: don't use xenstore to save/restore physmap anymore
  xen/mapcache: introduce xen_replace_cache_entry()
  xen/mapcache: add an ability to create dummy mappings
  xen: move physmap saving into a separate function
  xen-platform: separate unplugging of NVMe disks
  xen_pt_msi.c: Check for xen_host_pci_get_* failures in xen_pt_msix_init()
  hw/xen: Set emu_mask for igd_opregion register

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2017-07-19 16:31:08 +01:00
commit b3e46a8914
8 changed files with 267 additions and 63 deletions

18
configure vendored
View File

@ -2107,6 +2107,24 @@ EOF
# Xen unstable
elif
cat > $TMPC <<EOF &&
#undef XC_WANT_COMPAT_MAP_FOREIGN_API
#include <xenforeignmemory.h>
int main(void) {
xenforeignmemory_handle *xfmem;
xfmem = xenforeignmemory_open(0, 0);
xenforeignmemory_map2(xfmem, 0, 0, 0, 0, 0, 0, 0);
return 0;
}
EOF
compile_prog "" "$xen_libs -lxendevicemodel $xen_stable_libs"
then
xen_stable_libs="-lxendevicemodel $xen_stable_libs"
xen_ctrl_version=41000
xen=yes
elif
cat > $TMPC <<EOF &&
#undef XC_WANT_COMPAT_DEVICEMODEL_API
#define __XEN_TOOLS__
#include <xendevicemodel.h>

View File

@ -288,6 +288,7 @@ static XenPhysmap *get_physmapping(XenIOState *state,
return NULL;
}
#ifdef XEN_COMPAT_PHYSMAP
static hwaddr xen_phys_offset_to_gaddr(hwaddr start_addr,
ram_addr_t size, void *opaque)
{
@ -304,6 +305,42 @@ static hwaddr xen_phys_offset_to_gaddr(hwaddr start_addr,
return start_addr;
}
static int xen_save_physmap(XenIOState *state, XenPhysmap *physmap)
{
char path[80], value[17];
snprintf(path, sizeof(path),
"/local/domain/0/device-model/%d/physmap/%"PRIx64"/start_addr",
xen_domid, (uint64_t)physmap->phys_offset);
snprintf(value, sizeof(value), "%"PRIx64, (uint64_t)physmap->start_addr);
if (!xs_write(state->xenstore, 0, path, value, strlen(value))) {
return -1;
}
snprintf(path, sizeof(path),
"/local/domain/0/device-model/%d/physmap/%"PRIx64"/size",
xen_domid, (uint64_t)physmap->phys_offset);
snprintf(value, sizeof(value), "%"PRIx64, (uint64_t)physmap->size);
if (!xs_write(state->xenstore, 0, path, value, strlen(value))) {
return -1;
}
if (physmap->name) {
snprintf(path, sizeof(path),
"/local/domain/0/device-model/%d/physmap/%"PRIx64"/name",
xen_domid, (uint64_t)physmap->phys_offset);
if (!xs_write(state->xenstore, 0, path,
physmap->name, strlen(physmap->name))) {
return -1;
}
}
return 0;
}
#else
static int xen_save_physmap(XenIOState *state, XenPhysmap *physmap)
{
return 0;
}
#endif
static int xen_add_to_physmap(XenIOState *state,
hwaddr start_addr,
ram_addr_t size,
@ -315,7 +352,6 @@ static int xen_add_to_physmap(XenIOState *state,
XenPhysmap *physmap = NULL;
hwaddr pfn, start_gpfn;
hwaddr phys_offset = memory_region_get_ram_addr(mr);
char path[80], value[17];
const char *mr_name;
if (get_physmapping(state, start_addr, size)) {
@ -338,6 +374,26 @@ go_physmap:
DPRINTF("mapping vram to %"HWADDR_PRIx" - %"HWADDR_PRIx"\n",
start_addr, start_addr + size);
mr_name = memory_region_name(mr);
physmap = g_malloc(sizeof(XenPhysmap));
physmap->start_addr = start_addr;
physmap->size = size;
physmap->name = mr_name;
physmap->phys_offset = phys_offset;
QLIST_INSERT_HEAD(&state->physmap, physmap, list);
if (runstate_check(RUN_STATE_INMIGRATE)) {
/* Now when we have a physmap entry we can replace a dummy mapping with
* a real one of guest foreign memory. */
uint8_t *p = xen_replace_cache_entry(phys_offset, start_addr, size);
assert(p && p == memory_region_get_ram_ptr(mr));
return 0;
}
pfn = phys_offset >> TARGET_PAGE_BITS;
start_gpfn = start_addr >> TARGET_PAGE_BITS;
for (i = 0; i < size >> TARGET_PAGE_BITS; i++) {
@ -352,46 +408,11 @@ go_physmap:
}
}
mr_name = memory_region_name(mr);
physmap = g_malloc(sizeof (XenPhysmap));
physmap->start_addr = start_addr;
physmap->size = size;
physmap->name = mr_name;
physmap->phys_offset = phys_offset;
QLIST_INSERT_HEAD(&state->physmap, physmap, list);
xc_domain_pin_memory_cacheattr(xen_xc, xen_domid,
start_addr >> TARGET_PAGE_BITS,
(start_addr + size - 1) >> TARGET_PAGE_BITS,
XEN_DOMCTL_MEM_CACHEATTR_WB);
snprintf(path, sizeof(path),
"/local/domain/0/device-model/%d/physmap/%"PRIx64"/start_addr",
xen_domid, (uint64_t)phys_offset);
snprintf(value, sizeof(value), "%"PRIx64, (uint64_t)start_addr);
if (!xs_write(state->xenstore, 0, path, value, strlen(value))) {
return -1;
}
snprintf(path, sizeof(path),
"/local/domain/0/device-model/%d/physmap/%"PRIx64"/size",
xen_domid, (uint64_t)phys_offset);
snprintf(value, sizeof(value), "%"PRIx64, (uint64_t)size);
if (!xs_write(state->xenstore, 0, path, value, strlen(value))) {
return -1;
}
if (mr_name) {
snprintf(path, sizeof(path),
"/local/domain/0/device-model/%d/physmap/%"PRIx64"/name",
xen_domid, (uint64_t)phys_offset);
if (!xs_write(state->xenstore, 0, path, mr_name, strlen(mr_name))) {
return -1;
}
}
return 0;
return xen_save_physmap(state, physmap);
}
static int xen_remove_from_physmap(XenIOState *state,
@ -1152,6 +1173,7 @@ static void xen_exit_notifier(Notifier *n, void *data)
xs_daemon_close(state->xenstore);
}
#ifdef XEN_COMPAT_PHYSMAP
static void xen_read_physmap(XenIOState *state)
{
XenPhysmap *physmap = NULL;
@ -1199,6 +1221,11 @@ static void xen_read_physmap(XenIOState *state)
}
free(entries);
}
#else
static void xen_read_physmap(XenIOState *state)
{
}
#endif
static void xen_wakeup_notifier(Notifier *notifier, void *data)
{
@ -1325,7 +1352,11 @@ void xen_hvm_init(PCMachineState *pcms, MemoryRegion **ram_memory)
state->bufioreq_local_port = rc;
/* Init RAM management */
#ifdef XEN_COMPAT_PHYSMAP
xen_map_cache_init(xen_phys_offset_to_gaddr, state);
#else
xen_map_cache_init(NULL, state);
#endif
xen_ram_init(pcms, ram_size, ram_memory);
qemu_add_vm_change_state_handler(xen_hvm_change_state_handler, state);

View File

@ -53,6 +53,8 @@ typedef struct MapCacheEntry {
uint8_t *vaddr_base;
unsigned long *valid_mapping;
uint8_t lock;
#define XEN_MAPCACHE_ENTRY_DUMMY (1 << 0)
uint8_t flags;
hwaddr size;
struct MapCacheEntry *next;
} MapCacheEntry;
@ -149,8 +151,10 @@ void xen_map_cache_init(phys_offset_to_gaddr_t f, void *opaque)
}
static void xen_remap_bucket(MapCacheEntry *entry,
void *vaddr,
hwaddr size,
hwaddr address_index)
hwaddr address_index,
bool dummy)
{
uint8_t *vaddr_base;
xen_pfn_t *pfns;
@ -164,7 +168,9 @@ static void xen_remap_bucket(MapCacheEntry *entry,
err = g_malloc0(nb_pfn * sizeof (int));
if (entry->vaddr_base != NULL) {
if (!(entry->flags & XEN_MAPCACHE_ENTRY_DUMMY)) {
ram_block_notify_remove(entry->vaddr_base, entry->size);
}
if (munmap(entry->vaddr_base, entry->size) != 0) {
perror("unmap fails");
exit(-1);
@ -177,12 +183,30 @@ static void xen_remap_bucket(MapCacheEntry *entry,
pfns[i] = (address_index << (MCACHE_BUCKET_SHIFT-XC_PAGE_SHIFT)) + i;
}
vaddr_base = xenforeignmemory_map(xen_fmem, xen_domid, PROT_READ|PROT_WRITE,
if (!dummy) {
vaddr_base = xenforeignmemory_map2(xen_fmem, xen_domid, vaddr,
PROT_READ | PROT_WRITE, 0,
nb_pfn, pfns, err);
if (vaddr_base == NULL) {
perror("xenforeignmemory_map");
perror("xenforeignmemory_map2");
exit(-1);
}
} else {
/*
* We create dummy mappings where we are unable to create a foreign
* mapping immediately due to certain circumstances (i.e. on resume now)
*/
vaddr_base = mmap(vaddr, size, PROT_READ | PROT_WRITE,
MAP_ANON | MAP_SHARED, -1, 0);
if (vaddr_base == NULL) {
perror("mmap");
exit(-1);
}
}
if (!(entry->flags & XEN_MAPCACHE_ENTRY_DUMMY)) {
ram_block_notify_add(vaddr_base, size);
}
entry->vaddr_base = vaddr_base;
entry->paddr_index = address_index;
@ -190,7 +214,12 @@ static void xen_remap_bucket(MapCacheEntry *entry,
entry->valid_mapping = (unsigned long *) g_malloc0(sizeof(unsigned long) *
BITS_TO_LONGS(size >> XC_PAGE_SHIFT));
ram_block_notify_add(entry->vaddr_base, entry->size);
if (dummy) {
entry->flags |= XEN_MAPCACHE_ENTRY_DUMMY;
} else {
entry->flags &= ~(XEN_MAPCACHE_ENTRY_DUMMY);
}
bitmap_zero(entry->valid_mapping, nb_pfn);
for (i = 0; i < nb_pfn; i++) {
if (!err[i]) {
@ -210,7 +239,8 @@ static uint8_t *xen_map_cache_unlocked(hwaddr phys_addr, hwaddr size,
hwaddr address_offset;
hwaddr cache_size = size;
hwaddr test_bit_size;
bool translated = false;
bool translated G_GNUC_UNUSED = false;
bool dummy = false;
tryagain:
address_index = phys_addr >> MCACHE_BUCKET_SHIFT;
@ -262,14 +292,14 @@ tryagain:
if (!entry) {
entry = g_malloc0(sizeof (MapCacheEntry));
pentry->next = entry;
xen_remap_bucket(entry, cache_size, address_index);
xen_remap_bucket(entry, NULL, cache_size, address_index, dummy);
} else if (!entry->lock) {
if (!entry->vaddr_base || entry->paddr_index != address_index ||
entry->size != cache_size ||
!test_bits(address_offset >> XC_PAGE_SHIFT,
test_bit_size >> XC_PAGE_SHIFT,
entry->valid_mapping)) {
xen_remap_bucket(entry, cache_size, address_index);
xen_remap_bucket(entry, NULL, cache_size, address_index, dummy);
}
}
@ -277,11 +307,17 @@ tryagain:
test_bit_size >> XC_PAGE_SHIFT,
entry->valid_mapping)) {
mapcache->last_entry = NULL;
#ifdef XEN_COMPAT_PHYSMAP
if (!translated && mapcache->phys_offset_to_gaddr) {
phys_addr = mapcache->phys_offset_to_gaddr(phys_addr, size, mapcache->opaque);
translated = true;
goto tryagain;
}
#endif
if (!dummy && runstate_check(RUN_STATE_INMIGRATE)) {
dummy = true;
goto tryagain;
}
trace_xen_map_cache_return(NULL);
return NULL;
}
@ -462,3 +498,66 @@ void xen_invalidate_map_cache(void)
mapcache_unlock();
}
static uint8_t *xen_replace_cache_entry_unlocked(hwaddr old_phys_addr,
hwaddr new_phys_addr,
hwaddr size)
{
MapCacheEntry *entry;
hwaddr address_index, address_offset;
hwaddr test_bit_size, cache_size = size;
address_index = old_phys_addr >> MCACHE_BUCKET_SHIFT;
address_offset = old_phys_addr & (MCACHE_BUCKET_SIZE - 1);
assert(size);
/* test_bit_size is always a multiple of XC_PAGE_SIZE */
test_bit_size = size + (old_phys_addr & (XC_PAGE_SIZE - 1));
if (test_bit_size % XC_PAGE_SIZE) {
test_bit_size += XC_PAGE_SIZE - (test_bit_size % XC_PAGE_SIZE);
}
cache_size = size + address_offset;
if (cache_size % MCACHE_BUCKET_SIZE) {
cache_size += MCACHE_BUCKET_SIZE - (cache_size % MCACHE_BUCKET_SIZE);
}
entry = &mapcache->entry[address_index % mapcache->nr_buckets];
while (entry && !(entry->paddr_index == address_index &&
entry->size == cache_size)) {
entry = entry->next;
}
if (!entry) {
DPRINTF("Trying to update an entry for %lx " \
"that is not in the mapcache!\n", old_phys_addr);
return NULL;
}
address_index = new_phys_addr >> MCACHE_BUCKET_SHIFT;
address_offset = new_phys_addr & (MCACHE_BUCKET_SIZE - 1);
fprintf(stderr, "Replacing a dummy mapcache entry for %lx with %lx\n",
old_phys_addr, new_phys_addr);
xen_remap_bucket(entry, entry->vaddr_base,
cache_size, address_index, false);
if (!test_bits(address_offset >> XC_PAGE_SHIFT,
test_bit_size >> XC_PAGE_SHIFT,
entry->valid_mapping)) {
DPRINTF("Unable to update a mapcache entry for %lx!\n", old_phys_addr);
return NULL;
}
return entry->vaddr_base + address_offset;
}
uint8_t *xen_replace_cache_entry(hwaddr old_phys_addr,
hwaddr new_phys_addr,
hwaddr size)
{
uint8_t *p;
mapcache_lock();
p = xen_replace_cache_entry_unlocked(old_phys_addr, new_phys_addr, size);
mapcache_unlock();
return p;
}

View File

@ -87,10 +87,30 @@ static void log_writeb(PCIXenPlatformState *s, char val)
}
}
/* Xen Platform, Fixed IOPort */
#define UNPLUG_ALL_DISKS 1
#define UNPLUG_ALL_NICS 2
#define UNPLUG_AUX_IDE_DISKS 4
/*
* Unplug device flags.
*
* The logic got a little confused at some point in the past but this is
* what they do now.
*
* bit 0: Unplug all IDE and SCSI disks.
* bit 1: Unplug all NICs.
* bit 2: Unplug IDE disks except primary master. This is overridden if
* bit 0 is also present in the mask.
* bit 3: Unplug all NVMe disks.
*
*/
#define _UNPLUG_IDE_SCSI_DISKS 0
#define UNPLUG_IDE_SCSI_DISKS (1u << _UNPLUG_IDE_SCSI_DISKS)
#define _UNPLUG_ALL_NICS 1
#define UNPLUG_ALL_NICS (1u << _UNPLUG_ALL_NICS)
#define _UNPLUG_AUX_IDE_DISKS 2
#define UNPLUG_AUX_IDE_DISKS (1u << _UNPLUG_AUX_IDE_DISKS)
#define _UNPLUG_NVME_DISKS 3
#define UNPLUG_NVME_DISKS (1u << _UNPLUG_NVME_DISKS)
static void unplug_nic(PCIBus *b, PCIDevice *d, void *o)
{
@ -122,7 +142,7 @@ static void unplug_disks(PCIBus *b, PCIDevice *d, void *opaque)
{
uint32_t flags = *(uint32_t *)opaque;
bool aux = (flags & UNPLUG_AUX_IDE_DISKS) &&
!(flags & UNPLUG_ALL_DISKS);
!(flags & UNPLUG_IDE_SCSI_DISKS);
/* We have to ignore passthrough devices */
if (!strcmp(d->name, "xen-pci-passthrough")) {
@ -135,12 +155,16 @@ static void unplug_disks(PCIBus *b, PCIDevice *d, void *opaque)
break;
case PCI_CLASS_STORAGE_SCSI:
case PCI_CLASS_STORAGE_EXPRESS:
if (!aux) {
object_unparent(OBJECT(d));
}
break;
case PCI_CLASS_STORAGE_EXPRESS:
if (flags & UNPLUG_NVME_DISKS) {
object_unparent(OBJECT(d));
}
default:
break;
}
@ -158,10 +182,9 @@ static void platform_fixed_ioport_writew(void *opaque, uint32_t addr, uint32_t v
switch (addr) {
case 0: {
PCIDevice *pci_dev = PCI_DEVICE(s);
/* Unplug devices. Value is a bitmask of which devices to
unplug, with bit 0 the disk devices, bit 1 the network
devices, and bit 2 the non-primary-master IDE devices. */
if (val & (UNPLUG_ALL_DISKS | UNPLUG_AUX_IDE_DISKS)) {
/* Unplug devices. See comment above flag definitions */
if (val & (UNPLUG_IDE_SCSI_DISKS | UNPLUG_AUX_IDE_DISKS |
UNPLUG_NVME_DISKS)) {
DPRINTF("unplug disks\n");
pci_unplug_disks(pci_dev->bus, val);
}
@ -349,14 +372,14 @@ static void xen_platform_ioport_writeb(void *opaque, hwaddr addr,
* If VMDP was to control both disk and LAN it would use 4.
* If it controlled just disk or just LAN, it would use 8 below.
*/
pci_unplug_disks(pci_dev->bus, UNPLUG_ALL_DISKS);
pci_unplug_disks(pci_dev->bus, UNPLUG_IDE_SCSI_DISKS);
pci_unplug_nics(pci_dev->bus);
}
break;
case 8:
switch (val) {
case 1:
pci_unplug_disks(pci_dev->bus, UNPLUG_ALL_DISKS);
pci_unplug_disks(pci_dev->bus, UNPLUG_IDE_SCSI_DISKS);
break;
case 2:
pci_unplug_nics(pci_dev->bus);

View File

@ -1535,6 +1535,7 @@ static XenPTRegInfo xen_pt_emu_reg_igd_opregion[] = {
.offset = 0x0,
.size = 4,
.init_val = 0,
.emu_mask = 0xFFFFFFFF,
.u.dw.read = xen_pt_intel_opregion_read,
.u.dw.write = xen_pt_intel_opregion_write,
},

View File

@ -535,7 +535,11 @@ int xen_pt_msix_init(XenPCIPassthroughState *s, uint32_t base)
return -1;
}
xen_host_pci_get_word(hd, base + PCI_MSIX_FLAGS, &control);
rc = xen_host_pci_get_word(hd, base + PCI_MSIX_FLAGS, &control);
if (rc) {
XEN_PT_ERR(d, "Failed to read PCI_MSIX_FLAGS field\n");
return rc;
}
total_entries = control & PCI_MSIX_FLAGS_QSIZE;
total_entries += 1;
@ -554,7 +558,11 @@ int xen_pt_msix_init(XenPCIPassthroughState *s, uint32_t base)
+ XC_PAGE_SIZE - 1)
& XC_PAGE_MASK);
xen_host_pci_get_long(hd, base + PCI_MSIX_TABLE, &table_off);
rc = xen_host_pci_get_long(hd, base + PCI_MSIX_TABLE, &table_off);
if (rc) {
XEN_PT_ERR(d, "Failed to read PCI_MSIX_TABLE field\n");
goto error_out;
}
bar_index = msix->bar_index = table_off & PCI_MSIX_FLAGS_BIRMASK;
table_off = table_off & ~PCI_MSIX_FLAGS_BIRMASK;
msix->table_base = s->real_device.io_regions[bar_index].base_addr;

View File

@ -78,6 +78,21 @@ static inline void *xenforeignmemory_map(xc_interface *h, uint32_t dom,
extern xenforeignmemory_handle *xen_fmem;
#if CONFIG_XEN_CTRL_INTERFACE_VERSION < 41000
#define XEN_COMPAT_PHYSMAP
static inline void *xenforeignmemory_map2(xenforeignmemory_handle *h,
uint32_t dom, void *addr,
int prot, int flags, size_t pages,
const xen_pfn_t arr[/*pages*/],
int err[/*pages*/])
{
assert(addr == NULL && flags == 0);
return xenforeignmemory_map(h, dom, prot, pages, arr, err);
}
#endif
#if CONFIG_XEN_CTRL_INTERFACE_VERSION < 40900
typedef xc_interface xendevicemodel_handle;

View File

@ -21,7 +21,9 @@ uint8_t *xen_map_cache(hwaddr phys_addr, hwaddr size,
ram_addr_t xen_ram_addr_from_mapcache(void *ptr);
void xen_invalidate_map_cache_entry(uint8_t *buffer);
void xen_invalidate_map_cache(void);
uint8_t *xen_replace_cache_entry(hwaddr old_phys_addr,
hwaddr new_phys_addr,
hwaddr size);
#else
static inline void xen_map_cache_init(phys_offset_to_gaddr_t f,
@ -50,6 +52,13 @@ static inline void xen_invalidate_map_cache(void)
{
}
static inline uint8_t *xen_replace_cache_entry(hwaddr old_phys_addr,
hwaddr new_phys_addr,
hwaddr size)
{
abort();
}
#endif
#endif /* XEN_MAPCACHE_H */