From ce3451827ad6d7cf4b683701e0f30a204603be94 Mon Sep 17 00:00:00 2001 From: Li Fei1 Date: Thu, 21 May 2020 09:02:59 +0800 Subject: [PATCH] hv: vpci: add vmsix capability registers rw permission control Guest may write a MSI-X capability register with only RW bits setting on. This works well on native since the hardware will make sure RO register bits could not over-write. However, the software needs more efforts to achieve this. This patch does this by defining a RW permission mapping base on bits. When a guest tries to write a MSI-X Capability register, only modify the RW bits on vCFG space. Tracked-On: #4550 Signed-off-by: Li Fei1 --- hypervisor/dm/vpci/vmsix.c | 20 ++++++++++++-------- hypervisor/dm/vpci/vpci.c | 4 ++-- hypervisor/dm/vpci/vpci_priv.h | 4 ++-- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/hypervisor/dm/vpci/vmsix.c b/hypervisor/dm/vpci/vmsix.c index 0d6cf42ed..379c96787 100644 --- a/hypervisor/dm/vpci/vmsix.c +++ b/hypervisor/dm/vpci/vmsix.c @@ -112,7 +112,7 @@ static void remap_one_vmsix_entry(const struct pci_vdev *vdev, uint32_t index) /** * @pre vdev != NULL */ -void read_vmsix_cfg(const struct pci_vdev *vdev, uint32_t offset, uint32_t bytes, uint32_t *val) +void read_vmsix_cap_reg(const struct pci_vdev *vdev, uint32_t offset, uint32_t bytes, uint32_t *val) { /* For PIO access, we emulate Capability Structures only */ *val = pci_vdev_read_vcfg(vdev, offset, bytes); @@ -124,16 +124,20 @@ void read_vmsix_cfg(const struct pci_vdev *vdev, uint32_t offset, uint32_t bytes * @pre vdev != NULL * @pre vdev->pdev != NULL */ -void write_vmsix_cfg(struct pci_vdev *vdev, uint32_t offset, uint32_t bytes, uint32_t val) +void write_vmsix_cap_reg(struct pci_vdev *vdev, uint32_t offset, uint32_t bytes, uint32_t val) { - uint32_t old_msgctrl, msgctrl; + static const uint8_t msix_ro_mask[12U] = { + 0xffU, 0xffU, 0xffU, 0x3fU, /* Only Function Mask and MSI-X Enable writable */ + 0xffU, 0xffU, 0xffU, 0xffU, + 0xffU, 0xffU, 0xffU, 0xffU }; + uint32_t msgctrl, old, ro_mask = ~0U; - old_msgctrl = pci_vdev_read_vcfg(vdev, vdev->msix.capoff + PCIR_MSIX_CTRL, 2U); - /* Write to vdev */ - pci_vdev_write_vcfg(vdev, offset, bytes, val); - msgctrl = pci_vdev_read_vcfg(vdev, vdev->msix.capoff + PCIR_MSIX_CTRL, 2U); + (void)memcpy_s((void *)&ro_mask, bytes, (void *)&msix_ro_mask[offset - vdev->msix.capoff], bytes); + if (ro_mask != ~0U) { + old = pci_vdev_read_vcfg(vdev, vdev->msix.capoff, bytes); + pci_vdev_write_vcfg(vdev, offset, bytes, (old & ro_mask) | (val & ~ro_mask)); - if (((old_msgctrl ^ msgctrl) & (PCIM_MSIXCTRL_MSIX_ENABLE | PCIM_MSIXCTRL_FUNCTION_MASK)) != 0U) { + msgctrl = pci_vdev_read_vcfg(vdev, vdev->msix.capoff + PCIR_MSIX_CTRL, 2U); /* If MSI Enable is being set, make sure INTxDIS bit is set */ if ((msgctrl & PCIM_MSIXCTRL_MSIX_ENABLE) != 0U) { enable_disable_pci_intx(vdev->pdev->bdf, false); diff --git a/hypervisor/dm/vpci/vpci.c b/hypervisor/dm/vpci/vpci.c index 17d8930f1..d3bbcd6ae 100644 --- a/hypervisor/dm/vpci/vpci.c +++ b/hypervisor/dm/vpci/vpci.c @@ -498,7 +498,7 @@ static int32_t write_pt_dev_cfg(struct pci_vdev *vdev, uint32_t offset, } else if (msicap_access(vdev, offset)) { write_vmsi_cap_reg(vdev, offset, bytes, val); } else if (msixcap_access(vdev, offset)) { - write_vmsix_cfg(vdev, offset, bytes, val); + write_vmsix_cap_reg(vdev, offset, bytes, val); } else if (sriovcap_access(vdev, offset)) { write_sriov_cap_reg(vdev, offset, bytes, val); } else { @@ -523,7 +523,7 @@ static int32_t read_pt_dev_cfg(const struct pci_vdev *vdev, uint32_t offset, } else if (msicap_access(vdev, offset)) { read_vmsi_cap_reg(vdev, offset, bytes, val); } else if (msixcap_access(vdev, offset)) { - read_vmsix_cfg(vdev, offset, bytes, val); + read_vmsix_cap_reg(vdev, offset, bytes, val); } else if (sriovcap_access(vdev, offset)) { read_sriov_cap_reg(vdev, offset, bytes, val); } else { diff --git a/hypervisor/dm/vpci/vpci_priv.h b/hypervisor/dm/vpci/vpci_priv.h index 14570045f..749678c74 100644 --- a/hypervisor/dm/vpci/vpci_priv.h +++ b/hypervisor/dm/vpci/vpci_priv.h @@ -124,8 +124,8 @@ void deinit_vmsi(struct pci_vdev *vdev); void init_vmsix(struct pci_vdev *vdev); int32_t vmsix_handle_table_mmio_access(struct io_request *io_req, void *handler_private_data); -void read_vmsix_cfg(const struct pci_vdev *vdev, uint32_t offset, uint32_t bytes, uint32_t *val); -void write_vmsix_cfg(struct pci_vdev *vdev, uint32_t offset, uint32_t bytes, uint32_t val); +void read_vmsix_cap_reg(const struct pci_vdev *vdev, uint32_t offset, uint32_t bytes, uint32_t *val); +void write_vmsix_cap_reg(struct pci_vdev *vdev, uint32_t offset, uint32_t bytes, uint32_t val); void deinit_vmsix(struct pci_vdev *vdev); void init_vsriov(struct pci_vdev *vdev);