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

Re: [Xen-devel] [PATCH v4 1/9] xen/vpci: introduce basic handlers to trap accesses to the PCI config space



>>> On 14.07.17 at 17:33, <roger.pau@xxxxxxxxxx> wrote:
> On Thu, Jul 13, 2017 at 08:36:18AM -0600, Jan Beulich wrote:
>> >>> Roger Pau Monne <roger.pau@xxxxxxxxxx> 06/30/17 5:01 PM >>>
>> > +#define container_of(ptr, type, member) ({                      \
>> > +        typeof(((type *)0)->member) *__mptr = (ptr);            \
>> > +        (type *)((char *)__mptr - offsetof(type, member));      \
>> 
>> I don't know what tools maintainers think about such name space
>> violations; in hypervisor code I'd ask you to avoid leading underscores
>> in macro local variables (same in min()/max() and elsewhere then).
> 
> OK. container_of, max and min and verbatim copies of the macros in
> xen/include/xen/kernel.h, with the style adjusted in the container_of
> case IIRC (as requested in the previous review).

Well, that's one of the frequent problems we have: People copy and
paste things without questioning them. We only make things worse if
we clone code we wouldn't permit in anymore nowadays.

>> > +{
>> > +    unsigned int i;
>> > +
>> > +    /* Write using bytes. */
>> > +    for ( i = 0; i < 4; i++ )
>> > +        VPCI_WRITE_CHECK(reg + i, 1, (val >> (i * 8)) & UINT8_MAX);
>> > +    multiread4(reg, val);
>> > +
>> > +    /* Write using 2bytes. */
>> > +    for ( i = 0; i < 2; i++ )
>> > +        VPCI_WRITE_CHECK(reg + i * 2, 2, (val >> (i * 2 * 8)) & 
>> > UINT16_MAX);
>> > +    multiread4(reg, val);
>> > +
>> > +    VPCI_WRITE_CHECK(reg, 4, val);
>> > +    multiread4(reg, val);
>> > +}
>> 
>> Wouldn't it be better to vary the value written between the individual
>> sizes? Perhaps move the 32-bit write between the two loops, using ~val?
>> Otherwise you won't know whether what you read back is a result of the
>> writes you actually mean to test or earlier ones?
> 
> So storing a new value in val between each size test? I could even use
> something randomly generated.

Random data is bad for reproducibility (if e.g. you want to debug a
case where the test suddenly fails).

>> > +    /*
>> > +     * Test all possible read/write size combinations.
>> > +     *
>> > +     * Populate 128bits (16B) with 1B registers, 160bits (20B) with 2B
>> > +     * registers, and finally 192bits (24B) with 4B registers.
>> 
>> I can't see how the numbers here are in line with the code this is
>> meant to describe. Perhaps this is a leftover from an earlier variant
>> of the code?
> 
> I'm not sure I understand this, the registers (or layout) described in
> this comment are just added below the comment. Would you like me to
> first add the registers and place the comment afterwards?

No, my point is that code that follows this doesn't populate as
many bits as the comment says. From what I understand, you
use 4 byte registers, 2 word ones, and one dword one.

>> > --- a/xen/arch/arm/xen.lds.S
>> > +++ b/xen/arch/arm/xen.lds.S
>> > @@ -41,6 +41,9 @@ SECTIONS
>> >  
>> >    . = ALIGN(PAGE_SIZE);
>> >    .rodata : {
>> > +       __start_vpci_array = .;
>> > +       *(.rodata.vpci)
>> > +       __end_vpci_array = .;
>> 
>> Do you really need this (unconditionally)?
> 
> Right, this should have a ifdef CONFIG_PCI.

CONFIG_HAS_PCI for one, and then ARM doesn't select this at
all. Hence the question.

>> > +static int vpci_access_check(unsigned int reg, unsigned int len)
>> 
>> The way you use it, this function want to return bool.
>> 
>> > +void hvm_pci_decode_addr(unsigned int cf8, unsigned int addr,
>> > +                         unsigned int *bus, unsigned int *slot,
>> > +                         unsigned int *func, unsigned int *reg)
>> 
>> Since you return nothing right now, how about avoid one of the
>> indirections? Best candidate would probably be the register value.
> 
> I don't really like functions that return some data in the return
> value (if it's not an error code) and some other data in parameters.

Well, okay, I view it the other way around - return by indirection
is to be used if return by value is not reasonable (too much data).
Hence it's kind of an overflow to me, not a replacement.

>> > +int __hwdom_init vpci_add_handlers(struct pci_dev *pdev)
>> 
>> As pointed out in reply to an earlier version, this lacks a prereq
>> change: setup_one_hwdom_device() needs to be marked __hwdom_init. And
>> then, now that you have the annotation here, the placement of the
>> array in the linker script should depend on whether __hwdom_init is an
>> alias of __init.
> 
> The __hwdom_init prefix is dropped shortly from this function (patch
> #3), but I agree on sending a pre-patch to address
> setup_one_hwdom_device.

I have one ready, btw.

> The linker script I'm not sure it's worth modifying, by the end of the
> series the list of handlers must reside in .rodata.

As per the reply to that later patch, I'm not yet convinced that
these annotations will go away. Hence I'd prefer if things were
handled fully correctly here.

>> > +static uint32_t vpci_read_hw(unsigned int seg, unsigned int bus,
>> > +                             unsigned int slot, unsigned int func,
>> > +                             unsigned int reg, uint32_t size)
>> > +{
>> > +    uint32_t data;
>> > +
>> > +    switch ( size )
>> > +    {
>> > +    case 4:
>> > +        data = pci_conf_read32(seg, bus, slot, func, reg);
>> > +        break;
>> > +    case 2:
>> > +        data = pci_conf_read16(seg, bus, slot, func, reg);
>> > +        break;
>> > +    case 1:
>> > +        data = pci_conf_read8(seg, bus, slot, func, reg);
>> > +        break;
>> > +    default:
>> > +        BUG();
>> 
>> As long as this is Dom0-only, BUG()s like this are probably fine, but
>> if this ever gets extended to DomU-s, will we really remember to
>> convert them?
> 
> ASSERT_UNREACHABLE() and set data to ~0 to be safe?

Yes please.

>> > +     */
>> > +    data = vpci_read_hw(seg, bus, slot, func, reg, size);
>> 
>> I continue to be worried of reads that have side effects here. Granted
>> we currently don't emulate any, but it would feel better if we didn't
>> do the read for no reason. I.e. do hw reads only to fill gaps between
>> emulated fields.
> 
> Heh, right. I got this "idea" from pciback, but I will change it so
> the logic is similar to the write one (which obviously doesn't write
> everything and then checks for emulated registers).
> 
> As a side question, which kind of registers have read side effects on
> PCI? Reading the spec (PCIe 3.1A) there's no type of register listed
> in section 7.4 (ro, rw, rw1c and the sticky versions) that mentions
> read side effects. Is that described somewhere for specific
> registers?

I don't think there are any specified, but iirc a well known side effect
of VPD reads from some cards is that it'll hang the box for certain
(normally invalid) indexes. As said, we don't emulate anything like
that, but let's be defensive wrt hardware quirks.

>> > +int __must_check vpci_add_register(const struct pci_dev *pdev,
>> > +                                   vpci_read_t read_handler,
>> > +                                   vpci_write_t write_handler,
>> 
>> I'm surprised this compiles without (at least) warnings - you appear to
>> be lacking *s here.
> 
> I think in the previous version the type itself had a pointer, and
> then I removed it and haven't updated it here. But yes, none of the
> compilers seems to complain:
> 
> https://travis-ci.org/royger/xen/builds/248811315 
> 
> Is it maybe implicit that function types are pointers?

Well, maybe I'm wrong with my assumption that this formally is
illegal.

Jan

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel

 


Rackspace

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