diff --git a/hypervisor/arch/x86/cpu.c b/hypervisor/arch/x86/cpu.c index f1fe41a9f..0397e04b8 100644 --- a/hypervisor/arch/x86/cpu.c +++ b/hypervisor/arch/x86/cpu.c @@ -165,6 +165,8 @@ void init_pcpu_pre(bool is_bsp) panic("Platform CAT info is incorrect!"); } + /* NOTE: this must call after MMCONFIG is parsed in init_vboot and before APs are INIT. */ + pci_switch_to_mmio_cfg_ops(); } else { /* Switch this CPU to use the same page tables set-up by the * primary/boot CPU diff --git a/hypervisor/debug/uart16550.c b/hypervisor/debug/uart16550.c index 77c68aea7..747c9246b 100644 --- a/hypervisor/debug/uart16550.c +++ b/hypervisor/debug/uart16550.c @@ -45,6 +45,68 @@ static char pci_bdf_info[MAX_BDF_LEN + 1U]; typedef uint32_t uart_reg_t; static union pci_bdf serial_pci_bdf; + +static uint32_t pci_direct_calc_address(union pci_bdf bdf, uint32_t offset) +{ + uint32_t addr = (uint32_t)bdf.value; + + addr <<= 8U; + addr |= (offset | PCI_CFG_ENABLE); + return addr; +} + +static uint32_t pci_direct_read_cfg(union pci_bdf bdf, uint32_t offset, uint32_t bytes) +{ + uint32_t addr; + uint32_t val; + + addr = pci_direct_calc_address(bdf, offset); + + /* Write address to ADDRESS register */ + pio_write32(addr, (uint16_t)PCI_CONFIG_ADDR); + + /* Read result from DATA register */ + switch (bytes) { + case 1U: + val = (uint32_t)pio_read8((uint16_t)PCI_CONFIG_DATA + ((uint16_t)offset & 3U)); + break; + case 2U: + val = (uint32_t)pio_read16((uint16_t)PCI_CONFIG_DATA + ((uint16_t)offset & 2U)); + break; + default: + val = pio_read32((uint16_t)PCI_CONFIG_DATA); + break; + } + + return val; +} + +static void pci_direct_write_cfg(union pci_bdf bdf, uint32_t offset, uint32_t bytes, uint32_t val) +{ + uint32_t addr = pci_direct_calc_address(bdf, offset); + + /* Write address to ADDRESS register */ + pio_write32(addr, (uint16_t)PCI_CONFIG_ADDR); + + /* Write value to DATA register */ + switch (bytes) { + case 1U: + pio_write8((uint8_t)val, (uint16_t)PCI_CONFIG_DATA + ((uint16_t)offset & 3U)); + break; + case 2U: + pio_write16((uint16_t)val, (uint16_t)PCI_CONFIG_DATA + ((uint16_t)offset & 2U)); + break; + default: + pio_write32(val, (uint16_t)PCI_CONFIG_DATA); + break; + } +} + +struct pci_cfg_ops pci_direct_cfg_ops = { + .pci_read_cfg = pci_direct_read_cfg, + .pci_write_cfg = pci_direct_write_cfg, +}; + /* PCI BDF must follow format: bus:dev.func, for example 0:18.2 */ static uint16_t get_pci_bdf_value(char *bdf) { diff --git a/hypervisor/hw/pci.c b/hypervisor/hw/pci.c index 3c2b441a8..c3020a274 100644 --- a/hypervisor/hw/pci.c +++ b/hypervisor/hw/pci.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -62,94 +63,92 @@ uint64_t get_mmcfg_base(void) return pci_mmcfg_base; } -/* @brief: Find the DRHD index corresponding to a PCI device - * Runs through the pci_pdev_array and returns the value in drhd_idx - * member from pdev structure that matches matches B:D.F - * - * @pbdf[in] B:D.F of a PCI device - * - * @return if there is a matching pbdf in pci_pdev_array, pdev->drhd_idx, else INVALID_DRHD_INDEX +/* + * @pre offset < 0x1000U */ - -uint32_t pci_lookup_drhd_for_pbdf(uint16_t pbdf) +static inline uint32_t pci_mmcfg_calc_address(union pci_bdf bdf, uint32_t offset) { - uint32_t drhd_index = INVALID_DRHD_INDEX; - uint32_t index; - - for (index = 0U; index < num_pci_pdev; index++) { - if (pci_pdev_array[index].bdf.value == pbdf) { - drhd_index = pci_pdev_array[index].drhd_index; - break; - } - } - - return drhd_index; + return (uint32_t)pci_mmcfg_base + (((uint32_t)bdf.value << 12U) | offset); } -static uint32_t pci_pdev_calc_address(union pci_bdf bdf, uint32_t offset) +static uint32_t pci_mmcfg_read_cfg(union pci_bdf bdf, uint32_t offset, uint32_t bytes) { - uint32_t addr = (uint32_t)bdf.value; - - addr <<= 8U; - addr |= (offset | PCI_CFG_ENABLE); - return addr; -} - -uint32_t pci_pdev_read_cfg(union pci_bdf bdf, uint32_t offset, uint32_t bytes) -{ - uint32_t addr; + uint32_t addr = pci_mmcfg_calc_address(bdf, offset); + void *hva = hpa2hva(addr); uint32_t val; - addr = pci_pdev_calc_address(bdf, offset); - spinlock_obtain(&pci_device_lock); - - /* Write address to ADDRESS register */ - pio_write32(addr, (uint16_t)PCI_CONFIG_ADDR); - - /* Read result from DATA register */ + stac(); switch (bytes) { case 1U: - val = (uint32_t)pio_read8((uint16_t)PCI_CONFIG_DATA + ((uint16_t)offset & 3U)); + val = (uint32_t)mmio_read8(hva); break; case 2U: - val = (uint32_t)pio_read16((uint16_t)PCI_CONFIG_DATA + ((uint16_t)offset & 2U)); + val = (uint32_t)mmio_read16(hva); break; default: - val = pio_read32((uint16_t)PCI_CONFIG_DATA); + val = mmio_read32(hva); break; } + clac(); spinlock_release(&pci_device_lock); return val; } -void pci_pdev_write_cfg(union pci_bdf bdf, uint32_t offset, uint32_t bytes, uint32_t val) +/* + * @pre bytes == 1U || bytes == 2U || bytes == 4U + */ +static void pci_mmcfg_write_cfg(union pci_bdf bdf, uint32_t offset, uint32_t bytes, uint32_t val) { - uint32_t addr; + uint32_t addr = pci_mmcfg_calc_address(bdf, offset); + void *hva = hpa2hva(addr); spinlock_obtain(&pci_device_lock); - - addr = pci_pdev_calc_address(bdf, offset); - - /* Write address to ADDRESS register */ - pio_write32(addr, (uint16_t)PCI_CONFIG_ADDR); - - /* Write value to DATA register */ + stac(); switch (bytes) { case 1U: - pio_write8((uint8_t)val, (uint16_t)PCI_CONFIG_DATA + ((uint16_t)offset & 3U)); + mmio_write8((uint8_t)val, hva); break; case 2U: - pio_write16((uint16_t)val, (uint16_t)PCI_CONFIG_DATA + ((uint16_t)offset & 2U)); + mmio_write16((uint16_t)val, hva); break; default: - pio_write32(val, (uint16_t)PCI_CONFIG_DATA); + mmio_write32(val, hva); break; } + clac(); spinlock_release(&pci_device_lock); } +static struct pci_cfg_ops pci_mmcfg_cfg_ops = { + .pci_read_cfg = pci_mmcfg_read_cfg, + .pci_write_cfg = pci_mmcfg_write_cfg, +}; + +static struct pci_cfg_ops *acrn_pci_cfg_ops = &pci_direct_cfg_ops; + +void pci_switch_to_mmio_cfg_ops(void) +{ + acrn_pci_cfg_ops = &pci_mmcfg_cfg_ops; +} + +/* + * @pre bytes == 1U || bytes == 2U || bytes == 4U + */ +uint32_t pci_pdev_read_cfg(union pci_bdf bdf, uint32_t offset, uint32_t bytes) +{ + return acrn_pci_cfg_ops->pci_read_cfg(bdf, offset, bytes); +} + +/* + * @pre bytes == 1U || bytes == 2U || bytes == 4U + */ +void pci_pdev_write_cfg(union pci_bdf bdf, uint32_t offset, uint32_t bytes, uint32_t val) +{ + acrn_pci_cfg_ops->pci_write_cfg(bdf, offset, bytes, val); +} + bool pdev_need_bar_restore(const struct pci_pdev *pdev) { bool need_restore = false; @@ -184,6 +183,30 @@ void pdev_restore_bar(const struct pci_pdev *pdev) } } +/* @brief: Find the DRHD index corresponding to a PCI device + * Runs through the pci_pdev_array and returns the value in drhd_idx + * member from pdev structure that matches matches B:D.F + * + * @pbdf[in] B:D.F of a PCI device + * + * @return if there is a matching pbdf in pci_pdev_array, pdev->drhd_idx, else INVALID_DRHD_INDEX + */ + +uint32_t pci_lookup_drhd_for_pbdf(uint16_t pbdf) +{ + uint32_t drhd_index = INVALID_DRHD_INDEX; + uint32_t index; + + for (index = 0U; index < num_pci_pdev; index++) { + if (pci_pdev_array[index].bdf.value == pbdf) { + drhd_index = pci_pdev_array[index].drhd_index; + break; + } + } + + return drhd_index; +} + /* enable: 1: enable INTx; 0: Disable INTx */ void enable_disable_pci_intx(union pci_bdf bdf, bool enable) { diff --git a/hypervisor/include/debug/uart16550.h b/hypervisor/include/debug/uart16550.h index 5181fb2c5..f81adef73 100644 --- a/hypervisor/include/debug/uart16550.h +++ b/hypervisor/include/debug/uart16550.h @@ -7,6 +7,8 @@ #ifndef UART16550_H #define UART16550_H +#include + /* Register / bit definitions for 16c550 uart */ /*receive buffer register | base+00h, dlab=0b r*/ #define UART16550_RBR 0x00U @@ -127,6 +129,8 @@ /* UART oscillator clock */ #define UART_CLOCK_RATE 1843200U /* 1.8432 MHz */ +extern struct pci_cfg_ops pci_direct_cfg_ops; + void uart16550_init(bool early_boot); char uart16550_getc(void); size_t uart16550_puts(const char *buf, uint32_t len); diff --git a/hypervisor/include/hw/pci.h b/hypervisor/include/hw/pci.h index 39537d260..d8fee0aed 100644 --- a/hypervisor/include/hw/pci.h +++ b/hypervisor/include/hw/pci.h @@ -206,6 +206,11 @@ struct pci_pdev { bool has_af_flr; }; +struct pci_cfg_ops { + uint32_t (*pci_read_cfg)(union pci_bdf bdf, uint32_t offset, uint32_t bytes); + void (*pci_write_cfg)(union pci_bdf bdf, uint32_t offset, uint32_t bytes, uint32_t val); +}; + static inline uint32_t pci_bar_offset(uint32_t idx) { return PCIR_BARS + (idx << 2U); @@ -320,4 +325,5 @@ static inline bool is_pci_cfg_bridge(uint8_t header_type) bool pdev_need_bar_restore(const struct pci_pdev *pdev); void pdev_restore_bar(const struct pci_pdev *pdev); +void pci_switch_to_mmio_cfg_ops(void); #endif /* PCI_H_ */ diff --git a/hypervisor/release/uart16550.c b/hypervisor/release/uart16550.c index bdf762b62..b5ed068a0 100644 --- a/hypervisor/release/uart16550.c +++ b/hypervisor/release/uart16550.c @@ -5,5 +5,7 @@ */ #include +#include void uart16550_init(__unused bool early_boot) {} +struct pci_cfg_ops pci_direct_cfg_ops;