xen-devel.lists.xenproject.org archive mirror
 help / color / mirror / Atom feed
From: Tamas K Lengyel <tamas.lengyel@zentific.com>
To: Tim Deegan <tim@xen.org>
Cc: Ian Campbell <ian.campbell@citrix.com>,
	Julien Grall <julien.grall@linaro.org>,
	Ian Jackson <ian.jackson@eu.citrix.com>,
	"xen-devel@lists.xen.org" <xen-devel@lists.xen.org>,
	Stefano Stabellini <stefano.stabellini@citrix.com>,
	Andres Lagar-Cavilla <andres@lagarcavilla.org>,
	Jan Beulich <jbeulich@suse.com>,
	Daniel De Graaf <dgdegra@tycho.nsa.gov>,
	Tamas K Lengyel <tklengyel@sec.in.tum.de>
Subject: Re: [PATCH for-4.5 v7 07/21] xen: Relocate p2m_mem_access_check into common and refactor it.
Date: Thu, 18 Sep 2014 12:47:19 +0200	[thread overview]
Message-ID: <CAErYnsgj8jid5E8_WK-c-WRAnxBSbEdhbmwCL9_Nkpc8jjYWGA@mail.gmail.com> (raw)
In-Reply-To: <20140918103908.GC65000@deinos.phlegethon.org>


[-- Attachment #1.1: Type: text/plain, Size: 8135 bytes --]

On Thu, Sep 18, 2014 at 12:39 PM, Tim Deegan <tim@xen.org> wrote:

> Hi,
>
> Thanks for the patch.  Tidying this up is a great idea but I'm afraid
> it can't be done quite this way.
>
> At 22:51 +0200 on 17 Sep (1410990670), Tamas K Lengyel wrote:
> > The p2m_mem_access_check was used only to automatically promote the
> > special-case mem_access rights and to allocate the mem_access message.
> > In this patch we abstract the violation check into a common
> mem_access_check
> > function and change its return value to int.
> >
> > Return with rc < 0 means the fault wasn't triggered by mem_access
> permissions.
> > Return with rc == 0 it was but rights were not automatically promoted.
> > Return with rc > 0 means mem_access rights had been automatically
> promoted.
> >
> > As part of this patch, we relocate the x86/mm/mm-locks.h header into asm
> > as to be able to create a generic inlined p2m_gpfn_lock/unlock wrapper
> > that each arch can define based on its locking scheme.
>
> I'm afraid not.  mm-locks.h is hidden away in arch/x86/mm
> deliberately, to stop p2m internals from leaking out into the rest of
> the code and making it harder to reason about.  So the fact that you
> had to move it suggests that we need to think about using cleaner
> interfaces between the code you're extracting and the rest of the p2m
> code...
>
> > +int mem_access_check(paddr_t gpa, unsigned long gla, struct npfec npfec)
> > +{
> > +    bool_t violation;
> > +    mfn_t mfn;
> > +    p2m_access_t p2ma;
> > +    p2m_type_t p2mt;
> > +    mem_event_request_t *req;
> > +    int rc;
> > +    struct vcpu *v = current;
> > +    unsigned long gfn = gpa >> PAGE_SHIFT;
> > +    struct domain *d = v->domain;
> > +    struct p2m_domain* p2m = p2m_get_hostp2m(d);
> > +
> > +    /* First, handle rx2rw conversion automatically.
> > +     * These calls to p2m->set_entry() must succeed: we have the gfn
> > +     * locked and just did a successful get_entry(). */
> > +    p2m_gpfn_lock(p2m, gfn);
> > +    mfn = p2m->get_entry(p2m, gfn, &p2mt, &p2ma, 0, NULL);
>
> Neither of these (direct access to a p2m lock or direct call of a p2m
> function pointer) should happen outside the p2m code.
>
> From an outside caller you _could_ use get_gfn_type_access(p2m, gfn,
> &p2mt, &p2ma, 0, NULL) instead (and put_gfn() instead of
> p2m_gpfn_unlock()).  But directly calling p2m->set_entry() (or
> p2m_set_entry()) is still not OK.
>
> I think it would be better to leave an arch-specific
> "bool_t p2m_mem_access_check(p2m, gfn, npfec, &p2ma)" that does the
> lookup and the automatic promotions and returns the access type.  It
> should also do the check for missing listeners and automatically reset
> p2m entries (i.e. the second call to ->set_entry() below).  Then this
> function won't need to take any locks or get_gfn calls at all -- it
> will just have the check for non-vioating faults, the call to
> p2m_mem_access_check() that might ajdust entries, and the code to
> prepare a req.
>
> > +
> > +    /* Check if the access is against the permissions. */
> > +    switch ( p2ma )
> > +    {
> > +    case p2m_access_rwx:
> > +        violation = 0;
> > +        break;
> > +    case p2m_access_rw:
> > +        violation = npfec.insn_fetch;
> > +        break;
> > +    case p2m_access_wx:
> > +        violation = npfec.read_access;
> > +        break;
> > +    case p2m_access_rx:
> > +    case p2m_access_rx2rw:
> > +        violation = npfec.write_access;
> > +        break;
> > +    case p2m_access_x:
> > +        violation = npfec.read_access || npfec.write_access;
> > +        break;
> > +    case p2m_access_w:
> > +        violation = npfec.read_access || npfec.insn_fetch;
> > +        break;
> > +    case p2m_access_r:
> > +        violation = npfec.write_access || npfec.insn_fetch;
> > +        break;
> > +    case p2m_access_n:
> > +    case p2m_access_n2rwx:
> > +    default:
> > +        violation = npfec.read_access || npfec.write_access ||
> npfec.insn_fetch;
> > +        break;
> > +    }
>
> In any case this block, which doesn't depend on the p2m contents at
> all, should happen before any locks or lookups.  That way you can
> avoid taking the locks at all for non-violating faults (as the
> original code does).
>
> > +    /* If no violation is found here, it needs to be reinjected. */
> > +    if ( !violation )
> > +    {
> > +        p2m_gpfn_unlock(p2m, gfn);
> > +        return -EFAULT;
> > +    }
> > +
> > +    /* Check for automatic setting promotion. */
> > +    if ( npfec.write_access && p2ma == p2m_access_rx2rw )
> > +    {
> > +        rc = p2m->set_entry(p2m, gfn, mfn, PAGE_ORDER_4K, p2mt,
> p2m_access_rw);
> > +        ASSERT(rc == 0);
> > +        p2m_gpfn_unlock(p2m, gfn);
> > +        return 1;
> > +    }
> > +    else if ( p2ma == p2m_access_n2rwx )
> > +    {
> > +        ASSERT(npfec.write_access || npfec.read_access ||
> npfec.insn_fetch);
> > +        rc = p2m->set_entry(p2m, gfn, mfn, PAGE_ORDER_4K,
> > +                            p2mt, p2m_access_rwx);
> > +        ASSERT(rc == 0);
> > +    }
> > +    p2m_gpfn_unlock(p2m, gfn);
> > +
> > +    /* Otherwise, check if there is a memory event listener, and send
> the message along */
> > +    if ( !mem_event_check_ring(&d->mem_event->access) )
> > +    {
> > +        /* No listener */
> > +        if ( p2m->access_required )
> > +        {
> > +            gdprintk(XENLOG_INFO, "Memory access permissions failure, "
> > +                                  "no mem_event listener VCPU %d, dom
> %d\n",
> > +                                  v->vcpu_id, d->domain_id);
> > +            domain_crash(v->domain);
> > +            return -EFAULT;
> > +        }
> > +        else
> > +        {
> > +            p2m_gpfn_lock(p2m, gfn);
> > +            mfn = p2m->get_entry(p2m, gfn, &p2mt, &p2ma, 0, NULL);
> > +            if ( p2ma != p2m_access_n2rwx )
> > +
> > +            {
> > +                /* A listener is not required, so clear the access
> > +                 * restrictions.  This set must succeed: we have the
> > +                 * gfn locked and just did a successful get_entry(). */
> > +                rc = p2m->set_entry(p2m, gfn, mfn, PAGE_ORDER_4K,
> > +                                    p2mt, p2m_access_rwx);
> > +                ASSERT(rc == 0);
> > +            }
> > +            p2m_gpfn_unlock(p2m, gfn);
> > +            return 1;
> > +        }
> > +    }
> > +
> > +    req = xzalloc(mem_event_request_t);
> > +    if ( req )
> > +    {
> > +        req->reason = MEM_EVENT_REASON_VIOLATION;
> > +
> > +        /* Pause the current VCPU */
> > +        if ( p2ma != p2m_access_n2rwx )
> > +            req->flags |= MEM_EVENT_FLAG_VCPU_PAUSED;
> > +
> > +        /* Send request to mem event */
> > +        req->gfn = gfn;
> > +        req->offset = gpa & ((1 << PAGE_SHIFT) - 1);
> > +        req->gla_valid = npfec.gla_valid;
> > +        req->gla = gla;
> > +        if ( npfec.kind == npfec_kind_with_gla )
> > +            req->fault_with_gla = 1;
> > +        else if ( npfec.kind == npfec_kind_in_gpt )
> > +            req->fault_in_gpt = 1;
> > +        req->access_r = npfec.read_access;
> > +        req->access_w = npfec.write_access;
> > +        req->access_x = npfec.insn_fetch;
> > +        req->vcpu_id = v->vcpu_id;
> > +
> > +        mem_access_send_req(v->domain, req);
>
> The original function returned the req for the caller to send, and the
> caller delayed sending it until the end of hvm_hap_nested_page_fault(),
> when the last locks are dropped.  You need to keep this behaviour or
> the system can deadlock.
>
> I wonder whether we could add an ASSERT_NOT_IN_ATOMIC() at the top of
> mem_event_wait_slot() to make this kind of thing easier to spot.  At
> the moment it will only fail if it actually has to wait.
>
> Cheers,
>
> Tim.
>

Ack. I think I'll drop this patch for the time being as the refactoring
work required for it to be in common mem_access is quite significant, both
in the x86 and the ARM side. And it would only result in a bit of
code-deduplication. We could pick-it up later if there is a need for it /
value in it.

Thanks,
Tamas

[-- Attachment #1.2: Type: text/html, Size: 9785 bytes --]

[-- Attachment #2: Type: text/plain, Size: 126 bytes --]

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

  reply	other threads:[~2014-09-18 10:47 UTC|newest]

Thread overview: 46+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-09-17 20:51 [PATCH for-4.5 v7 00/21] Mem_event and mem_access for ARM Tamas K Lengyel
2014-09-17 20:51 ` [PATCH for-4.5 v7 01/21] xen: Relocate mem_access and mem_event into common Tamas K Lengyel
2014-09-17 20:51 ` [PATCH for-4.5 v7 02/21] xen: Relocate struct npfec definition " Tamas K Lengyel
2014-09-17 20:51 ` [PATCH for-4.5 v7 03/21] xen: Relocate mem_event_op domctl and access_op memop " Tamas K Lengyel
2014-09-17 20:51 ` [PATCH for-4.5 v7 04/21] xen: Relocate set_access_required domctl " Tamas K Lengyel
2014-09-18  9:18   ` Jan Beulich
2014-09-18 10:36     ` Tamas K Lengyel
2014-09-18 10:37       ` Tamas K Lengyel
2014-09-18 11:17         ` Tim Deegan
2014-09-18 11:21           ` Tamas K Lengyel
2014-09-18 12:34         ` Jan Beulich
2014-09-18 13:02           ` Tamas K Lengyel
2014-09-17 20:51 ` [PATCH for-4.5 v7 05/21] xen: Relocate p2m_access_t into common and swap the order Tamas K Lengyel
2014-09-18  9:22   ` Jan Beulich
2014-09-18 10:52     ` Tamas K Lengyel
2014-09-17 20:51 ` [PATCH for-4.5 v7 06/21] xen: Relocate p2m_mem_access_resume to mem_access common Tamas K Lengyel
2014-09-17 20:51 ` [PATCH for-4.5 v7 07/21] xen: Relocate p2m_mem_access_check into common and refactor it Tamas K Lengyel
2014-09-18  9:28   ` Jan Beulich
2014-09-18 10:39   ` Tim Deegan
2014-09-18 10:47     ` Tamas K Lengyel [this message]
2014-09-18 11:13       ` Tim Deegan
2014-09-22 12:08       ` Ian Campbell
2014-09-17 20:51 ` [PATCH for-4.5 v7 08/21] x86/p2m: Typo fix for spelling ambiguous Tamas K Lengyel
2014-09-17 20:51 ` [PATCH for-4.5 v7 09/21] x86/p2m: Fix conversion macro of p2m_access to XENMEM_access Tamas K Lengyel
2014-09-18  9:35   ` Jan Beulich
2014-09-18  9:41     ` Tamas K Lengyel
2014-09-17 20:51 ` [PATCH for-4.5 v7 10/21] xen/mem_event: Clean out superfluous white-spaces Tamas K Lengyel
2014-09-17 20:51 ` [PATCH for-4.5 v7 11/21] xen/mem_event: Relax error condition on debug builds Tamas K Lengyel
2014-09-17 20:51 ` [PATCH for-4.5 v7 12/21] xen/mem_event: Abstract architecture specific sanity checks Tamas K Lengyel
2014-09-17 20:51 ` [PATCH for-4.5 v7 13/21] xen/mem_access: Abstract architecture specific sanity check Tamas K Lengyel
2014-09-17 20:51 ` [PATCH for-4.5 v7 14/21] xen/arm: p2m changes for mem_access support Tamas K Lengyel
2014-09-22 12:20   ` Ian Campbell
2014-09-22 17:16     ` Tamas K Lengyel
2014-09-17 20:51 ` [PATCH for-4.5 v7 15/21] xen/arm: Implement domain_get_maximum_gpfn Tamas K Lengyel
2014-09-17 20:51 ` [PATCH for-4.5 v7 16/21] xen/arm: Add p2m_set_permission and p2m_shatter_page helpers Tamas K Lengyel
2014-09-22 12:24   ` Ian Campbell
2014-09-22 18:24     ` Tamas K Lengyel
2014-09-17 20:51 ` [PATCH for-4.5 v7 17/21] xen/arm: Data abort exception (R/W) mem_events Tamas K Lengyel
2014-09-17 20:51 ` [PATCH for-4.5 v7 18/21] xen/arm: Instruction prefetch abort (X) mem_event handling Tamas K Lengyel
2014-09-17 20:51 ` [PATCH for-4.5 v7 19/21] xen/arm: Enable the compilation of mem_access and mem_event on ARM Tamas K Lengyel
2014-09-17 20:51 ` [PATCH for-4.5 v7 20/21] tools/libxc: Allocate magic page for mem access " Tamas K Lengyel
2014-09-17 20:51 ` [PATCH for-4.5 v7 21/21] tools/tests: Enable xen-access " Tamas K Lengyel
2014-09-22 12:29   ` Ian Campbell
2014-09-22 17:11     ` Tamas K Lengyel
2014-09-23  8:37       ` Ian Campbell
2014-09-18  9:21 ` [PATCH for-4.5 v7 00/21] Mem_event and mem_access for ARM Tim Deegan

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CAErYnsgj8jid5E8_WK-c-WRAnxBSbEdhbmwCL9_Nkpc8jjYWGA@mail.gmail.com \
    --to=tamas.lengyel@zentific.com \
    --cc=andres@lagarcavilla.org \
    --cc=dgdegra@tycho.nsa.gov \
    --cc=ian.campbell@citrix.com \
    --cc=ian.jackson@eu.citrix.com \
    --cc=jbeulich@suse.com \
    --cc=julien.grall@linaro.org \
    --cc=stefano.stabellini@citrix.com \
    --cc=tim@xen.org \
    --cc=tklengyel@sec.in.tum.de \
    --cc=xen-devel@lists.xen.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).