mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-06-25 06:51:49 +00:00
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:
parent
08bafdffc6
commit
84752ab229
@ -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)));
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
};
|
||||
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user