dm: fix the issue when guest tries to disable memory range access

According to PCI spec 3.0 section 6.2.2 "Device Control", guest
could write the command register to control device response to
io/mem access.

The origial code register/unregister the memory range which is
not suitable because it can't handle the sequence:
  1. disble the device response to specific memory range
  2. reboot guest (DM will try to free the memory range which
     was freed in step 1 already)

Tracked-On: #1277
Signed-off-by: Yin Fengwei <fengwei.yin@intel.com>
Acked-by: Yu Wang <yu1.wang@intel.com>
This commit is contained in:
Yin Fengwei
2018-09-18 11:30:39 +08:00
committed by wenlingz
parent be0cde7dec
commit 8787b65fde
5 changed files with 182 additions and 4 deletions

View File

@@ -508,6 +508,66 @@ register_bar(struct pci_vdev *dev, int idx)
modify_bar_registration(dev, idx, 1);
}
static void
enable_bar(struct pci_vdev *dev, int idx)
{
int error = 0;
struct inout_port iop;
struct mem_range mr;
switch (dev->bar[idx].type) {
case PCIBAR_IO:
bzero(&iop, sizeof(struct inout_port));
iop.name = dev->name;
iop.port = dev->bar[idx].addr;
iop.size = dev->bar[idx].size;
error = enable_inout(&iop);
break;
case PCIBAR_MEM32:
case PCIBAR_MEM64:
bzero(&mr, sizeof(struct mem_range));
mr.name = dev->name;
mr.base = dev->bar[idx].addr;
mr.size = dev->bar[idx].size;
error = enable_mem(&mr);
break;
default:
error = EINVAL;
break;
}
assert(error == 0);
}
static void
disable_bar(struct pci_vdev *dev, int idx)
{
int error = 0;
struct inout_port iop;
struct mem_range mr;
switch (dev->bar[idx].type) {
case PCIBAR_IO:
bzero(&iop, sizeof(struct inout_port));
iop.name = dev->name;
iop.port = dev->bar[idx].addr;
iop.size = dev->bar[idx].size;
error = disable_inout(&iop);
break;
case PCIBAR_MEM32:
case PCIBAR_MEM64:
bzero(&mr, sizeof(struct mem_range));
mr.name = dev->name;
mr.base = dev->bar[idx].addr;
mr.size = dev->bar[idx].size;
error = disable_mem(&mr);
break;
default:
error = EINVAL;
break;
}
assert(error == 0);
}
/* Are we decoding i/o port accesses for the emulated pci device? */
static int
porten(struct pci_vdev *dev)
@@ -1875,9 +1935,9 @@ pci_emul_cmdsts_write(struct pci_vdev *dev, int coff, uint32_t new, int bytes)
/* I/O address space decoding changed? */
if (changed & PCIM_CMD_PORTEN) {
if (porten(dev))
register_bar(dev, i);
enable_bar(dev, i);
else
unregister_bar(dev, i);
disable_bar(dev, i);
}
break;
case PCIBAR_MEM32:
@@ -1885,9 +1945,9 @@ pci_emul_cmdsts_write(struct pci_vdev *dev, int coff, uint32_t new, int bytes)
/* MMIO address space decoding changed? */
if (changed & PCIM_CMD_MEMEN) {
if (memen(dev))
register_bar(dev, i);
enable_bar(dev, i);
else
unregister_bar(dev, i);
disable_bar(dev, i);
}
break;
default: