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 <fei1.li@intel.com>
This commit is contained in:
Li Fei1 2020-05-21 09:02:59 +08:00 committed by wenlingz
parent ea0ba47b02
commit ce3451827a
3 changed files with 16 additions and 12 deletions

View File

@ -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);

View File

@ -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 {

View File

@ -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);