Fix: HV: VM OS failed to assign new address to pci-vuart BARs

When wrong BAR address is set for pci-vuart, OS may assign a
new BAR address to it. Pci-vuart BAR can't be reprogrammed,
for its wrong fixed value. That can may because pci_vbar.fixed and
pci_vbar.type has overlap in abstraction, pci_vbar.fixed
has a confusing name, pci_vbar.type has PCIBAR_MEM64HI which is not
really a type of pci BARs.
So replace pci_vbar.type with pci_vbar.is_mem64hi, and change
pci_vbar.fixed to an union type with new name pci_vbar.bar_type.

Tracked-On: #5491
Signed-off-by: Tao Yuhong <yuhong.tao@intel.com>
This commit is contained in:
Tao Yuhong 2020-11-10 08:39:52 -05:00 committed by acrnsi-robot
parent 08bafdffc6
commit 84752ab229
8 changed files with 60 additions and 68 deletions

View File

@ -291,15 +291,12 @@ static int32_t write_ivshmem_vdev_cfg(struct pci_vdev *vdev, uint32_t offset, ui
static void init_ivshmem_bar(struct pci_vdev *vdev, uint32_t bar_idx)
{
struct pci_vbar *vbar;
enum pci_bar_type type;
uint64_t addr, mask, size = 0UL;
struct acrn_vm_pci_dev_config *dev_config = vdev->pci_dev_config;
addr = dev_config->vbar_base[bar_idx];
type = pci_get_bar_type((uint32_t) addr);
mask = (type == PCIBAR_IO_SPACE) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK;
mask = (is_pci_io_bar((uint32_t)addr)) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK;
vbar = &vdev->vbars[bar_idx];
vbar->type = type;
if (bar_idx == IVSHMEM_SHM_BAR) {
struct ivshmem_shm_region *region = find_shm_region(dev_config->shm_region_name);
if (region != NULL) {
@ -317,11 +314,11 @@ static void init_ivshmem_bar(struct pci_vdev *vdev, uint32_t bar_idx)
if (size != 0UL) {
vbar->size = size;
vbar->mask = (uint32_t) (~(size - 1UL));
vbar->fixed = (uint32_t) (addr & (~mask));
vbar->bar_type.bits = (uint32_t) (addr & (~mask));
pci_vdev_write_vbar(vdev, bar_idx, (uint32_t) addr);
if (type == PCIBAR_MEM64) {
if (is_pci_mem64_bar((uint32_t)addr)) {
vbar = &vdev->vbars[bar_idx + 1U];
vbar->type = PCIBAR_MEM64HI;
vbar->is_mem64hi = true;
vbar->mask = (uint32_t) ((~(size - 1UL)) >> 32U);
pci_vdev_write_vbar(vdev, (bar_idx + 1U), ((uint32_t)(addr >> 32U)));
}

View File

@ -292,18 +292,12 @@ void vdev_pt_write_vbar(struct pci_vdev *vdev, uint32_t idx, uint32_t val)
{
struct pci_vbar *vbar = &vdev->vbars[idx];
switch (vbar->type) {
case PCIBAR_IO_SPACE:
if (is_pci_io_bar(vbar->bar_type.bits)) {
vpci_update_one_vbar(vdev, idx, val, vdev_pt_allow_io_vbar, vdev_pt_deny_io_vbar);
break;
}
case PCIBAR_NONE:
/* Nothing to do */
break;
default:
if (is_pci_mem32_bar(vbar->bar_type.bits) || is_pci_mem64_bar(vbar->bar_type.bits) || vbar->is_mem64hi) {
vpci_update_one_vbar(vdev, idx, val, vdev_pt_map_mem_vbar, vdev_pt_unmap_mem_vbar);
break;
}
}
@ -343,7 +337,6 @@ void vdev_pt_write_vbar(struct pci_vdev *vdev, uint32_t idx, uint32_t val)
*/
static void init_bars(struct pci_vdev *vdev, bool is_sriov_bar)
{
enum pci_bar_type type;
uint32_t idx, bar_cnt;
struct pci_vbar *vbar;
uint32_t size32, offset, lo, hi = 0U;
@ -368,14 +361,13 @@ static void init_bars(struct pci_vdev *vdev, bool is_sriov_bar)
}
lo = pci_pdev_read_cfg(pbdf, offset, 4U);
type = pci_get_bar_type(lo);
if (type == PCIBAR_NONE) {
if (!(is_pci_io_bar(lo) || is_pci_mem32_bar(lo) || is_pci_mem64_bar(lo))) {
continue;
}
mask = (type == PCIBAR_IO_SPACE) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK;
mask = (is_pci_io_bar(lo)) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK;
vbar->base_hpa = (uint64_t)lo & mask;
if (type == PCIBAR_MEM64) {
if (is_pci_mem64_bar(lo)) {
hi = pci_pdev_read_cfg(pbdf, offset + 4U, 4U);
vbar->base_hpa |= ((uint64_t)hi << 32U);
}
@ -385,16 +377,15 @@ static void init_bars(struct pci_vdev *vdev, bool is_sriov_bar)
size32 = pci_pdev_read_cfg(pbdf, offset, 4U);
pci_pdev_write_cfg(pbdf, offset, 4U, lo);
vbar->type = type;
vbar->mask = size32 & mask;
vbar->fixed = lo & (~mask);
vbar->bar_type.bits = lo & (~mask);
vbar->size = (uint64_t)size32 & mask;
if (is_prelaunched_vm(vpci2vm(vdev->vpci))) {
lo = (uint32_t)vdev->pci_dev_config->vbar_base[idx];
}
if (type == PCIBAR_MEM64) {
if (is_pci_mem64_bar(lo)) {
idx++;
if (is_sriov_bar) {
offset = sriov_bar_offset(vdev, idx);
@ -416,7 +407,7 @@ static void init_bars(struct pci_vdev *vdev, bool is_sriov_bar)
}
vbar->mask = size32;
vbar->type = PCIBAR_MEM64HI;
vbar->is_mem64hi = true;
if (is_prelaunched_vm(vpci2vm(vdev->vpci))) {
hi = (uint32_t)(vdev->pci_dev_config->vbar_base[idx - 1U] >> 32U);
@ -428,9 +419,10 @@ static void init_bars(struct pci_vdev *vdev, bool is_sriov_bar)
}
} else {
vbar->size = vbar->size & ~(vbar->size - 1UL);
if (type == PCIBAR_MEM32) {
if (is_pci_mem32_bar(lo)) {
vbar->size = round_page_up(vbar->size);
}
/* if it is parsing SRIOV VF BARs, no need to write vdev bar */
if (!is_sriov_bar) {
pci_vdev_write_vbar(vdev, idx, lo);

View File

@ -101,7 +101,7 @@ uint32_t pci_vdev_read_vbar(const struct pci_vdev *vdev, uint32_t idx)
bar = pci_vdev_read_vcfg(vdev, offset, 4U);
/* Sizing BAR */
if (bar == ~0U) {
bar = vdev->vbars[idx].mask | vdev->vbars[idx].fixed;
bar = vdev->vbars[idx].mask | vdev->vbars[idx].bar_type.bits;
}
return bar;
}
@ -109,18 +109,16 @@ uint32_t pci_vdev_read_vbar(const struct pci_vdev *vdev, uint32_t idx)
static void pci_vdev_update_vbar_base(struct pci_vdev *vdev, uint32_t idx)
{
struct pci_vbar *vbar;
enum pci_bar_type type;
uint64_t base = 0UL;
uint32_t lo, hi, offset;
vbar = &vdev->vbars[idx];
offset = pci_bar_offset(idx);
lo = pci_vdev_read_vcfg(vdev, offset, 4U);
if ((vbar->type != PCIBAR_NONE) && (lo != ~0U)) {
type = vbar->type;
if (((is_pci_io_bar(vbar->bar_type.bits) || is_pci_mem32_bar(vbar->bar_type.bits) || is_pci_mem64_bar(vbar->bar_type.bits) || vbar->is_mem64hi)) && (lo != ~0U)) {
base = lo & vbar->mask;
if (vbar->type == PCIBAR_MEM64) {
if (is_pci_mem64_bar(vbar->bar_type.bits)) {
vbar = &vdev->vbars[idx + 1U];
hi = pci_vdev_read_vcfg(vdev, (offset + 4U), 4U);
if (hi != ~0U) {
@ -130,7 +128,7 @@ static void pci_vdev_update_vbar_base(struct pci_vdev *vdev, uint32_t idx)
base = 0UL;
}
}
if (type == PCIBAR_IO_SPACE) {
if (is_pci_io_bar(vbar->bar_type.bits)) {
base &= 0xffffUL;
}
}
@ -152,11 +150,11 @@ void pci_vdev_write_vbar(struct pci_vdev *vdev, uint32_t idx, uint32_t val)
vbar = &vdev->vbars[idx];
bar = val & vbar->mask;
bar |= vbar->fixed;
bar |= vbar->bar_type.bits;
offset = pci_bar_offset(idx);
pci_vdev_write_vcfg(vdev, offset, 4U, bar);
if (vbar->type == PCIBAR_MEM64HI) {
if (vbar->is_mem64hi) {
update_idx -= 1U;
}

View File

@ -130,18 +130,16 @@ static void init_vmcs9900(struct pci_vdev *vdev)
add_vmsix_capability(vdev, 1, MCS9900_MSIX_BAR);
/* initialize vuart-pci mem bar */
mmio_vbar->type = PCIBAR_MEM32;
mmio_vbar->size = 0x1000U;
mmio_vbar->base_gpa = pci_cfg->vbar_base[MCS9900_MMIO_BAR];
mmio_vbar->mask = (uint32_t) (~(mmio_vbar->size - 1UL));
mmio_vbar->fixed = (uint32_t) (mmio_vbar->base_gpa & PCI_BASE_ADDRESS_MEM_MASK);
mmio_vbar->bar_type.bits = PCIM_BAR_MEM_32;
/* initialize vuart-pci msix bar */
msix_vbar->type = PCIBAR_MEM32;
msix_vbar->size = 0x1000U;
msix_vbar->base_gpa = pci_cfg->vbar_base[MCS9900_MSIX_BAR];
msix_vbar->mask = (uint32_t) (~(msix_vbar->size - 1UL));
msix_vbar->fixed = (uint32_t) (msix_vbar->base_gpa & PCI_BASE_ADDRESS_MEM_MASK);
msix_vbar->bar_type.bits = PCIM_BAR_MEM_32;
vdev->nr_bars = 2;

View File

@ -83,7 +83,7 @@ void init_vmsix_on_msi(struct pci_vdev *vdev)
if (vdev->vbars[i].base_hpa == 0UL){
break;
}
if (vdev->vbars[i].type == PCIBAR_MEM64) {
if (is_pci_mem64_bar(vdev->vbars[i].bar_type.bits)) {
i++;
}
}
@ -106,12 +106,11 @@ void init_vmsix_on_msi(struct pci_vdev *vdev)
/* Init PBA table vBAR, offset is 2048 */
pci_vdev_write_vcfg(vdev, vdev->msix.capoff + 8U, 4U, 2048U + i);
vdev->vbars[i].type = PCIBAR_MEM32;
vdev->vbars[i].size = 4096U;
vdev->vbars[i].base_hpa = 0x0UL;
vdev->vbars[i].mask = 0xFFFFF000U & PCI_BASE_ADDRESS_MEM_MASK;
/* fixed for memory, 32bit, non-prefetchable */
vdev->vbars[i].fixed = 0U;
vdev->vbars[i].bar_type.bits = PCIM_BAR_MEM_32;
/* About MSI-x bar GPA:
* - For Service VM: when first time init, it is programmed as 0, then OS will program

View File

@ -783,7 +783,7 @@ void vpci_update_one_vbar(struct pci_vdev *vdev, uint32_t bar_idx, uint32_t val,
uint32_t offset = pci_bar_offset(bar_idx);
uint32_t update_idx = bar_idx;
if (vbar->type == PCIBAR_MEM64HI) {
if (vbar->is_mem64hi) {
update_idx -= 1U;
}
unmap_cb(vdev, update_idx);

View File

@ -38,11 +38,11 @@
#define VDEV_LIST_HASHSIZE (1U << VDEV_LIST_HASHBITS)
struct pci_vbar {
enum pci_bar_type type;
bool is_mem64hi;;
uint64_t size; /* BAR size */
uint64_t base_gpa; /* BAR guest physical address */
uint64_t base_hpa; /* BAR host physical address */
uint32_t fixed; /* BAR fix memory type encoding */
union pci_bar_type bar_type;
uint32_t mask; /* BAR size mask */
};

View File

@ -203,12 +203,17 @@ union pci_bdf {
} fields;
};
enum pci_bar_type {
PCIBAR_NONE = 0,
PCIBAR_IO_SPACE,
PCIBAR_MEM32,
PCIBAR_MEM64,
PCIBAR_MEM64HI,
union pci_bar_type {
uint32_t bits;
struct {
uint8_t indicator :1; /* BITs[0], mapped to I/O space if read as 1 */
uint8_t reserved :1; /* BITs[1], reserved */
} io_space;
struct {
uint8_t indicator :1; /* BITs[0], mapped to memory space if read as 0 */
uint8_t mem_type :2; /* BITs[1:2], 32-bit address if read as 00b, 64-bit address as 01b */
uint8_t prefetchable :1; /* BITs[3], set to 1b if the data is prefetchable and set to 0b otherwise */
} mem_space;
};
struct pci_mmcfg_region {
@ -304,29 +309,32 @@ static inline bool is_bar_offset(uint32_t nr_bars, uint32_t offset)
return ret;
}
static inline enum pci_bar_type pci_get_bar_type(uint32_t val)
static inline bool is_pci_io_bar(uint32_t val)
{
enum pci_bar_type type = PCIBAR_NONE;
union pci_bar_type bar_type = {.bits = val};
if ((val & PCIM_BAR_SPACE) == PCIM_BAR_IO_SPACE) {
type = PCIBAR_IO_SPACE;
} else {
switch (val & PCIM_BAR_MEM_TYPE) {
case PCIM_BAR_MEM_32:
type = PCIBAR_MEM32;
break;
return (bar_type.io_space.indicator == 1U);
}
case PCIM_BAR_MEM_64:
type = PCIBAR_MEM64;
break;
static inline bool is_pci_mem_bar(uint32_t val)
{
union pci_bar_type bar_type = {.bits = val};
default:
/*no actions are required for other cases.*/
break;
}
}
return ((bar_type.mem_space.indicator == 0U));
}
return type;
static inline bool is_pci_mem32_bar(uint32_t val)
{
union pci_bar_type bar_type = {.bits = val};
return (is_pci_mem_bar(val) && (bar_type.mem_space.mem_type == 0U));
}
static inline bool is_pci_mem64_bar(uint32_t val)
{
union pci_bar_type bar_type = {.bits = val};
return (is_pci_mem_bar(val) && (bar_type.mem_space.mem_type == 2U));
}
static inline bool bdf_is_equal(union pci_bdf a, union pci_bdf b)