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

Re: [Xen-devel] [PATCH 2/4] x86/pv: Introduce pv_create_exception_frame()



>>> On 08.05.17 at 17:48, <andrew.cooper3@xxxxxxxxxx> wrote:
> +void pv_create_exception_frame(void)
> +{
> +    struct vcpu *curr = current;
> +    struct trap_bounce *tb = &curr->arch.pv_vcpu.trap_bounce;

const (twice)?

> +    struct cpu_user_regs *regs = guest_cpu_user_regs();
> +    const bool user_mode_frame = !guest_kernel_mode(curr, regs);
> +    uint8_t *evt_mask = &vcpu_info(curr, evtchn_upcall_mask);
> +    unsigned long rflags;

Does this really need to be "long"?

> +    unsigned int bytes, missing;
> +
> +    ASSERT_NOT_IN_ATOMIC();
> +
> +    if ( unlikely(null_trap_bounce(curr, tb)) )
> +    {
> +        gprintk(XENLOG_ERR, "Fatal: Attempting to inject null trap 
> bounce\n");
> +        __domain_crash_synchronous();

Why not domain_crash() followed by "return"?

> +    }
> +
> +    /* Fold the upcall mask and architectural IOPL into the guests rflags. */
> +    rflags  = regs->rflags & ~(X86_EFLAGS_IF | X86_EFLAGS_IOPL);
> +    rflags |= ((*evt_mask ? 0 : X86_EFLAGS_IF) |
> +               (VM_ASSIST(curr->domain, architectural_iopl)
> +                ? curr->arch.pv_vcpu.iopl : 0));
> +
> +    if ( is_pv_32bit_vcpu(curr) )
> +    {
> +        /* { [ERRCODE,] EIP, CS/MASK , EFLAGS, [ESP, SS] } */
> +        unsigned int frame[6], *ptr = frame, ksp =
> +            (user_mode_frame ? curr->arch.pv_vcpu.kernel_sp : regs->esp);
> +
> +        if ( tb->flags & TBF_EXCEPTION_ERRCODE )
> +            *ptr++ = tb->error_code;
> +
> +        *ptr++ = regs->eip;
> +        *ptr++ = regs->cs | (((unsigned int)*evt_mask) << 16);

Do you really need the cast here? In no case is there a need for the
parentheses around the cast expression.

> +        *ptr++ = rflags;
> +
> +        if ( user_mode_frame )
> +        {
> +            *ptr++ = regs->esp;
> +            *ptr++ = regs->ss;
> +        }
> +
> +        /* Copy the constructed frame to the guest kernel stack. */
> +        bytes = _p(ptr) - _p(frame);
> +        ksp -= bytes;
> +
> +        if ( unlikely((missing = __copy_to_user(_p(ksp), frame, bytes)) != 
> 0) )

While I don't think we need to be really bothered, it's perhaps still
worth noting in a comment that the wrapping behavior here is
wrong (and slightly worse than the assembly original), due to
(implicit) address arithmetic all being done with 64-bit operands.

> +        {
> +            gprintk(XENLOG_ERR, "Fatal: Fault while writing exception 
> frame\n");
> +            show_page_walk(ksp + missing);
> +            __domain_crash_synchronous();
> +        }
> +
> +        /* Rewrite our stack frame. */
> +        regs->rip           = (uint32_t)tb->eip;
> +        regs->cs            = tb->cs;
> +        regs->eflags       &= ~(X86_EFLAGS_VM | X86_EFLAGS_RF |
> +                                X86_EFLAGS_NT | X86_EFLAGS_TF);

You write ->rip above and ->rsp below - preferably those would
become ->eip and ->esp, but alternatively (for consistency) this
may want switching to ->rflags.

> +        regs->rsp           = ksp;
> +        if ( user_mode_frame )
> +            regs->ss = curr->arch.pv_vcpu.kernel_ss;
> +    }
> +    else
> +    {
> +        /* { RCX, R11, [ERRCODE,] RIP, CS/MASK, RFLAGS, RSP, SS } */
> +        unsigned long frame[7], *ptr = frame, ksp =

I clearly count 8 elements in the comment.

> +            (user_mode_frame ? curr->arch.pv_vcpu.kernel_sp : regs->rsp) & 
> ~0xf;
> +
> +        if ( user_mode_frame )
> +            toggle_guest_mode(curr);
> +
> +        *ptr++ = regs->rcx;
> +        *ptr++ = regs->r11;
> +
> +        if ( tb->flags & TBF_EXCEPTION_ERRCODE )
> +            *ptr++ = tb->error_code;
> +
> +        *ptr++ = regs->rip;
> +        *ptr++ = (user_mode_frame ? regs->cs : regs->cs & ~3) |
> +            ((unsigned long)(*evt_mask) << 32);

Stray parentheses again.

> +        *ptr++ = rflags;
> +        *ptr++ = regs->rsp;
> +        *ptr++ = regs->ss;
> +
> +        /* Copy the constructed frame to the guest kernel stack. */
> +        bytes = _p(ptr) - _p(frame);
> +        ksp -= bytes;
> +
> +        if ( unlikely(!__addr_ok(ksp)) )
> +        {
> +            gprintk(XENLOG_ERR, "Fatal: Bad guest kernel stack %p\n", 
> _p(ksp));
> +            __domain_crash_synchronous();
> +        }
> +        else if ( unlikely((missing =
> +                            __copy_to_user(_p(ksp), frame, bytes)) != 0) )
> +        {
> +            gprintk(XENLOG_ERR, "Fatal: Fault while writing exception 
> frame\n");
> +            show_page_walk(ksp + missing);
> +            __domain_crash_synchronous();
> +        }
> +
> +        /* Rewrite our stack frame. */
> +        regs->entry_vector |= TRAP_syscall;
> +        regs->rip           = tb->eip;
> +        regs->cs            = FLAT_KERNEL_CS;
> +        regs->rflags       &= ~(X86_EFLAGS_AC | X86_EFLAGS_VM | 
> X86_EFLAGS_RF |
> +                                X86_EFLAGS_NT | X86_EFLAGS_TF);
> +        regs->rsp           = ksp;
> +        regs->ss            = FLAT_KERNEL_SS;
> +    }
> +
> +    /* Mask events if requested. */
> +    if ( tb->flags & TBF_INTERRUPT )
> +        *evt_mask = 1;
> +
> +    /*
> +     * Clobber the injection information now it has been completed.  Buggy
> +     * attempts to inject the same event twice will hit the 
> null_trap_bounce()
> +     * check above.
> +     */
> +    *tb = (struct trap_bounce){};

Ah, so that prevents tb becoming a pointer to const. I wonder
though whether, on a rather hot path, we really want to zap the
entire structure here. As I can see the value in satisfying
null_trap_bounce(), how about zapping just ->eip / ->cs on the
split paths above?

Overall, did you compare generated code with the current
assembly implementation? That one surely would have had some
room for improvement, so the result here at least shouldn't be
worse than that.

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®.