xen-devel.lists.xenproject.org archive mirror
 help / color / mirror / Atom feed
From: Sergej Proskurin <proskurin@sec.in.tum.de>
To: xen-devel@lists.xenproject.org
Cc: Sergej Proskurin <proskurin@sec.in.tum.de>,
	Julien Grall <julien.grall@arm.com>,
	Stefano Stabellini <sstabellini@kernel.org>
Subject: [PATCH 6/8] arm/mem_access: Add long-descriptor based gpt
Date: Thu,  1 Jun 2017 17:19:04 +0200	[thread overview]
Message-ID: <20170601151906.10213-15-proskurin@sec.in.tum.de> (raw)
In-Reply-To: <20170601151906.10213-1-proskurin@sec.in.tum.de>

This commit adds functionality to walk the guest's page tables using the
long-descriptor translation table format for both ARMv7 and ARMv8.
Similar to the hardware architecture, the implementation supports
different page granularities (4K, 16K, and 64K). The implementation is
based on ARM DDI 0487A-g J11-5608, J11-5679, and ARM DDI 0406C-b
B3-1510.

Note that the current implementation lacks support for 32-bit EL0
running on top of 64-bit EL1. The associated location in the code is
marked appropriately.

Signed-off-by: Sergej Proskurin <proskurin@sec.in.tum.de>
---
Cc: Stefano Stabellini <sstabellini@kernel.org>
Cc: Julien Grall <julien.grall@arm.com>
---
v2: Use TCR_SZ_MASK instead of TTBCR_SZ_MASK for ARM 32-bit guests using
    the long-descriptor translation table format.

    Cosmetic fixes.
---
 xen/arch/arm/p2m.c | 271 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 269 insertions(+), 2 deletions(-)

diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c
index 0337d83581..ea3be6f050 100644
--- a/xen/arch/arm/p2m.c
+++ b/xen/arch/arm/p2m.c
@@ -1573,8 +1573,275 @@ static int __p2m_walk_gpt_ld(struct p2m_domain *p2m,
                              vaddr_t gva, paddr_t *ipa,
                              unsigned int *perm_ro)
 {
-    /* Not implemented yet. */
-    return -EFAULT;
+    int t0_sz, t1_sz, disabled = 1;
+    unsigned int level, gran;
+    unsigned int topbit = 0, input_size = 0, output_size;
+    uint64_t ttbr = 0, ips;
+    paddr_t mask;
+    lpae_t pte, *table;
+    struct page_info *page;
+    register_t tcr = READ_SYSREG(TCR_EL1);
+    struct domain *d = p2m->domain;
+
+    const vaddr_t offsets[4][3] = {
+        {
+#ifdef CONFIG_ARM_64
+            zeroeth_guest_table_offset_4k(gva),
+            zeroeth_guest_table_offset_16k(gva),
+            0, /* There is no zeroeth lookup level with a 64K granule size. */
+#endif
+        },
+        {
+            first_guest_table_offset_4k(gva),
+#ifdef CONFIG_ARM_64
+            first_guest_table_offset_16k(gva),
+            first_guest_table_offset_64k(gva),
+#endif
+        },
+        {
+            second_guest_table_offset_4k(gva),
+#ifdef CONFIG_ARM_64
+            second_guest_table_offset_16k(gva),
+            second_guest_table_offset_64k(gva),
+#endif
+        },
+        {
+            third_guest_table_offset_4k(gva),
+#ifdef CONFIG_ARM_64
+            third_guest_table_offset_16k(gva),
+            third_guest_table_offset_64k(gva),
+#endif
+        }
+    };
+
+    const paddr_t masks[4][3] = {
+        {
+            ZEROETH_SIZE_4K - 1,
+            ZEROETH_SIZE_16K - 1,
+            0 /* There is no zeroeth lookup level with a 64K granule size. */
+        },
+        {
+            FIRST_SIZE_4K - 1,
+            FIRST_SIZE_16K - 1,
+            FIRST_SIZE_64K - 1
+        },
+        {
+            SECOND_SIZE_4K - 1,
+            SECOND_SIZE_16K - 1,
+            SECOND_SIZE_64K - 1
+        },
+        {
+            THIRD_SIZE_4K - 1,
+            THIRD_SIZE_16K - 1,
+            THIRD_SIZE_64K - 1
+        }
+    };
+
+    const unsigned int grainsizes[3] = {
+        PAGE_SHIFT_4K,
+        PAGE_SHIFT_16K,
+        PAGE_SHIFT_64K
+    };
+
+    const unsigned int strides[3] = {
+        LPAE_SHIFT_4K,
+        LPAE_SHIFT_16K,
+        LPAE_SHIFT_64K
+    };
+
+    t0_sz = (tcr >> TCR_T0SZ_SHIFT) & TCR_SZ_MASK;
+    t1_sz = (tcr >> TCR_T1SZ_SHIFT) & TCR_SZ_MASK;
+
+    /*
+     * Get the MSB number of the gva, according to "AddrTop" pseudocode
+     * implementation in ARM DDI 0487A-g J11-5739.
+     *
+     * XXX: We do not check whether the 64bit domain uses a 32-bit EL0. In this
+     * case, we need to set topbit to 31, as well.
+     */
+    if ( is_32bit_domain(d) )
+        topbit = TCR_TB_31;
+#ifdef CONFIG_ARM_64
+    else if ( is_64bit_domain(d) )
+    {
+        if ( ((gva & (1UL << TCR_TB_55)) && (tcr & TCR_TBI1)) ||
+             (!(gva & (1UL << TCR_TB_55)) && (tcr & TCR_TBI0)) )
+            topbit = TCR_TB_55;
+        else
+            topbit = TCR_TB_63;
+    }
+#endif
+
+#ifdef CONFIG_ARM_64
+    if ( is_64bit_domain(d) )
+    {
+        if ( (gva & (1UL << topbit)) == 0 )
+        {
+            input_size = REGISTER_WIDTH_64_BIT - t0_sz;
+
+            if ( input_size > IPS_MAX )
+                /* We limit the input_size to be max 48 bit. */
+                input_size = IPS_MAX;
+            else if ( input_size < IPS_MIN )
+                /* We limit the input_size to be max 25 bit. */
+                input_size = IPS_MIN;
+
+            /* Normalize granule size. */
+            switch ( tcr & TCR_TG0_MASK ) {
+            case TCR_TG0_16K:
+                gran = 1;
+                break;
+            case TCR_TG0_64K:
+                gran = 2;
+                break;
+            default:
+                gran = 0;
+            }
+
+            /* Use TTBR0 for GVA to IPA translation. */
+            ttbr = READ_SYSREG64(TTBR0_EL1);
+
+            /* If TCR.EPD0 is set, translations using TTBR0 are disabled. */
+            disabled = ( tcr & TCR_EPD0 ) ? 1 : 0;
+        }
+        else
+        {
+            input_size = REGISTER_WIDTH_64_BIT - t1_sz;
+
+            if ( input_size > IPS_MAX )
+                /* We limit the input_size to be max 48 bit. */
+                input_size = IPS_MAX;
+            else if ( input_size < IPS_MIN )
+                /* We limit the input_size to be max 25 bit. */
+                input_size = IPS_MIN;
+
+            /* Normalize granule size. */
+            switch ( tcr & TCR_TG1_MASK ) {
+            case TCR_TG1_16K:
+                gran = 1;
+                break;
+            case TCR_TG1_64K:
+                gran = 2;
+                break;
+            default:
+                gran = 0;
+            }
+
+            /* Use TTBR1 for GVA to IPA translation. */
+            ttbr = READ_SYSREG64(TTBR1_EL1);
+
+            /* If TCR.EPD1 is set, translations using TTBR1 are disabled. */
+            disabled = ( tcr & TCR_EPD1 ) ? 1 : 0;
+        }
+    }
+    else
+#endif
+    {
+        /* Granule size of Aarch32 or ARMv7 architectures is always 4K, indexed by 0. */
+        gran = 0;
+
+        mask = ((1ULL << REGISTER_WIDTH_32_BIT) - 1) &
+               ~((1ULL << (REGISTER_WIDTH_32_BIT - t0_sz)) - 1);
+
+        if ( t0_sz == 0 || !(gva & mask) )
+        {
+            input_size = REGISTER_WIDTH_32_BIT - t0_sz;
+
+            /* Use TTBR0 for GVA to IPA translation. */
+            ttbr = READ_SYSREG64(TTBR0_EL1);
+
+            /* If TCR.EPD0 is set, translations using TTBR0 are disabled. */
+            disabled = ( tcr & TCR_EPD0 ) ? 1 : 0;
+        }
+
+        mask = ((1ULL << REGISTER_WIDTH_32_BIT) - 1) &
+               ~((1ULL << (REGISTER_WIDTH_32_BIT - t1_sz)) - 1);
+
+        if ( ((t1_sz == 0) && !ttbr) || (t1_sz && (gva & mask) == mask) )
+        {
+            input_size = REGISTER_WIDTH_32_BIT - t1_sz;
+
+            /* Use TTBR1 for GVA to IPA translation. */
+            ttbr = READ_SYSREG64(TTBR1_EL1);
+
+            /* If TCR.EPD1 is set, translations using TTBR1 are disabled. */
+            disabled = ( tcr & TCR_EPD1 ) ? 1 : 0;
+        }
+    }
+
+    if ( disabled )
+        return -EFAULT;
+
+    level = 4 - DIV_ROUND_UP((input_size - grainsizes[gran]), strides[gran]);
+
+    /* XXX: We do not consider 32bit EL0 running on Aarch64, yet. */
+    if ( is_64bit_domain(d) )
+    {
+        /* Get the intermediate physical address size. */
+        ips = (tcr & TCR_IPS_MASK) >> TCR_IPS_SHIFT;
+
+        switch (ips) {
+        case TCR_IPS_32_BIT:
+            output_size = IPS_32_BIT;
+            break;
+        case TCR_IPS_36_BIT:
+            output_size = IPS_36_BIT;
+            break;
+        case TCR_IPS_40_BIT:
+            output_size = IPS_40_BIT;
+            break;
+        case TCR_IPS_42_BIT:
+            output_size = IPS_42_BIT;
+            break;
+        case TCR_IPS_44_BIT:
+            output_size = IPS_44_BIT;
+            break;
+        case TCR_IPS_48_BIT:
+        default:
+            output_size = IPS_48_BIT;
+        }
+    }
+    else
+        output_size = IPS_40_BIT;
+
+    /* Make sure the base address does not exceed its configured size. */
+    mask = ((1ULL << IPS_48_BIT) - 1) & ~((1ULL << output_size) - 1);
+    if ( output_size != IPS_48_BIT && (ttbr & mask) )
+        return -EFAULT;
+
+    mask = ((1ULL << output_size) - 1);
+    page = get_page_from_gfn(d, paddr_to_pfn(ttbr & mask), NULL, P2M_ALLOC);
+    if ( !page )
+        return -EFAULT;
+
+    table = __map_domain_page(page);
+
+    for ( ; ; level++ )
+    {
+        pte = table[offsets[level][gran]];
+
+        unmap_domain_page(table);
+        put_page(page);
+
+        if ( level == 3 || !pte.walk.valid || !pte.walk.table )
+            break;
+
+        page = get_page_from_gfn(d, pte.walk.base, NULL, P2M_ALLOC);
+        if ( !page )
+            return -EFAULT;
+
+        table = __map_domain_page(page);
+    }
+
+    if ( !pte.walk.valid || ((level == 3) & !pte.walk.table) )
+        return -EFAULT;
+
+    *ipa = pfn_to_paddr(pte.walk.base) | (gva & masks[level][gran]);
+
+    *perm_ro = pte.pt.ro;
+
+    /* Return the entire pte so that the caller can check flags by herself. */
+    return 0;
 }
 
 int p2m_walk_gpt(struct p2m_domain *p2m, vaddr_t gva,
-- 
2.12.2


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

  parent reply	other threads:[~2017-06-01 15:19 UTC|newest]

Thread overview: 35+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-06-01 15:18 [RFC PATCH v2 0/8] arm/mem_access: Walk guest page tables in SW if mem_access is active Sergej Proskurin
2017-06-01 15:18 ` [RFC PATCH v2 1/8] arm/mem_access: Add (TCR_|TTBCR_)* defines Sergej Proskurin
2017-06-02  7:31   ` Julien Grall
2017-06-07 14:56     ` Sergej Proskurin
2017-06-07 15:07       ` Julien Grall
2017-06-07 15:11         ` Julien Grall
2017-06-01 15:18 ` [RFC PATCH v2 2/8] arm/mem_access: Add defines holding the width of 32/64bit regs Sergej Proskurin
2017-06-01 15:18 ` [RFC PATCH v2 3/8] arm/mem_access: Add defines supporting PTs with varying page sizes Sergej Proskurin
2017-06-02  8:27   ` Julien Grall
2017-06-01 15:18 ` [RFC PATCH v2 4/8] arm/mem_access: Add short-descriptor pte typedefs Sergej Proskurin
2017-06-02  8:50   ` Julien Grall
2017-06-01 15:18 ` [RFC PATCH v2 5/8] arm/mem_access: Add software guest-page-table walk Sergej Proskurin
2017-06-02  9:02   ` Julien Grall
2017-06-08 12:43     ` Sergej Proskurin
2017-06-09  8:19       ` Julien Grall
2017-06-01 15:18 ` [RFC PATCH v2 6/8] arm/mem_access: Add long-descriptor based gpt Sergej Proskurin
2017-06-02 12:55   ` Julien Grall
2017-06-09 11:50     ` Sergej Proskurin
2017-06-09 12:39       ` Julien Grall
2017-06-12 10:12     ` Sergej Proskurin
2017-06-12 10:44       ` Julien Grall
2017-06-12 12:31         ` Sergej Proskurin
2017-06-01 15:18 ` [RFC PATCH v2 7/8] arm/mem_access: Add short-descriptor " Sergej Proskurin
2017-06-02 15:11   ` Julien Grall
2017-06-01 15:18 ` [RFC PATCH v2 8/8] arm/mem_access: Walk the guest's pt in software Sergej Proskurin
2017-06-01 15:18 ` [PATCH 1/8] arm/mem_access: Add (TCR_|TTBCR_)* defines Sergej Proskurin
2017-06-02 15:13   ` Julien Grall
2017-06-03  8:56     ` Sergej Proskurin
2017-06-01 15:19 ` [PATCH 2/8] arm/mem_access: Add defines holding the width of 32/64bit regs Sergej Proskurin
2017-06-01 15:19 ` [PATCH 3/8] arm/mem_access: Add defines supporting PTs with varying page sizes Sergej Proskurin
2017-06-01 15:19 ` [PATCH 4/8] arm/mem_access: Add short-descriptor pte typedefs Sergej Proskurin
2017-06-01 15:19 ` [PATCH 5/8] arm/mem_access: Add software guest-page-table walk Sergej Proskurin
2017-06-01 15:19 ` Sergej Proskurin [this message]
2017-06-01 15:19 ` [PATCH 7/8] arm/mem_access: Add short-descriptor based gpt Sergej Proskurin
2017-06-01 15:19 ` [PATCH 8/8] arm/mem_access: Walk the guest's pt in software Sergej Proskurin

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=20170601151906.10213-15-proskurin@sec.in.tum.de \
    --to=proskurin@sec.in.tum.de \
    --cc=julien.grall@arm.com \
    --cc=sstabellini@kernel.org \
    --cc=xen-devel@lists.xenproject.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).