* [PATCH] arm/arm64: KVM: Enforce Break-Before-Make on Stage-2 page tables
@ 2016-04-28 15:16 ` Marc Zyngier
0 siblings, 0 replies; 6+ messages in thread
From: Marc Zyngier @ 2016-04-28 15:16 UTC (permalink / raw)
To: Christoffer Dall; +Cc: kvmarm, linux-arm-kernel
The ARM architecture mandates that when changing a page table entry
from a valid entry to another valid entry, an invalid entry is first
written, TLB invalidated, and only then the new entry being written.
The current code doesn't respect this, directly writing the new
entry and only then invalidating TLBs. Let's fix it up.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
arch/arm/kvm/mmu.c | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
index 58dbd5c..edf1cd1 100644
--- a/arch/arm/kvm/mmu.c
+++ b/arch/arm/kvm/mmu.c
@@ -893,11 +893,14 @@ static int stage2_set_pmd_huge(struct kvm *kvm, struct kvm_mmu_memory_cache
VM_BUG_ON(pmd_present(*pmd) && pmd_pfn(*pmd) != pmd_pfn(*new_pmd));
old_pmd = *pmd;
- kvm_set_pmd(pmd, *new_pmd);
- if (pmd_present(old_pmd))
+ if (pmd_present(old_pmd)) {
+ pmd_clear(pmd);
kvm_tlb_flush_vmid_ipa(kvm, addr);
- else
+ } else {
get_page(virt_to_page(pmd));
+ }
+
+ kvm_set_pmd(pmd, *new_pmd);
return 0;
}
@@ -946,12 +949,14 @@ static int stage2_set_pte(struct kvm *kvm, struct kvm_mmu_memory_cache *cache,
/* Create 2nd stage page table mapping - Level 3 */
old_pte = *pte;
- kvm_set_pte(pte, *new_pte);
- if (pte_present(old_pte))
+ if (pte_present(old_pte)) {
+ kvm_set_pte(pte, __pte(0));
kvm_tlb_flush_vmid_ipa(kvm, addr);
- else
+ } else {
get_page(virt_to_page(pte));
+ }
+ kvm_set_pte(pte, *new_pte);
return 0;
}
--
2.1.4
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH] arm/arm64: KVM: Enforce Break-Before-Make on Stage-2 page tables
@ 2016-04-28 15:16 ` Marc Zyngier
0 siblings, 0 replies; 6+ messages in thread
From: Marc Zyngier @ 2016-04-28 15:16 UTC (permalink / raw)
To: linux-arm-kernel
The ARM architecture mandates that when changing a page table entry
from a valid entry to another valid entry, an invalid entry is first
written, TLB invalidated, and only then the new entry being written.
The current code doesn't respect this, directly writing the new
entry and only then invalidating TLBs. Let's fix it up.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
arch/arm/kvm/mmu.c | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
index 58dbd5c..edf1cd1 100644
--- a/arch/arm/kvm/mmu.c
+++ b/arch/arm/kvm/mmu.c
@@ -893,11 +893,14 @@ static int stage2_set_pmd_huge(struct kvm *kvm, struct kvm_mmu_memory_cache
VM_BUG_ON(pmd_present(*pmd) && pmd_pfn(*pmd) != pmd_pfn(*new_pmd));
old_pmd = *pmd;
- kvm_set_pmd(pmd, *new_pmd);
- if (pmd_present(old_pmd))
+ if (pmd_present(old_pmd)) {
+ pmd_clear(pmd);
kvm_tlb_flush_vmid_ipa(kvm, addr);
- else
+ } else {
get_page(virt_to_page(pmd));
+ }
+
+ kvm_set_pmd(pmd, *new_pmd);
return 0;
}
@@ -946,12 +949,14 @@ static int stage2_set_pte(struct kvm *kvm, struct kvm_mmu_memory_cache *cache,
/* Create 2nd stage page table mapping - Level 3 */
old_pte = *pte;
- kvm_set_pte(pte, *new_pte);
- if (pte_present(old_pte))
+ if (pte_present(old_pte)) {
+ kvm_set_pte(pte, __pte(0));
kvm_tlb_flush_vmid_ipa(kvm, addr);
- else
+ } else {
get_page(virt_to_page(pte));
+ }
+ kvm_set_pte(pte, *new_pte);
return 0;
}
--
2.1.4
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH] arm/arm64: KVM: Enforce Break-Before-Make on Stage-2 page tables
2016-04-28 15:16 ` Marc Zyngier
@ 2016-04-28 16:07 ` Mark Rutland
-1 siblings, 0 replies; 6+ messages in thread
From: Mark Rutland @ 2016-04-28 16:07 UTC (permalink / raw)
To: Marc Zyngier; +Cc: linux-arm-kernel, kvmarm
On Thu, Apr 28, 2016 at 04:16:31PM +0100, Marc Zyngier wrote:
> The ARM architecture mandates that when changing a page table entry
> from a valid entry to another valid entry, an invalid entry is first
> written, TLB invalidated, and only then the new entry being written.
>
> The current code doesn't respect this, directly writing the new
> entry and only then invalidating TLBs. Let's fix it up.
>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
FWIW, this looks correct to me.
Acked-by: Mark Rutland <mark.rutland@arm.com>
Mark.
> ---
> arch/arm/kvm/mmu.c | 17 +++++++++++------
> 1 file changed, 11 insertions(+), 6 deletions(-)
>
> diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
> index 58dbd5c..edf1cd1 100644
> --- a/arch/arm/kvm/mmu.c
> +++ b/arch/arm/kvm/mmu.c
> @@ -893,11 +893,14 @@ static int stage2_set_pmd_huge(struct kvm *kvm, struct kvm_mmu_memory_cache
> VM_BUG_ON(pmd_present(*pmd) && pmd_pfn(*pmd) != pmd_pfn(*new_pmd));
>
> old_pmd = *pmd;
> - kvm_set_pmd(pmd, *new_pmd);
> - if (pmd_present(old_pmd))
> + if (pmd_present(old_pmd)) {
> + pmd_clear(pmd);
> kvm_tlb_flush_vmid_ipa(kvm, addr);
> - else
> + } else {
> get_page(virt_to_page(pmd));
> + }
> +
> + kvm_set_pmd(pmd, *new_pmd);
> return 0;
> }
>
> @@ -946,12 +949,14 @@ static int stage2_set_pte(struct kvm *kvm, struct kvm_mmu_memory_cache *cache,
>
> /* Create 2nd stage page table mapping - Level 3 */
> old_pte = *pte;
> - kvm_set_pte(pte, *new_pte);
> - if (pte_present(old_pte))
> + if (pte_present(old_pte)) {
> + kvm_set_pte(pte, __pte(0));
> kvm_tlb_flush_vmid_ipa(kvm, addr);
> - else
> + } else {
> get_page(virt_to_page(pte));
> + }
>
> + kvm_set_pte(pte, *new_pte);
> return 0;
> }
>
> --
> 2.1.4
>
> _______________________________________________
> kvmarm mailing list
> kvmarm@lists.cs.columbia.edu
> https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
>
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH] arm/arm64: KVM: Enforce Break-Before-Make on Stage-2 page tables
@ 2016-04-28 16:07 ` Mark Rutland
0 siblings, 0 replies; 6+ messages in thread
From: Mark Rutland @ 2016-04-28 16:07 UTC (permalink / raw)
To: linux-arm-kernel
On Thu, Apr 28, 2016 at 04:16:31PM +0100, Marc Zyngier wrote:
> The ARM architecture mandates that when changing a page table entry
> from a valid entry to another valid entry, an invalid entry is first
> written, TLB invalidated, and only then the new entry being written.
>
> The current code doesn't respect this, directly writing the new
> entry and only then invalidating TLBs. Let's fix it up.
>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
FWIW, this looks correct to me.
Acked-by: Mark Rutland <mark.rutland@arm.com>
Mark.
> ---
> arch/arm/kvm/mmu.c | 17 +++++++++++------
> 1 file changed, 11 insertions(+), 6 deletions(-)
>
> diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
> index 58dbd5c..edf1cd1 100644
> --- a/arch/arm/kvm/mmu.c
> +++ b/arch/arm/kvm/mmu.c
> @@ -893,11 +893,14 @@ static int stage2_set_pmd_huge(struct kvm *kvm, struct kvm_mmu_memory_cache
> VM_BUG_ON(pmd_present(*pmd) && pmd_pfn(*pmd) != pmd_pfn(*new_pmd));
>
> old_pmd = *pmd;
> - kvm_set_pmd(pmd, *new_pmd);
> - if (pmd_present(old_pmd))
> + if (pmd_present(old_pmd)) {
> + pmd_clear(pmd);
> kvm_tlb_flush_vmid_ipa(kvm, addr);
> - else
> + } else {
> get_page(virt_to_page(pmd));
> + }
> +
> + kvm_set_pmd(pmd, *new_pmd);
> return 0;
> }
>
> @@ -946,12 +949,14 @@ static int stage2_set_pte(struct kvm *kvm, struct kvm_mmu_memory_cache *cache,
>
> /* Create 2nd stage page table mapping - Level 3 */
> old_pte = *pte;
> - kvm_set_pte(pte, *new_pte);
> - if (pte_present(old_pte))
> + if (pte_present(old_pte)) {
> + kvm_set_pte(pte, __pte(0));
> kvm_tlb_flush_vmid_ipa(kvm, addr);
> - else
> + } else {
> get_page(virt_to_page(pte));
> + }
>
> + kvm_set_pte(pte, *new_pte);
> return 0;
> }
>
> --
> 2.1.4
>
> _______________________________________________
> kvmarm mailing list
> kvmarm at lists.cs.columbia.edu
> https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
>
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] arm/arm64: KVM: Enforce Break-Before-Make on Stage-2 page tables
2016-04-28 15:16 ` Marc Zyngier
@ 2016-04-29 11:31 ` Christoffer Dall
-1 siblings, 0 replies; 6+ messages in thread
From: Christoffer Dall @ 2016-04-29 11:31 UTC (permalink / raw)
To: Marc Zyngier; +Cc: kvmarm, linux-arm-kernel
On Thu, Apr 28, 2016 at 04:16:31PM +0100, Marc Zyngier wrote:
> The ARM architecture mandates that when changing a page table entry
> from a valid entry to another valid entry, an invalid entry is first
> written, TLB invalidated, and only then the new entry being written.
>
> The current code doesn't respect this, directly writing the new
> entry and only then invalidating TLBs. Let's fix it up.
>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Thanks for fixing this, I've applied it to next.
-Christoffer
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH] arm/arm64: KVM: Enforce Break-Before-Make on Stage-2 page tables
@ 2016-04-29 11:31 ` Christoffer Dall
0 siblings, 0 replies; 6+ messages in thread
From: Christoffer Dall @ 2016-04-29 11:31 UTC (permalink / raw)
To: linux-arm-kernel
On Thu, Apr 28, 2016 at 04:16:31PM +0100, Marc Zyngier wrote:
> The ARM architecture mandates that when changing a page table entry
> from a valid entry to another valid entry, an invalid entry is first
> written, TLB invalidated, and only then the new entry being written.
>
> The current code doesn't respect this, directly writing the new
> entry and only then invalidating TLBs. Let's fix it up.
>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Thanks for fixing this, I've applied it to next.
-Christoffer
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2016-04-29 11:31 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-04-28 15:16 [PATCH] arm/arm64: KVM: Enforce Break-Before-Make on Stage-2 page tables Marc Zyngier
2016-04-28 15:16 ` Marc Zyngier
2016-04-28 16:07 ` Mark Rutland
2016-04-28 16:07 ` Mark Rutland
2016-04-29 11:31 ` Christoffer Dall
2016-04-29 11:31 ` Christoffer Dall
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.