|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH for-4.17 v2 5/5] vpci: refuse BAR writes only if the BAR is mapped
On 25.10.2022 16:44, Roger Pau Monne wrote:
> Writes to the BARs are ignored if memory decoding is enabled for the
> device, and the same happen with ROM BARs if the write is an attempt
> to change the position of the BAR without disabling it first.
>
> The reason of ignoring such writes is a limitation in Xen, as it would
> need to unmap the BAR, change the address, and remap the BAR at the
> new position, which the current logic doesn't support.
>
> Some devices however seem to (wrongly) have the memory decoding bit
> hardcoded to enabled, and attempts to disable it don't get reflected
> on the command register.
>
> This causes issues for well behaved guests that disable memory
> decoding and then try to size the BARs, as vPCI will think memory
> decoding is still enabled and ignore the write.
Just to avoid misunderstandings: "guests" here includes Dom0? In such
cases we typically prefer to say "domains". This then also affects
the next (final) paragraph.
> --- a/xen/drivers/vpci/header.c
> +++ b/xen/drivers/vpci/header.c
> @@ -128,7 +128,10 @@ static void modify_decoding(const struct pci_dev *pdev,
> uint16_t cmd,
> }
>
> if ( !rom_only )
> + {
> pci_conf_write16(pdev->sbdf, PCI_COMMAND, cmd);
> + header->bars_mapped = map;
> + }
> else
> ASSERT_UNREACHABLE();
> }
> @@ -355,13 +358,13 @@ static int modify_bars(const struct pci_dev *pdev,
> uint16_t cmd, bool rom_only)
> static void cf_check cmd_write(
> const struct pci_dev *pdev, unsigned int reg, uint32_t cmd, void *data)
> {
> - uint16_t current_cmd = pci_conf_read16(pdev->sbdf, reg);
> + struct vpci_header *header = data;
>
> /*
> * Let Dom0 play with all the bits directly except for the memory
> * decoding one.
> */
> - if ( (cmd ^ current_cmd) & PCI_COMMAND_MEMORY )
> + if ( header->bars_mapped != !!(cmd & PCI_COMMAND_MEMORY) )
> /*
> * Ignore the error. No memory has been added or removed from the p2m
> * (because the actual p2m changes are deferred in defer_map) and the
> @@ -388,12 +391,12 @@ static void cf_check bar_write(
> else
> val &= PCI_BASE_ADDRESS_MEM_MASK;
>
> - if ( pci_conf_read16(pdev->sbdf, PCI_COMMAND) & PCI_COMMAND_MEMORY )
> + if ( bar->enabled )
In 3 of the 4 cases you use header->bars_mapped as replacement. Since it's
not clear to me why you don't here, could you explain this to me? (I'm
therefore undecided whether this is merely a cosmetic [consistency] issue.)
> {
> /* If the value written is the current one avoid printing a warning.
> */
> if ( val != (uint32_t)(bar->addr >> (hi ? 32 : 0)) )
> gprintk(XENLOG_WARNING,
> - "%pp: ignored BAR %zu write with memory decoding
> enabled\n",
> + "%pp: ignored BAR %zu write while mapped\n",
> &pdev->sbdf, bar - pdev->vpci->header.bars + hi);
> return;
> }
> @@ -422,13 +425,12 @@ static void cf_check rom_write(
> {
> struct vpci_header *header = &pdev->vpci->header;
> struct vpci_bar *rom = data;
> - uint16_t cmd = pci_conf_read16(pdev->sbdf, PCI_COMMAND);
> bool new_enabled = val & PCI_ROM_ADDRESS_ENABLE;
>
> - if ( (cmd & PCI_COMMAND_MEMORY) && header->rom_enabled && new_enabled )
> + if ( header->bars_mapped && header->rom_enabled && new_enabled )
> {
> gprintk(XENLOG_WARNING,
> - "%pp: ignored ROM BAR write with memory decoding enabled\n",
> + "%pp: ignored ROM BAR write while mapped\n",
> &pdev->sbdf);
> return;
> }
> @@ -440,7 +442,7 @@ static void cf_check rom_write(
> */
> rom->addr = val & PCI_ROM_ADDRESS_MASK;
>
> - if ( !(cmd & PCI_COMMAND_MEMORY) || header->rom_enabled == new_enabled )
> + if ( !header->bars_mapped || header->rom_enabled == new_enabled )
> {
> /* Just update the ROM BAR field. */
> header->rom_enabled = new_enabled;
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |