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

Re: [Xen-devel] [PATCH v3 07/18] x86/hvm: unify internal portio and mmio intercepts



>>> On 23.06.15 at 12:39, <paul.durrant@xxxxxxxxxx> wrote:
> The implementation of mmio and portio intercepts is unnecessarily different.
> This leads to much code duplication. This patch unifies much of the
> intercept handling, leaving only distinct handlers for stdvga mmio and dpci
> portio. Subsequent patches will unify those handlers.
> 
> Signed-off-by: Paul Durrant <paul.durrant@xxxxxxxxxx>
> Cc: Keir Fraser <keir@xxxxxxx>
> Cc: Jan Beulich <jbeulich@xxxxxxxx>
> Cc: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
> ---

Please help reviewers of previous versions of your patches by
summarizing changes in the current version here.

> +static int hvm_portio_read(struct hvm_io_handler *handler,
> +                           uint64_t addr,
> +                           uint64_t size,
> +                           uint64_t *data)
>  {
> -    struct vcpu *curr = current;
> -    unsigned int i;
> +    uint32_t val = 0;
> +    int rc;
>  
> -    for ( i = 0; i < HVM_MMIO_HANDLER_NR; ++i )
> -        if ( hvm_mmio_handlers[i]->check(curr, gpa) )
> -            return 1;
> +    BUG_ON(handler->type != IOREQ_TYPE_PIO);
>  
> -    return 0;
> +    rc = handler->u.portio.action(IOREQ_READ, addr, size, &val);
> +    if ( rc == X86EMUL_OKAY )
> +        *data = val;

I think there would be no harm doing this unconditionally, and it
would eliminate the potential of the caller using uninitialized data.

> @@ -284,29 +185,37 @@ static int process_portio_intercept(portio_action_t 
> action, ioreq_t *p)
>      {
>          for ( i = 0; i < p->count; i++ )
>          {
> -            data = 0;
> -            switch ( hvm_copy_from_guest_phys(&data, p->data + step * i,
> -                                              p->size) )
> +            if ( p->data_is_ptr )
>              {
> -            case HVMCOPY_okay:
> -                break;
> -            case HVMCOPY_gfn_paged_out:
> -            case HVMCOPY_gfn_shared:
> -                rc = X86EMUL_RETRY;
> -                break;
> -            case HVMCOPY_bad_gfn_to_mfn:
> -                data = ~0;
> -                break;
> -            case HVMCOPY_bad_gva_to_gfn:
> -                ASSERT(0);
> -                /* fall through */
> -            default:
> -                rc = X86EMUL_UNHANDLEABLE;
> -                break;
> +                switch ( hvm_copy_from_guest_phys(&data, p->data + step * i,
> +                                                  p->size) )
> +                {
> +                case HVMCOPY_okay:
> +                    break;
> +                case HVMCOPY_gfn_paged_out:
> +                case HVMCOPY_gfn_shared:
> +                    rc = X86EMUL_RETRY;
> +                    break;
> +                case HVMCOPY_bad_gfn_to_mfn:
> +                    data = ~0;
> +                    break;
> +                case HVMCOPY_bad_gva_to_gfn:
> +                    ASSERT_UNREACHABLE();
> +                    /* fall through */
> +                default:
> +                    rc = X86EMUL_UNHANDLEABLE;
> +                    break;
> +                }
> +                if ( rc != X86EMUL_OKAY )
> +                    break;
>              }
> -            if ( rc != X86EMUL_OKAY )
> -                break;
> -            rc = action(IOREQ_WRITE, p->addr, p->size, &data);
> +            else
> +                data = p->data;
> +
> +            addr = (p->type == IOREQ_TYPE_COPY) ?
> +                p->addr + step * i :
> +                p->addr;

Indentation.

> @@ -324,78 +233,133 @@ static int process_portio_intercept(portio_action_t 
> action, ioreq_t *p)
>      return rc;
>  }
>  
> -/*
> - * Check if the request is handled inside xen
> - * return value: 0 --not handled; 1 --handled
> - */
> -int hvm_io_intercept(ioreq_t *p, int type)
> +static struct hvm_io_handler *hvm_find_io_handler(ioreq_t *p)
> +{
> +    struct vcpu *curr = current;
> +    struct domain *curr_d = curr->domain;

"curr" is used only once (here) and hence pointless as a local variable.

> +    const struct hvm_io_ops *ops =
> +        (p->type == IOREQ_TYPE_COPY) ?
> +        &mmio_ops :
> +        &portio_ops;
> +    unsigned int i;
> +
> +    for ( i = 0; i < curr_d->arch.hvm_domain.io_handler_count; i++ )
> +    {
> +        struct hvm_io_handler *handler =
> +            &curr_d->arch.hvm_domain.io_handler[i];
> +        uint64_t start, end, count = p->count, size = p->size;

I'm not really happy with all these 64-bit local variables, but I
guess they are the result of you not wanting to do things the
way they're currently done everywhere... From a logical pov,
start and end would better be paddr_t, count and size
unsigned long.

> +        if ( handler->type != p->type )
> +            continue;
> +
> +        switch ( handler->type )
> +        {
> +        case IOREQ_TYPE_PIO:
> +            start = p->addr;
> +            end = p->addr + size;
> +            break;
> +        case IOREQ_TYPE_COPY:
> +            if ( p->df )
> +            {
> +                start = (p->addr - (count - 1) * size);
> +                end = p->addr + size;
> +            }
> +            else
> +            {
> +                start = p->addr;
> +                end = p->addr + count * size;
> +            }
> +            break;
> +        default:
> +            BUG();
> +        }

Doing this over and over again during each iteration looks kind of
wasteful.

> +static struct hvm_io_handler *hvm_next_io_handler(struct domain *d)
>  {
> -    struct hvm_io_handler *handler = d->arch.hvm_domain.io_handler;
> -    int num = handler->num_slot;
> +    unsigned int i = d->arch.hvm_domain.io_handler_count++;
>  
> -    BUG_ON(num >= MAX_IO_HANDLER);
> +    if (i == NR_IO_HANDLERS)

Codingy style.

> +        domain_crash(d);

return NULL;

(or else you, despite having checked, return a pointer to an out of
bounds slot to your caller)

> +void relocate_portio_handler(struct domain *d, uint32_t old_addr,
> +                             uint32_t new_addr, uint32_t size)
> +{
> +    ioreq_t p = {
> +        .type = IOREQ_TYPE_PIO,
> +        .addr = old_addr,
> +        .size = size
> +    };
> +    struct hvm_io_handler *handler = hvm_find_io_handler(&p);

This isn't quite the same as the original checking - there was an
exact match of size required.

> +struct hvm_io_handler {
> +    union {
> +        struct {
> +            const struct hvm_mmio_ops *ops;
> +        } mmio;
> +        struct {
> +            uint32_t        start, end;
> +            portio_action_t action;
> +        } portio;
> +    } u;

No need to name this union, this is not a public interface.

Jan

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


 


Rackspace

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