hv: vpci: restore physical BARs when writing Command Register if necessary

When PCIe does Conventinal Reset or FLR, almost PCIe configurations and states will
lost. So we should save the configurations and states before do the reset and restore
them after the reset. This was done well by BIOS or Guest now. However, ACRN will trap
these access and handle them properly for security. Almost of these configurations and
states will be written to physical configuration space at last except for BAR values
for now. So we should do the restore for BAR values. One way is to do restore after
one type reset is detected. This will be too complex. Another way is to do the restore
when BIOS or guest tries to write the Command Register. This could work because:
1. The I/O Space Enable bit and Memory Space Enable bits in Command Register will reset
to zero.
2. Before BIOS or guest wants to enable these bits, the BAR couldn't be accessed.
3. So we could restore the BAR values before enable these bits if reset is detected.

Tracked-On: #3475
Signed-off-by: Li Fei1 <fei1.li@intel.com>
This commit is contained in:
Li Fei1
2019-12-26 00:35:34 +08:00
committed by wenlingz
parent 742abaf2e6
commit 6c549d48a8
5 changed files with 66 additions and 0 deletions

View File

@@ -151,6 +151,40 @@ void pci_pdev_write_cfg(union pci_bdf bdf, uint32_t offset, uint32_t bytes, uint
spinlock_release(&pci_device_lock);
}
bool pdev_need_bar_restore(const struct pci_pdev *pdev)
{
bool need_restore = false;
uint32_t idx, bar;
for (idx = 0U; idx < PCI_STD_NUM_BARS; idx++) {
bar = pci_pdev_read_cfg(pdev->bdf, pci_bar_offset(idx), 4U);
if (bar != pdev->bars[idx]) {
need_restore = true;
break;
}
}
return need_restore;
}
static inline void pdev_save_bar(struct pci_pdev *pdev)
{
uint32_t idx;
for (idx = 0U; idx < PCI_STD_NUM_BARS; idx++) {
pdev->bars[idx] = pci_pdev_read_cfg(pdev->bdf, pci_bar_offset(idx), 4U);
}
}
void pdev_restore_bar(const struct pci_pdev *pdev)
{
uint32_t idx;
for (idx = 0U; idx < PCI_STD_NUM_BARS; idx++) {
pci_pdev_write_cfg(pdev->bdf, pci_bar_offset(idx), 4U, pdev->bars[idx]);
}
}
/* enable: 1: enable INTx; 0: Disable INTx */
void enable_disable_pci_intx(union pci_bdf bdf, bool enable)
{
@@ -478,7 +512,11 @@ static void init_pdev(uint16_t pbdf, uint32_t drhd_index)
if ((hdr_type == PCIM_HDRTYPE_NORMAL) || (hdr_type == PCIM_HDRTYPE_BRIDGE)) {
pdev = &pci_pdev_array[num_pci_pdev];
pdev->bdf.value = pbdf;
pdev->hdr_type = hdr_type;
pdev->nr_bars = pci_pdev_get_nr_bars(hdr_type);
if (hdr_type == PCIM_HDRTYPE_NORMAL) {
pdev_save_bar(pdev);
}
if ((pci_pdev_read_cfg(bdf, PCIR_STATUS, 2U) & PCIM_STATUS_CAPPRESENT) != 0U) {
pci_read_cap(pdev);