[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [XEN PATCH v2] hvmloader: Enable MMIO and I/O decode, after all resource allocation



On Tue, 2020-04-14 at 10:20 +0200, Roger Pau Monné wrote:
> CAUTION: This email originated from outside of the organization. Do
> not click links or open attachments unless you can confirm the sender
> and know the content is safe.
> 
> 
> 
> On Tue, Apr 14, 2020 at 10:10:09AM +0200, Roger Pau Monné wrote:
> > On Mon, Apr 13, 2020 at 09:33:42PM +0000, Harsha Shamsundara
> > Havanur wrote:
> > > It was observed that PCI MMIO and/or IO BARs were programmed with
> > > BUS master, memory and I/O decodes (bits 0,1 and 2 of PCI COMMAND
> > > register) enabled, during PCI setup phase. This resulted in
> > > incorrect memory mapping as soon as the lower half of the 64 bit
> > > bar
> > > is programmed, which displaced any RAM mappings under 4G. After
> > > the
> > > upper half is programmed PCI memory mapping is restored to its
> > > intended mapping but the RAM displaced is not restored. The OS
> > > then
> > > continues to boot and function until it tries to access the
> > > displaced
> > > RAM at which point it suffers a page fault and crashes.
> > > 
> > > This patch address the issue by deferring enablement of memory
> > > and
> > > I/O decode in command register until all the resources, like
> > > interrupts
> > > I/O and/or MMIO BARs for all the PCI device functions are
> > > programmed.
> > > 
> > > Signed-off-by: Harsha Shamsundara Havanur <havanur@xxxxxxxxxx>
> > > Reviewed-by: Paul Durrant <pdurrant@xxxxxxxxxx>
> > > Acked-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
> > > ---
> > >  tools/firmware/hvmloader/pci.c | 35 +++++++++++++++++++++++++++-
> > > -------
> > >  1 file changed, 27 insertions(+), 8 deletions(-)
> > > 
> > > diff --git a/tools/firmware/hvmloader/pci.c
> > > b/tools/firmware/hvmloader/pci.c
> > > index 0b708bf578..f74471b255 100644
> > > --- a/tools/firmware/hvmloader/pci.c
> > > +++ b/tools/firmware/hvmloader/pci.c
> > > @@ -84,6 +84,7 @@ void pci_setup(void)
> > >      uint32_t vga_devfn = 256;
> > >      uint16_t class, vendor_id, device_id;
> > >      unsigned int bar, pin, link, isa_irq;
> > > +    uint8_t pci_devfn_decode_type[256] = {};
> > > 
> > >      /* Resources assignable to PCI devices via BARs. */
> > >      struct resource {
> > > @@ -120,6 +121,9 @@ void pci_setup(void)
> > >       */
> > >      bool allow_memory_relocate = 1;
> > > 
> > > +    BUILD_BUG_ON((typeof(*pci_devfn_decode_type))PCI_COMMAND_MEM
> > > ORY != PCI_COMMAND_MEMORY);
> > > +    BUILD_BUG_ON((typeof(*pci_devfn_decode_type))PCI_COMMAND_IO
> > > != PCI_COMMAND_IO);
> > > +    BUILD_BUG_ON((typeof(*pci_devfn_decode_type))PCI_COMMAND_IO
> > > != PCI_COMMAND_MASTER);
> > >      s = xenstore_read(HVM_XS_ALLOW_MEMORY_RELOCATE, NULL);
> > >      if ( s )
> > >          allow_memory_relocate = strtoll(s, NULL, 0);
> > > @@ -289,9 +293,22 @@ void pci_setup(void)
> > >                     devfn>>3, devfn&7, 'A'+pin-1, isa_irq);
> > >          }
> > > 
> > > -        /* Enable bus mastering. */
> > > +        /*
> > > +         * Disable bus mastering, memory and I/O space, which is
> > > typical device
> > > +         * reset state. It is recommended that BAR programming
> > > be done whilst
> > > +         * decode bits are cleared to avoid incorrect mappings
> > > being created,
> > > +         * when 64-bit memory BAR is programmed first by writing
> > > the lower half
> > > +         * and then the upper half, which first maps to an
> > > address under 4G
> > > +         * replacing any RAM mapped in that address, which is
> > > not restored
> > > +         * back after the upper half is written and PCI memory
> > > is correctly
> > > +         * mapped to its intended high mem address.
> > > +         *
> > > +         * Capture the state of bus master to restore it back
> > > once BAR
> > > +         * programming is completed.
> > > +         */
> > >          cmd = pci_readw(devfn, PCI_COMMAND);
> > > -        cmd |= PCI_COMMAND_MASTER;
> > > +        pci_devfn_decode_type[devfn] = cmd &
> > > ~(PCI_COMMAND_MEMORY | PCI_COMMAND_IO);
> > > +        cmd &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY |
> > > PCI_COMMAND_IO);
> > >          pci_writew(devfn, PCI_COMMAND, cmd);
> > >      }
> > > 
> > > @@ -503,10 +520,9 @@ void pci_setup(void)
> > >          if ( (bar_reg == PCI_ROM_ADDRESS) ||
> > >               ((bar_data & PCI_BASE_ADDRESS_SPACE) ==
> > >                PCI_BASE_ADDRESS_SPACE_MEMORY) )
> > > -            cmd |= PCI_COMMAND_MEMORY;
> > > +            pci_devfn_decode_type[devfn] |= PCI_COMMAND_MEMORY;
> > >          else
> > > -            cmd |= PCI_COMMAND_IO;
> > > -        pci_writew(devfn, PCI_COMMAND, cmd);
> > > +            pci_devfn_decode_type[devfn] |= PCI_COMMAND_IO;
> > >      }
> > > 
> > >      if ( pci_hi_mem_start )
> > > @@ -526,10 +542,13 @@ void pci_setup(void)
> > >           * has IO enabled, even if there is no I/O BAR on that
> > >           * particular device.
> > >           */
> > > -        cmd = pci_readw(vga_devfn, PCI_COMMAND);
> > > -        cmd |= PCI_COMMAND_IO;
> > > -        pci_writew(vga_devfn, PCI_COMMAND, cmd);
> > > +        pci_devfn_decode_type[vga_devfn] |= PCI_COMMAND_IO;
> > >      }
> > > +
> > > +    /* Enable memory and I/O space. Restore saved BUS MASTER
> > > state */
> > > +    for ( devfn = 0; devfn < 256; devfn++ )
> > > +        if ( pci_devfn_decode_type[devfn] )
> > > +            pci_writew(devfn, PCI_COMMAND,
> > > pci_devfn_decode_type[devfn]);
> > 
> > Why don't you enable the decoding after done with programming all
> > the
> > BARs on the device in the loop above? Is there any reason to defer
> > this until all devices have been programmed?
> > 
> > If so, I think you would also need to introduce a pre-loop that
> > disables all of this for all devices before programming the BARs,
> > or
> > else you are still programming BARs while some devices might have
> > the
> > bus mastering or decoding bits enabled.
> 
> Oh, forget that last paragraph, I see that decoding is indeed
> disabled
> before programming any devices BARs. I still think that it might be
> feasible to enable it once all BARs on the device have been
> programmed, which would allow to get rid of the extra loop and the
> pci_devfn_decode_type local variable.

BARs are programmed sorted by their memory requirement and thus same
pci function could be programmed multiple times in this loop
422     /* Assign iomem and ioport resources in descending order of
size. */
423     for ( i = 0; i < nr_bars; i++ )

Hence I am waiting for this loop to be completed to enable decode bits
in a saparate loop later.
> 
> Thanks, Roger.

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.