From f37bc03623cd22f3934264f50af926b9b63f6598 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Fri, 6 Jan 2017 12:06:12 +0800 Subject: [PATCH 01/41] migration: allow to prioritize save state entries During migration, save state entries are saved/loaded without a specific order - we just traverse the savevm_state.handlers list and do it one by one. This might not be enough. There are requirements that we need to load specific device's vmstate first before others. For example, VT-d IOMMU contains DMA address remapping information, which is required by all the PCI devices to do address translations. We need to make sure IOMMU's device state is loaded before the rest of the PCI devices, so that DMA address translation can work properly. This patch provide a VMStateDescription.priority value to allow specify the priority of the saved states. The loadvm operation will be done with those devices with higher vmsd priority. Before this patch, we are possibly achieving the ordering requirement by an assumption that the ordering will be the same with the ordering that objects are created. A better way is to mark it out explicitly in the VMStateDescription table, like what this patch does. Current ordering logic is still naive and slow, but after all that's not a critical path so IMO it's a workable solution for now. Signed-off-by: Peter Xu Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Dr. David Alan Gilbert --- include/migration/vmstate.h | 6 ++++++ migration/savevm.c | 34 ++++++++++++++++++++++++++++++---- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index 1638ee57f7..1a228872fa 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -186,6 +186,11 @@ enum VMStateFlags { VMS_MULTIPLY_ELEMENTS = 0x4000, }; +typedef enum { + MIG_PRI_DEFAULT = 0, + MIG_PRI_MAX, +} MigrationPriority; + typedef struct { const char *name; size_t offset; @@ -207,6 +212,7 @@ struct VMStateDescription { int version_id; int minimum_version_id; int minimum_version_id_old; + MigrationPriority priority; LoadStateHandler *load_state_old; int (*pre_load)(void *opaque); int (*post_load)(void *opaque, int version_id); diff --git a/migration/savevm.c b/migration/savevm.c index 0363372acc..f9c06e9f96 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -532,6 +532,34 @@ static int calculate_compat_instance_id(const char *idstr) return instance_id; } +static inline MigrationPriority save_state_priority(SaveStateEntry *se) +{ + if (se->vmsd) { + return se->vmsd->priority; + } + return MIG_PRI_DEFAULT; +} + +static void savevm_state_handler_insert(SaveStateEntry *nse) +{ + MigrationPriority priority = save_state_priority(nse); + SaveStateEntry *se; + + assert(priority <= MIG_PRI_MAX); + + QTAILQ_FOREACH(se, &savevm_state.handlers, entry) { + if (save_state_priority(se) < priority) { + break; + } + } + + if (se) { + QTAILQ_INSERT_BEFORE(se, nse, entry); + } else { + QTAILQ_INSERT_TAIL(&savevm_state.handlers, nse, entry); + } +} + /* TODO: Individual devices generally have very little idea about the rest of the system, so instance_id should be removed/replaced. Meanwhile pass -1 as instance_id if you do not already have a clearly @@ -578,8 +606,7 @@ int register_savevm_live(DeviceState *dev, se->instance_id = instance_id; } assert(!se->compat || se->instance_id == 0); - /* add at the end of list */ - QTAILQ_INSERT_TAIL(&savevm_state.handlers, se, entry); + savevm_state_handler_insert(se); return 0; } @@ -662,8 +689,7 @@ int vmstate_register_with_alias_id(DeviceState *dev, int instance_id, se->instance_id = instance_id; } assert(!se->compat || se->instance_id == 0); - /* add at the end of list */ - QTAILQ_INSERT_TAIL(&savevm_state.handlers, se, entry); + savevm_state_handler_insert(se); return 0; } From 8cdcf3c1e58d04b6811956d7608efeb66c42d719 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Fri, 6 Jan 2017 12:06:13 +0800 Subject: [PATCH 02/41] intel_iommu: allow migration IOMMU needs to be migrated before all the PCI devices (in case there are devices that will request for address translation). So marking it with a priority higher than the default (which PCI devices and other belong). Migration framework handled the rest. Signed-off-by: Peter Xu Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/intel_iommu.c | 22 +++++++++++++++++++++- include/migration/vmstate.h | 1 + 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 5f3e35123d..119217b612 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -1996,7 +1996,27 @@ static void vtd_iommu_notify_flag_changed(MemoryRegion *iommu, static const VMStateDescription vtd_vmstate = { .name = "iommu-intel", - .unmigratable = 1, + .version_id = 1, + .minimum_version_id = 1, + .priority = MIG_PRI_IOMMU, + .fields = (VMStateField[]) { + VMSTATE_UINT64(root, IntelIOMMUState), + VMSTATE_UINT64(intr_root, IntelIOMMUState), + VMSTATE_UINT64(iq, IntelIOMMUState), + VMSTATE_UINT32(intr_size, IntelIOMMUState), + VMSTATE_UINT16(iq_head, IntelIOMMUState), + VMSTATE_UINT16(iq_tail, IntelIOMMUState), + VMSTATE_UINT16(iq_size, IntelIOMMUState), + VMSTATE_UINT16(next_frcd_reg, IntelIOMMUState), + VMSTATE_UINT8_ARRAY(csr, IntelIOMMUState, DMAR_REG_SIZE), + VMSTATE_UINT8(iq_last_desc_type, IntelIOMMUState), + VMSTATE_BOOL(root_extended, IntelIOMMUState), + VMSTATE_BOOL(dmar_enabled, IntelIOMMUState), + VMSTATE_BOOL(qi_enabled, IntelIOMMUState), + VMSTATE_BOOL(intr_enabled, IntelIOMMUState), + VMSTATE_BOOL(intr_eime, IntelIOMMUState), + VMSTATE_END_OF_LIST() + } }; static const MemoryRegionOps vtd_mem_ops = { diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index 1a228872fa..2125829a16 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -188,6 +188,7 @@ enum VMStateFlags { typedef enum { MIG_PRI_DEFAULT = 0, + MIG_PRI_IOMMU, /* Must happen before PCI devices */ MIG_PRI_MAX, } MigrationPriority; From a08aaff811fb194950f79711d2afe5a892ae03a4 Mon Sep 17 00:00:00 2001 From: Gonglei Date: Tue, 3 Jan 2017 14:50:03 +0800 Subject: [PATCH 03/41] virtio-crypto: fix possible integer and heap overflow Because the 'size_t' type is 4 bytes in 32-bit platform, which is the same with 'int'. It's easy to make 'max_len' to zero when integer overflow and then cause heap overflow if 'max_len' is zero. Using uint_64 instead of size_t to avoid the integer overflow. Cc: qemu-stable@nongnu.org Reported-by: Li Qiang Signed-off-by: Gonglei Tested-by: Li Qiang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-crypto.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c index 2f2467e859..c23e1ad458 100644 --- a/hw/virtio/virtio-crypto.c +++ b/hw/virtio/virtio-crypto.c @@ -416,7 +416,7 @@ virtio_crypto_sym_op_helper(VirtIODevice *vdev, uint32_t hash_start_src_offset = 0, len_to_hash = 0; uint32_t cipher_start_src_offset = 0, len_to_cipher = 0; - size_t max_len, curr_size = 0; + uint64_t max_len, curr_size = 0; size_t s; /* Plain cipher */ @@ -441,7 +441,7 @@ virtio_crypto_sym_op_helper(VirtIODevice *vdev, return NULL; } - max_len = iv_len + aad_len + src_len + dst_len + hash_result_len; + max_len = (uint64_t)iv_len + aad_len + src_len + dst_len + hash_result_len; if (unlikely(max_len > vcrypto->conf.max_size)) { virtio_error(vdev, "virtio-crypto too big length"); return NULL; From 8607f5c3072caeebbe0217df28651fffd3a79fd9 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Fri, 30 Dec 2016 18:09:10 +0800 Subject: [PATCH 04/41] virtio: convert to use DMA api Currently, all virtio devices bypass IOMMU completely. This is because address_space_memory is assumed and used during DMA emulation. This patch converts the virtio core API to use DMA API. This idea is - introducing a new transport specific helper to query the dma address space. (only pci version is implemented). - query and use this address space during virtio device guest memory accessing when iommu platform (VIRTIO_F_IOMMU_PLATFORM) was enabled for this device. Cc: Michael S. Tsirkin Cc: Stefan Hajnoczi Cc: Kevin Wolf Cc: Amit Shah Cc: Paolo Bonzini Cc: qemu-block@nongnu.org Signed-off-by: Jason Wang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/block/virtio-blk.c | 2 +- hw/char/virtio-serial-bus.c | 3 +- hw/scsi/virtio-scsi.c | 4 ++- hw/virtio/virtio-bus.c | 8 +++++ hw/virtio/virtio-pci.c | 14 ++++++++ hw/virtio/virtio.c | 57 ++++++++++++++++++++----------- include/hw/virtio/virtio-access.h | 31 +++++++++++------ include/hw/virtio/virtio-bus.h | 1 + include/hw/virtio/virtio.h | 9 +++-- 9 files changed, 93 insertions(+), 36 deletions(-) diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index 50bb0cbb93..702eda863e 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -863,7 +863,7 @@ static int virtio_blk_load_device(VirtIODevice *vdev, QEMUFile *f, } } - req = qemu_get_virtqueue_element(f, sizeof(VirtIOBlockReq)); + req = qemu_get_virtqueue_element(vdev, f, sizeof(VirtIOBlockReq)); virtio_blk_init_request(s, virtio_get_queue(vdev, vq_idx), req); req->next = s->rq; s->rq = req; diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c index 7975c2cda1..d544cd91c0 100644 --- a/hw/char/virtio-serial-bus.c +++ b/hw/char/virtio-serial-bus.c @@ -732,6 +732,7 @@ static void virtio_serial_post_load_timer_cb(void *opaque) static int fetch_active_ports_list(QEMUFile *f, VirtIOSerial *s, uint32_t nr_active_ports) { + VirtIODevice *vdev = VIRTIO_DEVICE(s); uint32_t i; s->post_load = g_malloc0(sizeof(*s->post_load)); @@ -765,7 +766,7 @@ static int fetch_active_ports_list(QEMUFile *f, qemu_get_be64s(f, &port->iov_offset); port->elem = - qemu_get_virtqueue_element(f, sizeof(VirtQueueElement)); + qemu_get_virtqueue_element(vdev, f, sizeof(VirtQueueElement)); /* * Port was throttled on source machine. Let's diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 204e14f237..ce19efffc8 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -198,12 +198,14 @@ static void *virtio_scsi_load_request(QEMUFile *f, SCSIRequest *sreq) SCSIBus *bus = sreq->bus; VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus); VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s); + VirtIODevice *vdev = VIRTIO_DEVICE(s); VirtIOSCSIReq *req; uint32_t n; qemu_get_be32s(f, &n); assert(n < vs->conf.num_queues); - req = qemu_get_virtqueue_element(f, sizeof(VirtIOSCSIReq) + vs->cdb_size); + req = qemu_get_virtqueue_element(vdev, f, + sizeof(VirtIOSCSIReq) + vs->cdb_size); virtio_scsi_init_req(s, vs->cmd_vqs[n], req); if (virtio_scsi_parse_req(req, sizeof(VirtIOSCSICmdReq) + vs->cdb_size, diff --git a/hw/virtio/virtio-bus.c b/hw/virtio/virtio-bus.c index d6c0c72bd2..d31cc00e83 100644 --- a/hw/virtio/virtio-bus.c +++ b/hw/virtio/virtio-bus.c @@ -28,6 +28,7 @@ #include "hw/qdev.h" #include "hw/virtio/virtio-bus.h" #include "hw/virtio/virtio.h" +#include "exec/address-spaces.h" /* #define DEBUG_VIRTIO_BUS */ @@ -61,6 +62,13 @@ void virtio_bus_device_plugged(VirtIODevice *vdev, Error **errp) if (klass->device_plugged != NULL) { klass->device_plugged(qbus->parent, errp); } + + if (klass->get_dma_as != NULL && + virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM)) { + vdev->dma_as = klass->get_dma_as(qbus->parent); + } else { + vdev->dma_as = &address_space_memory; + } } /* Reset the virtio_bus */ diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 21c2b9dbfc..213d57e9fe 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1144,6 +1144,14 @@ static int virtio_pci_query_nvectors(DeviceState *d) return proxy->nvectors; } +static AddressSpace *virtio_pci_get_dma_as(DeviceState *d) +{ + VirtIOPCIProxy *proxy = VIRTIO_PCI(d); + PCIDevice *dev = &proxy->pci_dev; + + return pci_get_address_space(dev); +} + static int virtio_pci_add_mem_cap(VirtIOPCIProxy *proxy, struct virtio_pci_cap *cap) { @@ -1601,6 +1609,11 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) } if (legacy) { + if (virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM)) { + error_setg(errp, "VIRTIO_F_IOMMU_PLATFORM was supported by" + "neither legacy nor transitional device."); + return ; + } /* legacy and transitional */ pci_set_word(config + PCI_SUBSYSTEM_VENDOR_ID, pci_get_word(config + PCI_VENDOR_ID)); @@ -2520,6 +2533,7 @@ static void virtio_pci_bus_class_init(ObjectClass *klass, void *data) k->query_nvectors = virtio_pci_query_nvectors; k->ioeventfd_enabled = virtio_pci_ioeventfd_enabled; k->ioeventfd_assign = virtio_pci_ioeventfd_assign; + k->get_dma_as = virtio_pci_get_dma_as; } static const TypeInfo virtio_pci_bus_info = { diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index d40711a31d..933a3d749a 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -23,6 +23,7 @@ #include "hw/virtio/virtio-bus.h" #include "migration/migration.h" #include "hw/virtio/virtio-access.h" +#include "sysemu/dma.h" /* * The alignment to use between consumer and producer parts of vring. @@ -121,7 +122,7 @@ void virtio_queue_update_rings(VirtIODevice *vdev, int n) static void vring_desc_read(VirtIODevice *vdev, VRingDesc *desc, hwaddr desc_pa, int i) { - address_space_read(&address_space_memory, desc_pa + i * sizeof(VRingDesc), + address_space_read(vdev->dma_as, desc_pa + i * sizeof(VRingDesc), MEMTXATTRS_UNSPECIFIED, (void *)desc, sizeof(VRingDesc)); virtio_tswap64s(vdev, &desc->addr); virtio_tswap32s(vdev, &desc->len); @@ -163,7 +164,7 @@ static inline void vring_used_write(VirtQueue *vq, VRingUsedElem *uelem, virtio_tswap32s(vq->vdev, &uelem->id); virtio_tswap32s(vq->vdev, &uelem->len); pa = vq->vring.used + offsetof(VRingUsed, ring[i]); - address_space_write(&address_space_memory, pa, MEMTXATTRS_UNSPECIFIED, + address_space_write(vq->vdev->dma_as, pa, MEMTXATTRS_UNSPECIFIED, (void *)uelem, sizeof(VRingUsedElem)); } @@ -249,6 +250,7 @@ int virtio_queue_empty(VirtQueue *vq) static void virtqueue_unmap_sg(VirtQueue *vq, const VirtQueueElement *elem, unsigned int len) { + AddressSpace *dma_as = vq->vdev->dma_as; unsigned int offset; int i; @@ -256,17 +258,18 @@ static void virtqueue_unmap_sg(VirtQueue *vq, const VirtQueueElement *elem, for (i = 0; i < elem->in_num; i++) { size_t size = MIN(len - offset, elem->in_sg[i].iov_len); - cpu_physical_memory_unmap(elem->in_sg[i].iov_base, - elem->in_sg[i].iov_len, - 1, size); + dma_memory_unmap(dma_as, elem->in_sg[i].iov_base, + elem->in_sg[i].iov_len, + DMA_DIRECTION_FROM_DEVICE, size); offset += size; } for (i = 0; i < elem->out_num; i++) - cpu_physical_memory_unmap(elem->out_sg[i].iov_base, - elem->out_sg[i].iov_len, - 0, elem->out_sg[i].iov_len); + dma_memory_unmap(dma_as, elem->out_sg[i].iov_base, + elem->out_sg[i].iov_len, + DMA_DIRECTION_TO_DEVICE, + elem->out_sg[i].iov_len); } /* virtqueue_detach_element: @@ -560,7 +563,10 @@ static bool virtqueue_map_desc(VirtIODevice *vdev, unsigned int *p_num_sg, goto out; } - iov[num_sg].iov_base = cpu_physical_memory_map(pa, &len, is_write); + iov[num_sg].iov_base = dma_memory_map(vdev->dma_as, pa, &len, + is_write ? + DMA_DIRECTION_FROM_DEVICE : + DMA_DIRECTION_TO_DEVICE); if (!iov[num_sg].iov_base) { virtio_error(vdev, "virtio: bogus descriptor or out of resources"); goto out; @@ -597,9 +603,9 @@ static void virtqueue_undo_map_desc(unsigned int out_num, unsigned int in_num, } } -static void virtqueue_map_iovec(struct iovec *sg, hwaddr *addr, - unsigned int *num_sg, unsigned int max_size, - int is_write) +static void virtqueue_map_iovec(VirtIODevice *vdev, struct iovec *sg, + hwaddr *addr, unsigned int *num_sg, + unsigned int max_size, int is_write) { unsigned int i; hwaddr len; @@ -618,7 +624,10 @@ static void virtqueue_map_iovec(struct iovec *sg, hwaddr *addr, for (i = 0; i < *num_sg; i++) { len = sg[i].iov_len; - sg[i].iov_base = cpu_physical_memory_map(addr[i], &len, is_write); + sg[i].iov_base = dma_memory_map(vdev->dma_as, + addr[i], &len, is_write ? + DMA_DIRECTION_FROM_DEVICE : + DMA_DIRECTION_TO_DEVICE); if (!sg[i].iov_base) { error_report("virtio: error trying to map MMIO memory"); exit(1); @@ -630,12 +639,15 @@ static void virtqueue_map_iovec(struct iovec *sg, hwaddr *addr, } } -void virtqueue_map(VirtQueueElement *elem) +void virtqueue_map(VirtIODevice *vdev, VirtQueueElement *elem) { - virtqueue_map_iovec(elem->in_sg, elem->in_addr, &elem->in_num, - VIRTQUEUE_MAX_SIZE, 1); - virtqueue_map_iovec(elem->out_sg, elem->out_addr, &elem->out_num, - VIRTQUEUE_MAX_SIZE, 0); + virtqueue_map_iovec(vdev, elem->in_sg, elem->in_addr, &elem->in_num, + MIN(ARRAY_SIZE(elem->in_sg), ARRAY_SIZE(elem->in_addr)), + 1); + virtqueue_map_iovec(vdev, elem->out_sg, elem->out_addr, &elem->out_num, + MIN(ARRAY_SIZE(elem->out_sg), + ARRAY_SIZE(elem->out_addr)), + 0); } static void *virtqueue_alloc_element(size_t sz, unsigned out_num, unsigned in_num) @@ -788,7 +800,7 @@ typedef struct VirtQueueElementOld { struct iovec out_sg[VIRTQUEUE_MAX_SIZE]; } VirtQueueElementOld; -void *qemu_get_virtqueue_element(QEMUFile *f, size_t sz) +void *qemu_get_virtqueue_element(VirtIODevice *vdev, QEMUFile *f, size_t sz) { VirtQueueElement *elem; VirtQueueElementOld data; @@ -819,7 +831,7 @@ void *qemu_get_virtqueue_element(QEMUFile *f, size_t sz) elem->out_sg[i].iov_len = data.out_sg[i].iov_len; } - virtqueue_map(elem); + virtqueue_map(vdev, elem); return elem; } @@ -878,6 +890,11 @@ static int virtio_validate_features(VirtIODevice *vdev) { VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); + if (virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM) && + !virtio_vdev_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM)) { + return -EFAULT; + } + if (k->validate_features) { return k->validate_features(vdev); } else { diff --git a/include/hw/virtio/virtio-access.h b/include/hw/virtio/virtio-access.h index 440b4555ea..91ae14d254 100644 --- a/include/hw/virtio/virtio-access.h +++ b/include/hw/virtio/virtio-access.h @@ -17,6 +17,7 @@ #define QEMU_VIRTIO_ACCESS_H #include "hw/virtio/virtio.h" +#include "hw/virtio/virtio-bus.h" #include "exec/address-spaces.h" #if defined(TARGET_PPC64) || defined(TARGET_ARM) @@ -40,45 +41,55 @@ static inline bool virtio_access_is_big_endian(VirtIODevice *vdev) static inline uint16_t virtio_lduw_phys(VirtIODevice *vdev, hwaddr pa) { + AddressSpace *dma_as = vdev->dma_as; + if (virtio_access_is_big_endian(vdev)) { - return lduw_be_phys(&address_space_memory, pa); + return lduw_be_phys(dma_as, pa); } - return lduw_le_phys(&address_space_memory, pa); + return lduw_le_phys(dma_as, pa); } static inline uint32_t virtio_ldl_phys(VirtIODevice *vdev, hwaddr pa) { + AddressSpace *dma_as = vdev->dma_as; + if (virtio_access_is_big_endian(vdev)) { - return ldl_be_phys(&address_space_memory, pa); + return ldl_be_phys(dma_as, pa); } - return ldl_le_phys(&address_space_memory, pa); + return ldl_le_phys(dma_as, pa); } static inline uint64_t virtio_ldq_phys(VirtIODevice *vdev, hwaddr pa) { + AddressSpace *dma_as = vdev->dma_as; + if (virtio_access_is_big_endian(vdev)) { - return ldq_be_phys(&address_space_memory, pa); + return ldq_be_phys(dma_as, pa); } - return ldq_le_phys(&address_space_memory, pa); + return ldq_le_phys(dma_as, pa); } static inline void virtio_stw_phys(VirtIODevice *vdev, hwaddr pa, uint16_t value) { + AddressSpace *dma_as = vdev->dma_as; + if (virtio_access_is_big_endian(vdev)) { - stw_be_phys(&address_space_memory, pa, value); + stw_be_phys(dma_as, pa, value); } else { - stw_le_phys(&address_space_memory, pa, value); + stw_le_phys(dma_as, pa, value); } } static inline void virtio_stl_phys(VirtIODevice *vdev, hwaddr pa, uint32_t value) { + AddressSpace *dma_as = vdev->dma_as; + if (virtio_access_is_big_endian(vdev)) { - stl_be_phys(&address_space_memory, pa, value); + stl_be_phys(dma_as, pa, value); } else { - stl_le_phys(&address_space_memory, pa, value); + stl_le_phys(dma_as, pa, value); } } diff --git a/include/hw/virtio/virtio-bus.h b/include/hw/virtio/virtio-bus.h index 8a51e2c564..a63c1d216d 100644 --- a/include/hw/virtio/virtio-bus.h +++ b/include/hw/virtio/virtio-bus.h @@ -88,6 +88,7 @@ typedef struct VirtioBusClass { * Note that changing this will break migration for this transport. */ bool has_variable_vring_alignment; + AddressSpace *(*get_dma_as)(DeviceState *d); } VirtioBusClass; struct VirtioBusState { diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index ab0e030cc4..5e4176f94c 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -92,6 +92,7 @@ struct VirtIODevice char *bus_name; uint8_t device_endian; bool use_guest_notifier_mask; + AddressSpace *dma_as; QLIST_HEAD(, VirtQueue) *vector_queues; }; @@ -170,9 +171,9 @@ bool virtqueue_rewind(VirtQueue *vq, unsigned int num); void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem, unsigned int len, unsigned int idx); -void virtqueue_map(VirtQueueElement *elem); +void virtqueue_map(VirtIODevice *vdev, VirtQueueElement *elem); void *virtqueue_pop(VirtQueue *vq, size_t sz); -void *qemu_get_virtqueue_element(QEMUFile *f, size_t sz); +void *qemu_get_virtqueue_element(VirtIODevice *vdev, QEMUFile *f, size_t sz); void qemu_put_virtqueue_element(QEMUFile *f, VirtQueueElement *elem); int virtqueue_avail_bytes(VirtQueue *vq, unsigned int in_bytes, unsigned int out_bytes); @@ -255,7 +256,9 @@ typedef struct VirtIORNGConf VirtIORNGConf; DEFINE_PROP_BIT64("notify_on_empty", _state, _field, \ VIRTIO_F_NOTIFY_ON_EMPTY, true), \ DEFINE_PROP_BIT64("any_layout", _state, _field, \ - VIRTIO_F_ANY_LAYOUT, true) + VIRTIO_F_ANY_LAYOUT, true), \ + DEFINE_PROP_BIT64("iommu_platform", _state, _field, \ + VIRTIO_F_IOMMU_PLATFORM, false) hwaddr virtio_queue_get_desc_addr(VirtIODevice *vdev, int n); hwaddr virtio_queue_get_avail_addr(VirtIODevice *vdev, int n); From e0a3c8ccaa51c4b6b2bf093a0b5ef230a74d5a9e Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Fri, 30 Dec 2016 18:09:11 +0800 Subject: [PATCH 05/41] intel_iommu: name vtd address space with devfn To avoid duplicated name and ease debugging. Cc: Michael S. Tsirkin Cc: Paolo Bonzini Cc: Richard Henderson Cc: Eduardo Habkost Acked-by: Peter Xu Signed-off-by: Jason Wang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/intel_iommu.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 119217b612..0dd1c8f3c5 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -2344,6 +2344,7 @@ VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn) uintptr_t key = (uintptr_t)bus; VTDBus *vtd_bus = g_hash_table_lookup(s->vtd_as_by_busptr, &key); VTDAddressSpace *vtd_dev_as; + char name[128]; if (!vtd_bus) { /* No corresponding free() */ @@ -2357,6 +2358,7 @@ VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn) vtd_dev_as = vtd_bus->dev_as[devfn]; if (!vtd_dev_as) { + snprintf(name, sizeof(name), "intel_iommu_devfn_%d", devfn); vtd_bus->dev_as[devfn] = vtd_dev_as = g_malloc0(sizeof(VTDAddressSpace)); vtd_dev_as->bus = bus; @@ -2371,7 +2373,7 @@ VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn) memory_region_add_subregion(&vtd_dev_as->iommu, VTD_INTERRUPT_ADDR_FIRST, &vtd_dev_as->iommu_ir); address_space_init(&vtd_dev_as->as, - &vtd_dev_as->iommu, "intel_iommu"); + &vtd_dev_as->iommu, name); } return vtd_dev_as; } From 2d3fc5816eb629a14f8516bf3c964d7f266870c0 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Fri, 30 Dec 2016 18:09:12 +0800 Subject: [PATCH 06/41] intel_iommu: allocate new key when creating new address space We use the pointer to stack for key for new address space, this will break hash table searching, fixing by g_malloc() a new key instead. Cc: Michael S. Tsirkin Cc: Paolo Bonzini Cc: Richard Henderson Cc: Eduardo Habkost Acked-by: Peter Xu Signed-off-by: Jason Wang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/intel_iommu.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 0dd1c8f3c5..e39b764d75 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -2347,12 +2347,13 @@ VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn) char name[128]; if (!vtd_bus) { + uintptr_t *new_key = g_malloc(sizeof(*new_key)); + *new_key = (uintptr_t)bus; /* No corresponding free() */ vtd_bus = g_malloc0(sizeof(VTDBus) + sizeof(VTDAddressSpace *) * \ X86_IOMMU_PCI_DEVFN_MAX); vtd_bus->bus = bus; - key = (uintptr_t)bus; - g_hash_table_insert(s->vtd_as_by_busptr, &key, vtd_bus); + g_hash_table_insert(s->vtd_as_by_busptr, new_key, vtd_bus); } vtd_dev_as = vtd_bus->dev_as[devfn]; From 052c8fa9983f553fdfa0d61034774070dd639c2b Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Fri, 30 Dec 2016 18:09:13 +0800 Subject: [PATCH 07/41] exec: introduce address_space_get_iotlb_entry() This patch introduces a helper to query the iotlb entry for a possible iova. This will be used by later device IOTLB API to enable the capability for a dataplane (e.g vhost) to query the IOTLB. Cc: Paolo Bonzini Cc: Peter Crosthwaite Cc: Richard Henderson Acked-by: Paolo Bonzini Signed-off-by: Jason Wang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- exec.c | 33 +++++++++++++++++++++++++++++++++ include/exec/memory.h | 5 +++++ 2 files changed, 38 insertions(+) diff --git a/exec.c b/exec.c index 8d4bb0e8c1..47835c1dc1 100644 --- a/exec.c +++ b/exec.c @@ -448,6 +448,39 @@ address_space_translate_internal(AddressSpaceDispatch *d, hwaddr addr, hwaddr *x return section; } +/* Called from RCU critical section */ +IOMMUTLBEntry address_space_get_iotlb_entry(AddressSpace *as, hwaddr addr, + bool is_write) +{ + IOMMUTLBEntry iotlb = {0}; + MemoryRegionSection *section; + MemoryRegion *mr; + + for (;;) { + AddressSpaceDispatch *d = atomic_rcu_read(&as->dispatch); + section = address_space_lookup_region(d, addr, false); + addr = addr - section->offset_within_address_space + + section->offset_within_region; + mr = section->mr; + + if (!mr->iommu_ops) { + break; + } + + iotlb = mr->iommu_ops->translate(mr, addr, is_write); + if (!(iotlb.perm & (1 << is_write))) { + iotlb.target_as = NULL; + break; + } + + addr = ((iotlb.translated_addr & ~iotlb.addr_mask) + | (addr & iotlb.addr_mask)); + as = iotlb.target_as; + } + + return iotlb; +} + /* Called from RCU critical section */ MemoryRegion *address_space_translate(AddressSpace *as, hwaddr addr, hwaddr *xlat, hwaddr *plen, diff --git a/include/exec/memory.h b/include/exec/memory.h index 64560f61b4..358edfbbc7 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -1537,6 +1537,11 @@ void stl_le_phys_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val); void stl_be_phys_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val); void stq_le_phys_cached(MemoryRegionCache *cache, hwaddr addr, uint64_t val); void stq_be_phys_cached(MemoryRegionCache *cache, hwaddr addr, uint64_t val); +/* address_space_get_iotlb_entry: translate an address into an IOTLB + * entry. Should be called from an RCU critical section. + */ +IOMMUTLBEntry address_space_get_iotlb_entry(AddressSpace *as, hwaddr addr, + bool is_write); /* address_space_translate: translate an address range into an address space * into a MemoryRegion and an address range into that section. Should be From 554f5e16046236b264c66436870be1b4ef25c1dc Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Fri, 30 Dec 2016 18:09:14 +0800 Subject: [PATCH 08/41] intel_iommu: support device iotlb descriptor This patch enables device IOTLB support for intel iommu. The major work is to implement QI device IOTLB descriptor processing and notify the device through iommu notifier. Cc: Paolo Bonzini Cc: Richard Henderson Cc: Eduardo Habkost Cc: Michael S. Tsirkin Signed-off-by: Jason Wang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Peter Xu --- hw/i386/intel_iommu.c | 83 ++++++++++++++++++++++++++++++++-- hw/i386/intel_iommu_internal.h | 13 +++++- hw/i386/x86-iommu.c | 17 +++++++ include/hw/i386/x86-iommu.h | 1 + 4 files changed, 107 insertions(+), 7 deletions(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index e39b764d75..ec62239aba 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -738,11 +738,18 @@ static int vtd_dev_to_context_entry(IntelIOMMUState *s, uint8_t bus_num, "context-entry hi 0x%"PRIx64 " lo 0x%"PRIx64, ce->hi, ce->lo); return -VTD_FR_CONTEXT_ENTRY_INV; - } else if (ce->lo & VTD_CONTEXT_ENTRY_TT) { - VTD_DPRINTF(GENERAL, "error: unsupported Translation Type in " - "context-entry hi 0x%"PRIx64 " lo 0x%"PRIx64, - ce->hi, ce->lo); - return -VTD_FR_CONTEXT_ENTRY_INV; + } else { + switch (ce->lo & VTD_CONTEXT_ENTRY_TT) { + case VTD_CONTEXT_TT_MULTI_LEVEL: + /* fall through */ + case VTD_CONTEXT_TT_DEV_IOTLB: + break; + default: + VTD_DPRINTF(GENERAL, "error: unsupported Translation Type in " + "context-entry hi 0x%"PRIx64 " lo 0x%"PRIx64, + ce->hi, ce->lo); + return -VTD_FR_CONTEXT_ENTRY_INV; + } } return 0; } @@ -1438,7 +1445,61 @@ static bool vtd_process_inv_iec_desc(IntelIOMMUState *s, vtd_iec_notify_all(s, !inv_desc->iec.granularity, inv_desc->iec.index, inv_desc->iec.index_mask); + return true; +} +static bool vtd_process_device_iotlb_desc(IntelIOMMUState *s, + VTDInvDesc *inv_desc) +{ + VTDAddressSpace *vtd_dev_as; + IOMMUTLBEntry entry; + struct VTDBus *vtd_bus; + hwaddr addr; + uint64_t sz; + uint16_t sid; + uint8_t devfn; + bool size; + uint8_t bus_num; + + addr = VTD_INV_DESC_DEVICE_IOTLB_ADDR(inv_desc->hi); + sid = VTD_INV_DESC_DEVICE_IOTLB_SID(inv_desc->lo); + devfn = sid & 0xff; + bus_num = sid >> 8; + size = VTD_INV_DESC_DEVICE_IOTLB_SIZE(inv_desc->hi); + + if ((inv_desc->lo & VTD_INV_DESC_DEVICE_IOTLB_RSVD_LO) || + (inv_desc->hi & VTD_INV_DESC_DEVICE_IOTLB_RSVD_HI)) { + VTD_DPRINTF(GENERAL, "error: non-zero reserved field in Device " + "IOTLB Invalidate Descriptor hi 0x%"PRIx64 " lo 0x%"PRIx64, + inv_desc->hi, inv_desc->lo); + return false; + } + + vtd_bus = vtd_find_as_from_bus_num(s, bus_num); + if (!vtd_bus) { + goto done; + } + + vtd_dev_as = vtd_bus->dev_as[devfn]; + if (!vtd_dev_as) { + goto done; + } + + if (size) { + sz = 1 << (ctz64(~(addr | (VTD_PAGE_MASK_4K - 1))) + 1); + addr &= ~(sz - 1); + } else { + sz = VTD_PAGE_SIZE; + } + + entry.target_as = &vtd_dev_as->as; + entry.addr_mask = sz - 1; + entry.iova = addr; + entry.perm = IOMMU_NONE; + entry.translated_addr = 0; + memory_region_notify_iommu(entry.target_as->root, entry); + +done: return true; } @@ -1490,6 +1551,14 @@ static bool vtd_process_inv_desc(IntelIOMMUState *s) } break; + case VTD_INV_DESC_DEVICE: + VTD_DPRINTF(INV, "Device IOTLB Invalidation Descriptor hi 0x%"PRIx64 + " lo 0x%"PRIx64, inv_desc.hi, inv_desc.lo); + if (!vtd_process_device_iotlb_desc(s, &inv_desc)) { + return false; + } + break; + default: VTD_DPRINTF(GENERAL, "error: unkonw Invalidation Descriptor type " "hi 0x%"PRIx64 " lo 0x%"PRIx64 " type %"PRIu8, @@ -2415,6 +2484,10 @@ static void vtd_init(IntelIOMMUState *s) assert(s->intr_eim != ON_OFF_AUTO_AUTO); } + if (x86_iommu->dt_supported) { + s->ecap |= VTD_ECAP_DT; + } + vtd_reset_context_cache(s); vtd_reset_iotlb(s); diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h index 11abfa2233..356f188b73 100644 --- a/hw/i386/intel_iommu_internal.h +++ b/hw/i386/intel_iommu_internal.h @@ -183,6 +183,7 @@ /* (offset >> 4) << 8 */ #define VTD_ECAP_IRO (DMAR_IOTLB_REG_OFFSET << 4) #define VTD_ECAP_QI (1ULL << 1) +#define VTD_ECAP_DT (1ULL << 2) /* Interrupt Remapping support */ #define VTD_ECAP_IR (1ULL << 3) #define VTD_ECAP_EIM (1ULL << 4) @@ -326,6 +327,7 @@ typedef union VTDInvDesc VTDInvDesc; #define VTD_INV_DESC_TYPE 0xf #define VTD_INV_DESC_CC 0x1 /* Context-cache Invalidate Desc */ #define VTD_INV_DESC_IOTLB 0x2 +#define VTD_INV_DESC_DEVICE 0x3 #define VTD_INV_DESC_IEC 0x4 /* Interrupt Entry Cache Invalidate Descriptor */ #define VTD_INV_DESC_WAIT 0x5 /* Invalidation Wait Descriptor */ @@ -361,6 +363,13 @@ typedef union VTDInvDesc VTDInvDesc; #define VTD_INV_DESC_IOTLB_RSVD_LO 0xffffffff0000ff00ULL #define VTD_INV_DESC_IOTLB_RSVD_HI 0xf80ULL +/* Mask for Device IOTLB Invalidate Descriptor */ +#define VTD_INV_DESC_DEVICE_IOTLB_ADDR(val) ((val) & 0xfffffffffffff000ULL) +#define VTD_INV_DESC_DEVICE_IOTLB_SIZE(val) ((val) & 0x1) +#define VTD_INV_DESC_DEVICE_IOTLB_SID(val) (((val) >> 32) & 0xFFFFULL) +#define VTD_INV_DESC_DEVICE_IOTLB_RSVD_HI 0xffeULL +#define VTD_INV_DESC_DEVICE_IOTLB_RSVD_LO 0xffff0000ffe0fff8 + /* Information about page-selective IOTLB invalidate */ struct VTDIOTLBPageInvInfo { uint16_t domain_id; @@ -399,8 +408,8 @@ typedef struct VTDRootEntry VTDRootEntry; #define VTD_CONTEXT_ENTRY_FPD (1ULL << 1) /* Fault Processing Disable */ #define VTD_CONTEXT_ENTRY_TT (3ULL << 2) /* Translation Type */ #define VTD_CONTEXT_TT_MULTI_LEVEL 0 -#define VTD_CONTEXT_TT_DEV_IOTLB 1 -#define VTD_CONTEXT_TT_PASS_THROUGH 2 +#define VTD_CONTEXT_TT_DEV_IOTLB (1ULL << 2) +#define VTD_CONTEXT_TT_PASS_THROUGH (2ULL << 2) /* Second Level Page Translation Pointer*/ #define VTD_CONTEXT_ENTRY_SLPTPTR (~0xfffULL) #define VTD_CONTEXT_ENTRY_RSVD_LO (0xff0ULL | ~VTD_HAW_MASK) diff --git a/hw/i386/x86-iommu.c b/hw/i386/x86-iommu.c index 2278af7c32..23dcd3f039 100644 --- a/hw/i386/x86-iommu.c +++ b/hw/i386/x86-iommu.c @@ -106,6 +106,18 @@ static void x86_iommu_intremap_prop_set(Object *o, bool value, Error **errp) s->intr_supported = value; } +static bool x86_iommu_device_iotlb_prop_get(Object *o, Error **errp) +{ + X86IOMMUState *s = X86_IOMMU_DEVICE(o); + return s->dt_supported; +} + +static void x86_iommu_device_iotlb_prop_set(Object *o, bool value, Error **errp) +{ + X86IOMMUState *s = X86_IOMMU_DEVICE(o); + s->dt_supported = value; +} + static void x86_iommu_instance_init(Object *o) { X86IOMMUState *s = X86_IOMMU_DEVICE(o); @@ -114,6 +126,11 @@ static void x86_iommu_instance_init(Object *o) s->intr_supported = false; object_property_add_bool(o, "intremap", x86_iommu_intremap_prop_get, x86_iommu_intremap_prop_set, NULL); + s->dt_supported = false; + object_property_add_bool(o, "device-iotlb", + x86_iommu_device_iotlb_prop_get, + x86_iommu_device_iotlb_prop_set, + NULL); } static const TypeInfo x86_iommu_info = { diff --git a/include/hw/i386/x86-iommu.h b/include/hw/i386/x86-iommu.h index 0c89d9835b..361c07cdc6 100644 --- a/include/hw/i386/x86-iommu.h +++ b/include/hw/i386/x86-iommu.h @@ -73,6 +73,7 @@ typedef struct IEC_Notifier IEC_Notifier; struct X86IOMMUState { SysBusDevice busdev; bool intr_supported; /* Whether vIOMMU supports IR */ + bool dt_supported; /* Whether vIOMMU supports DT */ IommuType type; /* IOMMU type - AMD/Intel */ QLIST_HEAD(, IEC_Notifier) iec_notifiers; /* IEC notify list */ }; From 615c4ed20598ab3eda5e071ba7ba2a5bf70be59f Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Fri, 30 Dec 2016 18:09:15 +0800 Subject: [PATCH 09/41] virtio-pci: address space translation service (ATS) support This patches enable the Address Translation Service support for virtio pci devices. This is needed for a guest visible Device IOTLB implementation and will be required by vhost device IOTLB API implementation for intel IOMMU. Cc: Michael S. Tsirkin Signed-off-by: Jason Wang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci/pcie.c | 15 +++++++++++++++ hw/virtio/virtio-pci.c | 7 +++++++ hw/virtio/virtio-pci.h | 4 ++++ include/hw/pci/pcie.h | 4 ++++ include/standard-headers/linux/pci_regs.h | 1 + 5 files changed, 31 insertions(+) diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c index 99cfb4561b..adeda04036 100644 --- a/hw/pci/pcie.c +++ b/hw/pci/pcie.c @@ -717,3 +717,18 @@ void pcie_dev_ser_num_init(PCIDevice *dev, uint16_t offset, uint64_t ser_num) PCI_EXT_CAP_DSN_SIZEOF); pci_set_quad(dev->config + offset + pci_dsn_cap, ser_num); } + +void pcie_ats_init(PCIDevice *dev, uint16_t offset) +{ + pcie_add_capability(dev, PCI_EXT_CAP_ID_ATS, 0x1, + offset, PCI_EXT_CAP_ATS_SIZEOF); + + dev->exp.ats_cap = offset; + + /* Invalidate Queue Depth 0, Page Aligned Request 0 */ + pci_set_word(dev->config + offset + PCI_ATS_CAP, 0); + /* STU 0, Disabled by default */ + pci_set_word(dev->config + offset + PCI_ATS_CTRL, 0); + + pci_set_word(dev->wmask + dev->exp.ats_cap + PCI_ATS_CTRL, 0x800f); +} diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 213d57e9fe..854b8f22bf 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1815,6 +1815,11 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp) * PCI Power Management Interface Specification. */ pci_set_word(pci_dev->config + pos + PCI_PM_PMC, 0x3); + + if (proxy->flags & VIRTIO_PCI_FLAG_ATS) { + pcie_ats_init(pci_dev, 256); + } + } else { /* * make future invocations of pci_is_express() return false @@ -1868,6 +1873,8 @@ static Property virtio_pci_properties[] = { VIRTIO_PCI_FLAG_PAGE_PER_VQ_BIT, false), DEFINE_PROP_BOOL("x-ignore-backend-features", VirtIOPCIProxy, ignore_backend_features, false), + DEFINE_PROP_BIT("ats", VirtIOPCIProxy, flags, + VIRTIO_PCI_FLAG_ATS_BIT, false), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h index 5e078866c4..d00064cc0c 100644 --- a/hw/virtio/virtio-pci.h +++ b/hw/virtio/virtio-pci.h @@ -72,6 +72,7 @@ enum { VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY_BIT, VIRTIO_PCI_FLAG_DISABLE_PCIE_BIT, VIRTIO_PCI_FLAG_PAGE_PER_VQ_BIT, + VIRTIO_PCI_FLAG_ATS_BIT, }; /* Need to activate work-arounds for buggy guests at vmstate load. */ @@ -96,6 +97,9 @@ enum { #define VIRTIO_PCI_FLAG_PAGE_PER_VQ \ (1 << VIRTIO_PCI_FLAG_PAGE_PER_VQ_BIT) +/* address space translation service */ +#define VIRTIO_PCI_FLAG_ATS (1 << VIRTIO_PCI_FLAG_ATS_BIT) + typedef struct { MSIMessage msg; int virq; diff --git a/include/hw/pci/pcie.h b/include/hw/pci/pcie.h index 056d25e53c..b08451d2c5 100644 --- a/include/hw/pci/pcie.h +++ b/include/hw/pci/pcie.h @@ -74,6 +74,9 @@ struct PCIExpressDevice { /* AER */ uint16_t aer_cap; PCIEAERLog aer_log; + + /* Offset of ATS capability in config space */ + uint16_t ats_cap; }; #define COMPAT_PROP_PCP "power_controller_present" @@ -120,6 +123,7 @@ void pcie_add_capability(PCIDevice *dev, void pcie_ari_init(PCIDevice *dev, uint16_t offset, uint16_t nextfn); void pcie_dev_ser_num_init(PCIDevice *dev, uint16_t offset, uint64_t ser_num); +void pcie_ats_init(PCIDevice *dev, uint16_t offset); extern const VMStateDescription vmstate_pcie_device; diff --git a/include/standard-headers/linux/pci_regs.h b/include/standard-headers/linux/pci_regs.h index e5a2e68b22..be5b066aa4 100644 --- a/include/standard-headers/linux/pci_regs.h +++ b/include/standard-headers/linux/pci_regs.h @@ -678,6 +678,7 @@ #define PCI_EXT_CAP_ID_MAX PCI_EXT_CAP_ID_PTM #define PCI_EXT_CAP_DSN_SIZEOF 12 +#define PCI_EXT_CAP_ATS_SIZEOF 8 #define PCI_EXT_CAP_MCAST_ENDPOINT_SIZEOF 40 /* Advanced Error Reporting */ From bd2baaccd521a9cfcc56e0a9a69c903fcee56aa4 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Fri, 30 Dec 2016 18:09:16 +0800 Subject: [PATCH 10/41] acpi: add ATSR for q35 This patch provides ATSR which was a requirement for software that wants to enable ATS on endpoint devices behind a Root Port. This is done simply by setting ALL_PORTS which indicates all PCI-Express Root Ports support ATS transactions. Signed-off-by: Jason Wang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/acpi-build.c | 9 +++++++++ include/hw/acpi/acpi-defs.h | 12 ++++++++++++ 2 files changed, 21 insertions(+) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 42ecf619d5..4609db1359 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -2575,6 +2575,7 @@ build_dmar_q35(GArray *table_data, BIOSLinker *linker) AcpiTableDmar *dmar; AcpiDmarHardwareUnit *drhd; + AcpiDmarRootPortATS *atsr; uint8_t dmar_flags = 0; X86IOMMUState *iommu = x86_iommu_get_default(); AcpiDmarDeviceScope *scope = NULL; @@ -2608,6 +2609,14 @@ build_dmar_q35(GArray *table_data, BIOSLinker *linker) scope->path[0].device = PCI_SLOT(Q35_PSEUDO_DEVFN_IOAPIC); scope->path[0].function = PCI_FUNC(Q35_PSEUDO_DEVFN_IOAPIC); + if (iommu->dt_supported) { + atsr = acpi_data_push(table_data, sizeof(*atsr)); + atsr->type = cpu_to_le16(ACPI_DMAR_TYPE_ATSR); + atsr->length = cpu_to_le16(sizeof(*atsr)); + atsr->flags = ACPI_DMAR_ATSR_ALL_PORTS; + atsr->pci_segment = cpu_to_le16(0); + } + build_header(linker, table_data, (void *)(table_data->data + dmar_start), "DMAR", table_data->len - dmar_start, 1, NULL, NULL); } diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h index d43ec005cb..4cc3630e61 100644 --- a/include/hw/acpi/acpi-defs.h +++ b/include/hw/acpi/acpi-defs.h @@ -627,8 +627,20 @@ struct AcpiDmarHardwareUnit { } QEMU_PACKED; typedef struct AcpiDmarHardwareUnit AcpiDmarHardwareUnit; +/* Type 2: Root Port ATS Capability Reporting Structure */ +struct AcpiDmarRootPortATS { + uint16_t type; + uint16_t length; + uint8_t flags; + uint8_t reserved; + uint16_t pci_segment; + AcpiDmarDeviceScope scope[0]; +} QEMU_PACKED; +typedef struct AcpiDmarRootPortATS AcpiDmarRootPortATS; + /* Masks for Flags field above */ #define ACPI_DMAR_INCLUDE_PCI_ALL 1 +#define ACPI_DMAR_ATSR_ALL_PORTS 1 /* * Input Output Remapping Table (IORT) From efcd38c529fd9c461cfcd48265855ce6aab2ef0a Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Fri, 30 Dec 2016 18:09:17 +0800 Subject: [PATCH 11/41] memory: handle alias for iommu notifier Cc: Paolo Bonzini Acked-by: Paolo Bonzini Signed-off-by: Jason Wang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Peter Xu --- memory.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/memory.c b/memory.c index 33110e9698..2bfc37f65c 100644 --- a/memory.c +++ b/memory.c @@ -1603,6 +1603,11 @@ static void memory_region_update_iommu_notify_flags(MemoryRegion *mr) void memory_region_register_iommu_notifier(MemoryRegion *mr, IOMMUNotifier *n) { + if (mr->alias) { + memory_region_register_iommu_notifier(mr->alias, n); + return; + } + /* We need to register for at least one bitfield */ assert(n->notifier_flags != IOMMU_NOTIFIER_NONE); QLIST_INSERT_HEAD(&mr->iommu_notify, n, node); @@ -1643,6 +1648,10 @@ void memory_region_iommu_replay(MemoryRegion *mr, IOMMUNotifier *n, void memory_region_unregister_iommu_notifier(MemoryRegion *mr, IOMMUNotifier *n) { + if (mr->alias) { + memory_region_unregister_iommu_notifier(mr->alias, n); + return; + } QLIST_REMOVE(n, node); memory_region_update_iommu_notify_flags(mr); } From 12d37882f0c0def5dee1c21be5d8fea9c21baada Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Fri, 30 Dec 2016 18:09:18 +0800 Subject: [PATCH 12/41] memory: handle alias in memory_region_is_iommu() Cc: Paolo Bonzini Acked-by: Paolo Bonzini Signed-off-by: Jason Wang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Peter Xu --- include/exec/memory.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/exec/memory.h b/include/exec/memory.h index 358edfbbc7..bec9756667 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -628,6 +628,9 @@ static inline bool memory_region_is_romd(MemoryRegion *mr) */ static inline bool memory_region_is_iommu(MemoryRegion *mr) { + if (mr->alias) { + return memory_region_is_iommu(mr->alias); + } return mr->iommu_ops; } From 2e41dfe152331c4f5a8e6ccdb80bfc0d07422e82 Mon Sep 17 00:00:00 2001 From: Cao jin Date: Thu, 29 Dec 2016 09:19:37 +0800 Subject: [PATCH 13/41] doc/pcie: correct command line examples Nit picking: Multi-function PCI Express Root Ports should mean that 'addr' property is mandatory, and slot is optional because it defaults to 0, and 'chassis' is mandatory for 2nd & 3rd root port because it defaults to 0 too. Bonus: fix a typo(2->3) Signed-off-by: Cao jin Reviewed-by: Marcel Apfelbaum Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- docs/pcie.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/pcie.txt b/docs/pcie.txt index 9fb20aaed9..5bada24a15 100644 --- a/docs/pcie.txt +++ b/docs/pcie.txt @@ -110,18 +110,18 @@ Plug only PCI Express devices into PCI Express Ports. -device ioh3420,id=root_port1,chassis=x,slot=y[,bus=pcie.0][,addr=z] \ -device ,bus=root_port1 2.2.2 Using multi-function PCI Express Root Ports: - -device ioh3420,id=root_port1,multifunction=on,chassis=x,slot=y[,bus=pcie.0][,addr=z.0] \ - -device ioh3420,id=root_port2,chassis=x1,slot=y1[,bus=pcie.0][,addr=z.1] \ - -device ioh3420,id=root_port3,chassis=x2,slot=y2[,bus=pcie.0][,addr=z.2] \ -2.2.2 Plugging a PCI Express device into a Switch: + -device ioh3420,id=root_port1,multifunction=on,chassis=x,addr=z.0[,slot=y][,bus=pcie.0] \ + -device ioh3420,id=root_port2,chassis=x1,addr=z.1[,slot=y1][,bus=pcie.0] \ + -device ioh3420,id=root_port3,chassis=x2,addr=z.2[,slot=y2][,bus=pcie.0] \ +2.2.3 Plugging a PCI Express device into a Switch: -device ioh3420,id=root_port1,chassis=x,slot=y[,bus=pcie.0][,addr=z] \ -device x3130-upstream,id=upstream_port1,bus=root_port1[,addr=x] \ -device xio3130-downstream,id=downstream_port1,bus=upstream_port1,chassis=x1,slot=y1[,addr=z1]] \ -device ,bus=downstream_port1 Notes: - - (slot, chassis) pair is mandatory and must be - unique for each PCI Express Root Port. + - (slot, chassis) pair is mandatory and must be unique for each + PCI Express Root Port. slot defaults to 0 when not specified. - 'addr' parameter can be 0 for all the examples above. From c159a4d1d0434fcf670f8684273bce0eca117a27 Mon Sep 17 00:00:00 2001 From: Gonglei Date: Thu, 22 Dec 2016 11:37:03 +0800 Subject: [PATCH 14/41] virtio-crypto: use the correct length for cipher operation In some modes of cipher algorithms, the length of destination data maybe larger then source data, such as ciphertext stealing (CTS). For symmetric algorithms, the length of ciphertext is definitly equal to the plaintext for each crypto operation. So we should use the src_len instead of dst_len avoid to pass the incorrect cryptographical results to the frontend driver. Signed-off-by: Gonglei Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-crypto.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c index c23e1ad458..f872c87cb9 100644 --- a/hw/virtio/virtio-crypto.c +++ b/hw/virtio/virtio-crypto.c @@ -355,7 +355,7 @@ virtio_crypto_sym_input_data_helper(VirtIODevice *vdev, return; } - len = sym_op_info->dst_len; + len = sym_op_info->src_len; /* Save the cipher result */ s = iov_from_buf(req->in_iov, req->in_num, 0, sym_op_info->dst, len); if (s != len) { From 46fd17054548b15b3b8a5991492f5f0dc37957d4 Mon Sep 17 00:00:00 2001 From: Gonglei Date: Thu, 22 Dec 2016 11:12:38 +0800 Subject: [PATCH 15/41] cryptodev: introduce a new is_used property This property is used to Tag the cryptodev backend is used by virtio-crypto or not. Making cryptodev can't be hot unplugged when it's in use. Cleanup resources when cryptodev is finalized. Signed-off-by: Gonglei Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- backends/cryptodev.c | 19 +++++++++++++++++++ hw/virtio/virtio-crypto.c | 2 ++ include/sysemu/cryptodev.h | 23 +++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/backends/cryptodev.c b/backends/cryptodev.c index 4a49f9762f..6a66c27d68 100644 --- a/backends/cryptodev.c +++ b/backends/cryptodev.c @@ -197,6 +197,22 @@ out: error_propagate(errp, local_err); } +void cryptodev_backend_set_used(CryptoDevBackend *backend, bool used) +{ + backend->is_used = used; +} + +bool cryptodev_backend_is_used(CryptoDevBackend *backend) +{ + return backend->is_used; +} + +static bool +cryptodev_backend_can_be_deleted(UserCreatable *uc, Error **errp) +{ + return !cryptodev_backend_is_used(CRYPTODEV_BACKEND(uc)); +} + static void cryptodev_backend_instance_init(Object *obj) { object_property_add(obj, "queues", "int", @@ -209,7 +225,9 @@ static void cryptodev_backend_instance_init(Object *obj) static void cryptodev_backend_finalize(Object *obj) { + CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj); + cryptodev_backend_cleanup(backend, NULL); } static void @@ -218,6 +236,7 @@ cryptodev_backend_class_init(ObjectClass *oc, void *data) UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); ucc->complete = cryptodev_backend_complete; + ucc->can_be_deleted = cryptodev_backend_can_be_deleted; QTAILQ_INIT(&crypto_clients); } diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c index f872c87cb9..6318fcf01b 100644 --- a/hw/virtio/virtio-crypto.c +++ b/hw/virtio/virtio-crypto.c @@ -799,6 +799,7 @@ static void virtio_crypto_device_realize(DeviceState *dev, Error **errp) } virtio_crypto_init_config(vdev); + cryptodev_backend_set_used(vcrypto->cryptodev, true); } static void virtio_crypto_device_unrealize(DeviceState *dev, Error **errp) @@ -818,6 +819,7 @@ static void virtio_crypto_device_unrealize(DeviceState *dev, Error **errp) g_free(vcrypto->vqs); virtio_cleanup(vdev); + cryptodev_backend_set_used(vcrypto->cryptodev, false); } static const VMStateDescription vmstate_virtio_crypto = { diff --git a/include/sysemu/cryptodev.h b/include/sysemu/cryptodev.h index 84526c0d35..461389df85 100644 --- a/include/sysemu/cryptodev.h +++ b/include/sysemu/cryptodev.h @@ -202,6 +202,8 @@ struct CryptoDevBackend { Object parent_obj; bool ready; + /* Tag the cryptodev backend is used by virtio-crypto or not */ + bool is_used; CryptoDevBackendConf conf; }; @@ -295,4 +297,25 @@ int cryptodev_backend_crypto_operation( void *opaque, uint32_t queue_index, Error **errp); +/** + * cryptodev_backend_set_used: + * @backend: the cryptodev backend object + * @used: ture or false + * + * Set the cryptodev backend is used by virtio-crypto or not + */ +void cryptodev_backend_set_used(CryptoDevBackend *backend, bool used); + +/** + * cryptodev_backend_is_used: + * @backend: the cryptodev backend object + * + * Return the status that the cryptodev backend is used + * by virtio-crypto or not + * + * Returns: true on used, or false on not used + */ +bool cryptodev_backend_is_used(CryptoDevBackend *backend); + + #endif /* CRYPTODEV_H */ From 6138dbda5a4bfa6c724fd04b9225181d3a3c85a7 Mon Sep 17 00:00:00 2001 From: Gonglei Date: Thu, 22 Dec 2016 11:12:39 +0800 Subject: [PATCH 16/41] cryptodev: wrap the ready flag The ready flag should be set by the children of cryptodev backend interface. Warp the setter/getter functions for it. Signed-off-by: Gonglei Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- backends/cryptodev-builtin.c | 4 ++++ backends/cryptodev.c | 15 +++++++++++---- hw/virtio/virtio-crypto.c | 4 ++-- include/sysemu/cryptodev.h | 19 +++++++++++++++++++ 4 files changed, 36 insertions(+), 6 deletions(-) diff --git a/backends/cryptodev-builtin.c b/backends/cryptodev-builtin.c index 486b4a62bc..82a068e792 100644 --- a/backends/cryptodev-builtin.c +++ b/backends/cryptodev-builtin.c @@ -94,6 +94,8 @@ static void cryptodev_builtin_init( backend->conf.max_size = LONG_MAX - sizeof(CryptoDevBackendSymOpInfo); backend->conf.max_cipher_key_len = CRYPTODEV_BUITLIN_MAX_CIPHER_KEY_LEN; backend->conf.max_auth_key_len = CRYPTODEV_BUITLIN_MAX_AUTH_KEY_LEN; + + cryptodev_backend_set_ready(backend, true); } static int @@ -366,6 +368,8 @@ static void cryptodev_builtin_cleanup( backend->conf.peers.ccs[i] = NULL; } } + + cryptodev_backend_set_ready(backend, false); } static void diff --git a/backends/cryptodev.c b/backends/cryptodev.c index 6a66c27d68..832f056266 100644 --- a/backends/cryptodev.c +++ b/backends/cryptodev.c @@ -73,8 +73,6 @@ void cryptodev_backend_cleanup( if (bc->cleanup) { bc->cleanup(backend, errp); } - - backend->ready = false; } int64_t cryptodev_backend_sym_create_session( @@ -189,11 +187,10 @@ cryptodev_backend_complete(UserCreatable *uc, Error **errp) goto out; } } - backend->ready = true; + return; out: - backend->ready = false; error_propagate(errp, local_err); } @@ -207,6 +204,16 @@ bool cryptodev_backend_is_used(CryptoDevBackend *backend) return backend->is_used; } +void cryptodev_backend_set_ready(CryptoDevBackend *backend, bool ready) +{ + backend->ready = ready; +} + +bool cryptodev_backend_is_ready(CryptoDevBackend *backend) +{ + return backend->ready; +} + static bool cryptodev_backend_can_be_deleted(UserCreatable *uc, Error **errp) { diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c index 6318fcf01b..9213258f6f 100644 --- a/hw/virtio/virtio-crypto.c +++ b/hw/virtio/virtio-crypto.c @@ -732,7 +732,7 @@ static void virtio_crypto_reset(VirtIODevice *vdev) VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev); /* multiqueue is disabled by default */ vcrypto->curr_queues = 1; - if (!vcrypto->cryptodev->ready) { + if (!cryptodev_backend_is_ready(vcrypto->cryptodev)) { vcrypto->status &= ~VIRTIO_CRYPTO_S_HW_READY; } else { vcrypto->status |= VIRTIO_CRYPTO_S_HW_READY; @@ -792,7 +792,7 @@ static void virtio_crypto_device_realize(DeviceState *dev, Error **errp) } vcrypto->ctrl_vq = virtio_add_queue(vdev, 64, virtio_crypto_handle_ctrl); - if (!vcrypto->cryptodev->ready) { + if (!cryptodev_backend_is_ready(vcrypto->cryptodev)) { vcrypto->status &= ~VIRTIO_CRYPTO_S_HW_READY; } else { vcrypto->status |= VIRTIO_CRYPTO_S_HW_READY; diff --git a/include/sysemu/cryptodev.h b/include/sysemu/cryptodev.h index 461389df85..a9d0d1ee25 100644 --- a/include/sysemu/cryptodev.h +++ b/include/sysemu/cryptodev.h @@ -317,5 +317,24 @@ void cryptodev_backend_set_used(CryptoDevBackend *backend, bool used); */ bool cryptodev_backend_is_used(CryptoDevBackend *backend); +/** + * cryptodev_backend_set_ready: + * @backend: the cryptodev backend object + * @ready: ture or false + * + * Set the cryptodev backend is ready or not, which is called + * by the children of the cryptodev banckend interface. + */ +void cryptodev_backend_set_ready(CryptoDevBackend *backend, bool ready); + +/** + * cryptodev_backend_is_ready: + * @backend: the cryptodev backend object + * + * Return the status that the cryptodev backend is ready or not + * + * Returns: true on ready, or false on not ready + */ +bool cryptodev_backend_is_ready(CryptoDevBackend *backend); #endif /* CRYPTODEV_H */ From 305f5131ac30b4a03e698bae0976f4cd24bb0a86 Mon Sep 17 00:00:00 2001 From: Gonglei Date: Thu, 22 Dec 2016 11:12:40 +0800 Subject: [PATCH 17/41] virtio-crypto-pci: add check for cryptodev object We must assure each virtio crypto pci device has an vaild cryptodev backend object. Signed-off-by: Gonglei Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-crypto-pci.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/virtio/virtio-crypto-pci.c b/hw/virtio/virtio-crypto-pci.c index a1b09064c0..14bd12c634 100644 --- a/hw/virtio/virtio-crypto-pci.c +++ b/hw/virtio/virtio-crypto-pci.c @@ -31,6 +31,11 @@ static void virtio_crypto_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) VirtIOCryptoPCI *vcrypto = VIRTIO_CRYPTO_PCI(vpci_dev); DeviceState *vdev = DEVICE(&vcrypto->vdev); + if (vcrypto->vdev.conf.cryptodev == NULL) { + error_setg(errp, "'cryptodev' parameter expects a valid object"); + return; + } + qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); virtio_pci_force_virtio_1(vpci_dev); object_property_set_bool(OBJECT(vdev), true, "realized", errp); From b89f8c80ccdaf6915271df6bb16ef6b292f47f9f Mon Sep 17 00:00:00 2001 From: Gonglei Date: Thu, 22 Dec 2016 11:12:41 +0800 Subject: [PATCH 18/41] virtio-crypto: avoid one cryptodev device is used by multiple virtio crypto devices Add the check condition for cryptodev device in order to avoid one cryptodev device is used by multiple virtio crypto devices. Signed-off-by: Gonglei Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-crypto.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c index 9213258f6f..fc30bc3ddc 100644 --- a/hw/virtio/virtio-crypto.c +++ b/hw/virtio/virtio-crypto.c @@ -877,6 +877,20 @@ static void virtio_crypto_class_init(ObjectClass *klass, void *data) vdc->reset = virtio_crypto_reset; } +static void +virtio_crypto_check_cryptodev_is_used(Object *obj, const char *name, + Object *val, Error **errp) +{ + if (cryptodev_backend_is_used(CRYPTODEV_BACKEND(val))) { + char *path = object_get_canonical_path_component(val); + error_setg(errp, + "can't use already used cryptodev backend: %s", path); + g_free(path); + } else { + qdev_prop_allow_set_link_before_realize(obj, name, val, errp); + } +} + static void virtio_crypto_instance_init(Object *obj) { VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(obj); @@ -890,7 +904,7 @@ static void virtio_crypto_instance_init(Object *obj) object_property_add_link(obj, "cryptodev", TYPE_CRYPTODEV_BACKEND, (Object **)&vcrypto->conf.cryptodev, - qdev_prop_allow_set_link_before_realize, + virtio_crypto_check_cryptodev_is_used, OBJ_PROP_LINK_UNREF_ON_RELEASE, NULL); } From ef69d971cd63cd427e602098837bd09bcddd9410 Mon Sep 17 00:00:00 2001 From: Gonglei Date: Thu, 22 Dec 2016 11:12:42 +0800 Subject: [PATCH 19/41] virtio-crypto-pci: tag virtio-crypto device hot pluggable After resolving the relationship with cryptodev backend, the virtio crypto device supports hotplug now. Signed-off-by: Gonglei Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-crypto-pci.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/virtio/virtio-crypto-pci.c b/hw/virtio/virtio-crypto-pci.c index 14bd12c634..422aca3a98 100644 --- a/hw/virtio/virtio-crypto-pci.c +++ b/hw/virtio/virtio-crypto-pci.c @@ -53,7 +53,6 @@ static void virtio_crypto_pci_class_init(ObjectClass *klass, void *data) k->realize = virtio_crypto_pci_realize; set_bit(DEVICE_CATEGORY_MISC, dc->categories); dc->props = virtio_crypto_pci_properties; - dc->hotpluggable = false; pcidev_k->class_id = PCI_CLASS_OTHERS; } From 02ed3e7c1665205ddae052774d6f26c71d3d9b30 Mon Sep 17 00:00:00 2001 From: Gonglei Date: Thu, 22 Dec 2016 11:01:28 +0800 Subject: [PATCH 20/41] virtio-crypto: zeroize the key material before free Common practice with sensitive information (key material, passwords, etc). Prevents sensitive information from being exposed by accident later in coredumps, memory disclosure bugs when heap memory is reused, etc. Sensitive information is sometimes also held in mlocked pages to prevent it being swapped to disk but that's not being done here. Let's zeroize the memory of CryptoDevBackendSymOpInfo structure pointed for key material security. [Thanks to Stefan for help with crafting the commit message] Signed-off-by: Gonglei Reviewed-by: Stefan Hajnoczi Reviewed-by: Eric Blake Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-crypto.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c index fc30bc3ddc..296472fc6e 100644 --- a/hw/virtio/virtio-crypto.c +++ b/hw/virtio/virtio-crypto.c @@ -337,7 +337,18 @@ static void virtio_crypto_free_request(VirtIOCryptoReq *req) { if (req) { if (req->flags == CRYPTODEV_BACKEND_ALG_SYM) { - g_free(req->u.sym_op_info); + size_t max_len; + CryptoDevBackendSymOpInfo *op_info = req->u.sym_op_info; + + max_len = op_info->iv_len + + op_info->aad_len + + op_info->src_len + + op_info->dst_len + + op_info->digest_result_len; + + /* Zeroize and free request data structure */ + memset(op_info, 0, sizeof(*op_info) + max_len); + g_free(op_info); } g_free(req); } From 33848ceed79679b5c9e558b768447af2614b8db2 Mon Sep 17 00:00:00 2001 From: Cao jin Date: Wed, 21 Dec 2016 16:21:30 +0800 Subject: [PATCH 21/41] pcie_aer: Convert pcie_aer_init to Error When user specify invalid value for property aer_log_max, device should fail to create, and report appropriate message. Signed-off-by: Cao jin Reviewed-by: Marcel Apfelbaum Acked-by: Dmitry Fleytman Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/net/e1000e.c | 2 +- hw/pci-bridge/ioh3420.c | 3 ++- hw/pci-bridge/xio3130_downstream.c | 3 ++- hw/pci-bridge/xio3130_upstream.c | 3 ++- hw/pci/pcie_aer.c | 17 +++++++---------- include/hw/pci/pcie_aer.h | 4 ++-- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/hw/net/e1000e.c b/hw/net/e1000e.c index 4994e1ca00..89f96eb4a0 100644 --- a/hw/net/e1000e.c +++ b/hw/net/e1000e.c @@ -472,7 +472,7 @@ static void e1000e_pci_realize(PCIDevice *pci_dev, Error **errp) hw_error("Failed to initialize PM capability"); } - if (pcie_aer_init(pci_dev, e1000e_aer_offset, PCI_ERR_SIZEOF) < 0) { + if (pcie_aer_init(pci_dev, e1000e_aer_offset, PCI_ERR_SIZEOF, NULL) < 0) { hw_error("Failed to initialize AER capability"); } diff --git a/hw/pci-bridge/ioh3420.c b/hw/pci-bridge/ioh3420.c index c8b5ac4207..04180af794 100644 --- a/hw/pci-bridge/ioh3420.c +++ b/hw/pci-bridge/ioh3420.c @@ -135,8 +135,9 @@ static int ioh3420_initfn(PCIDevice *d) goto err_pcie_cap; } - rc = pcie_aer_init(d, IOH_EP_AER_OFFSET, PCI_ERR_SIZEOF); + rc = pcie_aer_init(d, IOH_EP_AER_OFFSET, PCI_ERR_SIZEOF, &err); if (rc < 0) { + error_report_err(err); goto err; } pcie_aer_root_init(d); diff --git a/hw/pci-bridge/xio3130_downstream.c b/hw/pci-bridge/xio3130_downstream.c index cef6e1325e..571334185b 100644 --- a/hw/pci-bridge/xio3130_downstream.c +++ b/hw/pci-bridge/xio3130_downstream.c @@ -97,8 +97,9 @@ static int xio3130_downstream_initfn(PCIDevice *d) goto err_pcie_cap; } - rc = pcie_aer_init(d, XIO3130_AER_OFFSET, PCI_ERR_SIZEOF); + rc = pcie_aer_init(d, XIO3130_AER_OFFSET, PCI_ERR_SIZEOF, &err); if (rc < 0) { + error_report_err(err); goto err; } diff --git a/hw/pci-bridge/xio3130_upstream.c b/hw/pci-bridge/xio3130_upstream.c index 4ad0440aa1..94c1691006 100644 --- a/hw/pci-bridge/xio3130_upstream.c +++ b/hw/pci-bridge/xio3130_upstream.c @@ -85,8 +85,9 @@ static int xio3130_upstream_initfn(PCIDevice *d) pcie_cap_flr_init(d); pcie_cap_deverr_init(d); - rc = pcie_aer_init(d, XIO3130_AER_OFFSET, PCI_ERR_SIZEOF); + rc = pcie_aer_init(d, XIO3130_AER_OFFSET, PCI_ERR_SIZEOF, &err); if (rc < 0) { + error_report_err(err); goto err; } diff --git a/hw/pci/pcie_aer.c b/hw/pci/pcie_aer.c index 048ce6a424..2a4bd5aef6 100644 --- a/hw/pci/pcie_aer.c +++ b/hw/pci/pcie_aer.c @@ -29,6 +29,7 @@ #include "hw/pci/msi.h" #include "hw/pci/pci_bus.h" #include "hw/pci/pcie_regs.h" +#include "qapi/error.h" //#define DEBUG_PCIE #ifdef DEBUG_PCIE @@ -96,21 +97,17 @@ static void aer_log_clear_all_err(PCIEAERLog *aer_log) aer_log->log_num = 0; } -int pcie_aer_init(PCIDevice *dev, uint16_t offset, uint16_t size) +int pcie_aer_init(PCIDevice *dev, uint16_t offset, uint16_t size, + Error **errp) { - PCIExpressDevice *exp; - pcie_add_capability(dev, PCI_EXT_CAP_ID_ERR, PCI_ERR_VER, offset, size); - exp = &dev->exp; - exp->aer_cap = offset; + dev->exp.aer_cap = offset; - /* log_max is property */ - if (dev->exp.aer_log.log_max == PCIE_AER_LOG_MAX_UNSET) { - dev->exp.aer_log.log_max = PCIE_AER_LOG_MAX_DEFAULT; - } - /* clip down the value to avoid unreasobale memory usage */ + /* clip down the value to avoid unreasonable memory usage */ if (dev->exp.aer_log.log_max > PCIE_AER_LOG_MAX_LIMIT) { + error_setg(errp, "Invalid aer_log_max %d. The max number of aer log " + "is %d", dev->exp.aer_log.log_max, PCIE_AER_LOG_MAX_LIMIT); return -EINVAL; } dev->exp.aer_log.log = g_malloc0(sizeof dev->exp.aer_log.log[0] * diff --git a/include/hw/pci/pcie_aer.h b/include/hw/pci/pcie_aer.h index c2ee4e2bdb..5891b6816e 100644 --- a/include/hw/pci/pcie_aer.h +++ b/include/hw/pci/pcie_aer.h @@ -44,7 +44,6 @@ struct PCIEAERLog { */ #define PCIE_AER_LOG_MAX_DEFAULT 8 #define PCIE_AER_LOG_MAX_LIMIT 128 -#define PCIE_AER_LOG_MAX_UNSET 0xffff uint16_t log_max; /* Error log. log_max-sized array */ @@ -87,7 +86,8 @@ struct PCIEAERErr { extern const VMStateDescription vmstate_pcie_aer_log; -int pcie_aer_init(PCIDevice *dev, uint16_t offset, uint16_t size); +int pcie_aer_init(PCIDevice *dev, uint16_t offset, uint16_t size, + Error **errp); void pcie_aer_exit(PCIDevice *dev); void pcie_aer_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len); From f18c697b55d1374af67b84c581abaece8ab2aca3 Mon Sep 17 00:00:00 2001 From: Dou Liyang Date: Wed, 21 Dec 2016 16:21:31 +0800 Subject: [PATCH 22/41] pcie_aer: support configurable AER capa version Now, AER capa version is fixed to v2, if assigned device isn't v2, then this value will be inconsistent between guest and host Signed-off-by: Dou Liyang Signed-off-by: Cao jin Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/net/e1000e.c | 3 ++- hw/pci-bridge/ioh3420.c | 3 ++- hw/pci-bridge/xio3130_downstream.c | 3 ++- hw/pci-bridge/xio3130_upstream.c | 3 ++- hw/pci/pcie_aer.c | 6 +++--- include/hw/pci/pcie_aer.h | 4 ++-- 6 files changed, 13 insertions(+), 9 deletions(-) diff --git a/hw/net/e1000e.c b/hw/net/e1000e.c index 89f96eb4a0..77a4b3e5bf 100644 --- a/hw/net/e1000e.c +++ b/hw/net/e1000e.c @@ -472,7 +472,8 @@ static void e1000e_pci_realize(PCIDevice *pci_dev, Error **errp) hw_error("Failed to initialize PM capability"); } - if (pcie_aer_init(pci_dev, e1000e_aer_offset, PCI_ERR_SIZEOF, NULL) < 0) { + if (pcie_aer_init(pci_dev, PCI_ERR_VER, e1000e_aer_offset, + PCI_ERR_SIZEOF, NULL) < 0) { hw_error("Failed to initialize AER capability"); } diff --git a/hw/pci-bridge/ioh3420.c b/hw/pci-bridge/ioh3420.c index 04180af794..84b7946c31 100644 --- a/hw/pci-bridge/ioh3420.c +++ b/hw/pci-bridge/ioh3420.c @@ -135,7 +135,8 @@ static int ioh3420_initfn(PCIDevice *d) goto err_pcie_cap; } - rc = pcie_aer_init(d, IOH_EP_AER_OFFSET, PCI_ERR_SIZEOF, &err); + rc = pcie_aer_init(d, PCI_ERR_VER, IOH_EP_AER_OFFSET, + PCI_ERR_SIZEOF, &err); if (rc < 0) { error_report_err(err); goto err; diff --git a/hw/pci-bridge/xio3130_downstream.c b/hw/pci-bridge/xio3130_downstream.c index 571334185b..04b8e5b847 100644 --- a/hw/pci-bridge/xio3130_downstream.c +++ b/hw/pci-bridge/xio3130_downstream.c @@ -97,7 +97,8 @@ static int xio3130_downstream_initfn(PCIDevice *d) goto err_pcie_cap; } - rc = pcie_aer_init(d, XIO3130_AER_OFFSET, PCI_ERR_SIZEOF, &err); + rc = pcie_aer_init(d, PCI_ERR_VER, XIO3130_AER_OFFSET, + PCI_ERR_SIZEOF, &err); if (rc < 0) { error_report_err(err); goto err; diff --git a/hw/pci-bridge/xio3130_upstream.c b/hw/pci-bridge/xio3130_upstream.c index 94c1691006..d1f59c8834 100644 --- a/hw/pci-bridge/xio3130_upstream.c +++ b/hw/pci-bridge/xio3130_upstream.c @@ -85,7 +85,8 @@ static int xio3130_upstream_initfn(PCIDevice *d) pcie_cap_flr_init(d); pcie_cap_deverr_init(d); - rc = pcie_aer_init(d, XIO3130_AER_OFFSET, PCI_ERR_SIZEOF, &err); + rc = pcie_aer_init(d, PCI_ERR_VER, XIO3130_AER_OFFSET, + PCI_ERR_SIZEOF, &err); if (rc < 0) { error_report_err(err); goto err; diff --git a/hw/pci/pcie_aer.c b/hw/pci/pcie_aer.c index 2a4bd5aef6..daf1f65427 100644 --- a/hw/pci/pcie_aer.c +++ b/hw/pci/pcie_aer.c @@ -97,10 +97,10 @@ static void aer_log_clear_all_err(PCIEAERLog *aer_log) aer_log->log_num = 0; } -int pcie_aer_init(PCIDevice *dev, uint16_t offset, uint16_t size, - Error **errp) +int pcie_aer_init(PCIDevice *dev, uint8_t cap_ver, uint16_t offset, + uint16_t size, Error **errp) { - pcie_add_capability(dev, PCI_EXT_CAP_ID_ERR, PCI_ERR_VER, + pcie_add_capability(dev, PCI_EXT_CAP_ID_ERR, cap_ver, offset, size); dev->exp.aer_cap = offset; diff --git a/include/hw/pci/pcie_aer.h b/include/hw/pci/pcie_aer.h index 5891b6816e..526802bd31 100644 --- a/include/hw/pci/pcie_aer.h +++ b/include/hw/pci/pcie_aer.h @@ -86,8 +86,8 @@ struct PCIEAERErr { extern const VMStateDescription vmstate_pcie_aer_log; -int pcie_aer_init(PCIDevice *dev, uint16_t offset, uint16_t size, - Error **errp); +int pcie_aer_init(PCIDevice *dev, uint8_t cap_ver, uint16_t offset, + uint16_t size, Error **errp); void pcie_aer_exit(PCIDevice *dev); void pcie_aer_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len); From e66bcc408146730958d1a840bda85d7ad51e0cd7 Mon Sep 17 00:00:00 2001 From: Halil Pasic Date: Mon, 19 Dec 2016 16:44:44 +0100 Subject: [PATCH 23/41] virtio: fix vq->inuse recalc after migr Correct recalculation of vq->inuse after migration for the corner case where the avail_idx has already wrapped but used_idx not yet. Also change the type of the VirtQueue.inuse to unsigned int. This is done to be consistent with other members representing sizes (VRing.num), and because C99 guarantees max ring size < UINT_MAX but does not guarantee max ring size < INT_MAX. Signed-off-by: Halil Pasic Fixes: bccdef6b ("virtio: recalculate vq->inuse after migration") CC: qemu-stable@nongnu.org Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Stefan Hajnoczi --- hw/virtio/virtio.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 933a3d749a..8357218ae6 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -93,7 +93,7 @@ struct VirtQueue uint16_t queue_index; - int inuse; + unsigned int inuse; uint16_t vector; VirtIOHandleOutput handle_output; @@ -1878,9 +1878,11 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id) /* * Some devices migrate VirtQueueElements that have been popped * from the avail ring but not yet returned to the used ring. + * Since max ring size < UINT16_MAX it's safe to use modulo + * UINT16_MAX + 1 subtraction. */ - vdev->vq[i].inuse = vdev->vq[i].last_avail_idx - - vdev->vq[i].used_idx; + vdev->vq[i].inuse = (uint16_t)(vdev->vq[i].last_avail_idx - + vdev->vq[i].used_idx); if (vdev->vq[i].inuse > vdev->vq[i].vring.num) { error_report("VQ %d size 0x%x < last_avail_idx 0x%x - " "used_idx 0x%x", From f2fd57db363e465653efa55102104039b5516759 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Fri, 16 Dec 2016 11:41:55 +0000 Subject: [PATCH 24/41] balloon: Don't balloon roms A broken guest can specify physical addresses that correspond to any memory region, but it shouldn't be able to change ROM. Signed-off-by: Dr. David Alan Gilbert Cc: qemu-stable@nongnu.org Acked-by: Paolo Bonzini Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/trace-events | 2 ++ hw/virtio/virtio-balloon.c | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events index 7b6f55e70e..6926eedd3f 100644 --- a/hw/virtio/trace-events +++ b/hw/virtio/trace-events @@ -15,6 +15,8 @@ virtio_rng_pushed(void *rng, size_t len) "rng %p: %zd bytes pushed" virtio_rng_request(void *rng, size_t size, unsigned quota) "rng %p: %zd bytes requested, %u bytes quota left" # hw/virtio/virtio-balloon.c +# +virtio_balloon_bad_addr(uint64_t gpa) "%"PRIx64 virtio_balloon_handle_output(const char *name, uint64_t gpa) "section name: %s gpa: %"PRIx64 virtio_balloon_get_config(uint32_t num_pages, uint32_t actual) "num_pages: %d actual: %d" virtio_balloon_set_config(uint32_t actual, uint32_t oldactual) "actual: %d oldactual: %d" diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index 884570a57d..a705e0ec55 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -228,8 +228,13 @@ static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq) /* FIXME: remove get_system_memory(), but how? */ section = memory_region_find(get_system_memory(), pa, 1); - if (!int128_nz(section.size) || !memory_region_is_ram(section.mr)) + if (!int128_nz(section.size) || + !memory_region_is_ram(section.mr) || + memory_region_is_rom(section.mr) || + memory_region_is_romd(section.mr)) { + trace_virtio_balloon_bad_addr(pa); continue; + } trace_virtio_balloon_handle_output(memory_region_name(section.mr), pa); From 312d3b35349a153e5a069e53170fd929e6b73a2b Mon Sep 17 00:00:00 2001 From: Yuri Benditovich Date: Tue, 13 Dec 2016 10:12:05 +0200 Subject: [PATCH 25/41] net: Add virtio queue interface to update used index from vring state Bring virtio queue to correct internal state for host-to-guest operations when vhost is temporary stopped. Signed-off-by: Yuri Benditovich Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio.c | 5 +++++ include/hw/virtio/virtio.h | 1 + 2 files changed, 6 insertions(+) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 8357218ae6..baffff703f 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -2020,6 +2020,11 @@ void virtio_queue_set_last_avail_idx(VirtIODevice *vdev, int n, uint16_t idx) vdev->vq[n].shadow_avail_idx = idx; } +void virtio_queue_update_used_idx(VirtIODevice *vdev, int n) +{ + vdev->vq[n].used_idx = vring_used_idx(&vdev->vq[n]); +} + void virtio_queue_invalidate_signalled_used(VirtIODevice *vdev, int n) { vdev->vq[n].signalled_used_valid = false; diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index 5e4176f94c..e15c06489b 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -269,6 +269,7 @@ hwaddr virtio_queue_get_used_size(VirtIODevice *vdev, int n); uint16_t virtio_queue_get_last_avail_idx(VirtIODevice *vdev, int n); void virtio_queue_set_last_avail_idx(VirtIODevice *vdev, int n, uint16_t idx); void virtio_queue_invalidate_signalled_used(VirtIODevice *vdev, int n); +void virtio_queue_update_used_idx(VirtIODevice *vdev, int n); VirtQueue *virtio_get_queue(VirtIODevice *vdev, int n); uint16_t virtio_get_queue_index(VirtQueue *vq); EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq); From aa94d52142f674c7abe638f9cfb19bd89a99f154 Mon Sep 17 00:00:00 2001 From: Yuri Benditovich Date: Tue, 13 Dec 2016 10:12:06 +0200 Subject: [PATCH 26/41] net: vhost stop updates virtio queue state Make virtio queue suitable for push operation from qemu after vhost was stopped. Signed-off-by: Yuri Benditovich Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index f7f70237db..d396b22531 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -993,6 +993,7 @@ static void vhost_virtqueue_stop(struct vhost_dev *dev, virtio_queue_set_last_avail_idx(vdev, idx, state.num); } virtio_queue_invalidate_signalled_used(vdev, idx); + virtio_queue_update_used_idx(vdev, idx); /* In the cross-endian case, we need to reset the vring endianness to * native as legacy devices expect so by default. From 54e17709ac2d2ea8275101655fe746bba7ae0064 Mon Sep 17 00:00:00 2001 From: Yuri Benditovich Date: Tue, 13 Dec 2016 10:12:07 +0200 Subject: [PATCH 27/41] virtio: Introduce virtqueue_drop_all procedure Add procedure for fast drop of queued packets, acting like pop and push without mapping the buffers into memory. Signed-off-by: Yuri Benditovich Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio.c | 38 ++++++++++++++++++++++++++++++++++++++ include/hw/virtio/virtio.h | 1 + 2 files changed, 39 insertions(+) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index baffff703f..aa4f38f50a 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -783,6 +783,44 @@ err_undo_map: return NULL; } +/* virtqueue_drop_all: + * @vq: The #VirtQueue + * Drops all queued buffers and indicates them to the guest + * as if they are done. Useful when buffers can not be + * processed but must be returned to the guest. + */ +unsigned int virtqueue_drop_all(VirtQueue *vq) +{ + unsigned int dropped = 0; + VirtQueueElement elem = {}; + VirtIODevice *vdev = vq->vdev; + bool fEventIdx = virtio_vdev_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX); + + if (unlikely(vdev->broken)) { + return 0; + } + + while (!virtio_queue_empty(vq) && vq->inuse < vq->vring.num) { + /* works similar to virtqueue_pop but does not map buffers + * and does not allocate any memory */ + smp_rmb(); + if (!virtqueue_get_head(vq, vq->last_avail_idx, &elem.index)) { + break; + } + vq->inuse++; + vq->last_avail_idx++; + if (fEventIdx) { + vring_set_avail_event(vq, vq->last_avail_idx); + } + /* immediately push the element, nothing to unmap + * as both in_num and out_num are set to 0 */ + virtqueue_push(vq, &elem, 0); + dropped++; + } + + return dropped; +} + /* Reading and writing a structure directly to QEMUFile is *awful*, but * it is what QEMU has always done by mistake. We can change it sooner * or later by bumping the version number of the affected vm states. diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index e15c06489b..e5541c61f7 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -173,6 +173,7 @@ void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem, void virtqueue_map(VirtIODevice *vdev, VirtQueueElement *elem); void *virtqueue_pop(VirtQueue *vq, size_t sz); +unsigned int virtqueue_drop_all(VirtQueue *vq); void *qemu_get_virtqueue_element(VirtIODevice *vdev, QEMUFile *f, size_t sz); void qemu_put_virtqueue_element(QEMUFile *f, VirtQueueElement *elem); int virtqueue_avail_bytes(VirtQueue *vq, unsigned int in_bytes, From 283e2c2adcb80148c7f67d71d52134af80d2fbae Mon Sep 17 00:00:00 2001 From: Yuri Benditovich Date: Tue, 13 Dec 2016 10:12:08 +0200 Subject: [PATCH 28/41] net: virtio-net discards TX data after link down https://bugzilla.redhat.com/show_bug.cgi?id=1295637 Upon set_link monitor command or upon netdev deletion virtio-net sends link down indication to the guest and stops vhost if one is used. Guest driver can still submit data for TX until it recognizes link loss. If these packets not returned by the host, the Windows guest will never be able to finish disable/removal/shutdown. Now each packet sent by guest after NIC indicated link down will be completed immediately. Signed-off-by: Yuri Benditovich Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/net/virtio-net.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 5009533cfa..6f98eab2ba 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -218,6 +218,14 @@ static void virtio_net_vnet_endian_status(VirtIONet *n, uint8_t status) } } +static void virtio_net_drop_tx_queue_data(VirtIODevice *vdev, VirtQueue *vq) +{ + unsigned int dropped = virtqueue_drop_all(vq); + if (dropped) { + virtio_notify(vdev, vq); + } +} + static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status) { VirtIONet *n = VIRTIO_NET(vdev); @@ -262,6 +270,14 @@ static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status) } else { qemu_bh_cancel(q->tx_bh); } + if ((n->status & VIRTIO_NET_S_LINK_UP) == 0 && + (queue_status & VIRTIO_CONFIG_S_DRIVER_OK)) { + /* if tx is waiting we are likely have some packets in tx queue + * and disabled notification */ + q->tx_waiting = 0; + virtio_queue_set_notification(q->tx_vq, 1); + virtio_net_drop_tx_queue_data(vdev, q->tx_vq); + } } } } @@ -1323,6 +1339,11 @@ static void virtio_net_handle_tx_timer(VirtIODevice *vdev, VirtQueue *vq) VirtIONet *n = VIRTIO_NET(vdev); VirtIONetQueue *q = &n->vqs[vq2q(virtio_get_queue_index(vq))]; + if (unlikely((n->status & VIRTIO_NET_S_LINK_UP) == 0)) { + virtio_net_drop_tx_queue_data(vdev, vq); + return; + } + /* This happens when device was stopped but VCPU wasn't. */ if (!vdev->vm_running) { q->tx_waiting = 1; @@ -1349,6 +1370,11 @@ static void virtio_net_handle_tx_bh(VirtIODevice *vdev, VirtQueue *vq) VirtIONet *n = VIRTIO_NET(vdev); VirtIONetQueue *q = &n->vqs[vq2q(virtio_get_queue_index(vq))]; + if (unlikely((n->status & VIRTIO_NET_S_LINK_UP) == 0)) { + virtio_net_drop_tx_queue_data(vdev, vq); + return; + } + if (unlikely(q->tx_waiting)) { return; } From c5f048d8fb69ae9b52a02ff4435b403b2ba19db7 Mon Sep 17 00:00:00 2001 From: Maxime Coquelin Date: Sat, 10 Dec 2016 16:30:36 +0100 Subject: [PATCH 29/41] vhost-user: Add MTU protocol feature and op This patch implements VHOST_USER_PROTOCOL_F_NET_MTU protocol feature and VHOST_USER_NET_SET_MTU request so that the backend gets notified of the user defined host MTU. If backend supports VHOST_USER_PROTOCOL_F_REPLY_ACK, QEMU assumes MTU is valid if success is returned. Vhost-net driver sends this request through a new vhost_net_set_mtu vhost_ops entry. Cc: Michael S. Tsirkin Cc: Aaron Conole Signed-off-by: Maxime Coquelin Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- docs/specs/vhost-user.txt | 16 +++++++++++++++ hw/virtio/vhost-user.c | 34 +++++++++++++++++++++++++++++++ include/hw/virtio/vhost-backend.h | 2 ++ 3 files changed, 52 insertions(+) diff --git a/docs/specs/vhost-user.txt b/docs/specs/vhost-user.txt index d70bd83b13..036890feb0 100644 --- a/docs/specs/vhost-user.txt +++ b/docs/specs/vhost-user.txt @@ -259,6 +259,7 @@ Protocol features #define VHOST_USER_PROTOCOL_F_LOG_SHMFD 1 #define VHOST_USER_PROTOCOL_F_RARP 2 #define VHOST_USER_PROTOCOL_F_REPLY_ACK 3 +#define VHOST_USER_PROTOCOL_F_MTU 4 Message types ------------- @@ -470,6 +471,21 @@ Message types The first 6 bytes of the payload contain the mac address of the guest to allow the vhost user backend to construct and broadcast the fake RARP. + * VHOST_USER_NET_SET_MTU + + Id: 20 + Equivalent ioctl: N/A + Master payload: u64 + + Set host MTU value exposed to the guest. + This request should be sent only when VIRTIO_NET_F_MTU feature has been + successfully negotiated, VHOST_USER_F_PROTOCOL_FEATURES is present in + VHOST_USER_GET_FEATURES and protocol feature bit + VHOST_USER_PROTOCOL_F_NET_MTU is present in + VHOST_USER_GET_PROTOCOL_FEATURES. + If VHOST_USER_PROTOCOL_F_REPLY_ACK is negotiated, slave must respond + with zero in case the specified MTU is valid, or non-zero otherwise. + VHOST_USER_PROTOCOL_F_REPLY_ACK: ------------------------------- The original vhost-user specification only demands replies for certain diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 7ee92b32c5..9334a8ae22 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -32,6 +32,7 @@ enum VhostUserProtocolFeature { VHOST_USER_PROTOCOL_F_LOG_SHMFD = 1, VHOST_USER_PROTOCOL_F_RARP = 2, VHOST_USER_PROTOCOL_F_REPLY_ACK = 3, + VHOST_USER_PROTOCOL_F_NET_MTU = 4, VHOST_USER_PROTOCOL_F_MAX }; @@ -59,6 +60,7 @@ typedef enum VhostUserRequest { VHOST_USER_GET_QUEUE_NUM = 17, VHOST_USER_SET_VRING_ENABLE = 18, VHOST_USER_SEND_RARP = 19, + VHOST_USER_NET_SET_MTU = 20, VHOST_USER_MAX } VhostUserRequest; @@ -186,6 +188,7 @@ static bool vhost_user_one_time_request(VhostUserRequest request) case VHOST_USER_RESET_OWNER: case VHOST_USER_SET_MEM_TABLE: case VHOST_USER_GET_QUEUE_NUM: + case VHOST_USER_NET_SET_MTU: return true; default: return false; @@ -685,6 +688,36 @@ static bool vhost_user_can_merge(struct vhost_dev *dev, return mfd == rfd; } +static int vhost_user_net_set_mtu(struct vhost_dev *dev, uint16_t mtu) +{ + VhostUserMsg msg; + bool reply_supported = virtio_has_feature(dev->protocol_features, + VHOST_USER_PROTOCOL_F_REPLY_ACK); + + if (!(dev->protocol_features & (1ULL << VHOST_USER_PROTOCOL_F_NET_MTU))) { + return 0; + } + + msg.request = VHOST_USER_NET_SET_MTU; + msg.payload.u64 = mtu; + msg.size = sizeof(msg.payload.u64); + msg.flags = VHOST_USER_VERSION; + if (reply_supported) { + msg.flags |= VHOST_USER_NEED_REPLY_MASK; + } + + if (vhost_user_write(dev, &msg, NULL, 0) < 0) { + return -1; + } + + /* If reply_ack supported, slave has to ack specified MTU is valid */ + if (reply_supported) { + return process_message_reply(dev, msg.request); + } + + return 0; +} + const VhostOps user_ops = { .backend_type = VHOST_BACKEND_TYPE_USER, .vhost_backend_init = vhost_user_init, @@ -708,4 +741,5 @@ const VhostOps user_ops = { .vhost_requires_shm_log = vhost_user_requires_shm_log, .vhost_migration_done = vhost_user_migration_done, .vhost_backend_can_merge = vhost_user_can_merge, + .vhost_net_set_mtu = vhost_user_net_set_mtu, }; diff --git a/include/hw/virtio/vhost-backend.h b/include/hw/virtio/vhost-backend.h index 6e90703cad..30abc11cf1 100644 --- a/include/hw/virtio/vhost-backend.h +++ b/include/hw/virtio/vhost-backend.h @@ -32,6 +32,7 @@ typedef int (*vhost_backend_memslots_limit)(struct vhost_dev *dev); typedef int (*vhost_net_set_backend_op)(struct vhost_dev *dev, struct vhost_vring_file *file); +typedef int (*vhost_net_set_mtu_op)(struct vhost_dev *dev, uint16_t mtu); typedef int (*vhost_scsi_set_endpoint_op)(struct vhost_dev *dev, struct vhost_scsi_target *target); typedef int (*vhost_scsi_clear_endpoint_op)(struct vhost_dev *dev, @@ -83,6 +84,7 @@ typedef struct VhostOps { vhost_backend_cleanup vhost_backend_cleanup; vhost_backend_memslots_limit vhost_backend_memslots_limit; vhost_net_set_backend_op vhost_net_set_backend; + vhost_net_set_mtu_op vhost_net_set_mtu; vhost_scsi_set_endpoint_op vhost_scsi_set_endpoint; vhost_scsi_clear_endpoint_op vhost_scsi_clear_endpoint; vhost_scsi_get_abi_version_op vhost_scsi_get_abi_version; From 45a368ad4f6135f32be5c051823a060eada0ac12 Mon Sep 17 00:00:00 2001 From: Maxime Coquelin Date: Sat, 10 Dec 2016 16:30:37 +0100 Subject: [PATCH 30/41] vhost-net: Notify the backend about the host MTU This patch provides a way for virtio-net to notify the backend about the host MTU set by the user. Cc: Michael S. Tsirkin Cc: Aaron Conole Signed-off-by: Maxime Coquelin Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/net/vhost_net.c | 18 ++++++++++++++++++ include/net/vhost_net.h | 2 ++ 2 files changed, 20 insertions(+) diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c index f2d49ad7e7..6280422d02 100644 --- a/hw/net/vhost_net.c +++ b/hw/net/vhost_net.c @@ -51,6 +51,7 @@ static const int kernel_feature_bits[] = { VIRTIO_RING_F_EVENT_IDX, VIRTIO_NET_F_MRG_RXBUF, VIRTIO_F_VERSION_1, + VIRTIO_NET_F_MTU, VHOST_INVALID_FEATURE_BIT }; @@ -74,6 +75,7 @@ static const int user_feature_bits[] = { VIRTIO_NET_F_HOST_ECN, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_MRG_RXBUF, + VIRTIO_NET_F_MTU, /* This bit implies RARP isn't sent by QEMU out of band */ VIRTIO_NET_F_GUEST_ANNOUNCE, @@ -435,6 +437,17 @@ int vhost_set_vring_enable(NetClientState *nc, int enable) return 0; } +int vhost_net_set_mtu(struct vhost_net *net, uint16_t mtu) +{ + const VhostOps *vhost_ops = net->dev.vhost_ops; + + if (!vhost_ops->vhost_net_set_mtu) { + return 0; + } + + return vhost_ops->vhost_net_set_mtu(&net->dev, mtu); +} + #else uint64_t vhost_net_get_max_queues(VHostNetState *net) { @@ -501,4 +514,9 @@ int vhost_set_vring_enable(NetClientState *nc, int enable) { return 0; } + +int vhost_net_set_mtu(struct vhost_net *net, uint16_t mtu) +{ + return 0; +} #endif diff --git a/include/net/vhost_net.h b/include/net/vhost_net.h index 5a08efffef..afc1499eb9 100644 --- a/include/net/vhost_net.h +++ b/include/net/vhost_net.h @@ -35,4 +35,6 @@ int vhost_set_vring_enable(NetClientState * nc, int enable); uint64_t vhost_net_get_acked_features(VHostNetState *net); +int vhost_net_set_mtu(struct vhost_net *net, uint16_t mtu); + #endif From a93e599d4a04c3cf7edcf5a24f3397e27431c027 Mon Sep 17 00:00:00 2001 From: Maxime Coquelin Date: Sat, 10 Dec 2016 16:30:38 +0100 Subject: [PATCH 31/41] virtio-net: Add MTU feature support This patch allows advising guest with host MTU's by setting host_mtu parameter. If VIRTIO_NET_F_MTU has been successfully negotiated, MTU value is passed to the backend. Cc: Michael S. Tsirkin Cc: Aaron Conole Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/net/virtio-net.c | 19 +++++++++++++++++++ include/hw/virtio/virtio-net.h | 1 + 2 files changed, 20 insertions(+) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 6f98eab2ba..7b3ad4a9f0 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -55,6 +55,8 @@ static VirtIOFeature feature_sizes[] = { .end = endof(struct virtio_net_config, status)}, {.flags = 1 << VIRTIO_NET_F_MQ, .end = endof(struct virtio_net_config, max_virtqueue_pairs)}, + {.flags = 1 << VIRTIO_NET_F_MTU, + .end = endof(struct virtio_net_config, mtu)}, {} }; @@ -81,6 +83,7 @@ static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config) virtio_stw_p(vdev, &netcfg.status, n->status); virtio_stw_p(vdev, &netcfg.max_virtqueue_pairs, n->max_queues); + virtio_stw_p(vdev, &netcfg.mtu, n->net_conf.mtu); memcpy(netcfg.mac, n->mac, ETH_ALEN); memcpy(config, &netcfg, n->config_size); } @@ -152,6 +155,16 @@ static void virtio_net_vhost_status(VirtIONet *n, uint8_t status) qemu_net_queue_purge(qnc->incoming_queue, qnc->peer); } + if (virtio_has_feature(vdev->guest_features, VIRTIO_NET_F_MTU)) { + r = vhost_net_set_mtu(get_vhost_net(nc->peer), n->net_conf.mtu); + if (r < 0) { + error_report("%uBytes MTU not supported by the backend", + n->net_conf.mtu); + + return; + } + } + n->vhost_started = 1; r = vhost_net_start(vdev, n->nic->ncs, queues); if (r < 0) { @@ -1721,6 +1734,7 @@ static void virtio_net_set_config_size(VirtIONet *n, uint64_t host_features) { int i, config_size = 0; virtio_add_feature(&host_features, VIRTIO_NET_F_MAC); + for (i = 0; feature_sizes[i].flags != 0; i++) { if (host_features & feature_sizes[i].flags) { config_size = MAX(feature_sizes[i].end, config_size); @@ -1750,6 +1764,10 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp) NetClientState *nc; int i; + if (n->net_conf.mtu) { + n->host_features |= (0x1 << VIRTIO_NET_F_MTU); + } + virtio_net_set_config_size(n, n->host_features); virtio_init(vdev, "virtio-net", VIRTIO_ID_NET, n->config_size); @@ -1948,6 +1966,7 @@ static Property virtio_net_properties[] = { DEFINE_PROP_STRING("tx", VirtIONet, net_conf.tx), DEFINE_PROP_UINT16("rx_queue_size", VirtIONet, net_conf.rx_queue_size, VIRTIO_NET_RX_QUEUE_DEFAULT_SIZE), + DEFINE_PROP_UINT16("host_mtu", VirtIONet, net_conf.mtu, 0), DEFINE_PROP_END_OF_LIST(), }; diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h index 0ced975c57..8ea56a8f60 100644 --- a/include/hw/virtio/virtio-net.h +++ b/include/hw/virtio/virtio-net.h @@ -36,6 +36,7 @@ typedef struct virtio_net_conf int32_t txburst; char *tx; uint16_t rx_queue_size; + uint16_t mtu; } virtio_net_conf; /* Maximum packet size we can receive from tap device: header + 64k */ From 4462fc604a5f7d07bcbea14ba87673476b1e9125 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Tue, 6 Dec 2016 00:32:20 +0100 Subject: [PATCH 32/41] tests: pc: add memory hotplug acpi tables tests This also adds SRAT and DSDT blobs for memory hotplug variant Signed-off-by: Igor Mammedov Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Marcel Apfelbaum --- tests/acpi-test-data/pc/DSDT.memhp | Bin 0 -> 6613 bytes tests/acpi-test-data/pc/SRAT.memhp | Bin 0 -> 224 bytes tests/acpi-test-data/q35/DSDT.memhp | Bin 0 -> 9375 bytes tests/acpi-test-data/q35/SRAT.memhp | Bin 0 -> 224 bytes tests/bios-tables-test.c | 24 ++++++++++++++++++++++++ 5 files changed, 24 insertions(+) create mode 100644 tests/acpi-test-data/pc/DSDT.memhp create mode 100644 tests/acpi-test-data/pc/SRAT.memhp create mode 100644 tests/acpi-test-data/q35/DSDT.memhp create mode 100644 tests/acpi-test-data/q35/SRAT.memhp diff --git a/tests/acpi-test-data/pc/DSDT.memhp b/tests/acpi-test-data/pc/DSDT.memhp new file mode 100644 index 0000000000000000000000000000000000000000..a1010c7fb5c526278d743891f2543d873f9ef9b9 GIT binary patch literal 6613 zcmdT|&2JmW6`$pYw49}+rL?wXD~VXyNt(2_`QgY3S`;RCDUlYJT5~Da#Tw;OmQgB5 z>xB{nQH%f*11L^z0qdeYl{R>`|Ah8W$ffu6+*^vqK3V;}T@J-iS|GW#1Vqhy?>Fyb z=DjyFG;E{skF$(P|0=HQWjkHGW$6ZZ5@U?U^k1#SZZl`kD6TdoB@&aIeZ?Q+t0-$f zH;Nmp(x2PzpIrB&&t0kIvCSvyqs^B0*+X}e5$OJ=$2kqurKVkMI-LbeuVmzAxnd*> zU-PKkEEshrH#aJVq?&SoDamE4)DR#EAc)~c*=m?9$=KH~6&7>$Rifu^mTE@YsvFI; zw%oKE1?CaQ^@!E_#O12nOMcaLS=Ut#5Bsb){Z+Tc{@6;gfBq-lXMH{+H}$%mO7ZD~ z1R{oV7GrFesjpumZ^&JzbJn_*&HKJ4qfCM;RyMCk7(Z06#YbRztYR0M0S*gGxGNbw z!d(t`-}vn%(n2#CD_>@lRjX8!*t;yM7ibXGi} zxxO)+I5RgsQReX_rV_9quNeAp6DJ2AE%5nO>D%bHQ5IX3o=2Z!p_Z<(w`0EU>`K)t zh|OLxDzj;o@i<@S8HqpR5&k;?xO#;za1k!HqP&jI^_7 zm#(7}<)@TU3K4oSQ@Rd8v1ZmKMGXW*=*8NGnRcXNRbOM;>y}=+9&yeSb$IBtN$BlL z+l;0=ZxXxD)EY{t*i_dzrM+hGrd4k+Z#J^$daU)Nn0VCUd)_B49$}l_gPqnU<56~} zr*`iElt9^3YikDE>RssGk$S0ai^qm+n{7Rw8d3#-Qr$Z|GUOBooam6Fvn}t_-A%4C z6fS$X#hCY?1$z&-B<5{BbX)9xtM5Ad7cNK1TdEbRHp!~r$jJE0(pQeY^0GEpxq(&f zB_8m-Hi|yc=ZdymxuMq+0Ms+7X|8-R!4iJ5?XoY4$K&{}^prr>AGp4)yxtos@tV%8c3tiNNdSvrB;zWMogzuym;I1Qt&14Z>peMl}sj^ArFG{ zJg%km#>#IZJ>G4z13i<;Y-{BS^sqw0Ie+_dOdMx=y5j=!-s3Z_ z^X4&0b*=AeW}G7WafYOERnTyveyu#M+j>n73qx|B6qK%uBN?r7Tq#z#w;DSZkiQdH zu5maPU-FK52DB%+kJnp)J*8>b|V=U=!yGv%vnV2ZJ!XA z$0Orhg1$e_#1fq7o%7jRjM54$T`-Z5()b2=;5Nmky4p`oq;KpPXxm&b-Spmv zP!CjUOD1w2m%Z#Q>sKCMfg$qioQ}kn8OIq-DDNgb~Je*7s(e%Nd{jEQtdg!FOoxg z%HM&1kM0Y{e$WMrJ`v_i#A`u5Jp9|sK=SwR=*^tl$91u%?5U*T%Kz4FG!Q%AoSleCa2n$)%~?5y zXAmAZpxz+~1)%=oX!)GZrIlanD}e(yO6CSSVUEya9;g>nFVEW>p&@m7_CI*wlI2p7>|Ij#wKtcJ4f$w-a4t&r4-}#RB>cDr( zoxv;Se|_E2{EjY`lswyX$CM5*%x?FTZktDFoZD8-dw!=WBIi)Dik->ehXVSQ$?3dp zX9om&ON42toUDPPnFcvA$kV{-yk%$K#YB6fHu#kaQ=&|p_0xkM(`10e1kI6Jg5oUz zQ-I<(i4dsJ8W+%b7&I@m;uR2Rod|^rt&;*e83w%~wBk3GK&u=I6 z<)Kia6-_p9Kna5`3#~~3O@=~+)+qs<3WHu1TBikcIut6j;*}rxIuizcS7=oQR1Jj+ zttkObg+bpFT4x1xHWVtf&I#yT7_=a?BJ+c=v{0zfdP+b~g+Yr#>uCW!9SRj%&j{$5 zFsLrH&I{;#C{$=YE1+k?poY+TPC(CvLWR}^0bK}#mW0+<1oV|qsL=YVfW8_AT@hMe z6VTT}p+f7TfG(Z{)yfOT%~~VUOFn4h!E`{qZrdkR5a?zBktRY&u7N;D3M6|(kYwsX zTfuAVz(!jcP!XbrvKS~dhk=Z2y)%@NF_ic~M%I>xGBSrk9mvSuRg%p-XrsI0#&lq# z-~^336X+v3ZcYa_N=L}?A_RRTSBXXu2zlD4kL1^gMmh`mo=+di{fLp6LXN}az}83P z6g5(8D5toM5jjPUWEslSM32a?fyTBE<$FX!t}W8_8$bKg@3*vtIO{f~!NB0r{{l^z Bd0PMg literal 0 HcmV?d00001 diff --git a/tests/acpi-test-data/pc/SRAT.memhp b/tests/acpi-test-data/pc/SRAT.memhp new file mode 100644 index 0000000000000000000000000000000000000000..66ce9a898191d1da961c0c968c04ec56810a5785 GIT binary patch literal 224 zcmWFzatwLEz`(%x+sWVABUr&HBEUHqD8>jB1F=Cg2*ZH@DxXmUE(2w7!3B`@A=Cj4 c0D}+gFooFF!DO-12=n0X`2kbO3}XOk0FlrO0RR91 literal 0 HcmV?d00001 diff --git a/tests/acpi-test-data/q35/DSDT.memhp b/tests/acpi-test-data/q35/DSDT.memhp new file mode 100644 index 0000000000000000000000000000000000000000..ecd0d8564b21016028d8ecd740f8647e0cbf8878 GIT binary patch literal 9375 zcmdT~U2hx56`dt1YPF=KrL>miPq9wWG-;hslIs-x2u$u$BqOdwk#s&l1Ek%gm6Enu zC=QS`2p}myKKxLiVH31Zr2{?ZFEl?PZw=6=zV@{!;-{$R-r137mJ$%ZwR#}u&YpAc zoY~nq%UuPXp!?Uyg|MzxHvM|1Sb3@C2k5he5Y(n`w~@IedV4{o*0*x0jMdxEaT^~M z+xt;axmmORygm4AFu42Sz`7lYJDG$?pey3~Y z#1~GU+Z8L9|ANw@zjCAHH!8NfnP=!hEswZl_v?)yU;fIm?Y=KtX}ezz+QRPNYy_6w zx!Gz7+wZoU!V9MQn;k!M?{(n^FD{SPCWqUFdB^RA|5*KI>EeygUc6iW@)v*q)xFo9 z3;-+mw(-3hQ9ya9u}Z1lr4Q#4eU98uhC9}KII_&><rO#S!svX@FM zAHME}w$xL#>#b^6>9L>!w=5#+ z8AQ}|`}YIK9gOmS91g^AkUKg$6r-6x4sVM;-Oh`D{%7J)96Ga@t#+qSaArQ3!ihw3 zkrCn@;og{hnubGD+dJ^HjZV4G(}@8rVKA*mdn@G(==3zP9#YPplj`lCqqguj!*W_! z_^RNm+3E%^0h=H)cdPTf~?<*-N?HxQ3 zZr(g5&dw)^wli@>xCDF-T8@Dk;VsG;r|}O)S+SU0Y1_WC$AzjH z%*nD+G-1h=snXDdoR;Q6`axRQS6oiBMrl?OX`Iw?9?a>fc~TEj$YUdq-D>!2!pryZ zZAIG@xqo=sqEq1d|Kdxk)$X?D*5BNl%Vn^7L~~=kDrDP2dri#csozNM z=cJ)?($tAi*J&F%Z9}JR>O`pP#15g&^pv4<%G8Na*XbBK9Yd#M>O`pP%o#d!hR&R+ z6QQmXJC$}m^M=m6sS}~DbK1~3ZRngfbt2St&KNpp44pHkPK3J7SwrWnp>x*MiBQ++ z8aiD=r)%m&sOu~kItzx*f~gasu5-@NIcMmcGj$@=b{=saucM5yarG;}T+Iu}iy2z8z3 zm|2c@!gI{5#GBnY$@CwF#0+BWd4qZ0V4gRb2zBNKgL%PVUND&mb>>BbdC_2AG?@r> z<|Tu9$zWbGnFw{}Wo9auxy($p$6uCAwQ(aPrgD-cqvn!PbIGiUP}a0zpk>WKYn{fi zfufDVv4J8$SsA1esG=}XiDOH$aKFPq<(Mf6RUt8zG#IGFDg)J^WS|ntOfpb}7>zPe ziH#$wsl1j9R6>sp6d{JrSQx0p#t|{qE$G3{-=Xfl4Sd$v_b* zoiI>|WhM+%gOY(tC^N}G5h|T9P>E$G3{-=Xfl4Sd$v_b*oiI>|WhM+%gOY(tC^N}G z5h|T9P>E$G3{-=Xfl4Sd$v_b*oiI>|WhM+%gOY(tC^N}G5h|T9P>E$G3{-=Xfl4Sd z$v_b*oiI>|WhM+%gOY(tC^N}G5h|T9P>E$G3{-=Xfl4Sd$v_b*oiI>|WhM+%gOY(t zC^N}G5h|T9P>E$G3{-=Xfl4Sd$v_b*oiI>|WhM+%gOY(tC^N}G5h|T9P>E$G3{-=X zfl4Sd$v_b*oiI>|WhM+%gOY(tC^N}G5h|T9P>E$G3{-=Xfl4Sd$v_b*oiI>|WhM+% zgOY(tC^N}G5h|T9P>E$G3{-=Xfl4Sd$v_b*oiI>|WhM+%gOY(tC^N}G5h|T9P>E$G z3{-=Xfl4Sd$v_b*oiI>|WhM+%gOY(tC^N}G5h|T9P(+%6BGL^Mp>CiEH3QX{Fi?$2 z2C6a1Ks6=|RAa(GH6|IT#v}vPm@rU{2?N!bWS|<83{+#nKs6=|RAZ8XYD_XvjR^xq zq|Po36cNrCPbL{CLYxK_5>w4B3>1-?TNo%JHMeA-2-Vz@fg%iqcfJn`6{Gx+f2b5uE*uvwb z(bT)n-ZmbBOdUEo?^o^= znv=LkD68M%c|1;`hcz~a-6QMsWjY8VE-1_iIL5lmCq$;2pCP-EA)d#N4!UE zXODYk=}Ct;qyce!w%=)Ytb5z>7^pn;$JHx|>Uga1ovT;0>J_eD!T9v*74PKgmEJ)} z+WkazC-n&BeXYFD<^4o?|CI86Ts}ya$K$f^tUl1n2V6c#ln+iRAH?OW$?};;C|}je zSGjyOQNDUg`D$E#Em?lz5z4P=<=43UTB7{gDdpGV^0j37>?4$~Y2|BNzLqFoJEeRr zE?-ZUpL~S!b*+4z%hwa->!*~jqkM+8vSfKzmRFkxZY$_98$Y!)`@Ae)^7x|bI!>3o zjGcm+4)+>k>15xD>Bg?hIWrw@K*rL^z7x}pU1#%VI^30vrIURprW?C%JTo0`RmRfE zz7x}pT?c2(bhv*RODFqIOgFZ!7tD0HsToTr`%X+ZwocEQ>2RkrmQMDW>DmVB`Wttn-@Ntf;_j<&zVX)XFJFCA^en&CT#r}ewByvQ zuk&B$tvnuW!*}R?%h!24(BFTIg0d+3^jzL=Y;-KY9ll`s)#po=$oPI3*uDKZ0;T;< zwOIr*D0ho^l-$^8*pZ;l-a+N+Eq;T5vB>dFm;F|wR9Y_42;>`@39sOH*IrJIoZ+_k zz%P|bJ6=7DS3l*c-eb3($*A`Mq>;vcbQEnTyHP9>gVFh6@&JuKa%Km;C&rF6*AE9? zI6;aYt&o*Wg$yU=_v$l#$KS9|lVJ@$FXx5>yvZ0uBAFC3JgQ~J1o4@`bS2@Kd@C9o z8PJh6xWAqm)yGru`8+w5lOE3nIC7mVG@SA`JKg+gLQgzjV}pg_Xy*i7k&{aH67;oX zC#K-U(e>V6&(N~M6^1{oP%JI`kQNvgVOZ`Ka*i$Vd!Fv}yj-7FI4ug{&EN%LH%H3E z_Red#USA4@cL6K9)~fcar4^hrep^MWn@+U5aaDU?R=yh6TXM^sZf&$m<AzEj*DyEwghzAYS04Z~ogjWWPi8*CyvGZ<`B zHs{c+%jWl+Rn_|xnsM(!SbizSo=3ADh3!h6NYrRjA~c$HB2c4ANp`858pNf54-iyvacekhrwl1!4w@>W+I2kHCJ zgysymadQC!>PJ+W4o8%n4n{OiIuxHFq8&G{U-KRhu^_GF35d|!S0{Dg{UF5h&5VI| z!p-Un(Q7#9%aq=g5Nkd)2DH!}55VPx&o&cp<5=`tC)mo|dZH$ji-NzL}@@ zwv|cecOOlQ6do$k#Lx%c!#>DA$Xho0EjfAL;P8X|aXih__-}o39ZV|ykfOho;3NDq z4dItZM}Pa44~Q?HqxZFb23M>6&w#{bNd1~K;>~-v?BwLV8arb#Tg+N`>FYju3s-Ju zwLh25SSW<{wf>x)aZ(N*u_F309igJ`&mKzd9X!4EqA%}Crnjo$O>99cgicg(C)^40 zU-$XdTm0g6!`7Ug_Yk_a9sH=FIpmSyr=%km$+PRNu#NwbaGb^7{t^XgTKq-26!6ic zRue6(iDGa65&_EMhQpUL78^DR-V<<+@sAZ}B%kb@mIppMezAA(d@gL2FoU#pmEOia zs_r!Md){UFJ5k$;`SfF;1jk|8We<~wvCqVZX-geDj7~oMJ=%ZMV~5d6hp{DlOT1f; zA+VAe5sw{j+vBk>|KE)rulVD!)7p{$2Jt^X@7Q%7-qF$G*`b>|>jN~GcSgD4wv(dv z%8t91k^fwh>y%3PuL}BCo!-GyozhQafSte+_*u|d4&a8=SW%5tZe&~jMpyh7`-Sj% literal 0 HcmV?d00001 diff --git a/tests/acpi-test-data/q35/SRAT.memhp b/tests/acpi-test-data/q35/SRAT.memhp new file mode 100644 index 0000000000000000000000000000000000000000..66ce9a898191d1da961c0c968c04ec56810a5785 GIT binary patch literal 224 zcmWFzatwLEz`(%x+sWVABUr&HBEUHqD8>jB1F=Cg2*ZH@DxXmUE(2w7!3B`@A=Cj4 c0D}+gFooFF!DO-12=n0X`2kbO3}XOk0FlrO0RR91 literal 0 HcmV?d00001 diff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c index 812f830539..54048050c0 100644 --- a/tests/bios-tables-test.c +++ b/tests/bios-tables-test.c @@ -867,6 +867,28 @@ static void test_acpi_piix4_tcg_ipmi(void) free_test_data(&data); } +static void test_acpi_q35_tcg_memhp(void) +{ + test_data data; + + memset(&data, 0, sizeof(data)); + data.machine = MACHINE_Q35; + data.variant = ".memhp"; + test_acpi_one(" -m 128,slots=3,maxmem=1G -numa node", &data); + free_test_data(&data); +} + +static void test_acpi_piix4_tcg_memhp(void) +{ + test_data data; + + memset(&data, 0, sizeof(data)); + data.machine = MACHINE_PC; + data.variant = ".memhp"; + test_acpi_one(" -m 128,slots=3,maxmem=1G -numa node", &data); + free_test_data(&data); +} + int main(int argc, char *argv[]) { const char *arch = qtest_get_arch(); @@ -887,6 +909,8 @@ int main(int argc, char *argv[]) qtest_add_func("acpi/q35/ipmi", test_acpi_q35_tcg_ipmi); qtest_add_func("acpi/piix4/cpuhp", test_acpi_piix4_tcg_cphp); qtest_add_func("acpi/q35/cpuhp", test_acpi_q35_tcg_cphp); + qtest_add_func("acpi/piix4/memhp", test_acpi_piix4_tcg_memhp); + qtest_add_func("acpi/q35/memhp", test_acpi_q35_tcg_memhp); } ret = g_test_run(); boot_sector_cleanup(disk); From a2088da36e940ed591023799fbc0ac3d2bb25782 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Tue, 6 Dec 2016 00:32:22 +0100 Subject: [PATCH 33/41] memhp: move build_memory_hotplug_aml() into memory_hotplug.c Signed-off-by: Igor Mammedov Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Marcel Apfelbaum --- hw/acpi/Makefile.objs | 2 +- hw/acpi/memory_hotplug.c | 247 ++++++++++++++++++++++++++ hw/acpi/memory_hotplug_acpi_table.c | 262 ---------------------------- 3 files changed, 248 insertions(+), 263 deletions(-) delete mode 100644 hw/acpi/memory_hotplug_acpi_table.c diff --git a/hw/acpi/Makefile.objs b/hw/acpi/Makefile.objs index 489e63bb75..834c63b980 100644 --- a/hw/acpi/Makefile.objs +++ b/hw/acpi/Makefile.objs @@ -1,7 +1,7 @@ common-obj-$(CONFIG_ACPI_X86) += core.o piix4.o pcihp.o common-obj-$(CONFIG_ACPI_X86_ICH) += ich9.o tco.o common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu_hotplug.o -common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o memory_hotplug_acpi_table.o +common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu.o common-obj-$(CONFIG_ACPI_NVDIMM) += nvdimm.o common-obj-$(CONFIG_ACPI) += acpi_interface.o diff --git a/hw/acpi/memory_hotplug.c b/hw/acpi/memory_hotplug.c index ec4e64b361..57ac4fc2d0 100644 --- a/hw/acpi/memory_hotplug.c +++ b/hw/acpi/memory_hotplug.c @@ -306,3 +306,250 @@ const VMStateDescription vmstate_memory_hotplug = { VMSTATE_END_OF_LIST() } }; + +void build_memory_hotplug_aml(Aml *ctx, uint32_t nr_mem, + uint16_t io_base, uint16_t io_len) +{ + Aml *ifctx; + Aml *method; + Aml *pci_scope; + Aml *mem_ctrl_dev; + + /* scope for memory hotplug controller device node */ + pci_scope = aml_scope("_SB.PCI0"); + mem_ctrl_dev = aml_device(MEMORY_HOTPLUG_DEVICE); + { + Aml *one = aml_int(1); + Aml *zero = aml_int(0); + Aml *ret_val = aml_local(0); + Aml *slot_arg0 = aml_arg(0); + Aml *slots_nr = aml_name(MEMORY_SLOTS_NUMBER); + Aml *ctrl_lock = aml_name(MEMORY_SLOT_LOCK); + Aml *slot_selector = aml_name(MEMORY_SLOT_SLECTOR); + + aml_append(mem_ctrl_dev, aml_name_decl("_HID", aml_string("PNP0A06"))); + aml_append(mem_ctrl_dev, + aml_name_decl("_UID", aml_string("Memory hotplug resources"))); + + method = aml_method("_STA", 0, AML_NOTSERIALIZED); + ifctx = aml_if(aml_equal(slots_nr, zero)); + { + aml_append(ifctx, aml_return(zero)); + } + aml_append(method, ifctx); + /* present, functioning, decoding, not shown in UI */ + aml_append(method, aml_return(aml_int(0xB))); + aml_append(mem_ctrl_dev, method); + + aml_append(mem_ctrl_dev, aml_mutex(MEMORY_SLOT_LOCK, 0)); + + method = aml_method(MEMORY_SLOT_SCAN_METHOD, 0, AML_NOTSERIALIZED); + { + Aml *else_ctx; + Aml *while_ctx; + Aml *idx = aml_local(0); + Aml *eject_req = aml_int(3); + Aml *dev_chk = aml_int(1); + + ifctx = aml_if(aml_equal(slots_nr, zero)); + { + aml_append(ifctx, aml_return(zero)); + } + aml_append(method, ifctx); + + aml_append(method, aml_store(zero, idx)); + aml_append(method, aml_acquire(ctrl_lock, 0xFFFF)); + /* build AML that: + * loops over all slots and Notifies DIMMs with + * Device Check or Eject Request notifications if + * slot has corresponding status bit set and clears + * slot status. + */ + while_ctx = aml_while(aml_lless(idx, slots_nr)); + { + Aml *ins_evt = aml_name(MEMORY_SLOT_INSERT_EVENT); + Aml *rm_evt = aml_name(MEMORY_SLOT_REMOVE_EVENT); + + aml_append(while_ctx, aml_store(idx, slot_selector)); + ifctx = aml_if(aml_equal(ins_evt, one)); + { + aml_append(ifctx, + aml_call2(MEMORY_SLOT_NOTIFY_METHOD, + idx, dev_chk)); + aml_append(ifctx, aml_store(one, ins_evt)); + } + aml_append(while_ctx, ifctx); + + else_ctx = aml_else(); + ifctx = aml_if(aml_equal(rm_evt, one)); + { + aml_append(ifctx, + aml_call2(MEMORY_SLOT_NOTIFY_METHOD, + idx, eject_req)); + aml_append(ifctx, aml_store(one, rm_evt)); + } + aml_append(else_ctx, ifctx); + aml_append(while_ctx, else_ctx); + + aml_append(while_ctx, aml_add(idx, one, idx)); + } + aml_append(method, while_ctx); + aml_append(method, aml_release(ctrl_lock)); + aml_append(method, aml_return(one)); + } + aml_append(mem_ctrl_dev, method); + + method = aml_method(MEMORY_SLOT_STATUS_METHOD, 1, AML_NOTSERIALIZED); + { + Aml *slot_enabled = aml_name(MEMORY_SLOT_ENABLED); + + aml_append(method, aml_store(zero, ret_val)); + aml_append(method, aml_acquire(ctrl_lock, 0xFFFF)); + aml_append(method, + aml_store(aml_to_integer(slot_arg0), slot_selector)); + + ifctx = aml_if(aml_equal(slot_enabled, one)); + { + aml_append(ifctx, aml_store(aml_int(0xF), ret_val)); + } + aml_append(method, ifctx); + + aml_append(method, aml_release(ctrl_lock)); + aml_append(method, aml_return(ret_val)); + } + aml_append(mem_ctrl_dev, method); + + method = aml_method(MEMORY_SLOT_CRS_METHOD, 1, AML_SERIALIZED); + { + Aml *mr64 = aml_name("MR64"); + Aml *mr32 = aml_name("MR32"); + Aml *crs_tmpl = aml_resource_template(); + Aml *minl = aml_name("MINL"); + Aml *minh = aml_name("MINH"); + Aml *maxl = aml_name("MAXL"); + Aml *maxh = aml_name("MAXH"); + Aml *lenl = aml_name("LENL"); + Aml *lenh = aml_name("LENH"); + + aml_append(method, aml_acquire(ctrl_lock, 0xFFFF)); + aml_append(method, aml_store(aml_to_integer(slot_arg0), + slot_selector)); + + aml_append(crs_tmpl, + aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, + AML_CACHEABLE, AML_READ_WRITE, + 0, 0x0, 0xFFFFFFFFFFFFFFFEULL, 0, + 0xFFFFFFFFFFFFFFFFULL)); + aml_append(method, aml_name_decl("MR64", crs_tmpl)); + aml_append(method, + aml_create_dword_field(mr64, aml_int(14), "MINL")); + aml_append(method, + aml_create_dword_field(mr64, aml_int(18), "MINH")); + aml_append(method, + aml_create_dword_field(mr64, aml_int(38), "LENL")); + aml_append(method, + aml_create_dword_field(mr64, aml_int(42), "LENH")); + aml_append(method, + aml_create_dword_field(mr64, aml_int(22), "MAXL")); + aml_append(method, + aml_create_dword_field(mr64, aml_int(26), "MAXH")); + + aml_append(method, + aml_store(aml_name(MEMORY_SLOT_ADDR_HIGH), minh)); + aml_append(method, + aml_store(aml_name(MEMORY_SLOT_ADDR_LOW), minl)); + aml_append(method, + aml_store(aml_name(MEMORY_SLOT_SIZE_HIGH), lenh)); + aml_append(method, + aml_store(aml_name(MEMORY_SLOT_SIZE_LOW), lenl)); + + /* 64-bit math: MAX = MIN + LEN - 1 */ + aml_append(method, aml_add(minl, lenl, maxl)); + aml_append(method, aml_add(minh, lenh, maxh)); + ifctx = aml_if(aml_lless(maxl, minl)); + { + aml_append(ifctx, aml_add(maxh, one, maxh)); + } + aml_append(method, ifctx); + ifctx = aml_if(aml_lless(maxl, one)); + { + aml_append(ifctx, aml_subtract(maxh, one, maxh)); + } + aml_append(method, ifctx); + aml_append(method, aml_subtract(maxl, one, maxl)); + + /* return 32-bit _CRS if addr/size is in low mem */ + /* TODO: remove it since all hotplugged DIMMs are in high mem */ + ifctx = aml_if(aml_equal(maxh, zero)); + { + crs_tmpl = aml_resource_template(); + aml_append(crs_tmpl, + aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, + AML_MAX_FIXED, AML_CACHEABLE, + AML_READ_WRITE, + 0, 0x0, 0xFFFFFFFE, 0, + 0xFFFFFFFF)); + aml_append(ifctx, aml_name_decl("MR32", crs_tmpl)); + aml_append(ifctx, + aml_create_dword_field(mr32, aml_int(10), "MIN")); + aml_append(ifctx, + aml_create_dword_field(mr32, aml_int(14), "MAX")); + aml_append(ifctx, + aml_create_dword_field(mr32, aml_int(22), "LEN")); + aml_append(ifctx, aml_store(minl, aml_name("MIN"))); + aml_append(ifctx, aml_store(maxl, aml_name("MAX"))); + aml_append(ifctx, aml_store(lenl, aml_name("LEN"))); + + aml_append(ifctx, aml_release(ctrl_lock)); + aml_append(ifctx, aml_return(mr32)); + } + aml_append(method, ifctx); + + aml_append(method, aml_release(ctrl_lock)); + aml_append(method, aml_return(mr64)); + } + aml_append(mem_ctrl_dev, method); + + method = aml_method(MEMORY_SLOT_PROXIMITY_METHOD, 1, + AML_NOTSERIALIZED); + { + Aml *proximity = aml_name(MEMORY_SLOT_PROXIMITY); + + aml_append(method, aml_acquire(ctrl_lock, 0xFFFF)); + aml_append(method, aml_store(aml_to_integer(slot_arg0), + slot_selector)); + aml_append(method, aml_store(proximity, ret_val)); + aml_append(method, aml_release(ctrl_lock)); + aml_append(method, aml_return(ret_val)); + } + aml_append(mem_ctrl_dev, method); + + method = aml_method(MEMORY_SLOT_OST_METHOD, 4, AML_NOTSERIALIZED); + { + Aml *ost_evt = aml_name(MEMORY_SLOT_OST_EVENT); + Aml *ost_status = aml_name(MEMORY_SLOT_OST_STATUS); + + aml_append(method, aml_acquire(ctrl_lock, 0xFFFF)); + aml_append(method, aml_store(aml_to_integer(slot_arg0), + slot_selector)); + aml_append(method, aml_store(aml_arg(1), ost_evt)); + aml_append(method, aml_store(aml_arg(2), ost_status)); + aml_append(method, aml_release(ctrl_lock)); + } + aml_append(mem_ctrl_dev, method); + + method = aml_method(MEMORY_SLOT_EJECT_METHOD, 2, AML_NOTSERIALIZED); + { + Aml *eject = aml_name(MEMORY_SLOT_EJECT); + + aml_append(method, aml_acquire(ctrl_lock, 0xFFFF)); + aml_append(method, aml_store(aml_to_integer(slot_arg0), + slot_selector)); + aml_append(method, aml_store(one, eject)); + aml_append(method, aml_release(ctrl_lock)); + } + aml_append(mem_ctrl_dev, method); + } + aml_append(pci_scope, mem_ctrl_dev); + aml_append(ctx, pci_scope); +} diff --git a/hw/acpi/memory_hotplug_acpi_table.c b/hw/acpi/memory_hotplug_acpi_table.c deleted file mode 100644 index c75660215d..0000000000 --- a/hw/acpi/memory_hotplug_acpi_table.c +++ /dev/null @@ -1,262 +0,0 @@ -/* - * Memory hotplug AML code of DSDT ACPI table - * - * Copyright (C) 2015 Red Hat Inc - * - * Author: Igor Mammedov - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - */ - -#include "qemu/osdep.h" -#include "hw/acpi/memory_hotplug.h" -#include "include/hw/acpi/pc-hotplug.h" -#include "hw/boards.h" - -void build_memory_hotplug_aml(Aml *ctx, uint32_t nr_mem, - uint16_t io_base, uint16_t io_len) -{ - Aml *ifctx; - Aml *method; - Aml *pci_scope; - Aml *mem_ctrl_dev; - - /* scope for memory hotplug controller device node */ - pci_scope = aml_scope("_SB.PCI0"); - mem_ctrl_dev = aml_device(MEMORY_HOTPLUG_DEVICE); - { - Aml *one = aml_int(1); - Aml *zero = aml_int(0); - Aml *ret_val = aml_local(0); - Aml *slot_arg0 = aml_arg(0); - Aml *slots_nr = aml_name(MEMORY_SLOTS_NUMBER); - Aml *ctrl_lock = aml_name(MEMORY_SLOT_LOCK); - Aml *slot_selector = aml_name(MEMORY_SLOT_SLECTOR); - - aml_append(mem_ctrl_dev, aml_name_decl("_HID", aml_string("PNP0A06"))); - aml_append(mem_ctrl_dev, - aml_name_decl("_UID", aml_string("Memory hotplug resources"))); - - method = aml_method("_STA", 0, AML_NOTSERIALIZED); - ifctx = aml_if(aml_equal(slots_nr, zero)); - { - aml_append(ifctx, aml_return(zero)); - } - aml_append(method, ifctx); - /* present, functioning, decoding, not shown in UI */ - aml_append(method, aml_return(aml_int(0xB))); - aml_append(mem_ctrl_dev, method); - - aml_append(mem_ctrl_dev, aml_mutex(MEMORY_SLOT_LOCK, 0)); - - method = aml_method(MEMORY_SLOT_SCAN_METHOD, 0, AML_NOTSERIALIZED); - { - Aml *else_ctx; - Aml *while_ctx; - Aml *idx = aml_local(0); - Aml *eject_req = aml_int(3); - Aml *dev_chk = aml_int(1); - - ifctx = aml_if(aml_equal(slots_nr, zero)); - { - aml_append(ifctx, aml_return(zero)); - } - aml_append(method, ifctx); - - aml_append(method, aml_store(zero, idx)); - aml_append(method, aml_acquire(ctrl_lock, 0xFFFF)); - /* build AML that: - * loops over all slots and Notifies DIMMs with - * Device Check or Eject Request notifications if - * slot has corresponding status bit set and clears - * slot status. - */ - while_ctx = aml_while(aml_lless(idx, slots_nr)); - { - Aml *ins_evt = aml_name(MEMORY_SLOT_INSERT_EVENT); - Aml *rm_evt = aml_name(MEMORY_SLOT_REMOVE_EVENT); - - aml_append(while_ctx, aml_store(idx, slot_selector)); - ifctx = aml_if(aml_equal(ins_evt, one)); - { - aml_append(ifctx, - aml_call2(MEMORY_SLOT_NOTIFY_METHOD, - idx, dev_chk)); - aml_append(ifctx, aml_store(one, ins_evt)); - } - aml_append(while_ctx, ifctx); - - else_ctx = aml_else(); - ifctx = aml_if(aml_equal(rm_evt, one)); - { - aml_append(ifctx, - aml_call2(MEMORY_SLOT_NOTIFY_METHOD, - idx, eject_req)); - aml_append(ifctx, aml_store(one, rm_evt)); - } - aml_append(else_ctx, ifctx); - aml_append(while_ctx, else_ctx); - - aml_append(while_ctx, aml_add(idx, one, idx)); - } - aml_append(method, while_ctx); - aml_append(method, aml_release(ctrl_lock)); - aml_append(method, aml_return(one)); - } - aml_append(mem_ctrl_dev, method); - - method = aml_method(MEMORY_SLOT_STATUS_METHOD, 1, AML_NOTSERIALIZED); - { - Aml *slot_enabled = aml_name(MEMORY_SLOT_ENABLED); - - aml_append(method, aml_store(zero, ret_val)); - aml_append(method, aml_acquire(ctrl_lock, 0xFFFF)); - aml_append(method, - aml_store(aml_to_integer(slot_arg0), slot_selector)); - - ifctx = aml_if(aml_equal(slot_enabled, one)); - { - aml_append(ifctx, aml_store(aml_int(0xF), ret_val)); - } - aml_append(method, ifctx); - - aml_append(method, aml_release(ctrl_lock)); - aml_append(method, aml_return(ret_val)); - } - aml_append(mem_ctrl_dev, method); - - method = aml_method(MEMORY_SLOT_CRS_METHOD, 1, AML_SERIALIZED); - { - Aml *mr64 = aml_name("MR64"); - Aml *mr32 = aml_name("MR32"); - Aml *crs_tmpl = aml_resource_template(); - Aml *minl = aml_name("MINL"); - Aml *minh = aml_name("MINH"); - Aml *maxl = aml_name("MAXL"); - Aml *maxh = aml_name("MAXH"); - Aml *lenl = aml_name("LENL"); - Aml *lenh = aml_name("LENH"); - - aml_append(method, aml_acquire(ctrl_lock, 0xFFFF)); - aml_append(method, aml_store(aml_to_integer(slot_arg0), - slot_selector)); - - aml_append(crs_tmpl, - aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, - AML_CACHEABLE, AML_READ_WRITE, - 0, 0x0, 0xFFFFFFFFFFFFFFFEULL, 0, - 0xFFFFFFFFFFFFFFFFULL)); - aml_append(method, aml_name_decl("MR64", crs_tmpl)); - aml_append(method, - aml_create_dword_field(mr64, aml_int(14), "MINL")); - aml_append(method, - aml_create_dword_field(mr64, aml_int(18), "MINH")); - aml_append(method, - aml_create_dword_field(mr64, aml_int(38), "LENL")); - aml_append(method, - aml_create_dword_field(mr64, aml_int(42), "LENH")); - aml_append(method, - aml_create_dword_field(mr64, aml_int(22), "MAXL")); - aml_append(method, - aml_create_dword_field(mr64, aml_int(26), "MAXH")); - - aml_append(method, - aml_store(aml_name(MEMORY_SLOT_ADDR_HIGH), minh)); - aml_append(method, - aml_store(aml_name(MEMORY_SLOT_ADDR_LOW), minl)); - aml_append(method, - aml_store(aml_name(MEMORY_SLOT_SIZE_HIGH), lenh)); - aml_append(method, - aml_store(aml_name(MEMORY_SLOT_SIZE_LOW), lenl)); - - /* 64-bit math: MAX = MIN + LEN - 1 */ - aml_append(method, aml_add(minl, lenl, maxl)); - aml_append(method, aml_add(minh, lenh, maxh)); - ifctx = aml_if(aml_lless(maxl, minl)); - { - aml_append(ifctx, aml_add(maxh, one, maxh)); - } - aml_append(method, ifctx); - ifctx = aml_if(aml_lless(maxl, one)); - { - aml_append(ifctx, aml_subtract(maxh, one, maxh)); - } - aml_append(method, ifctx); - aml_append(method, aml_subtract(maxl, one, maxl)); - - /* return 32-bit _CRS if addr/size is in low mem */ - /* TODO: remove it since all hotplugged DIMMs are in high mem */ - ifctx = aml_if(aml_equal(maxh, zero)); - { - crs_tmpl = aml_resource_template(); - aml_append(crs_tmpl, - aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, - AML_MAX_FIXED, AML_CACHEABLE, - AML_READ_WRITE, - 0, 0x0, 0xFFFFFFFE, 0, - 0xFFFFFFFF)); - aml_append(ifctx, aml_name_decl("MR32", crs_tmpl)); - aml_append(ifctx, - aml_create_dword_field(mr32, aml_int(10), "MIN")); - aml_append(ifctx, - aml_create_dword_field(mr32, aml_int(14), "MAX")); - aml_append(ifctx, - aml_create_dword_field(mr32, aml_int(22), "LEN")); - aml_append(ifctx, aml_store(minl, aml_name("MIN"))); - aml_append(ifctx, aml_store(maxl, aml_name("MAX"))); - aml_append(ifctx, aml_store(lenl, aml_name("LEN"))); - - aml_append(ifctx, aml_release(ctrl_lock)); - aml_append(ifctx, aml_return(mr32)); - } - aml_append(method, ifctx); - - aml_append(method, aml_release(ctrl_lock)); - aml_append(method, aml_return(mr64)); - } - aml_append(mem_ctrl_dev, method); - - method = aml_method(MEMORY_SLOT_PROXIMITY_METHOD, 1, - AML_NOTSERIALIZED); - { - Aml *proximity = aml_name(MEMORY_SLOT_PROXIMITY); - - aml_append(method, aml_acquire(ctrl_lock, 0xFFFF)); - aml_append(method, aml_store(aml_to_integer(slot_arg0), - slot_selector)); - aml_append(method, aml_store(proximity, ret_val)); - aml_append(method, aml_release(ctrl_lock)); - aml_append(method, aml_return(ret_val)); - } - aml_append(mem_ctrl_dev, method); - - method = aml_method(MEMORY_SLOT_OST_METHOD, 4, AML_NOTSERIALIZED); - { - Aml *ost_evt = aml_name(MEMORY_SLOT_OST_EVENT); - Aml *ost_status = aml_name(MEMORY_SLOT_OST_STATUS); - - aml_append(method, aml_acquire(ctrl_lock, 0xFFFF)); - aml_append(method, aml_store(aml_to_integer(slot_arg0), - slot_selector)); - aml_append(method, aml_store(aml_arg(1), ost_evt)); - aml_append(method, aml_store(aml_arg(2), ost_status)); - aml_append(method, aml_release(ctrl_lock)); - } - aml_append(mem_ctrl_dev, method); - - method = aml_method(MEMORY_SLOT_EJECT_METHOD, 2, AML_NOTSERIALIZED); - { - Aml *eject = aml_name(MEMORY_SLOT_EJECT); - - aml_append(method, aml_acquire(ctrl_lock, 0xFFFF)); - aml_append(method, aml_store(aml_to_integer(slot_arg0), - slot_selector)); - aml_append(method, aml_store(one, eject)); - aml_append(method, aml_release(ctrl_lock)); - } - aml_append(mem_ctrl_dev, method); - } - aml_append(pci_scope, mem_ctrl_dev); - aml_append(ctx, pci_scope); -} From 75ff0f0c901eecb5148e2d332a3b8dbbf4ab5821 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Tue, 6 Dec 2016 00:32:23 +0100 Subject: [PATCH 34/41] memhp: move build_memory_devices() into memory_hotplug.c Signed-off-by: Igor Mammedov Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Marcel Apfelbaum --- hw/acpi/memory_hotplug.c | 124 +++++++++++++++++++++++++++++++ hw/i386/acpi-build.c | 124 ------------------------------- include/hw/acpi/memory_hotplug.h | 2 + 3 files changed, 126 insertions(+), 124 deletions(-) diff --git a/hw/acpi/memory_hotplug.c b/hw/acpi/memory_hotplug.c index 57ac4fc2d0..67dd3f899e 100644 --- a/hw/acpi/memory_hotplug.c +++ b/hw/acpi/memory_hotplug.c @@ -553,3 +553,127 @@ void build_memory_hotplug_aml(Aml *ctx, uint32_t nr_mem, aml_append(pci_scope, mem_ctrl_dev); aml_append(ctx, pci_scope); } + +void build_memory_devices(Aml *sb_scope, int nr_mem, + uint16_t io_base, uint16_t io_len) +{ + int i; + Aml *scope; + Aml *crs; + Aml *field; + Aml *dev; + Aml *method; + Aml *ifctx; + + /* build memory devices */ + assert(nr_mem <= ACPI_MAX_RAM_SLOTS); + scope = aml_scope("\\_SB.PCI0." MEMORY_HOTPLUG_DEVICE); + aml_append(scope, + aml_name_decl(MEMORY_SLOTS_NUMBER, aml_int(nr_mem)) + ); + + crs = aml_resource_template(); + aml_append(crs, + aml_io(AML_DECODE16, io_base, io_base, 0, io_len) + ); + aml_append(scope, aml_name_decl("_CRS", crs)); + + aml_append(scope, aml_operation_region( + MEMORY_HOTPLUG_IO_REGION, AML_SYSTEM_IO, + aml_int(io_base), io_len) + ); + + field = aml_field(MEMORY_HOTPLUG_IO_REGION, AML_DWORD_ACC, + AML_NOLOCK, AML_PRESERVE); + aml_append(field, /* read only */ + aml_named_field(MEMORY_SLOT_ADDR_LOW, 32)); + aml_append(field, /* read only */ + aml_named_field(MEMORY_SLOT_ADDR_HIGH, 32)); + aml_append(field, /* read only */ + aml_named_field(MEMORY_SLOT_SIZE_LOW, 32)); + aml_append(field, /* read only */ + aml_named_field(MEMORY_SLOT_SIZE_HIGH, 32)); + aml_append(field, /* read only */ + aml_named_field(MEMORY_SLOT_PROXIMITY, 32)); + aml_append(scope, field); + + field = aml_field(MEMORY_HOTPLUG_IO_REGION, AML_BYTE_ACC, + AML_NOLOCK, AML_WRITE_AS_ZEROS); + aml_append(field, aml_reserved_field(160 /* bits, Offset(20) */)); + aml_append(field, /* 1 if enabled, read only */ + aml_named_field(MEMORY_SLOT_ENABLED, 1)); + aml_append(field, + /*(read) 1 if has a insert event. (write) 1 to clear event */ + aml_named_field(MEMORY_SLOT_INSERT_EVENT, 1)); + aml_append(field, + /* (read) 1 if has a remove event. (write) 1 to clear event */ + aml_named_field(MEMORY_SLOT_REMOVE_EVENT, 1)); + aml_append(field, + /* initiates device eject, write only */ + aml_named_field(MEMORY_SLOT_EJECT, 1)); + aml_append(scope, field); + + field = aml_field(MEMORY_HOTPLUG_IO_REGION, AML_DWORD_ACC, + AML_NOLOCK, AML_PRESERVE); + aml_append(field, /* DIMM selector, write only */ + aml_named_field(MEMORY_SLOT_SLECTOR, 32)); + aml_append(field, /* _OST event code, write only */ + aml_named_field(MEMORY_SLOT_OST_EVENT, 32)); + aml_append(field, /* _OST status code, write only */ + aml_named_field(MEMORY_SLOT_OST_STATUS, 32)); + aml_append(scope, field); + aml_append(sb_scope, scope); + + for (i = 0; i < nr_mem; i++) { + #define BASEPATH "\\_SB.PCI0." MEMORY_HOTPLUG_DEVICE "." + const char *s; + + dev = aml_device("MP%02X", i); + aml_append(dev, aml_name_decl("_UID", aml_string("0x%02X", i))); + aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C80"))); + + method = aml_method("_CRS", 0, AML_NOTSERIALIZED); + s = BASEPATH MEMORY_SLOT_CRS_METHOD; + aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); + aml_append(dev, method); + + method = aml_method("_STA", 0, AML_NOTSERIALIZED); + s = BASEPATH MEMORY_SLOT_STATUS_METHOD; + aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); + aml_append(dev, method); + + method = aml_method("_PXM", 0, AML_NOTSERIALIZED); + s = BASEPATH MEMORY_SLOT_PROXIMITY_METHOD; + aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); + aml_append(dev, method); + + method = aml_method("_OST", 3, AML_NOTSERIALIZED); + s = BASEPATH MEMORY_SLOT_OST_METHOD; + + aml_append(method, aml_return(aml_call4( + s, aml_name("_UID"), aml_arg(0), aml_arg(1), aml_arg(2) + ))); + aml_append(dev, method); + + method = aml_method("_EJ0", 1, AML_NOTSERIALIZED); + s = BASEPATH MEMORY_SLOT_EJECT_METHOD; + aml_append(method, aml_return(aml_call2( + s, aml_name("_UID"), aml_arg(0)))); + aml_append(dev, method); + + aml_append(sb_scope, dev); + } + + /* build Method(MEMORY_SLOT_NOTIFY_METHOD, 2) { + * If (LEqual(Arg0, 0x00)) {Notify(MP00, Arg1)} ... } + */ + method = aml_method(MEMORY_SLOT_NOTIFY_METHOD, 2, AML_NOTSERIALIZED); + for (i = 0; i < nr_mem; i++) { + ifctx = aml_if(aml_equal(aml_arg(0), aml_int(i))); + aml_append(ifctx, + aml_notify(aml_name("MP%.02X", i), aml_arg(1)) + ); + aml_append(method, ifctx); + } + aml_append(sb_scope, method); +} diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 4609db1359..a3f9caa712 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -1038,130 +1038,6 @@ static Aml *build_crs(PCIHostState *host, CrsRangeSet *range_set) return crs; } -static void build_memory_devices(Aml *sb_scope, int nr_mem, - uint16_t io_base, uint16_t io_len) -{ - int i; - Aml *scope; - Aml *crs; - Aml *field; - Aml *dev; - Aml *method; - Aml *ifctx; - - /* build memory devices */ - assert(nr_mem <= ACPI_MAX_RAM_SLOTS); - scope = aml_scope("\\_SB.PCI0." MEMORY_HOTPLUG_DEVICE); - aml_append(scope, - aml_name_decl(MEMORY_SLOTS_NUMBER, aml_int(nr_mem)) - ); - - crs = aml_resource_template(); - aml_append(crs, - aml_io(AML_DECODE16, io_base, io_base, 0, io_len) - ); - aml_append(scope, aml_name_decl("_CRS", crs)); - - aml_append(scope, aml_operation_region( - MEMORY_HOTPLUG_IO_REGION, AML_SYSTEM_IO, - aml_int(io_base), io_len) - ); - - field = aml_field(MEMORY_HOTPLUG_IO_REGION, AML_DWORD_ACC, - AML_NOLOCK, AML_PRESERVE); - aml_append(field, /* read only */ - aml_named_field(MEMORY_SLOT_ADDR_LOW, 32)); - aml_append(field, /* read only */ - aml_named_field(MEMORY_SLOT_ADDR_HIGH, 32)); - aml_append(field, /* read only */ - aml_named_field(MEMORY_SLOT_SIZE_LOW, 32)); - aml_append(field, /* read only */ - aml_named_field(MEMORY_SLOT_SIZE_HIGH, 32)); - aml_append(field, /* read only */ - aml_named_field(MEMORY_SLOT_PROXIMITY, 32)); - aml_append(scope, field); - - field = aml_field(MEMORY_HOTPLUG_IO_REGION, AML_BYTE_ACC, - AML_NOLOCK, AML_WRITE_AS_ZEROS); - aml_append(field, aml_reserved_field(160 /* bits, Offset(20) */)); - aml_append(field, /* 1 if enabled, read only */ - aml_named_field(MEMORY_SLOT_ENABLED, 1)); - aml_append(field, - /*(read) 1 if has a insert event. (write) 1 to clear event */ - aml_named_field(MEMORY_SLOT_INSERT_EVENT, 1)); - aml_append(field, - /* (read) 1 if has a remove event. (write) 1 to clear event */ - aml_named_field(MEMORY_SLOT_REMOVE_EVENT, 1)); - aml_append(field, - /* initiates device eject, write only */ - aml_named_field(MEMORY_SLOT_EJECT, 1)); - aml_append(scope, field); - - field = aml_field(MEMORY_HOTPLUG_IO_REGION, AML_DWORD_ACC, - AML_NOLOCK, AML_PRESERVE); - aml_append(field, /* DIMM selector, write only */ - aml_named_field(MEMORY_SLOT_SLECTOR, 32)); - aml_append(field, /* _OST event code, write only */ - aml_named_field(MEMORY_SLOT_OST_EVENT, 32)); - aml_append(field, /* _OST status code, write only */ - aml_named_field(MEMORY_SLOT_OST_STATUS, 32)); - aml_append(scope, field); - aml_append(sb_scope, scope); - - for (i = 0; i < nr_mem; i++) { - #define BASEPATH "\\_SB.PCI0." MEMORY_HOTPLUG_DEVICE "." - const char *s; - - dev = aml_device("MP%02X", i); - aml_append(dev, aml_name_decl("_UID", aml_string("0x%02X", i))); - aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C80"))); - - method = aml_method("_CRS", 0, AML_NOTSERIALIZED); - s = BASEPATH MEMORY_SLOT_CRS_METHOD; - aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); - aml_append(dev, method); - - method = aml_method("_STA", 0, AML_NOTSERIALIZED); - s = BASEPATH MEMORY_SLOT_STATUS_METHOD; - aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); - aml_append(dev, method); - - method = aml_method("_PXM", 0, AML_NOTSERIALIZED); - s = BASEPATH MEMORY_SLOT_PROXIMITY_METHOD; - aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); - aml_append(dev, method); - - method = aml_method("_OST", 3, AML_NOTSERIALIZED); - s = BASEPATH MEMORY_SLOT_OST_METHOD; - - aml_append(method, aml_return(aml_call4( - s, aml_name("_UID"), aml_arg(0), aml_arg(1), aml_arg(2) - ))); - aml_append(dev, method); - - method = aml_method("_EJ0", 1, AML_NOTSERIALIZED); - s = BASEPATH MEMORY_SLOT_EJECT_METHOD; - aml_append(method, aml_return(aml_call2( - s, aml_name("_UID"), aml_arg(0)))); - aml_append(dev, method); - - aml_append(sb_scope, dev); - } - - /* build Method(MEMORY_SLOT_NOTIFY_METHOD, 2) { - * If (LEqual(Arg0, 0x00)) {Notify(MP00, Arg1)} ... } - */ - method = aml_method(MEMORY_SLOT_NOTIFY_METHOD, 2, AML_NOTSERIALIZED); - for (i = 0; i < nr_mem; i++) { - ifctx = aml_if(aml_equal(aml_arg(0), aml_int(i))); - aml_append(ifctx, - aml_notify(aml_name("MP%.02X", i), aml_arg(1)) - ); - aml_append(method, ifctx); - } - aml_append(sb_scope, method); -} - static void build_hpet_aml(Aml *table) { Aml *crs; diff --git a/include/hw/acpi/memory_hotplug.h b/include/hw/acpi/memory_hotplug.h index d2c7452397..964c2442a6 100644 --- a/include/hw/acpi/memory_hotplug.h +++ b/include/hw/acpi/memory_hotplug.h @@ -54,4 +54,6 @@ void acpi_memory_ospm_status(MemHotplugState *mem_st, ACPIOSTInfoList ***list); void build_memory_hotplug_aml(Aml *ctx, uint32_t nr_mem, uint16_t io_base, uint16_t io_len); +void build_memory_devices(Aml *sb_scope, int nr_mem, + uint16_t io_base, uint16_t io_len); #endif From 8dfba500af730e89d3d5a2cbf9440002cce59b9b Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Tue, 6 Dec 2016 00:32:24 +0100 Subject: [PATCH 35/41] memhp: consolidate scattered MHPD device declaration since static and dynamic parts of memory MHPD device are now in the same table (DSDT), there is no point keeping them scattered across the table, so consolidate it in one place. There aren't any functional change, only AML text movement from externally refferenced MHPD scope directly into MHPD device declaration. Signed-off-by: Igor Mammedov Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Marcel Apfelbaum --- hw/acpi/memory_hotplug.c | 123 +++++++++++++++---------------- include/hw/acpi/memory_hotplug.h | 2 +- 2 files changed, 61 insertions(+), 64 deletions(-) diff --git a/hw/acpi/memory_hotplug.c b/hw/acpi/memory_hotplug.c index 67dd3f899e..fb40a5ea81 100644 --- a/hw/acpi/memory_hotplug.c +++ b/hw/acpi/memory_hotplug.c @@ -307,7 +307,7 @@ const VMStateDescription vmstate_memory_hotplug = { } }; -void build_memory_hotplug_aml(Aml *ctx, uint32_t nr_mem, +void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem, uint16_t io_base, uint16_t io_len) { Aml *ifctx; @@ -319,6 +319,8 @@ void build_memory_hotplug_aml(Aml *ctx, uint32_t nr_mem, pci_scope = aml_scope("_SB.PCI0"); mem_ctrl_dev = aml_device(MEMORY_HOTPLUG_DEVICE); { + Aml *crs; + Aml *field; Aml *one = aml_int(1); Aml *zero = aml_int(0); Aml *ret_val = aml_local(0); @@ -331,6 +333,62 @@ void build_memory_hotplug_aml(Aml *ctx, uint32_t nr_mem, aml_append(mem_ctrl_dev, aml_name_decl("_UID", aml_string("Memory hotplug resources"))); + assert(nr_mem <= ACPI_MAX_RAM_SLOTS); + aml_append(mem_ctrl_dev, + aml_name_decl(MEMORY_SLOTS_NUMBER, aml_int(nr_mem)) + ); + + crs = aml_resource_template(); + aml_append(crs, + aml_io(AML_DECODE16, io_base, io_base, 0, io_len) + ); + aml_append(mem_ctrl_dev, aml_name_decl("_CRS", crs)); + + aml_append(mem_ctrl_dev, aml_operation_region( + MEMORY_HOTPLUG_IO_REGION, AML_SYSTEM_IO, + aml_int(io_base), io_len) + ); + + field = aml_field(MEMORY_HOTPLUG_IO_REGION, AML_DWORD_ACC, + AML_NOLOCK, AML_PRESERVE); + aml_append(field, /* read only */ + aml_named_field(MEMORY_SLOT_ADDR_LOW, 32)); + aml_append(field, /* read only */ + aml_named_field(MEMORY_SLOT_ADDR_HIGH, 32)); + aml_append(field, /* read only */ + aml_named_field(MEMORY_SLOT_SIZE_LOW, 32)); + aml_append(field, /* read only */ + aml_named_field(MEMORY_SLOT_SIZE_HIGH, 32)); + aml_append(field, /* read only */ + aml_named_field(MEMORY_SLOT_PROXIMITY, 32)); + aml_append(mem_ctrl_dev, field); + + field = aml_field(MEMORY_HOTPLUG_IO_REGION, AML_BYTE_ACC, + AML_NOLOCK, AML_WRITE_AS_ZEROS); + aml_append(field, aml_reserved_field(160 /* bits, Offset(20) */)); + aml_append(field, /* 1 if enabled, read only */ + aml_named_field(MEMORY_SLOT_ENABLED, 1)); + aml_append(field, + /*(read) 1 if has a insert event. (write) 1 to clear event */ + aml_named_field(MEMORY_SLOT_INSERT_EVENT, 1)); + aml_append(field, + /* (read) 1 if has a remove event. (write) 1 to clear event */ + aml_named_field(MEMORY_SLOT_REMOVE_EVENT, 1)); + aml_append(field, + /* initiates device eject, write only */ + aml_named_field(MEMORY_SLOT_EJECT, 1)); + aml_append(mem_ctrl_dev, field); + + field = aml_field(MEMORY_HOTPLUG_IO_REGION, AML_DWORD_ACC, + AML_NOLOCK, AML_PRESERVE); + aml_append(field, /* DIMM selector, write only */ + aml_named_field(MEMORY_SLOT_SLECTOR, 32)); + aml_append(field, /* _OST event code, write only */ + aml_named_field(MEMORY_SLOT_OST_EVENT, 32)); + aml_append(field, /* _OST status code, write only */ + aml_named_field(MEMORY_SLOT_OST_STATUS, 32)); + aml_append(mem_ctrl_dev, field); + method = aml_method("_STA", 0, AML_NOTSERIALIZED); ifctx = aml_if(aml_equal(slots_nr, zero)); { @@ -551,79 +609,18 @@ void build_memory_hotplug_aml(Aml *ctx, uint32_t nr_mem, aml_append(mem_ctrl_dev, method); } aml_append(pci_scope, mem_ctrl_dev); - aml_append(ctx, pci_scope); + aml_append(table, pci_scope); } void build_memory_devices(Aml *sb_scope, int nr_mem, uint16_t io_base, uint16_t io_len) { int i; - Aml *scope; - Aml *crs; - Aml *field; Aml *dev; Aml *method; Aml *ifctx; /* build memory devices */ - assert(nr_mem <= ACPI_MAX_RAM_SLOTS); - scope = aml_scope("\\_SB.PCI0." MEMORY_HOTPLUG_DEVICE); - aml_append(scope, - aml_name_decl(MEMORY_SLOTS_NUMBER, aml_int(nr_mem)) - ); - - crs = aml_resource_template(); - aml_append(crs, - aml_io(AML_DECODE16, io_base, io_base, 0, io_len) - ); - aml_append(scope, aml_name_decl("_CRS", crs)); - - aml_append(scope, aml_operation_region( - MEMORY_HOTPLUG_IO_REGION, AML_SYSTEM_IO, - aml_int(io_base), io_len) - ); - - field = aml_field(MEMORY_HOTPLUG_IO_REGION, AML_DWORD_ACC, - AML_NOLOCK, AML_PRESERVE); - aml_append(field, /* read only */ - aml_named_field(MEMORY_SLOT_ADDR_LOW, 32)); - aml_append(field, /* read only */ - aml_named_field(MEMORY_SLOT_ADDR_HIGH, 32)); - aml_append(field, /* read only */ - aml_named_field(MEMORY_SLOT_SIZE_LOW, 32)); - aml_append(field, /* read only */ - aml_named_field(MEMORY_SLOT_SIZE_HIGH, 32)); - aml_append(field, /* read only */ - aml_named_field(MEMORY_SLOT_PROXIMITY, 32)); - aml_append(scope, field); - - field = aml_field(MEMORY_HOTPLUG_IO_REGION, AML_BYTE_ACC, - AML_NOLOCK, AML_WRITE_AS_ZEROS); - aml_append(field, aml_reserved_field(160 /* bits, Offset(20) */)); - aml_append(field, /* 1 if enabled, read only */ - aml_named_field(MEMORY_SLOT_ENABLED, 1)); - aml_append(field, - /*(read) 1 if has a insert event. (write) 1 to clear event */ - aml_named_field(MEMORY_SLOT_INSERT_EVENT, 1)); - aml_append(field, - /* (read) 1 if has a remove event. (write) 1 to clear event */ - aml_named_field(MEMORY_SLOT_REMOVE_EVENT, 1)); - aml_append(field, - /* initiates device eject, write only */ - aml_named_field(MEMORY_SLOT_EJECT, 1)); - aml_append(scope, field); - - field = aml_field(MEMORY_HOTPLUG_IO_REGION, AML_DWORD_ACC, - AML_NOLOCK, AML_PRESERVE); - aml_append(field, /* DIMM selector, write only */ - aml_named_field(MEMORY_SLOT_SLECTOR, 32)); - aml_append(field, /* _OST event code, write only */ - aml_named_field(MEMORY_SLOT_OST_EVENT, 32)); - aml_append(field, /* _OST status code, write only */ - aml_named_field(MEMORY_SLOT_OST_STATUS, 32)); - aml_append(scope, field); - aml_append(sb_scope, scope); - for (i = 0; i < nr_mem; i++) { #define BASEPATH "\\_SB.PCI0." MEMORY_HOTPLUG_DEVICE "." const char *s; diff --git a/include/hw/acpi/memory_hotplug.h b/include/hw/acpi/memory_hotplug.h index 964c2442a6..c70481ece5 100644 --- a/include/hw/acpi/memory_hotplug.h +++ b/include/hw/acpi/memory_hotplug.h @@ -52,7 +52,7 @@ void acpi_memory_ospm_status(MemHotplugState *mem_st, ACPIOSTInfoList ***list); #define MEMORY_HOTPLUG_HANDLER_PATH "\\_SB.PCI0." \ MEMORY_HOTPLUG_DEVICE "." MEMORY_SLOT_SCAN_METHOD -void build_memory_hotplug_aml(Aml *ctx, uint32_t nr_mem, +void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem, uint16_t io_base, uint16_t io_len); void build_memory_devices(Aml *sb_scope, int nr_mem, uint16_t io_base, uint16_t io_len); From 8b35ab271c069c212ff2a107a6bc5478eba097f1 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Tue, 6 Dec 2016 00:32:25 +0100 Subject: [PATCH 36/41] memhp: merge build_memory_devices() into build_memory_hotplug_aml() It consolidates memory hotplug AML in one place within DSDT Signed-off-by: Igor Mammedov Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/memory_hotplug.c | 14 +++---- hw/i386/acpi-build.c | 67 +++++++++++++++----------------- include/hw/acpi/memory_hotplug.h | 2 - 3 files changed, 36 insertions(+), 47 deletions(-) diff --git a/hw/acpi/memory_hotplug.c b/hw/acpi/memory_hotplug.c index fb40a5ea81..18b95f2cf2 100644 --- a/hw/acpi/memory_hotplug.c +++ b/hw/acpi/memory_hotplug.c @@ -310,9 +310,11 @@ const VMStateDescription vmstate_memory_hotplug = { void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem, uint16_t io_base, uint16_t io_len) { + int i; Aml *ifctx; Aml *method; Aml *pci_scope; + Aml *sb_scope; Aml *mem_ctrl_dev; /* scope for memory hotplug controller device node */ @@ -610,19 +612,12 @@ void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem, } aml_append(pci_scope, mem_ctrl_dev); aml_append(table, pci_scope); -} - -void build_memory_devices(Aml *sb_scope, int nr_mem, - uint16_t io_base, uint16_t io_len) -{ - int i; - Aml *dev; - Aml *method; - Aml *ifctx; + sb_scope = aml_scope("_SB"); /* build memory devices */ for (i = 0; i < nr_mem; i++) { #define BASEPATH "\\_SB.PCI0." MEMORY_HOTPLUG_DEVICE "." + Aml *dev; const char *s; dev = aml_device("MP%02X", i); @@ -673,4 +668,5 @@ void build_memory_devices(Aml *sb_scope, int nr_mem, aml_append(method, ifctx); } aml_append(sb_scope, method); + aml_append(table, sb_scope); } diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index a3f9caa712..ca4165eeb8 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -2197,45 +2197,40 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, sb_scope = aml_scope("\\_SB"); { - build_memory_devices(sb_scope, nr_mem, pm->mem_hp_io_base, - pm->mem_hp_io_len); + Object *pci_host; + PCIBus *bus = NULL; - { - Object *pci_host; - PCIBus *bus = NULL; - - pci_host = acpi_get_i386_pci_host(); - if (pci_host) { - bus = PCI_HOST_BRIDGE(pci_host)->bus; - } - - if (bus) { - Aml *scope = aml_scope("PCI0"); - /* Scan all PCI buses. Generate tables to support hotplug. */ - build_append_pci_bus_devices(scope, bus, pm->pcihp_bridge_en); - - if (misc->tpm_version != TPM_VERSION_UNSPEC) { - dev = aml_device("ISA.TPM"); - aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C31"))); - aml_append(dev, aml_name_decl("_STA", aml_int(0xF))); - crs = aml_resource_template(); - aml_append(crs, aml_memory32_fixed(TPM_TIS_ADDR_BASE, - TPM_TIS_ADDR_SIZE, AML_READ_WRITE)); - /* - FIXME: TPM_TIS_IRQ=5 conflicts with PNP0C0F irqs, - Rewrite to take IRQ from TPM device model and - fix default IRQ value there to use some unused IRQ - */ - /* aml_append(crs, aml_irq_no_flags(TPM_TIS_IRQ)); */ - aml_append(dev, aml_name_decl("_CRS", crs)); - aml_append(scope, dev); - } - - aml_append(sb_scope, scope); - } + pci_host = acpi_get_i386_pci_host(); + if (pci_host) { + bus = PCI_HOST_BRIDGE(pci_host)->bus; + } + + if (bus) { + Aml *scope = aml_scope("PCI0"); + /* Scan all PCI buses. Generate tables to support hotplug. */ + build_append_pci_bus_devices(scope, bus, pm->pcihp_bridge_en); + + if (misc->tpm_version != TPM_VERSION_UNSPEC) { + dev = aml_device("ISA.TPM"); + aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C31"))); + aml_append(dev, aml_name_decl("_STA", aml_int(0xF))); + crs = aml_resource_template(); + aml_append(crs, aml_memory32_fixed(TPM_TIS_ADDR_BASE, + TPM_TIS_ADDR_SIZE, AML_READ_WRITE)); + /* + FIXME: TPM_TIS_IRQ=5 conflicts with PNP0C0F irqs, + Rewrite to take IRQ from TPM device model and + fix default IRQ value there to use some unused IRQ + */ + /* aml_append(crs, aml_irq_no_flags(TPM_TIS_IRQ)); */ + aml_append(dev, aml_name_decl("_CRS", crs)); + aml_append(scope, dev); + } + + aml_append(sb_scope, scope); } - aml_append(dsdt, sb_scope); } + aml_append(dsdt, sb_scope); /* copy AML table into ACPI tables blob and patch header there */ g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len); diff --git a/include/hw/acpi/memory_hotplug.h b/include/hw/acpi/memory_hotplug.h index c70481ece5..6dc48d2345 100644 --- a/include/hw/acpi/memory_hotplug.h +++ b/include/hw/acpi/memory_hotplug.h @@ -54,6 +54,4 @@ void acpi_memory_ospm_status(MemHotplugState *mem_st, ACPIOSTInfoList ***list); void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem, uint16_t io_base, uint16_t io_len); -void build_memory_devices(Aml *sb_scope, int nr_mem, - uint16_t io_base, uint16_t io_len); #endif From d1957dac344f08f79a64b90ed2cb4406581362fb Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Tue, 6 Dec 2016 00:32:26 +0100 Subject: [PATCH 37/41] memhp: move GPE handler_E03 into build_memory_hotplug_aml() >From this patch all the memory hotplug related AML bits are consolidated in one place within DSTD. Follow up patches will utilize that to simplify memory hotplug related C/AML code. Signed-off-by: Igor Mammedov Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Marcel Apfelbaum --- hw/acpi/memory_hotplug.c | 42 ++++++++++++++++++++------------ hw/i386/acpi-build.c | 7 ++---- include/hw/acpi/memory_hotplug.h | 6 ++--- 3 files changed, 32 insertions(+), 23 deletions(-) diff --git a/hw/acpi/memory_hotplug.c b/hw/acpi/memory_hotplug.c index 18b95f2cf2..49e856f415 100644 --- a/hw/acpi/memory_hotplug.c +++ b/hw/acpi/memory_hotplug.c @@ -308,18 +308,19 @@ const VMStateDescription vmstate_memory_hotplug = { }; void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem, - uint16_t io_base, uint16_t io_len) + uint16_t io_base, uint16_t io_len, + const char *res_root, + const char *event_handler_method) { int i; Aml *ifctx; Aml *method; - Aml *pci_scope; Aml *sb_scope; Aml *mem_ctrl_dev; + char *scan_path; + char *mhp_res_path = g_strdup_printf("%s." MEMORY_HOTPLUG_DEVICE, res_root); - /* scope for memory hotplug controller device node */ - pci_scope = aml_scope("_SB.PCI0"); - mem_ctrl_dev = aml_device(MEMORY_HOTPLUG_DEVICE); + mem_ctrl_dev = aml_device("%s", mhp_res_path); { Aml *crs; Aml *field; @@ -610,47 +611,50 @@ void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem, } aml_append(mem_ctrl_dev, method); } - aml_append(pci_scope, mem_ctrl_dev); - aml_append(table, pci_scope); + aml_append(table, mem_ctrl_dev); sb_scope = aml_scope("_SB"); /* build memory devices */ for (i = 0; i < nr_mem; i++) { - #define BASEPATH "\\_SB.PCI0." MEMORY_HOTPLUG_DEVICE "." Aml *dev; - const char *s; + char *s; dev = aml_device("MP%02X", i); aml_append(dev, aml_name_decl("_UID", aml_string("0x%02X", i))); aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C80"))); method = aml_method("_CRS", 0, AML_NOTSERIALIZED); - s = BASEPATH MEMORY_SLOT_CRS_METHOD; + s = g_strdup_printf("%s.%s", mhp_res_path, MEMORY_SLOT_CRS_METHOD); aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); + g_free(s); aml_append(dev, method); method = aml_method("_STA", 0, AML_NOTSERIALIZED); - s = BASEPATH MEMORY_SLOT_STATUS_METHOD; + s = g_strdup_printf("%s.%s", mhp_res_path, MEMORY_SLOT_STATUS_METHOD); aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); + g_free(s); aml_append(dev, method); method = aml_method("_PXM", 0, AML_NOTSERIALIZED); - s = BASEPATH MEMORY_SLOT_PROXIMITY_METHOD; + s = g_strdup_printf("%s.%s", mhp_res_path, + MEMORY_SLOT_PROXIMITY_METHOD); aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); + g_free(s); aml_append(dev, method); method = aml_method("_OST", 3, AML_NOTSERIALIZED); - s = BASEPATH MEMORY_SLOT_OST_METHOD; - + s = g_strdup_printf("%s.%s", mhp_res_path, MEMORY_SLOT_OST_METHOD); aml_append(method, aml_return(aml_call4( s, aml_name("_UID"), aml_arg(0), aml_arg(1), aml_arg(2) ))); + g_free(s); aml_append(dev, method); method = aml_method("_EJ0", 1, AML_NOTSERIALIZED); - s = BASEPATH MEMORY_SLOT_EJECT_METHOD; + s = g_strdup_printf("%s.%s", mhp_res_path, MEMORY_SLOT_EJECT_METHOD); aml_append(method, aml_return(aml_call2( s, aml_name("_UID"), aml_arg(0)))); + g_free(s); aml_append(dev, method); aml_append(sb_scope, dev); @@ -669,4 +673,12 @@ void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem, } aml_append(sb_scope, method); aml_append(table, sb_scope); + + method = aml_method(event_handler_method, 0, AML_NOTSERIALIZED); + scan_path = g_strdup_printf("%s.%s", mhp_res_path, MEMORY_SLOT_SCAN_METHOD); + aml_append(method, aml_call0(scan_path)); + g_free(scan_path); + aml_append(table, method); + + g_free(mhp_res_path); } diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index ca4165eeb8..9f3cfbaee1 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -1926,7 +1926,8 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, "\\_SB.PCI0", "\\_GPE._E02"); } build_memory_hotplug_aml(dsdt, nr_mem, pm->mem_hp_io_base, - pm->mem_hp_io_len); + pm->mem_hp_io_len, + "\\_SB.PCI0", "\\_GPE._E03"); scope = aml_scope("_GPE"); { @@ -1941,10 +1942,6 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, aml_append(scope, method); } - method = aml_method("_E03", 0, AML_NOTSERIALIZED); - aml_append(method, aml_call0(MEMORY_HOTPLUG_HANDLER_PATH)); - aml_append(scope, method); - if (pcms->acpi_nvdimm_state.is_enabled) { method = aml_method("_E04", 0, AML_NOTSERIALIZED); aml_append(method, aml_notify(aml_name("\\_SB.NVDR"), diff --git a/include/hw/acpi/memory_hotplug.h b/include/hw/acpi/memory_hotplug.h index 6dc48d2345..37e2706249 100644 --- a/include/hw/acpi/memory_hotplug.h +++ b/include/hw/acpi/memory_hotplug.h @@ -49,9 +49,9 @@ void acpi_memory_ospm_status(MemHotplugState *mem_st, ACPIOSTInfoList ***list); #define MEMORY_HOTPLUG_DEVICE "MHPD" #define MEMORY_SLOT_SCAN_METHOD "MSCN" -#define MEMORY_HOTPLUG_HANDLER_PATH "\\_SB.PCI0." \ - MEMORY_HOTPLUG_DEVICE "." MEMORY_SLOT_SCAN_METHOD void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem, - uint16_t io_base, uint16_t io_len); + uint16_t io_base, uint16_t io_len, + const char *res_root, + const char *event_handler_method); #endif From c9c085458060db9a63fa05c51e33c75e8390b2dc Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Tue, 6 Dec 2016 00:32:27 +0100 Subject: [PATCH 38/41] memhp: move memory hotplug only defines to memory_hotplug.c Move defines used locally only by memory_hotplug.c into it from header files. Signed-off-by: Igor Mammedov Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Marcel Apfelbaum --- hw/acpi/memory_hotplug.c | 24 ++++++++++++++++++++++++ include/hw/acpi/memory_hotplug.h | 3 --- include/hw/acpi/pc-hotplug.h | 22 ---------------------- 3 files changed, 24 insertions(+), 25 deletions(-) diff --git a/hw/acpi/memory_hotplug.c b/hw/acpi/memory_hotplug.c index 49e856f415..da293329d0 100644 --- a/hw/acpi/memory_hotplug.c +++ b/hw/acpi/memory_hotplug.c @@ -7,6 +7,30 @@ #include "trace.h" #include "qapi-event.h" +#define MEMORY_SLOTS_NUMBER "MDNR" +#define MEMORY_HOTPLUG_IO_REGION "HPMR" +#define MEMORY_SLOT_ADDR_LOW "MRBL" +#define MEMORY_SLOT_ADDR_HIGH "MRBH" +#define MEMORY_SLOT_SIZE_LOW "MRLL" +#define MEMORY_SLOT_SIZE_HIGH "MRLH" +#define MEMORY_SLOT_PROXIMITY "MPX" +#define MEMORY_SLOT_ENABLED "MES" +#define MEMORY_SLOT_INSERT_EVENT "MINS" +#define MEMORY_SLOT_REMOVE_EVENT "MRMV" +#define MEMORY_SLOT_EJECT "MEJ" +#define MEMORY_SLOT_SLECTOR "MSEL" +#define MEMORY_SLOT_OST_EVENT "MOEV" +#define MEMORY_SLOT_OST_STATUS "MOSC" +#define MEMORY_SLOT_LOCK "MLCK" +#define MEMORY_SLOT_STATUS_METHOD "MRST" +#define MEMORY_SLOT_CRS_METHOD "MCRS" +#define MEMORY_SLOT_OST_METHOD "MOST" +#define MEMORY_SLOT_PROXIMITY_METHOD "MPXM" +#define MEMORY_SLOT_EJECT_METHOD "MEJ0" +#define MEMORY_SLOT_NOTIFY_METHOD "MTFY" +#define MEMORY_SLOT_SCAN_METHOD "MSCN" +#define MEMORY_HOTPLUG_DEVICE "MHPD" + static ACPIOSTInfo *acpi_memory_device_status(int slot, MemStatus *mdev) { ACPIOSTInfo *info = g_new0(ACPIOSTInfo, 1); diff --git a/include/hw/acpi/memory_hotplug.h b/include/hw/acpi/memory_hotplug.h index 37e2706249..91d40459b3 100644 --- a/include/hw/acpi/memory_hotplug.h +++ b/include/hw/acpi/memory_hotplug.h @@ -47,9 +47,6 @@ extern const VMStateDescription vmstate_memory_hotplug; void acpi_memory_ospm_status(MemHotplugState *mem_st, ACPIOSTInfoList ***list); -#define MEMORY_HOTPLUG_DEVICE "MHPD" -#define MEMORY_SLOT_SCAN_METHOD "MSCN" - void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem, uint16_t io_base, uint16_t io_len, const char *res_root, diff --git a/include/hw/acpi/pc-hotplug.h b/include/hw/acpi/pc-hotplug.h index 6a8d268f84..a4f513d710 100644 --- a/include/hw/acpi/pc-hotplug.h +++ b/include/hw/acpi/pc-hotplug.h @@ -32,26 +32,4 @@ #define ACPI_MEMORY_HOTPLUG_IO_LEN 24 #define ACPI_MEMORY_HOTPLUG_BASE 0x0a00 -#define MEMORY_SLOTS_NUMBER "MDNR" -#define MEMORY_HOTPLUG_IO_REGION "HPMR" -#define MEMORY_SLOT_ADDR_LOW "MRBL" -#define MEMORY_SLOT_ADDR_HIGH "MRBH" -#define MEMORY_SLOT_SIZE_LOW "MRLL" -#define MEMORY_SLOT_SIZE_HIGH "MRLH" -#define MEMORY_SLOT_PROXIMITY "MPX" -#define MEMORY_SLOT_ENABLED "MES" -#define MEMORY_SLOT_INSERT_EVENT "MINS" -#define MEMORY_SLOT_REMOVE_EVENT "MRMV" -#define MEMORY_SLOT_EJECT "MEJ" -#define MEMORY_SLOT_SLECTOR "MSEL" -#define MEMORY_SLOT_OST_EVENT "MOEV" -#define MEMORY_SLOT_OST_STATUS "MOSC" -#define MEMORY_SLOT_LOCK "MLCK" -#define MEMORY_SLOT_STATUS_METHOD "MRST" -#define MEMORY_SLOT_CRS_METHOD "MCRS" -#define MEMORY_SLOT_OST_METHOD "MOST" -#define MEMORY_SLOT_PROXIMITY_METHOD "MPXM" -#define MEMORY_SLOT_EJECT_METHOD "MEJ0" -#define MEMORY_SLOT_NOTIFY_METHOD "MTFY" - #endif From 80db0e7822962554c91bef05d784c898e8ab1c3c Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Tue, 6 Dec 2016 00:32:28 +0100 Subject: [PATCH 39/41] memhp: don't generate memory hotplug AML if it's not enabled/supported That reduces DSDT by 910 bytes when memory hotplug isn't enabled. While doing so drop intermediate variables/arguments passing around ACPI_MEMORY_HOTPLUG_IO_LEN and making it local to memory_hotplug.c, hardcoding it there as it can't change. Also don't pass around ACPI_MEMORY_HOTPLUG_BASE through intermediate variables/arguments where it's not needed. Instead initialize in module static variable when MMIO region is mapped and use that within memory_hotplug.c whenever it's required. That way MMIO base specified only at one place and AML with MMIO would always use the same value. Signed-off-by: Igor Mammedov Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Marcel Apfelbaum --- hw/acpi/ich9.c | 3 ++- hw/acpi/memory_hotplug.c | 24 +++++++++++++++++------- hw/acpi/piix4.c | 3 ++- hw/i386/acpi-build.c | 9 +-------- include/hw/acpi/memory_hotplug.h | 3 +-- include/hw/acpi/pc-hotplug.h | 1 - 6 files changed, 23 insertions(+), 20 deletions(-) diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c index 830c475127..5c279bbaca 100644 --- a/hw/acpi/ich9.c +++ b/hw/acpi/ich9.c @@ -306,7 +306,8 @@ void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm, if (pm->acpi_memory_hotplug.is_enabled) { acpi_memory_hotplug_init(pci_address_space_io(lpc_pci), OBJECT(lpc_pci), - &pm->acpi_memory_hotplug); + &pm->acpi_memory_hotplug, + ACPI_MEMORY_HOTPLUG_BASE); } } diff --git a/hw/acpi/memory_hotplug.c b/hw/acpi/memory_hotplug.c index da293329d0..fb04d246a1 100644 --- a/hw/acpi/memory_hotplug.c +++ b/hw/acpi/memory_hotplug.c @@ -30,6 +30,9 @@ #define MEMORY_SLOT_NOTIFY_METHOD "MTFY" #define MEMORY_SLOT_SCAN_METHOD "MSCN" #define MEMORY_HOTPLUG_DEVICE "MHPD" +#define MEMORY_HOTPLUG_IO_LEN 24 + +static uint16_t memhp_io_base; static ACPIOSTInfo *acpi_memory_device_status(int slot, MemStatus *mdev) { @@ -202,7 +205,7 @@ static const MemoryRegionOps acpi_memory_hotplug_ops = { }; void acpi_memory_hotplug_init(MemoryRegion *as, Object *owner, - MemHotplugState *state) + MemHotplugState *state, uint16_t io_base) { MachineState *machine = MACHINE(qdev_get_machine()); @@ -211,10 +214,12 @@ void acpi_memory_hotplug_init(MemoryRegion *as, Object *owner, return; } + assert(!memhp_io_base); + memhp_io_base = io_base; state->devs = g_malloc0(sizeof(*state->devs) * state->dev_count); memory_region_init_io(&state->io, owner, &acpi_memory_hotplug_ops, state, - "acpi-mem-hotplug", ACPI_MEMORY_HOTPLUG_IO_LEN); - memory_region_add_subregion(as, ACPI_MEMORY_HOTPLUG_BASE, &state->io); + "acpi-mem-hotplug", MEMORY_HOTPLUG_IO_LEN); + memory_region_add_subregion(as, memhp_io_base, &state->io); } /** @@ -332,7 +337,6 @@ const VMStateDescription vmstate_memory_hotplug = { }; void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem, - uint16_t io_base, uint16_t io_len, const char *res_root, const char *event_handler_method) { @@ -342,8 +346,13 @@ void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem, Aml *sb_scope; Aml *mem_ctrl_dev; char *scan_path; - char *mhp_res_path = g_strdup_printf("%s." MEMORY_HOTPLUG_DEVICE, res_root); + char *mhp_res_path; + if (!memhp_io_base) { + return; + } + + mhp_res_path = g_strdup_printf("%s." MEMORY_HOTPLUG_DEVICE, res_root); mem_ctrl_dev = aml_device("%s", mhp_res_path); { Aml *crs; @@ -367,13 +376,14 @@ void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem, crs = aml_resource_template(); aml_append(crs, - aml_io(AML_DECODE16, io_base, io_base, 0, io_len) + aml_io(AML_DECODE16, memhp_io_base, memhp_io_base, 0, + MEMORY_HOTPLUG_IO_LEN) ); aml_append(mem_ctrl_dev, aml_name_decl("_CRS", crs)); aml_append(mem_ctrl_dev, aml_operation_region( MEMORY_HOTPLUG_IO_REGION, AML_SYSTEM_IO, - aml_int(io_base), io_len) + aml_int(memhp_io_base), MEMORY_HOTPLUG_IO_LEN) ); field = aml_field(MEMORY_HOTPLUG_IO_REGION, AML_DWORD_ACC, diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c index 17d36bd595..6d99fe407c 100644 --- a/hw/acpi/piix4.c +++ b/hw/acpi/piix4.c @@ -644,7 +644,8 @@ static void piix4_acpi_system_hot_add_init(MemoryRegion *parent, PIIX4_CPU_HOTPLUG_IO_BASE); if (s->acpi_memory_hotplug.is_enabled) { - acpi_memory_hotplug_init(parent, OBJECT(s), &s->acpi_memory_hotplug); + acpi_memory_hotplug_init(parent, OBJECT(s), &s->acpi_memory_hotplug, + ACPI_MEMORY_HOTPLUG_BASE); } } diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 9f3cfbaee1..0c8912fd86 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -101,8 +101,6 @@ typedef struct AcpiPmInfo { uint32_t gpe0_blk_len; uint32_t io_base; uint16_t cpu_hp_io_base; - uint16_t mem_hp_io_base; - uint16_t mem_hp_io_len; uint16_t pcihp_io_base; uint16_t pcihp_io_len; } AcpiPmInfo; @@ -148,9 +146,6 @@ static void acpi_get_pm_info(AcpiPmInfo *pm) } assert(obj); - pm->mem_hp_io_base = ACPI_MEMORY_HOTPLUG_BASE; - pm->mem_hp_io_len = ACPI_MEMORY_HOTPLUG_IO_LEN; - /* Fill in optional s3/s4 related properties */ o = object_property_get_qobject(obj, ACPI_PM_PROP_S3_DISABLED, NULL); if (o) { @@ -1925,9 +1920,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, build_cpus_aml(dsdt, machine, opts, pm->cpu_hp_io_base, "\\_SB.PCI0", "\\_GPE._E02"); } - build_memory_hotplug_aml(dsdt, nr_mem, pm->mem_hp_io_base, - pm->mem_hp_io_len, - "\\_SB.PCI0", "\\_GPE._E03"); + build_memory_hotplug_aml(dsdt, nr_mem, "\\_SB.PCI0", "\\_GPE._E03"); scope = aml_scope("_GPE"); { diff --git a/include/hw/acpi/memory_hotplug.h b/include/hw/acpi/memory_hotplug.h index 91d40459b3..db8ebc9cea 100644 --- a/include/hw/acpi/memory_hotplug.h +++ b/include/hw/acpi/memory_hotplug.h @@ -30,7 +30,7 @@ typedef struct MemHotplugState { } MemHotplugState; void acpi_memory_hotplug_init(MemoryRegion *as, Object *owner, - MemHotplugState *state); + MemHotplugState *state, uint16_t io_base); void acpi_memory_plug_cb(HotplugHandler *hotplug_dev, MemHotplugState *mem_st, DeviceState *dev, Error **errp); @@ -48,7 +48,6 @@ extern const VMStateDescription vmstate_memory_hotplug; void acpi_memory_ospm_status(MemHotplugState *mem_st, ACPIOSTInfoList ***list); void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem, - uint16_t io_base, uint16_t io_len, const char *res_root, const char *event_handler_method); #endif diff --git a/include/hw/acpi/pc-hotplug.h b/include/hw/acpi/pc-hotplug.h index a4f513d710..31bc9191c3 100644 --- a/include/hw/acpi/pc-hotplug.h +++ b/include/hw/acpi/pc-hotplug.h @@ -29,7 +29,6 @@ #define PIIX4_CPU_HOTPLUG_IO_BASE 0xaf00 #define CPU_HOTPLUG_RESOURCE_DEVICE PRES -#define ACPI_MEMORY_HOTPLUG_IO_LEN 24 #define ACPI_MEMORY_HOTPLUG_BASE 0x0a00 #endif From e1a58fc05aba0ffe014a8dc0bddc0c9dc5a0631a Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Tue, 6 Dec 2016 00:32:29 +0100 Subject: [PATCH 40/41] memhp: move DIMM devices into dedicated scope with related common methods Move DIMM devices from global _SB scope to a new \_SB.MHPC container along with common methods used by DIMMs: MCRS, MRST, MPXM, MOST, MEJ00, MSCN, MTFY this reduces AML size on 12 * #slots bytes, i.e. up to 3072 bytes for 265 slots. Signed-off-by: Igor Mammedov Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Marcel Apfelbaum --- hw/acpi/memory_hotplug.c | 192 ++++++++++++++++++++------------------- 1 file changed, 98 insertions(+), 94 deletions(-) diff --git a/hw/acpi/memory_hotplug.c b/hw/acpi/memory_hotplug.c index fb04d246a1..210073d283 100644 --- a/hw/acpi/memory_hotplug.c +++ b/hw/acpi/memory_hotplug.c @@ -31,6 +31,7 @@ #define MEMORY_SLOT_SCAN_METHOD "MSCN" #define MEMORY_HOTPLUG_DEVICE "MHPD" #define MEMORY_HOTPLUG_IO_LEN 24 +#define MEMORY_DEVICES_CONTAINER "\\_SB.MHPC" static uint16_t memhp_io_base; @@ -343,9 +344,8 @@ void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem, int i; Aml *ifctx; Aml *method; - Aml *sb_scope; + Aml *dev_container; Aml *mem_ctrl_dev; - char *scan_path; char *mhp_res_path; if (!memhp_io_base) { @@ -356,24 +356,11 @@ void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem, mem_ctrl_dev = aml_device("%s", mhp_res_path); { Aml *crs; - Aml *field; - Aml *one = aml_int(1); - Aml *zero = aml_int(0); - Aml *ret_val = aml_local(0); - Aml *slot_arg0 = aml_arg(0); - Aml *slots_nr = aml_name(MEMORY_SLOTS_NUMBER); - Aml *ctrl_lock = aml_name(MEMORY_SLOT_LOCK); - Aml *slot_selector = aml_name(MEMORY_SLOT_SLECTOR); aml_append(mem_ctrl_dev, aml_name_decl("_HID", aml_string("PNP0A06"))); aml_append(mem_ctrl_dev, aml_name_decl("_UID", aml_string("Memory hotplug resources"))); - assert(nr_mem <= ACPI_MAX_RAM_SLOTS); - aml_append(mem_ctrl_dev, - aml_name_decl(MEMORY_SLOTS_NUMBER, aml_int(nr_mem)) - ); - crs = aml_resource_template(); aml_append(crs, aml_io(AML_DECODE16, memhp_io_base, memhp_io_base, 0, @@ -386,7 +373,32 @@ void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem, aml_int(memhp_io_base), MEMORY_HOTPLUG_IO_LEN) ); - field = aml_field(MEMORY_HOTPLUG_IO_REGION, AML_DWORD_ACC, + } + aml_append(table, mem_ctrl_dev); + + dev_container = aml_device(MEMORY_DEVICES_CONTAINER); + { + Aml *field; + Aml *one = aml_int(1); + Aml *zero = aml_int(0); + Aml *ret_val = aml_local(0); + Aml *slot_arg0 = aml_arg(0); + Aml *slots_nr = aml_name(MEMORY_SLOTS_NUMBER); + Aml *ctrl_lock = aml_name(MEMORY_SLOT_LOCK); + Aml *slot_selector = aml_name(MEMORY_SLOT_SLECTOR); + char *mmio_path = g_strdup_printf("%s." MEMORY_HOTPLUG_IO_REGION, + mhp_res_path); + + aml_append(dev_container, aml_name_decl("_HID", aml_string("PNP0A06"))); + aml_append(dev_container, + aml_name_decl("_UID", aml_string("DIMM devices"))); + + assert(nr_mem <= ACPI_MAX_RAM_SLOTS); + aml_append(dev_container, + aml_name_decl(MEMORY_SLOTS_NUMBER, aml_int(nr_mem)) + ); + + field = aml_field(mmio_path, AML_DWORD_ACC, AML_NOLOCK, AML_PRESERVE); aml_append(field, /* read only */ aml_named_field(MEMORY_SLOT_ADDR_LOW, 32)); @@ -398,9 +410,9 @@ void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem, aml_named_field(MEMORY_SLOT_SIZE_HIGH, 32)); aml_append(field, /* read only */ aml_named_field(MEMORY_SLOT_PROXIMITY, 32)); - aml_append(mem_ctrl_dev, field); + aml_append(dev_container, field); - field = aml_field(MEMORY_HOTPLUG_IO_REGION, AML_BYTE_ACC, + field = aml_field(mmio_path, AML_BYTE_ACC, AML_NOLOCK, AML_WRITE_AS_ZEROS); aml_append(field, aml_reserved_field(160 /* bits, Offset(20) */)); aml_append(field, /* 1 if enabled, read only */ @@ -414,9 +426,9 @@ void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem, aml_append(field, /* initiates device eject, write only */ aml_named_field(MEMORY_SLOT_EJECT, 1)); - aml_append(mem_ctrl_dev, field); + aml_append(dev_container, field); - field = aml_field(MEMORY_HOTPLUG_IO_REGION, AML_DWORD_ACC, + field = aml_field(mmio_path, AML_DWORD_ACC, AML_NOLOCK, AML_PRESERVE); aml_append(field, /* DIMM selector, write only */ aml_named_field(MEMORY_SLOT_SLECTOR, 32)); @@ -424,7 +436,8 @@ void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem, aml_named_field(MEMORY_SLOT_OST_EVENT, 32)); aml_append(field, /* _OST status code, write only */ aml_named_field(MEMORY_SLOT_OST_STATUS, 32)); - aml_append(mem_ctrl_dev, field); + aml_append(dev_container, field); + g_free(mmio_path); method = aml_method("_STA", 0, AML_NOTSERIALIZED); ifctx = aml_if(aml_equal(slots_nr, zero)); @@ -434,9 +447,9 @@ void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem, aml_append(method, ifctx); /* present, functioning, decoding, not shown in UI */ aml_append(method, aml_return(aml_int(0xB))); - aml_append(mem_ctrl_dev, method); + aml_append(dev_container, method); - aml_append(mem_ctrl_dev, aml_mutex(MEMORY_SLOT_LOCK, 0)); + aml_append(dev_container, aml_mutex(MEMORY_SLOT_LOCK, 0)); method = aml_method(MEMORY_SLOT_SCAN_METHOD, 0, AML_NOTSERIALIZED); { @@ -492,7 +505,7 @@ void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem, aml_append(method, aml_release(ctrl_lock)); aml_append(method, aml_return(one)); } - aml_append(mem_ctrl_dev, method); + aml_append(dev_container, method); method = aml_method(MEMORY_SLOT_STATUS_METHOD, 1, AML_NOTSERIALIZED); { @@ -512,7 +525,7 @@ void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem, aml_append(method, aml_release(ctrl_lock)); aml_append(method, aml_return(ret_val)); } - aml_append(mem_ctrl_dev, method); + aml_append(dev_container, method); method = aml_method(MEMORY_SLOT_CRS_METHOD, 1, AML_SERIALIZED); { @@ -603,7 +616,7 @@ void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem, aml_append(method, aml_release(ctrl_lock)); aml_append(method, aml_return(mr64)); } - aml_append(mem_ctrl_dev, method); + aml_append(dev_container, method); method = aml_method(MEMORY_SLOT_PROXIMITY_METHOD, 1, AML_NOTSERIALIZED); @@ -617,7 +630,7 @@ void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem, aml_append(method, aml_release(ctrl_lock)); aml_append(method, aml_return(ret_val)); } - aml_append(mem_ctrl_dev, method); + aml_append(dev_container, method); method = aml_method(MEMORY_SLOT_OST_METHOD, 4, AML_NOTSERIALIZED); { @@ -631,7 +644,7 @@ void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem, aml_append(method, aml_store(aml_arg(2), ost_status)); aml_append(method, aml_release(ctrl_lock)); } - aml_append(mem_ctrl_dev, method); + aml_append(dev_container, method); method = aml_method(MEMORY_SLOT_EJECT_METHOD, 2, AML_NOTSERIALIZED); { @@ -643,75 +656,66 @@ void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem, aml_append(method, aml_store(one, eject)); aml_append(method, aml_release(ctrl_lock)); } - aml_append(mem_ctrl_dev, method); + aml_append(dev_container, method); + + /* build memory devices */ + for (i = 0; i < nr_mem; i++) { + Aml *dev; + const char *s; + + dev = aml_device("MP%02X", i); + aml_append(dev, aml_name_decl("_UID", aml_string("0x%02X", i))); + aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C80"))); + + method = aml_method("_CRS", 0, AML_NOTSERIALIZED); + s = MEMORY_SLOT_CRS_METHOD; + aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); + aml_append(dev, method); + + method = aml_method("_STA", 0, AML_NOTSERIALIZED); + s = MEMORY_SLOT_STATUS_METHOD; + aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); + aml_append(dev, method); + + method = aml_method("_PXM", 0, AML_NOTSERIALIZED); + s = MEMORY_SLOT_PROXIMITY_METHOD; + aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); + aml_append(dev, method); + + method = aml_method("_OST", 3, AML_NOTSERIALIZED); + s = MEMORY_SLOT_OST_METHOD; + aml_append(method, aml_return(aml_call4( + s, aml_name("_UID"), aml_arg(0), aml_arg(1), aml_arg(2) + ))); + aml_append(dev, method); + + method = aml_method("_EJ0", 1, AML_NOTSERIALIZED); + s = MEMORY_SLOT_EJECT_METHOD; + aml_append(method, aml_return(aml_call2( + s, aml_name("_UID"), aml_arg(0)))); + aml_append(dev, method); + + aml_append(dev_container, dev); + } + + /* build Method(MEMORY_SLOT_NOTIFY_METHOD, 2) { + * If (LEqual(Arg0, 0x00)) {Notify(MP00, Arg1)} ... } + */ + method = aml_method(MEMORY_SLOT_NOTIFY_METHOD, 2, AML_NOTSERIALIZED); + for (i = 0; i < nr_mem; i++) { + ifctx = aml_if(aml_equal(aml_arg(0), aml_int(i))); + aml_append(ifctx, + aml_notify(aml_name("MP%.02X", i), aml_arg(1)) + ); + aml_append(method, ifctx); + } + aml_append(dev_container, method); } - aml_append(table, mem_ctrl_dev); - - sb_scope = aml_scope("_SB"); - /* build memory devices */ - for (i = 0; i < nr_mem; i++) { - Aml *dev; - char *s; - - dev = aml_device("MP%02X", i); - aml_append(dev, aml_name_decl("_UID", aml_string("0x%02X", i))); - aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C80"))); - - method = aml_method("_CRS", 0, AML_NOTSERIALIZED); - s = g_strdup_printf("%s.%s", mhp_res_path, MEMORY_SLOT_CRS_METHOD); - aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); - g_free(s); - aml_append(dev, method); - - method = aml_method("_STA", 0, AML_NOTSERIALIZED); - s = g_strdup_printf("%s.%s", mhp_res_path, MEMORY_SLOT_STATUS_METHOD); - aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); - g_free(s); - aml_append(dev, method); - - method = aml_method("_PXM", 0, AML_NOTSERIALIZED); - s = g_strdup_printf("%s.%s", mhp_res_path, - MEMORY_SLOT_PROXIMITY_METHOD); - aml_append(method, aml_return(aml_call1(s, aml_name("_UID")))); - g_free(s); - aml_append(dev, method); - - method = aml_method("_OST", 3, AML_NOTSERIALIZED); - s = g_strdup_printf("%s.%s", mhp_res_path, MEMORY_SLOT_OST_METHOD); - aml_append(method, aml_return(aml_call4( - s, aml_name("_UID"), aml_arg(0), aml_arg(1), aml_arg(2) - ))); - g_free(s); - aml_append(dev, method); - - method = aml_method("_EJ0", 1, AML_NOTSERIALIZED); - s = g_strdup_printf("%s.%s", mhp_res_path, MEMORY_SLOT_EJECT_METHOD); - aml_append(method, aml_return(aml_call2( - s, aml_name("_UID"), aml_arg(0)))); - g_free(s); - aml_append(dev, method); - - aml_append(sb_scope, dev); - } - - /* build Method(MEMORY_SLOT_NOTIFY_METHOD, 2) { - * If (LEqual(Arg0, 0x00)) {Notify(MP00, Arg1)} ... } - */ - method = aml_method(MEMORY_SLOT_NOTIFY_METHOD, 2, AML_NOTSERIALIZED); - for (i = 0; i < nr_mem; i++) { - ifctx = aml_if(aml_equal(aml_arg(0), aml_int(i))); - aml_append(ifctx, - aml_notify(aml_name("MP%.02X", i), aml_arg(1)) - ); - aml_append(method, ifctx); - } - aml_append(sb_scope, method); - aml_append(table, sb_scope); + aml_append(table, dev_container); method = aml_method(event_handler_method, 0, AML_NOTSERIALIZED); - scan_path = g_strdup_printf("%s.%s", mhp_res_path, MEMORY_SLOT_SCAN_METHOD); - aml_append(method, aml_call0(scan_path)); - g_free(scan_path); + aml_append(method, + aml_call0(MEMORY_DEVICES_CONTAINER "." MEMORY_SLOT_SCAN_METHOD)); aml_append(table, method); g_free(mhp_res_path); From 987da7be996e63c294dc6485acb1c37af7696257 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 10 Jan 2017 07:06:42 +0200 Subject: [PATCH 41/41] acpi-test: update expected files clean up warnings after latest hotplug changes. Signed-off-by: Michael S. Tsirkin --- tests/acpi-test-data/pc/DSDT | Bin 6008 -> 5098 bytes tests/acpi-test-data/pc/DSDT.bridge | Bin 7867 -> 6957 bytes tests/acpi-test-data/pc/DSDT.cphp | Bin 6471 -> 5561 bytes tests/acpi-test-data/pc/DSDT.ipmikcs | Bin 6080 -> 5170 bytes tests/acpi-test-data/pc/DSDT.memhp | Bin 6613 -> 6463 bytes tests/acpi-test-data/q35/DSDT | Bin 8770 -> 7860 bytes tests/acpi-test-data/q35/DSDT.bridge | Bin 8787 -> 7877 bytes tests/acpi-test-data/q35/DSDT.cphp | Bin 9233 -> 8323 bytes tests/acpi-test-data/q35/DSDT.ipmibt | Bin 8845 -> 7935 bytes tests/acpi-test-data/q35/DSDT.memhp | Bin 9375 -> 9225 bytes 10 files changed, 0 insertions(+), 0 deletions(-) diff --git a/tests/acpi-test-data/pc/DSDT b/tests/acpi-test-data/pc/DSDT index 8053d711058c0f9541d6d97690819f9de697751c..15c3135d65f168a91edfdc3471ea1d3f012a824f 100644 GIT binary patch delta 44 zcmeyN_e!11CDCV68Ogk06tL; AL;wH) delta 961 zcmZWoO>fgc5Z!I6;I8`>YC`~wh}oY z6D~--T0L+JD1QL;U!nd0P7O2uXd|$t)tmQb#xtJT-|K%inC|M$Pd5pn=fBv395%`u zzPsbwwYutk)ymwob;&pD`kdXcRZXoD$$tqJZ-4Ce`lU|yNPIYcTk5qByT`rP?L(q0 z`EFAq!MFpX#f$SBLeOk)^I7}^@dA% z^VzF_3W~;$;!ugW!}k-G<$wmO7tp|4$1EeNl)2+J=|o=fy+h)Ja>NbSr-ChH-hrYm z^P1z%WHo?q7&}Ycscsi4Og(u_$ZU@M^IVLRC!VBkVb&PXv8uY=1@6B4)q?|G$so%NslfW zL>6k+P`?%-O`zw>Rv}ztcfP?kTs4i&Vx!n(++bykG05*jR{-ZBIE6*1$QSr&lm%u- zQDC7cr9;B7OIY1j?sNNq({u)J#@WCG(Ein^9`Zf6IXy9{cu?XU-!t~bdk||$PUS8) zcGao>94XLg1&j53bX(>t$}QheE2OnKoozgBJFe(iNB&I1-F^#&MJ}~AbCWJoyxNiv zyHl8B>^UV2-sL{=zL++5s7x4J_6BQc3K6{b>3uZ?dasU7T diff --git a/tests/acpi-test-data/pc/DSDT.bridge b/tests/acpi-test-data/pc/DSDT.bridge index 850e71a973e52cc5e546fdd2757f0e089fed7192..d38586c95bf31f0212279a2505efd8e2fd321ccc 100644 GIT binary patch delta 44 zcmdmOyVi`$CDfgc5Z!I6;I8`>YCaKMvBcBqOR$(B$cAW&9md&mKq za6#%d>VaE8xpF`~_AkL-Ak6rqL|{v+H}B1iXFRjt%cl>8;TX-+tBmpcKg5z6)C>1K zXWMI3YDM>xUI4RUD4tm}78>q_?qTm`d!K15 zp3~IXXl@8b-DYDp7OKm^syt(wo(88}}&wck6Wf^m=0JhWQQ+ef=4hs{iL#R3)mtraL_BA~R z72BChYCzv0bXLGFZ)HlNcyyPs`4s!-`8|oAgpSQgpB+)4Sj1|r2%bl1M)0OpP1rjK zV>S!=UhKPyFfb+9+a^U3uqYD(%cKYb7G>!XO@M;Q2xTS}NM=HkADl6S zEYhrzac)R7!=6iyW25@o*}6Elqb~=H%zRzW4{km>6pS diff --git a/tests/acpi-test-data/pc/DSDT.cphp b/tests/acpi-test-data/pc/DSDT.cphp index 9f405cfd83d39a8e06bc08428e160a0192fc9704..2dd70bf9520406c36c3684714bb714e536a28d20 100644 GIT binary patch delta 44 zcmX?Zv{ReQCD=eJ*Q|KQX07V@R AcK`qY delta 961 zcmZWo&2G~`5Z-O7;BJ0ss0nFB)rcZMRH0T0Gc+R%hsMIv~qh0{BQB^#%R!ueP4Ncd|O!1zf1?_j8ZZCh>IhJovUgf*(qs~e9 zMf-@UOPGV1)w<0_Y$Osc2dnawsd^loN_|F?%y-vG8;`#}I`c6iu%!=7WJcwCCB zQ*U3@b5OCJg=r1w8-&gZ*yXKENoc1Vj3s02pXXvcd8Tw^j(hBs0!13DwI=WyLURJ| zSjLpSk1%4hpdUoOD+mKqg1v206akAeA+St}AYf6JF3|)in2bC|rL&ze{8dk3ih-TPxshA1Y#LZ7PW}BvFsZnY&Y_L=m0`q&=6~Z(IM=*;Od6GU& zvZU-JN-C73Xh;-x3CmmRZDduvm)^ekWl?UG@yE#9Ev4(~YNXrxiVan0n8H-Cm1?MNnFsu~`=- zTy4d}-N~ec*x^jzo9i+6gV_L^Czud9x4%Y4jHZ~Unc`s)vJhcwdAGkx4mx`*!p+2= khWj3_HB4B=C<703gE+ A!~g&Q delta 986 zcmZWo-)qxQ6ux&IwYzb1b+OjrSW(fT)W)?G1RuWc4sBrYgL+;Dv=*p*3iAge{L zIquw~2Z#;h;2d}AwS1K+M-K?OoFV@_XXE6V(5X4@lOs%I3(&2Vz^eew1m3lb340%4 z$`-h~o5n5!3{AnE4HL5vSXc>wWnu;b3#;^yMu5p^#BMOmp?r)S`g>^8n9Ro{Jve6& zS?IHd`lSeI0-CGq`EZrp{07@_AsWS^P!t&ptgbT#^?gtUZ~>B2Sb&avfuBaV!0PA} z*eJTvAz|7%tk>i_+}`Chok2LB3`_v+UyN#vZ@aD8sY%6y5^wpou_NArQ%h>fx45yT z%={NfflfPEY-IgS+ep@0)$E3%z+TIbeM5N^eUfU+@(qAh(yq)-P65vVclYF%^qGcR z{Wdxld9Gc_Oo!y+ozMBORQY+vHYs87EB1-^#k9FYCBj(I8?2&{!SR-G*zmFtS%5%u v$s4R-fJ&aScxB<=ghPn;9yCyIWpFJi0C!SC{qS@BZo|ne0t)U;PQEdE zAW>hB0B4SP4^J1~0KWhOM*}kkj`&a@&&AW%S0N>}EHgQ^n1RFB#V?49Il56VMxO;{ z7Eq_lWHkW=0UdNfcL6yS6*NJQ0N)^H-(XiC1z&&HFdz}^tgtzrdma-@bdx{Z1QGuD;1EY3KPWf^$`6R}1@eI;m@gFX9~{EG1ZWgkJ|iGe$Rxf~1*!gI#?T zeEnU+fJCsfLUfZCw{L)f0Y`kOrwgw^g@FMBN4$rp3yzaPj2b{89t$PBHB6oGdS3wAoSU9~%JQMaRbg diff --git a/tests/acpi-test-data/q35/DSDT b/tests/acpi-test-data/q35/DSDT index 58fbb3d2e2dc8e8256984744bfb9411feb2e35fe..d11567c3dc220894911166681ee7303fadfe04e8 100644 GIT binary patch delta 42 ycmX@)vc;CmCDv6ux&Xv%5GPQW+X?WHV|sY;{bYTw-Y}MSEG(;xbc`HZjC$T)1J|15XuS zO!nIB!8bJg0i(abA10pDmPr(n<~!ea&fy%+*Pna8bf&v{r?Ei@-TThg%3-^@<+}~v z)>?}9Nv(3z)+OI;=__{IR#c@xpeym#Cm3@b7NbW^iGIe@ZF9| z#>)}c+YXtK3CntvTiQz^t4rL~+H;y9fwzg;bo%Y-MF16{BLeOk*0>PyR@!#G*uPJK6DW6Jp>Lat`WKcC;zyw1Ax&WC+D<-PXSYAE%`c71;-a`@ykKpIG3f8ZRseHQoWdeZ15BR>@S)996d?@jb?;8i=J&0P;Q{Ldl3uWQI zL<)2|!RnUZw2j2os%Ezo1#B(f^bMs(3f=9+ng7xIXxJZ5%8zNN<+>=Wa;dwWnNN{o zqf0(GDZj#4lM)8s(vWx`O`AJ3OBgG8qjd~2c+(1A7#yf|T6U;{9LbhYL_t)!O4~(N zCTx(pwYp#zP<{aM4SWG>euXgOM~NVjtTX4#OlC62Kc4*5neOUscY_f6>l<6Egss}9 z@9z4x)>OQYYK@z=F8O9tU$R@aqACp{`7a^jy`%nMSUv2Yi1(*&s)OEf|8(%WcTD7> z@3vJkUW~Zja>#^CSl*-D(q0f*UEr?Pn$ZLayj!SEr(YkR2T&0@BH*rJjf)X)wp_~F z&t3&oPz=75#&X0Revq&%2Q);3fCk=O>@uNpjXQ3e&h!qgkVb&T7{oFJ=2$*Q4)p=XG$so%Nlz{q zL>6k+Sick@OdC3+#@f zz(G+;kA!6xu(2cG=5~kE^akNHJD334|9h%?eBW))&s-`#lz7YcjRWxxL@ntlZ*b$e zGWTC11v;Hzb<^Lojl|WeW;YcDY%O2&4W&+s-L3h||LA=*?Dt2Nhcwhzx+tu2sk@b% zO_5@wOFlTMu*BFNB@DjhA@M$#Hg{;AFjn?P>lozlrd7N!JS;>OAXv2OjVhR+lBX>8 lDg1@t{@Cm=IQ1%{t4RZRIjXocJY20RFW?(87aiT~`~iJg8i4=+ diff --git a/tests/acpi-test-data/q35/DSDT.cphp b/tests/acpi-test-data/q35/DSDT.cphp index a0ce6b3264c69999c6e82a8ae7bab49338e4819b..79902d0d30f02d74594cb87b14460ea02764d460 100644 GIT binary patch delta 57 zcmbQ}(d@|O66_MvtiZs)7`Tz^nVg77ynBEvN4$rp3$LSdfTw|hff>W*zlw&8?0zgU N@xe~BfU-?{eGQJguN(eR_ zAlpY;q>x85@VW0kpeiG-RKRvxe5S7adc>lN*$@oJ<5FBtqJ2dxfo?ksNe@YE2JEfP zd`(o(9y4||#V%cc$K(E(u7r;aJbLVmGDQyCwI=WeLURJ|TSme@LKw3}&<^9+C4{B~ zd&i_C0u~iQV40Laz@j1n^pPh-$pJ-^pVEiQ1#y%Ykj*19ACdfI$`G>1XASFDLZTUp zu5IMY;?9>_v!YRKq?0s8`f3|O(EB}9g*b=FF)U&eo}^dfgMj)#r=&*76%UEhrf_Rh zS%u~y@XIrh$a?=L^$_-*R(cxrG@hz_3;V`_e1~3rQd7AL#*6CQG%^X~NXH#4u7!VA z3QNjuZ|dp(_OIBhp==+AWd3GeHMgZcYl|@1T-O QJRDtB=INi93%AwXe}v%_7XSbN diff --git a/tests/acpi-test-data/q35/DSDT.ipmibt b/tests/acpi-test-data/q35/DSDT.ipmibt index 0ea38e1e72977e82053b087a6bd2e4ea21373420..b658329c5b8e7eba009ad96f7cd26674b5a2c861 100644 GIT binary patch delta 57 zcmeBm{cp?V66_N4Uygx+@$W{iBv}!Wc=rHTj(87G7hXr_08ax012cxrl?sN8?0zgU M@xe~8!sY-mMANxL>BCk3~gH5=WRF1xW*Ht?28u!@pL+8%P+ z#*0wsDfHkiO8x=y;$P=Fvp;Ik1eR~UZ)P%+`8IrZZm@>i=$x++LJxkhgL2TWZU}cr z*m_I#K5JEO+KsF*Ta6{VZL6AECt2|tBHsJd9}Fvp{bTv@z+84Qo;u^H$rXyz}CX zPbJ0RTXCX{xx@EjmSup3Xy8-ddw^Z0RH<^u?a-ON^6Mdq8s^5_a0Qj@TAJ-ET8Zn9 zyO_=Zxj~eikl+}i*HQ*vj=#3}?9b^>6TSb@O8E(4?yU@-=f41qaOE|5cgfH958d_>aYO9qjJ znl))$86!<#=h{|2SY>y<+?-t+m&HYK$!Nja7Guy~z*Yd4p*Vp>m`F(cX_O^)M^WOS zC?!Y2vP)RsR_<|opVQ<9L6{y)0xkZY>LK5CJM%M_iVh{;^Ic<4egILAdn#+(c&X0) zmq>w5CRo`JP1}fFt?714Rl(NEEn%oNQs{2Zr~XIpqhWuZmY>i-U+$u?!n57Y%xp?F zGI~~klk!W9H7Q~6Ee(lxYTDePIl@@U8?9oH!JAg_!tk&VS%6^CiZ?1_f<~UR$fxiZ ig8L)0!{F2_k8Z>b;N_^`((rKgin4%j$lUnX-R2*u`WpiP diff --git a/tests/acpi-test-data/q35/DSDT.memhp b/tests/acpi-test-data/q35/DSDT.memhp index ecd0d8564b21016028d8ecd740f8647e0cbf8878..e46c1fb5a21b8b45a4db5955989941875169a46d 100644 GIT binary patch delta 536 zcmbR5+3CUM66_Mfslvd(czYw4jI3~UlP_zGK68AqQ+$B4r-83WfXn2A3L=yJWF;rJ zDk|_cIr+xufn4c>mxK<|RO*!15WHSt0`Qu3iR=OMHPONJ$3R z?A=OI^)xcuH^9J%17s7gL4|=414q1vrwfnc1)c_=gMLy2!DtEm_nibw+^$UVR{ x-qpaE0UDK{$np(#_7e~R$$%~Ab#xB!G%zqQW7uq>V93bs#}WgIugMWA?f}=0mk|H} delta 716 zcmeD5nD5Eu66_K(Uxk5zQFkMkjI4lwpRQhfuv2`1v!_9HlcVlrQ(42!_Hy%>^ab?d z-2+@X;ypZFcpaSsJPiyC%os!@<6RAm8DjKVV48eA0$hB9o&7dPfn9nU}}_~d{$P0QFiiQSvg5jj{x5wX5U~}9|d23*DxRv?5q&o zr35%iPQm5e4IQg#ObnF_{n