hv: support for pci uart with high mmio

to enable early print output by pci uart, which has mmio address
above 4G, add the early pagetable map for the MMIO range.

we make an assumption that only map it with 2MB page, since platform
with 39bit memory width have no 1G huge page feature and we cannot
get the capacity at runtime, since it is a very early code stage.

v2->v1:
1. add hva2hpa_early
2. add process when *pdpte is not present

Signed-off-by: hangliu1 <hang1.liu@linux.intel.com>
Reviewed-by: fei1.li <fei1.li@intel.com>
Tracked-On: #6690
This commit is contained in:
hangliu1 2022-11-17 03:19:44 -05:00 committed by acrnsi-robot
parent b17b5992c8
commit bb2118d98b
1 changed files with 39 additions and 11 deletions

View File

@ -121,6 +121,35 @@ static void uart16550_set_baud_rate(uint32_t baud_rate)
uart16550_write_reg(uart, temp_reg, UART16550_LCR);
}
static uint8_t uart_pde_page[PAGE_SIZE]__aligned(PAGE_SIZE);
static uint8_t uart_pdpte_page[PAGE_SIZE]__aligned(PAGE_SIZE);
static void early_pgtable_map_uart(uint64_t addr)
{
uint64_t *pml4e, *pdpte, *pde;
uint64_t value;
CPU_CR_READ(cr3, &value);
/*assumpiton for map high mmio in early pagetable is that it is only used for
2MB page since 1G page may not available when memory width is 39bit */
pml4e = pml4e_offset((uint64_t *)value, addr);
/* address is above 512G */
if(!(*pml4e & PAGE_PRESENT)) {
*pml4e = hva2hpa_early(uart_pdpte_page) + (PAGE_PRESENT|PAGE_RW);
}
pdpte = pdpte_offset(pml4e, addr);
if(!(*pdpte & PAGE_PRESENT)) {
*(pdpte) = hva2hpa_early(uart_pde_page) + (PAGE_PRESENT|PAGE_RW);
pde = pde_offset(pdpte, addr);
*pde = (addr & PDE_MASK) + (PAGE_PRESENT|PAGE_RW|PAGE_PSE);
} else if(!(*pdpte & PAGE_PSE)) {
pde = pde_offset(pdpte, addr);
if(!(*pde & PAGE_PRESENT)) {
*pde = (addr & PDE_MASK) + (PAGE_PRESENT|PAGE_RW|PAGE_PSE);
}
}
}
void uart16550_init(bool early_boot)
{
void *mmio_base_va = NULL;
@ -154,19 +183,18 @@ void uart16550_init(bool early_boot)
uart.port_address = (uint16_t)(bar0 & PCI_BASE_ADDRESS_IO_MASK);
uart.reg_width = 1;
pci_pdev_write_cfg(uart.bdf, PCIR_COMMAND, 2U, cmd | PCIM_CMD_PORTEN);
} else {
uint32_t bar_hi = pci_pdev_read_cfg(uart.bdf, pci_bar_offset(1), 4U);
/* Enable the PCI UART if the BAR is 32bit, or 64bit with 4GB- mmio space. */
if (((bar0 & 0x7U) == 0U) || (((bar0 & 0x7U) == 4U) && (bar_hi == 0U))) {
} else if (((bar0 & 0x7U) == 0U) || ((bar0 & 0x7U) == 4U)) {
uart.type = MMIO;
uart.mmio_base_vaddr = hpa2hva_early((bar0 & PCI_BASE_ADDRESS_MEM_MASK));
uint32_t bar_hi = pci_pdev_read_cfg(uart.bdf, pci_bar_offset(1), 4U);
uint64_t addr = (bar0 & PCI_BASE_ADDRESS_MEM_MASK)|(((uint64_t)bar_hi) << 32U);
if (bar_hi != 0U) {
early_pgtable_map_uart(addr);
}
uart.mmio_base_vaddr = hpa2hva_early(addr);
pci_pdev_write_cfg(uart.bdf, PCIR_COMMAND, 2U, cmd | PCIM_CMD_MEMEN);
} else {
/* TODO: enable 64bit BAR with 4GB+ mmio space */
uart.enabled = false;
return;
}
} else {
uart.enabled = false;
return;
}
}
}