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

Re: [PATCH v2 1/9] drivers/char: Add support for Xue USB3 debugger



On Tue, Jul 12, 2022 at 05:59:51PM +0200, Jan Beulich wrote:
> On 06.07.2022 17:32, Marek Marczykowski-Górecki wrote:
> > --- a/docs/misc/xen-command-line.pandoc
> > +++ b/docs/misc/xen-command-line.pandoc
> > @@ -721,10 +721,15 @@ Available alternatives, with their meaning, are:
> >  
> >  ### dbgp
> >  > `= ehci[ <integer> | @pci<bus>:<slot>.<func> ]`
> > +> `= xue`
> >  
> >  Specify the USB controller to use, either by instance number (when going
> >  over the PCI busses sequentially) or by PCI device (must be on segment 0).
> >  
> > +Use `ehci` for EHCI debug port, use `xue` for XHCI debug capability.
> > +Xue driver will wait indefinitely for the debug host to connect - make 
> > sure the
> > +cable is connected.
> 
> Especially without it being clear what "xue" stands for, I wonder
> whether "xhci" would be the better (more commonly known) token to
> use here.

Sure, I can change that. I modify this code heavily anyway, so there is
little point in keeping it similar to the original xue driver.

> > --- a/xen/arch/x86/setup.c
> > +++ b/xen/arch/x86/setup.c
> > @@ -946,6 +946,9 @@ void __init noreturn __start_xen(unsigned long mbi_p)
> >      ns16550.irq     = 3;
> >      ns16550_init(1, &ns16550);
> >      ehci_dbgp_init();
> > +#ifdef CONFIG_HAS_XHCI
> > +    xue_uart_init();
> > +#endif
> 
> Can you make an empty inline stub to avoid the #ifdef here?

Ok.

> > --- a/xen/drivers/char/Kconfig
> > +++ b/xen/drivers/char/Kconfig
> > @@ -74,3 +74,12 @@ config HAS_EHCI
> >     help
> >       This selects the USB based EHCI debug port to be used as a UART. If
> >       you have an x86 based system with USB, say Y.
> > +
> > +config HAS_XHCI
> > +   bool "XHCI DbC UART driver"
> 
> I'm afraid I consider most of the other options here wrong in
> starting with HAS_: Such named options should have no prompt, and
> be exclusively engaged by "select". Hence I'd like to ask to drop
> the HAS_ here.

Ok.

> > +   depends on X86
> > +   help
> > +     This selects the USB based XHCI debug capability to be used as a UART.
> 
> s/used/usable/?

Yes.

> > --- /dev/null
> > +++ b/xen/drivers/char/xue.c
> > @@ -0,0 +1,933 @@
> > +/*
> > + * drivers/char/xue.c
> > + *
> > + * Xen port for the xue debugger
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License as published by
> > + * the Free Software Foundation; either version 2 of the License, or
> > + * (at your option) any later version.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > + * GNU General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU General Public License
> > + * along with this program; If not, see <http://www.gnu.org/licenses/>.
> > + *
> > + * Copyright (c) 2019 Assured Information Security.
> > + */
> > +
> > +#include <xen/delay.h>
> > +#include <xen/types.h>
> > +#include <asm/string.h>
> > +#include <asm/system.h>
> > +#include <xen/serial.h>
> > +#include <xen/timer.h>
> > +#include <xen/param.h>
> > +#include <asm/fixmap.h>
> > +#include <asm/io.h>
> > +#include <xen/mm.h>
> 
> Please sort xen/ before asm/ and alphabetically within each group.

Ok.

> > +/* uncomment to have xue_uart_dump() debug function */
> > +/* #define XUE_DEBUG 1 */
> > +
> > +#define XUE_POLL_INTERVAL 100 /* us */
> > +
> > +#define XUE_PAGE_SIZE 4096ULL
> 
> I think I had asked before - why this odd suffix?
> 
> > +static void xue_sys_pause(void)
> > +{
> > +    asm volatile("pause" ::: "memory");
> > +}
> 
> I wonder whether the open-coded inline assembly is really needed
> here: Can't you use cpu_relax()? If not, style nit: Several blanks
> missing.

Probably I can.

> > +static bool __init xue_init_xhc(struct xue *xue)
> > +{
> > +    uint32_t bar0;
> > +    uint64_t bar1;
> > +    uint64_t devfn;
> > +
> > +    /*
> > +     * Search PCI bus 0 for the xHC. All the host controllers supported so 
> > far
> > +     * are part of the chipset and are on bus 0.
> > +     */
> > +    for ( devfn = 0; devfn < 256; devfn++ )
> > +    {
> > +        pci_sbdf_t sbdf = PCI_SBDF(0, 0, devfn);
> > +        uint32_t hdr = pci_conf_read8(sbdf, PCI_HEADER_TYPE);
> > +
> > +        if ( hdr == 0 || hdr == 0x80 )
> > +        {
> > +            if ( (pci_conf_read32(sbdf, PCI_CLASS_REVISION) >> 8) == 
> > XUE_XHC_CLASSC )
> > +            {
> > +                xue->sbdf = sbdf;
> > +                break;
> > +            }
> > +        }
> > +    }
> > +
> > +    if ( !xue->sbdf.sbdf )
> > +    {
> > +        xue_error("Compatible xHC not found on bus 0\n");
> > +        return false;
> > +    }
> > +
> > +    /* ...we found it, so parse the BAR and map the registers */
> > +    bar0 = pci_conf_read32(xue->sbdf, PCI_BASE_ADDRESS_0);
> > +    bar1 = pci_conf_read32(xue->sbdf, PCI_BASE_ADDRESS_1);
> > +
> > +    /* IO BARs not allowed; BAR must be 64-bit */
> > +    if ( (bar0 & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_MEMORY 
> > ||
> > +         (bar0 & PCI_BASE_ADDRESS_MEM_TYPE_MASK) != 
> > PCI_BASE_ADDRESS_MEM_TYPE_64 )
> > +        return false;
> > +
> > +    pci_conf_write32(xue->sbdf, PCI_BASE_ADDRESS_0, 0xFFFFFFFF);
> > +    xue->xhc_mmio_size = ~(pci_conf_read32(xue->sbdf, PCI_BASE_ADDRESS_0) 
> > & 0xFFFFFFF0) + 1;
> > +    pci_conf_write32(xue->sbdf, PCI_BASE_ADDRESS_0, bar0);
> 
> Why is a 64-bit BAR required when you size only the low 32 bits?

xHCI spec says the first BAR is required to be 64-bit, so I'm checking
this assumption to handle just this one case. But then, the size is 64K
in practice (and xue_sys_map_xhc() checks for that), so just 32 bits are
enough. Anyway, I can add sizing the whole thing, for consistency.

> Also you need to disable memory decoding around this (and
> somewhere you also need to explicitly enable it, assuming here
> you would afterwards restore the original value of the command
> register). 

Actually, this is a good place to enable memory decoding.

> Further you're still open-coding
> PCI_BASE_ADDRESS_MEM_MASK here.
> 
> > +/**
> > + * The first register of the debug capability is found by traversing the
> > + * host controller's capability list (xcap) until a capability
> > + * with ID = 0xA is found. The xHCI capability list begins at address
> > + * mmio + (HCCPARAMS1[31:16] << 2)
> > + */
> > +static struct xue_dbc_reg *xue_find_dbc(struct xue *xue)
> > +{
> > +    uint32_t *xcap;
> > +    uint32_t next;
> > +    uint32_t id;
> > +    uint8_t *mmio = (uint8_t *)xue->xhc_mmio;
> > +    uint32_t *hccp1 = (uint32_t *)(mmio + 0x10);
> > +    const uint32_t DBC_ID = 0xA;
> > +
> > +    /**
> > +     * Paranoid check against a zero value. The spec mandates that
> > +     * at least one "supported protocol" capability must be implemented,
> > +     * so this should always be false.
> > +     */
> > +    if ( (*hccp1 & 0xFFFF0000) == 0 )
> > +        return NULL;
> > +
> > +    xcap = (uint32_t *)(mmio + (((*hccp1 & 0xFFFF0000) >> 16) << 2));
> 
> Why not either
> 
>     xcap = (uint32_t *)(mmio + ((*hccp1 >> 16) << 2));
> 
> or
> 
>     xcap = (uint32_t *)(mmio + ((*hccp1 & 0xFFFF0000) >> 14));
> 
> ?

Ok.

> > +    next = (*xcap & 0xFF00) >> 8;
> > +    id = *xcap & 0xFF;
> > +
> > +    /**
> > +     * Table 7-1 states that 'next' is relative to
> > +     * the current value of xcap and is a dword offset.
> > +     */
> > +    while ( id != DBC_ID && next ) {
> 
> Nit: Brace placement.
> 
> > +        xcap += next;
> > +        id = *xcap & 0xFF;
> > +        next = (*xcap & 0xFF00) >> 8;
> > +    }
> 
> Is this loop guaranteed to terminate? See drivers/pci/pci.c where
> circular chains are being dealt with in a similar situation.

Proper device shouldn't have circular chains here, but yes, adding
protection against this is a good idea.

> > +/* Initialize the DbC info with USB string descriptor addresses */
> > +static void xue_init_strings(struct xue *xue, uint32_t *info)
> > +{
> > +    uint64_t *sda;
> > +
> > +    /* clang-format off */
> 
> What's this?
> 
> > +    const char strings[] = {
> 
> static?
> 
> > +        6,  3, 9, 0, 4, 0,
> > +        8,  3, 'A', 0, 'I', 0, 'S', 0,
> > +        30, 3, 'X', 0, 'u', 0, 'e', 0, ' ', 0,
> > +               'D', 0, 'b', 0, 'C', 0, ' ', 0,
> > +               'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0,
> > +        4, 3, '0', 0
> > +    };
> > +    /* clang-format on */
> > +
> > +    memcpy(xue->dbc_str, strings, sizeof(strings));
> 
> Can't you simply assign to xue->dbc_str? I don't see this being used
> elsewhere, so it might even be possible to omit the field altogether
> (and with it the str_buf static variable consuming an entire page).

That is an option, but honestly (as you note below), there is a bit too
much magic here.

> > +    sda = (uint64_t *)&info[0];
> > +    sda[0] = virt_to_maddr(xue->dbc_str);
> > +    sda[1] = sda[0] + 6;
> > +    sda[2] = sda[0] + 6 + 8;
> > +    sda[3] = sda[0] + 6 + 8 + 30;
> > +    info[8] = (4 << 24) | (30 << 16) | (8 << 8) | 6;
> 
> Wow, magic numbers. And, apparently, some used several times.

I think I can make this whole string table init a bit clearer (at a
negligible higher runtime cost).

-- 
Best Regards,
Marek Marczykowski-Górecki
Invisible Things Lab

Attachment: signature.asc
Description: PGP signature


 


Rackspace

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