From: Joel Schopp <joel.schopp@amd.com>
To: <kvmarm@lists.cs.columbia.edu>,
<linux-arm-kernel@lists.infradead.org>, <kvm@vger.kernel.org>
Cc: <jungseoklee85@gmail.com>,
Sungjinn Chung <sungjinn.chung@samsung.com>,
Christoffer Dall <christoffer.dall@linaro.org>,
Jungseok Lee <jays.lee@samsung.com>
Subject: [PATCH v4] arm64: fix VTTBR_BADDR_MASK
Date: Mon, 11 Aug 2014 15:38:23 -0500 [thread overview]
Message-ID: <20140811203823.2828.36074.stgit@joelaarch64.amd.com> (raw)
The current VTTBR_BADDR_MASK only masks 39 bits, which is broken on current
systems. Rather than just add a bit it seems like a good time to also set
things at run-time instead of compile time to accomodate more hardware.
This patch sets TCR_EL2.PS, VTCR_EL2.T0SZ and vttbr_baddr_mask in runtime,
not compile time.
In ARMv8, EL2 physical address size (TCR_EL2.PS) and stage2 input address
size (VTCR_EL2.T0SZE) cannot be determined in compile time since they
depend on hardware capability.
According to Table D4-23 and Table D4-25 in ARM DDI 0487A.b document,
vttbr_x is calculated using different fixed values with consideration
of T0SZ, granule size and the level of translation tables. Therefore,
vttbr_baddr_mask should be determined dynamically.
Changes since v3:
Another rebase
Addressed minor comments from v2
Changes since v2:
Rebased on https://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm.git next branch
Changes since v1:
Rebased fix on Jungseok Lee's patch https://lkml.org/lkml/2014/5/12/189 to
provide better long term fix. Updated that patch to log error instead of
silently fail on unaligned vttbr.
Cc: Christoffer Dall <christoffer.dall@linaro.org>
Cc: Sungjinn Chung <sungjinn.chung@samsung.com>
Signed-off-by: Jungseok Lee <jays.lee@samsung.com>
Signed-off-by: Joel Schopp <joel.schopp@amd.com>
---
arch/arm/kvm/arm.c | 116 +++++++++++++++++++++++++++++++++++++-
arch/arm64/include/asm/kvm_arm.h | 17 +-----
arch/arm64/kvm/hyp-init.S | 20 +++++--
3 files changed, 131 insertions(+), 22 deletions(-)
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index 3c82b37..b4859fa 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -37,6 +37,7 @@
#include <asm/mman.h>
#include <asm/tlbflush.h>
#include <asm/cacheflush.h>
+#include <asm/cputype.h>
#include <asm/virt.h>
#include <asm/kvm_arm.h>
#include <asm/kvm_asm.h>
@@ -61,6 +62,8 @@ static atomic64_t kvm_vmid_gen = ATOMIC64_INIT(1);
static u8 kvm_next_vmid;
static DEFINE_SPINLOCK(kvm_vmid_lock);
+static u64 vttbr_baddr_mask;
+
static bool vgic_present;
static void kvm_arm_set_running_vcpu(struct kvm_vcpu *vcpu)
@@ -412,6 +415,103 @@ static bool need_new_vmid_gen(struct kvm *kvm)
return unlikely(kvm->arch.vmid_gen != atomic64_read(&kvm_vmid_gen));
}
+
+
+ /*
+ * ARMv8 64K architecture limitations:
+ * 16 <= T0SZ <= 21 is valid under 3 level of translation tables
+ * 18 <= T0SZ <= 34 is valid under 2 level of translation tables
+ * 31 <= T0SZ <= 39 is valid under 1 level of transltaion tables
+ *
+ * ARMv8 4K architecture limitations:
+ * 16 <= T0SZ <= 24 is valid under 4 level of translation tables
+ * 21 <= T0SZ <= 30 is valid under 3 level of translation tables
+ * 30 <= T0SZ <= 39 is valid under 2 level of translation tables
+ *
+ *
+ * We further limit T0SZ in ARM64 Linux by not supporting 1 level
+ * translation tables at all, not supporting 2 level translation
+ * tables with 4k pages, not supporting different levels of translation
+ * tables in stage 1 vs stage 2, not supporting different page sizes in
+ * stage 1 vs stage 2, not supporting less than 40 bit address space
+ * with 64k pages, and not supporting less than 32 bit address space
+ * with 4K pages.
+ *
+ * See Table D4-23 and Table D4-25 in ARM DDI 0487A.b to figure out
+ * the origin of the hardcoded values, 38 and 37.
+ */
+
+#ifdef CONFIG_ARM64_64K_PAGES
+static inline int t0sz_to_vttbr_x(int t0sz){
+ if (t0sz < 16 || t0sz > 24) {
+ kvm_err("Cannot support %d-bit address space\n", 64 - t0sz);
+ return -EINVAL;
+ }
+
+ return 38 - t0sz;
+}
+#elif CONFIG_ARM64 && !CONFIG_ARM64_64K_PAGES
+static inline int t0sz_to_vttbr_x(int t0sz){
+ if (t0sz < 16 || t0sz > 32) {
+ kvm_err("Cannot support %d-bit address space\n", 64 - t0sz);
+ return -EINVAL;
+ }
+ return 37 - t0sz;
+}
+#endif
+
+
+/**
+ * set_vttbr_baddr_mask - set mask value for vttbr base address
+ *
+ * In ARMv8, vttbr_baddr_mask cannot be determined in compile time since the
+ * stage2 input address size depends on hardware capability. Thus, we first
+ * need to read ID_AA64MMFR0_EL1.PARange first and then set vttbr_baddr_mask
+ * with consideration of both granule size and the level of translation tables.
+ */
+#ifndef CONFIG_ARM64
+static int set_vttbr_baddr_mask(void)
+{
+ vttbr_baddr_mask = VTTBR_BADDR_MASK;
+ return 0;
+}
+#else
+static int set_vttbr_baddr_mask(void)
+{
+ int pa_range, t0sz, vttbr_x;
+
+ pa_range = read_cpuid(ID_AA64MMFR0_EL1) & 0xf;
+
+ switch (pa_range) {
+ case 0:
+ t0sz = VTCR_EL2_T0SZ(32);
+ break;
+ case 1:
+ t0sz = VTCR_EL2_T0SZ(36);
+ break;
+ case 2:
+ t0sz = VTCR_EL2_T0SZ(40);
+ break;
+ case 3:
+ t0sz = VTCR_EL2_T0SZ(42);
+ break;
+ case 4:
+ t0sz = VTCR_EL2_T0SZ(44);
+ break;
+ case 5:
+ t0sz = VTCR_EL2_T0SZ(48);
+ break;
+ default:
+ kvm_err("Invalid EL2 pa_range");
+ return -EINVAL;
+ }
+
+ vttbr_x = t0sz_to_vttbr_x(t0sz);
+ vttbr_baddr_mask = (((1LLU << (48 - vttbr_x)) - 1) << (vttbr_x - 1));
+
+ return 0;
+}
+#endif
/**
* update_vttbr - Update the VTTBR with a valid VMID before the guest runs
* @kvm The guest that we are about to run
@@ -466,8 +566,14 @@ static void update_vttbr(struct kvm *kvm)
/* update vttbr to be used with the new vmid */
pgd_phys = virt_to_phys(kvm->arch.pgd);
vmid = ((u64)(kvm->arch.vmid) << VTTBR_VMID_SHIFT) & VTTBR_VMID_MASK;
- kvm->arch.vttbr = pgd_phys & VTTBR_BADDR_MASK;
- kvm->arch.vttbr |= vmid;
+
+ /*
+ * If the VTTBR isn't aligned there is something wrong with the system
+ * or kernel.
+ */
+ BUG_ON(pgd_phys & ~vttbr_baddr_mask);
+
+ kvm->arch.vttbr = pgd_phys | vmid;
spin_unlock(&kvm_vmid_lock);
}
@@ -1052,6 +1158,12 @@ int kvm_arch_init(void *opaque)
}
}
+ err = set_vttbr_baddr_mask();
+ if (err) {
+ kvm_err("Cannot set vttbr_baddr_mask\n");
+ return -EINVAL;
+ }
+
cpu_notifier_register_begin();
err = init_hyp_mode();
diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
index 3d69030..8dbef70 100644
--- a/arch/arm64/include/asm/kvm_arm.h
+++ b/arch/arm64/include/asm/kvm_arm.h
@@ -94,7 +94,6 @@
/* TCR_EL2 Registers bits */
#define TCR_EL2_TBI (1 << 20)
#define TCR_EL2_PS (7 << 16)
-#define TCR_EL2_PS_40B (2 << 16)
#define TCR_EL2_TG0 (1 << 14)
#define TCR_EL2_SH0 (3 << 12)
#define TCR_EL2_ORGN0 (3 << 10)
@@ -103,8 +102,6 @@
#define TCR_EL2_MASK (TCR_EL2_TG0 | TCR_EL2_SH0 | \
TCR_EL2_ORGN0 | TCR_EL2_IRGN0 | TCR_EL2_T0SZ)
-#define TCR_EL2_FLAGS (TCR_EL2_PS_40B)
-
/* VTCR_EL2 Registers bits */
#define VTCR_EL2_PS_MASK (7 << 16)
#define VTCR_EL2_TG0_MASK (1 << 14)
@@ -119,36 +116,28 @@
#define VTCR_EL2_SL0_MASK (3 << 6)
#define VTCR_EL2_SL0_LVL1 (1 << 6)
#define VTCR_EL2_T0SZ_MASK 0x3f
-#define VTCR_EL2_T0SZ_40B 24
+#define VTCR_EL2_T0SZ(bits) (64 - (bits))
#ifdef CONFIG_ARM64_64K_PAGES
/*
* Stage2 translation configuration:
- * 40bits output (PS = 2)
- * 40bits input (T0SZ = 24)
* 64kB pages (TG0 = 1)
* 2 level page tables (SL = 1)
*/
#define VTCR_EL2_FLAGS (VTCR_EL2_TG0_64K | VTCR_EL2_SH0_INNER | \
VTCR_EL2_ORGN0_WBWA | VTCR_EL2_IRGN0_WBWA | \
- VTCR_EL2_SL0_LVL1 | VTCR_EL2_T0SZ_40B)
-#define VTTBR_X (38 - VTCR_EL2_T0SZ_40B)
+ VTCR_EL2_SL0_LVL1)
#else
/*
* Stage2 translation configuration:
- * 40bits output (PS = 2)
- * 40bits input (T0SZ = 24)
* 4kB pages (TG0 = 0)
* 3 level page tables (SL = 1)
*/
#define VTCR_EL2_FLAGS (VTCR_EL2_TG0_4K | VTCR_EL2_SH0_INNER | \
VTCR_EL2_ORGN0_WBWA | VTCR_EL2_IRGN0_WBWA | \
- VTCR_EL2_SL0_LVL1 | VTCR_EL2_T0SZ_40B)
-#define VTTBR_X (37 - VTCR_EL2_T0SZ_40B)
+ VTCR_EL2_SL0_LVL1)
#endif
-#define VTTBR_BADDR_SHIFT (VTTBR_X - 1)
-#define VTTBR_BADDR_MASK (((1LLU << (40 - VTTBR_X)) - 1) << VTTBR_BADDR_SHIFT)
#define VTTBR_VMID_SHIFT (48LLU)
#define VTTBR_VMID_MASK (0xffLLU << VTTBR_VMID_SHIFT)
diff --git a/arch/arm64/kvm/hyp-init.S b/arch/arm64/kvm/hyp-init.S
index d968796..c0f7634 100644
--- a/arch/arm64/kvm/hyp-init.S
+++ b/arch/arm64/kvm/hyp-init.S
@@ -63,17 +63,21 @@ __do_hyp_init:
mrs x4, tcr_el1
ldr x5, =TCR_EL2_MASK
and x4, x4, x5
- ldr x5, =TCR_EL2_FLAGS
- orr x4, x4, x5
- msr tcr_el2, x4
-
- ldr x4, =VTCR_EL2_FLAGS
/*
* Read the PARange bits from ID_AA64MMFR0_EL1 and set the PS bits in
- * VTCR_EL2.
+ * TCR_EL2 and both PS bits and T0SZ bits in VTCR_EL2.
*/
mrs x5, ID_AA64MMFR0_EL1
bfi x4, x5, #16, #3
+ msr tcr_el2, x4
+
+ ldr x4, =VTCR_EL2_FLAGS
+ bfi x4, x5, #16, #3
+ and x5, x5, #0xf
+ adr x6, t0sz
+ add x6, x6, x5, lsl #2
+ ldr w5, [x6]
+ orr x4, x4, x5
msr vtcr_el2, x4
mrs x4, mair_el1
@@ -109,6 +113,10 @@ target: /* We're now in the trampoline code, switch page tables */
/* Hello, World! */
eret
+
+t0sz:
+ .word VTCR_EL2_T0SZ(32), VTCR_EL2_T0SZ(36), VTCR_EL2_T0SZ(40)
+ .word VTCR_EL2_T0SZ(42), VTCR_EL2_T0SZ(44), VTCR_EL2_T0SZ(48)
ENDPROC(__kvm_hyp_init)
.ltorg
next reply other threads:[~2014-08-11 20:38 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-08-11 20:38 Joel Schopp [this message]
2014-08-12 16:05 ` [PATCH v4] arm64: fix VTTBR_BADDR_MASK Christoffer Dall
2014-08-13 11:33 ` Christoffer Dall
2014-08-13 14:06 ` Jungseok Lee
2014-08-18 20:30 ` Joel Schopp
2014-08-19 12:22 ` Christoffer Dall
2014-08-19 14:05 ` Joel Schopp
2014-08-19 14:37 ` Christoffer Dall
2014-08-19 14:53 ` Joel Schopp
2014-08-19 15:14 ` Christoffer Dall
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=20140811203823.2828.36074.stgit@joelaarch64.amd.com \
--to=joel.schopp@amd.com \
--cc=christoffer.dall@linaro.org \
--cc=jays.lee@samsung.com \
--cc=jungseoklee85@gmail.com \
--cc=kvm@vger.kernel.org \
--cc=kvmarm@lists.cs.columbia.edu \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=sungjinn.chung@samsung.com \
/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