KVM: arm64: Rewrite page-table code and fault handling
Will Deacon
maintainerv5 cover KVM: arm64: Rewrite page-table code and fault handling
It's me again, with version five of the KVM page-table rework previously seen at:
v1: https://lore.kernel.org/r/[email protected]
v2: https://lore.kernel.org/r/[email protected]
v3: https://lore.kernel.org/r/[email protected]
v4: https://lore.kernel.org/r/[email protected]
Changes since v4 include:
* Add comments to the kerneldoc describing alignment behaviour for addresses and size parameters
* Fix formatting of IPA size messages
* Fix handling of unaligned addresses in kvm_phys_addr_ioremap()
* Add DSB after zeroing stage-2 PGD pages
* Add reviewer tags
Once again, thanks to Alex, Gavin and Andrew for their comments.
Will
--->8
Quentin Perret (4):
KVM: arm64: Add support for stage-2 write-protect in generic
page-table
KVM: arm64: Convert write-protect operation to generic page-table API
KVM: arm64: Add support for stage-2 cache flushing in generic
page-table
KVM: arm64: Convert memslot cache-flushing code to generic page-table
API
Will Deacon (17):
KVM: arm64: Remove kvm_mmu_free_memory_caches()
KVM: arm64: Add stand-alone page-table walker infrastructure
KVM: arm64: Add support for creating kernel-agnostic stage-1 page
tables
KVM: arm64: Use generic allocator for hyp stage-1 page-tables
KVM: arm64: Add support for creating kernel-agnostic stage-2 page
tables
KVM: arm64: Add support for stage-2 map()/unmap() in generic
page-table
KVM: arm64: Convert kvm_phys_addr_ioremap() to generic page-table API
KVM: arm64: Convert kvm_set_spte_hva() to generic page-table API
KVM: arm64: Convert unmap_stage2_range() to generic page-table API
KVM: arm64: Add support for stage-2 page-aging in generic page-table
KVM: arm64: Convert page-aging and access faults to generic page-table
API
KVM: arm64: Add support for relaxing stage-2 perms in generic
page-table code
KVM: arm64: Convert user_mem_abort() to generic page-table API
KVM: arm64: Check the pgt instead of the pgd when modifying page-table
KVM: arm64: Remove unused page-table code
KVM: arm64: Remove unused 'pgd' field from 'struct kvm_s2_mmu'
KVM: arm64: Don't constrain maximum IPA size based on host
configuration
arch/arm64/include/asm/kvm_host.h | 2 +- arch/arm64/include/asm/kvm_mmu.h | 251 +--- arch/arm64/include/asm/kvm_pgtable.h | 309 ++++ arch/arm64/include/asm/pgtable-hwdef.h | 24 - arch/arm64/include/asm/pgtable-prot.h | 19 - arch/arm64/include/asm/stage2_pgtable.h | 215 --- arch/arm64/kvm/arm.c | 2 +- arch/arm64/kvm/hyp/Makefile | 2 +- arch/arm64/kvm/hyp/pgtable.c | 883 ++++++++++++ arch/arm64/kvm/mmu.c | 1748 ++++------------------- arch/arm64/kvm/reset.c | 40 +- 11 files changed, 1479 insertions(+), 2016 deletions(-) create mode 100644 arch/arm64/include/asm/kvm_pgtable.h create mode 100644 arch/arm64/kvm/hyp/pgtable.c
Signature · 6 lines
2.28.0.618.gf4bc123cb7-goog _______________________________________________ kvmarm mailing list [email protected] https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Will Deacon
maintainerPATCH v5 1/21 KVM: arm64: Remove kvm_mmu_free_memory_caches()
kvm_mmu_free_memory_caches() is only called by kvm_arch_vcpu_destroy(), so inline the implementation and get rid of the extra function.
--- arch/arm64/include/asm/kvm_mmu.h | 2 -- arch/arm64/kvm/arm.c | 2 +- arch/arm64/kvm/mmu.c | 5 ----- 3 files changed, 1 insertion(+), 8 deletions(-)
arch/arm64/include/asm/kvm_mmu.h +0 -2
@@ -141,8 +141,6 @@ int kvm_phys_addr_ioremap(struct kvm *kvm, phys_addr_t guest_ipa,int kvm_handle_guest_abort (struct kvm_vcpu *vcpu); -void kvm_mmu_free_memory_caches (struct kvm_vcpu *vcpu); -phys_addr_t kvm_mmu_get_httbr (void );phys_addr_t kvm_get_idmap_vector (void );int kvm_mmu_init (void );
arch/arm64/kvm/arm.c +1 -1
@@ -283,7 +283,7 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)if (vcpu->arch.has_run_once &&unlikely (!irqchip_in_kernel (vcpu->kvm)))static_branch_dec (&userspace_irqchip_in_use); -kvm_mmu_free_memory_caches (vcpu); +kvm_mmu_free_memory_cache (&vcpu->arch.mmu_page_cache);kvm_timer_vcpu_terminate (vcpu);kvm_pmu_vcpu_destroy (vcpu);
arch/arm64/kvm/mmu.c +0 -5
@@ -2324,11 +2324,6 @@ int kvm_test_age_hva(struct kvm *kvm, unsigned long hva) kvm_test_age_hva_handler, NULL); } -void kvm_mmu_free_memory_caches (struct kvm_vcpu *vcpu) -{ -kvm_mmu_free_memory_cache (&vcpu->arch.mmu_page_cache); -} -phys_addr_t kvm_mmu_get_httbr (void ) {if (__kvm_cpu_uses_extended_idmap ())
Signature · 6 lines
2.28.0.618.gf4bc123cb7-goog _______________________________________________ kvmarm mailing list [email protected] https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Will Deacon
maintainerPATCH v5 2/21 KVM: arm64: Add stand-alone page-table walker infrastructure
In reply to Will DeaconThe KVM page-table code is intricately tied into the kernel page-table code and re-uses the pte/pmd/pud/p4d/pgd macros directly in an attempt to reduce code duplication. Unfortunately, the reality is that there is an awful lot of code required to make this work, and at the end of the day you're limited to creating page-tables with the same configuration as the host kernel. Furthermore, lifting the page-table code to run directly at EL2 on a non-VHE system (as we plan to to do in future patches) is practically impossible due to the number of dependencies it has on the core kernel.
Introduce a framework for walking Armv8 page-tables configured independently from the host kernel.
--- arch/arm64/include/asm/kvm_pgtable.h | 104 ++++++++++ arch/arm64/kvm/hyp/Makefile | 2 +- arch/arm64/kvm/hyp/pgtable.c | 285 +++++++++++++++++++++++++++ 3 files changed, 390 insertions(+), 1 deletion(-) create mode 100644 arch/arm64/include/asm/kvm_pgtable.h create mode 100644 arch/arm64/kvm/hyp/pgtable.c
arch/arm64/include/asm/kvm_pgtable.h new file +104 -0
@@ -0,0 +1,104 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* +* Copyright (C) 2020 Google LLC +* Author: Will Deacon <[email protected]> +*/ + +#ifndef __ARM64_KVM_PGTABLE_H__ +#define __ARM64_KVM_PGTABLE_H__ + +#include <linux/bits.h> +#include <linux/kvm_host.h> +#include <linux/types.h> + +typedef u64 kvm_pte_t ; + +/** +* struct kvm_pgtable - KVM page-table. +* @ia_bits: Maximum input address size, in bits. +* @start_level: Level at which the page-table walk starts. +* @pgd: Pointer to the first top-level entry of the page-table. +* @mmu: Stage-2 KVM MMU struct. Unused for stage-1 page-tables. +*/ +struct kvm_pgtable { +u32 ia_bits; +u32 start_level; +kvm_pte_t *pgd; + +/* Stage-2 only */ +struct kvm_s2_mmu *mmu; +}; + +/** +* enum kvm_pgtable_prot - Page-table permissions and attributes. +* @KVM_PGTABLE_PROT_X: Execute permission. +* @KVM_PGTABLE_PROT_W: Write permission. +* @KVM_PGTABLE_PROT_R: Read permission. +* @KVM_PGTABLE_PROT_DEVICE: Device attributes. +*/ +enum kvm_pgtable_prot { +KVM_PGTABLE_PROT_X =BIT (0 ), +KVM_PGTABLE_PROT_W =BIT (1 ), +KVM_PGTABLE_PROT_R =BIT (2 ), + +KVM_PGTABLE_PROT_DEVICE =BIT (3 ), +}; + +/** +* enum kvm_pgtable_walk_flags - Flags to control a depth-first page-table walk. +* @KVM_PGTABLE_WALK_LEAF: Visit leaf entries, including invalid +* entries. +* @KVM_PGTABLE_WALK_TABLE_PRE: Visit table entries before their +* children. +* @KVM_PGTABLE_WALK_TABLE_POST: Visit table entries after their +* children. +*/ +enum kvm_pgtable_walk_flags { +KVM_PGTABLE_WALK_LEAF =BIT (0 ), +KVM_PGTABLE_WALK_TABLE_PRE =BIT (1 ), +KVM_PGTABLE_WALK_TABLE_POST =BIT (2 ), +}; + +typedef int (*kvm_pgtable_visitor_fn_t )(u64 addr,u64 end,u32 level, +kvm_pte_t *ptep, +enum kvm_pgtable_walk_flags flag, +void *const arg); + +/** +* struct kvm_pgtable_walker - Hook into a page-table walk. +* @cb: Callback function to invoke during the walk. +* @arg: Argument passed to the callback function. +* @flags: Bitwise-OR of flags to identify the entry types on which to +* invoke the callback function. +*/ +struct kvm_pgtable_walker { +const kvm_pgtable_visitor_fn_t cb; +void *const arg; +const enum kvm_pgtable_walk_flags flags; +}; + +/** +* kvm_pgtable_walk() - Walk a page-table. +* @pgt: Page-table structure initialised by kvm_pgtable_*_init(). +* @addr: Input address for the start of the walk. +* @size: Size of the range to walk. +* @walker: Walker callback description. +* +* The offset of @addr within a page is ignored and @size is rounded-up to +* the next page boundary. +* +* The walker will walk the page-table entries corresponding to the input +* address range specified, visiting entries according to the walker flags. +* Invalid entries are treated as leaf entries. Leaf entries are reloaded +* after invoking the walker callback, allowing the walker to descend into +* a newly installed table. +* +* Returning a negative error code from the walker callback function will +* terminate the walk immediately with the same error code. +* +* Return: 0 on success, negative error code on failure. +*/ +int kvm_pgtable_walk (struct kvm_pgtable *pgt,u64 addr,u64 size, +struct kvm_pgtable_walker *walker); + +#endif /* __ARM64_KVM_PGTABLE_H__ */
arch/arm64/kvm/hyp/Makefile +1 -1
@@ -10,5 +10,5 @@ subdir-ccflags-y := -I$(incdir) \ -DDISABLE_BRANCH_PROFILING \ $(DISABLE_STACKLEAK_PLUGIN) -obj-$(CONFIG_KVM) += vhe/ nvhe/ +obj-$(CONFIG_KVM) += vhe/ nvhe/ pgtable.o obj-$(CONFIG_KVM_INDIRECT_VECTORS) += smccc_wa.o
arch/arm64/kvm/hyp/pgtable.c new file +285 -0
285 lines not on this page · raw message
Signature · 6 lines
2.28.0.618.gf4bc123cb7-goog _______________________________________________ kvmarm mailing list [email protected] https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Will Deacon
maintainerPATCH v5 3/21 KVM: arm64: Add support for creating kernel-agnostic stage-1 page tables
In reply to Will DeaconThe generic page-table walker is pretty useless as it stands, because it doesn't understand enough to allocate anything. Teach it about stage-1 page-tables, and hook up an API for allocating these for the hypervisor at EL2.
--- arch/arm64/include/asm/kvm_pgtable.h | 40 ++++++++ arch/arm64/kvm/hyp/pgtable.c | 133 +++++++++++++++++++++++++++ 2 files changed, 173 insertions(+)
arch/arm64/include/asm/kvm_pgtable.h +40 -0
@@ -77,6 +77,46 @@ struct kvm_pgtable_walker {const enum kvm_pgtable_walk_flags flags; }; +/** +* kvm_pgtable_hyp_init() - Initialise a hypervisor stage-1 page-table. +* @pgt: Uninitialised page-table structure to initialise. +* @va_bits: Maximum virtual address bits. +* +* Return: 0 on success, negative error code on failure. +*/ +int kvm_pgtable_hyp_init (struct kvm_pgtable *pgt,u32 va_bits); + +/** +* kvm_pgtable_hyp_destroy() - Destroy an unused hypervisor stage-1 page-table. +* @pgt: Page-table structure initialised by kvm_pgtable_hyp_init(). +* +* The page-table is assumed to be unreachable by any hardware walkers prior +* to freeing and therefore no TLB invalidation is performed. +*/ +void kvm_pgtable_hyp_destroy (struct kvm_pgtable *pgt); + +/** +* kvm_pgtable_hyp_map() - Install a mapping in a hypervisor stage-1 page-table. +* @pgt: Page-table structure initialised by kvm_pgtable_hyp_init(). +* @addr: Virtual address at which to place the mapping. +* @size: Size of the mapping. +* @phys: Physical address of the memory to map. +* @prot: Permissions and attributes for the mapping. +* +* The offset of @addr within a page is ignored, @size is rounded-up to +* the next page boundary and @phys is rounded-down to the previous page +* boundary. +* +* If device attributes are not explicitly requested in @prot, then the +* mapping will be normal, cacheable. Attempts to install a new mapping +* for a virtual address that is already mapped will be rejected with an +* error and a WARN(). +* +* Return: 0 on success, negative error code on failure. +*/ +int kvm_pgtable_hyp_map (struct kvm_pgtable *pgt,u64 addr,u64 size,u64 phys, +enum kvm_pgtable_prot prot); +/** * kvm_pgtable_walk() - Walk a page-table. * @pgt: Page-table structure initialised by kvm_pgtable_*_init().
arch/arm64/kvm/hyp/pgtable.c +133 -0
144 lines not on this page · raw message
Signature · 6 lines
2.28.0.618.gf4bc123cb7-goog _______________________________________________ kvmarm mailing list [email protected] https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Will Deacon
maintainerPATCH v5 4/21 KVM: arm64: Use generic allocator for hyp stage-1 page-tables
In reply to Will DeaconNow that we have a shiny new page-table allocator, replace the hyp page-table code with calls into the new API. This also allows us to remove the extended idmap code, as we can now simply ensure that the VA size is large enough to map everything we need.
--- arch/arm64/include/asm/kvm_mmu.h | 78 +---- arch/arm64/include/asm/kvm_pgtable.h | 5 + arch/arm64/include/asm/pgtable-hwdef.h | 6 - arch/arm64/include/asm/pgtable-prot.h | 6 - arch/arm64/kvm/mmu.c | 414 +++---------------------- 5 files changed, 45 insertions(+), 464 deletions(-)
arch/arm64/include/asm/kvm_mmu.h +2 -76
@@ -43,16 +43,6 @@* HYP_VA_MIN = 1 << (VA_BITS - 1) * HYP_VA_MAX = HYP_VA_MIN + (1 << (VA_BITS - 1)) - 1 * -* This of course assumes that the trampoline page exists within the -* VA_BITS range. If it doesn't, then it means we're in the odd case -* where the kernel idmap (as well as HYP) uses more levels than the -* kernel runtime page tables (as seen when the kernel is configured -* for 4k pages, 39bits VA, and yet memory lives just above that -* limit, forcing the idmap to use 4 levels of page tables while the -* kernel itself only uses 3). In this particular case, it doesn't -* matter which side of VA_BITS we use, as we're guaranteed not to -* conflict with anything. -* * When using VHE, there are no separate hyp mappings and all KVM * functionality is already mapped as part of the main kernel * mappings, and none of this applies in that case.
@@ -123,9 +113,10 @@ static inline bool kvm_page_empty(void *ptr)return page_count (ptr_page) ==1 ; } +#include <asm/kvm_pgtable.h> #include <asm/stage2_pgtable.h> -int create_hyp_mappings (void *from,void *to,pgprot_t prot); +int create_hyp_mappings (void *from,void *to,enum kvm_pgtable_prot prot);int create_hyp_io_mappings (phys_addr_t phys_addr,size_t size,void __iomem **kaddr,void __iomem **haddr);
@@ -144,8 +135,6 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu);phys_addr_t kvm_mmu_get_httbr (void );phys_addr_t kvm_get_idmap_vector (void );int kvm_mmu_init (void ); -void kvm_clear_hyp_idmap (void ); -#define kvm_mk_pmd (ptep) \ __pmd(__phys_to_pmd_val(__pa(ptep)) | PMD_TYPE_TABLE)#define kvm_mk_pud (pmdp) \
@@ -263,25 +252,6 @@ static inline bool kvm_s2pud_young(pud_t pud)return pud_young (pud); } -#define hyp_pte_table_empty (ptep) kvm_page_empty(ptep) - -#ifdef __PAGETABLE_PMD_FOLDED -#define hyp_pmd_table_empty (pmdp) (0) -#else -#define hyp_pmd_table_empty (pmdp) kvm_page_empty(pmdp) -#endif - -#ifdef __PAGETABLE_PUD_FOLDED -#define hyp_pud_table_empty (pudp) (0) -#else -#define hyp_pud_table_empty (pudp) kvm_page_empty(pudp) -#endif - -#ifdef __PAGETABLE_P4D_FOLDED -#define hyp_p4d_table_empty (p4dp) (0) -#else -#define hyp_p4d_table_empty (p4dp) kvm_page_empty(p4dp) -#endif struct kvm ;
@@ -350,50 +320,6 @@ static inline void __kvm_flush_dcache_pud(pud_t pud)void kvm_set_way_flush (struct kvm_vcpu *vcpu);void kvm_toggle_cache (struct kvm_vcpu *vcpu,bool was_enabled); -static inline bool __kvm_cpu_uses_extended_idmap (void ) -{ -return __cpu_uses_extended_idmap_level (); -} - -static inline unsigned long __kvm_idmap_ptrs_per_pgd (void ) -{ -return idmap_ptrs_per_pgd; -} - -/* -* Can't use pgd_populate here, because the extended idmap adds an extra level -* above CONFIG_PGTABLE_LEVELS (which is 2 or 3 if we're using the extended -* idmap), and pgd_populate is only available if CONFIG_PGTABLE_LEVELS = 4. -*/ -static inline void __kvm_extend_hypmap (pgd_t *boot_hyp_pgd, -pgd_t *hyp_pgd, -pgd_t *merged_hyp_pgd, -unsigned long hyp_idmap_start) -{ -int idmap_idx; -u64 pgd_addr; - -/* -* Use the first entry to access the HYP mappings. It is -* guaranteed to be free, otherwise we wouldn't use an -* extended idmap. -*/ -VM_BUG_ON (pgd_val (merged_hyp_pgd[0 ])); - pgd_addr =__phys_to_pgd_val (__pa (hyp_pgd)); - merged_hyp_pgd[0 ] =__pgd (pgd_addr |PMD_TYPE_TABLE ); - -/* -* Create another extended level entry that points to the boot HYP map, -* which contains an ID mapping of the HYP init code. We essentially -* merge the boot and runtime HYP maps by doing so, but they don't -* overlap anyway, so this is fine. -*/ - idmap_idx = hyp_idmap_start >>VA_BITS ; -VM_BUG_ON (pgd_val (merged_hyp_pgd[idmap_idx])); - pgd_addr =__phys_to_pgd_val (__pa (boot_hyp_pgd)); - merged_hyp_pgd[idmap_idx] =__pgd (pgd_addr |PMD_TYPE_TABLE ); -} -static inline unsigned int kvm_get_vmid_bits (void ) {int reg =read_sanitised_ftr_reg (SYS_ID_AA64MMFR1_EL1 );
arch/arm64/include/asm/kvm_pgtable.h +5 -0
@@ -44,6 +44,11 @@ enum kvm_pgtable_prot { KVM_PGTABLE_PROT_DEVICE = BIT(3), }; +#define PAGE_HYP (KVM_PGTABLE_PROT_R | KVM_PGTABLE_PROT_W) +#define PAGE_HYP_EXEC (KVM_PGTABLE_PROT_R | KVM_PGTABLE_PROT_X) +#define PAGE_HYP_RO (KVM_PGTABLE_PROT_R) +#define PAGE_HYP_DEVICE (PAGE_HYP | KVM_PGTABLE_PROT_DEVICE) +/** * enum kvm_pgtable_walk_flags - Flags to control a depth-first page-table walk. * @KVM_PGTABLE_WALK_LEAF: Visit leaf entries, including invalid
arch/arm64/include/asm/pgtable-hwdef.h +0 -6
@@ -194,12 +194,6 @@*/ #define PTE_S2_MEMATTR (t) (_AT(pteval_t, (t)) << 2) -/* -* EL2/HYP PTE/PMD definitions -*/ -#define PMD_HYP PMD_SECT_USER -#define PTE_HYP PTE_USER -/* * Highest possible physical address supported. */
arch/arm64/include/asm/pgtable-prot.h +0 -6
@@ -56,7 +56,6 @@ extern bool arm64_use_ng_mappings;#define PROT_SECT_NORMAL_EXEC (PROT_SECT_DEFAULT | PMD_SECT_UXN | PMD_ATTRINDX(MT_NORMAL))#define _PAGE_DEFAULT (_PROT_DEFAULT | PTE_ATTRINDX(MT_NORMAL)) -#define _HYP_PAGE_DEFAULT _PAGE_DEFAULT#define PAGE_KERNEL __pgprot(PROT_NORMAL)#define PAGE_KERNEL_RO __pgprot((PROT_NORMAL & ~PTE_WRITE) | PTE_RDONLY)
@@ -64,11 +63,6 @@ extern bool arm64_use_ng_mappings;#define PAGE_KERNEL_EXEC __pgprot(PROT_NORMAL & ~PTE_PXN)#define PAGE_KERNEL_EXEC_CONT __pgprot((PROT_NORMAL & ~PTE_PXN) | PTE_CONT) -#define PAGE_HYP __pgprot(_HYP_PAGE_DEFAULT | PTE_HYP | PTE_HYP_XN) -#define PAGE_HYP_EXEC __pgprot(_HYP_PAGE_DEFAULT | PTE_HYP | PTE_RDONLY) -#define PAGE_HYP_RO __pgprot(_HYP_PAGE_DEFAULT | PTE_HYP | PTE_RDONLY | PTE_HYP_XN) -#define PAGE_HYP_DEVICE __pgprot(_PROT_DEFAULT | PTE_ATTRINDX(MT_DEVICE_nGnRE) | PTE_HYP | PTE_HYP_XN) -#define PAGE_S2_MEMATTR (attr) \ ({ \ u64 __val; \
arch/arm64/kvm/mmu.c +38 -376
521 lines not on this page · raw message
Signature · 6 lines
2.28.0.618.gf4bc123cb7-goog _______________________________________________ kvmarm mailing list [email protected] https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Will Deacon
maintainerPATCH v5 5/21 KVM: arm64: Add support for creating kernel-agnostic stage-2 page tables
In reply to Will DeaconIntroduce alloc() and free() functions to the generic page-table code for guest stage-2 page-tables and plumb these into the existing KVM page-table allocator. Subsequent patches will convert other operations within the KVM allocator over to the generic code.
--- arch/arm64/include/asm/kvm_host.h | 1 + arch/arm64/include/asm/kvm_pgtable.h | 18 +++++++++ arch/arm64/kvm/hyp/pgtable.c | 54 +++++++++++++++++++++++++++ arch/arm64/kvm/mmu.c | 55 +++++++++++++++------------- 4 files changed, 102 insertions(+), 26 deletions(-)
arch/arm64/include/asm/kvm_host.h +1 -0
@@ -81,6 +81,7 @@ struct kvm_s2_mmu {*/ pgd_t *pgd;phys_addr_t pgd_phys; +struct kvm_pgtable *pgt;/* The last vcpu id that ran on each physical CPU */ int __percpu *last_vcpu_ran;
arch/arm64/include/asm/kvm_pgtable.h +18 -0
@@ -122,6 +122,24 @@ void kvm_pgtable_hyp_destroy(struct kvm_pgtable *pgt);int kvm_pgtable_hyp_map (struct kvm_pgtable *pgt,u64 addr,u64 size,u64 phys,enum kvm_pgtable_prot prot); +/** +* kvm_pgtable_stage2_init() - Initialise a guest stage-2 page-table. +* @pgt: Uninitialised page-table structure to initialise. +* @kvm: KVM structure representing the guest virtual machine. +* +* Return: 0 on success, negative error code on failure. +*/ +int kvm_pgtable_stage2_init (struct kvm_pgtable *pgt,struct kvm *kvm); + +/** +* kvm_pgtable_stage2_destroy() - Destroy an unused guest stage-2 page-table. +* @pgt: Page-table structure initialised by kvm_pgtable_stage2_init(). +* +* The page-table is assumed to be unreachable by any hardware walkers prior +* to freeing and therefore no TLB invalidation is performed. +*/ +void kvm_pgtable_stage2_destroy (struct kvm_pgtable *pgt); +/** * kvm_pgtable_walk() - Walk a page-table. * @pgt: Page-table structure initialised by kvm_pgtable_*_init().
arch/arm64/kvm/hyp/pgtable.c +54 -0
57 lines not on this page · raw message
arch/arm64/kvm/mmu.c +29 -26
96 lines not on this page · raw message
Signature · 6 lines
2.28.0.618.gf4bc123cb7-goog _______________________________________________ kvmarm mailing list [email protected] https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Will Deacon
maintainerPATCH v5 6/21 KVM: arm64: Add support for stage-2 map()/unmap() in generic page-table
In reply to Will DeaconAdd stage-2 map() and unmap() operations to the generic page-table code.
--- arch/arm64/include/asm/kvm_pgtable.h | 46 +++++ arch/arm64/kvm/hyp/pgtable.c | 273 +++++++++++++++++++++++++++ 2 files changed, 319 insertions(+)
arch/arm64/include/asm/kvm_pgtable.h +46 -0
@@ -140,6 +140,52 @@ int kvm_pgtable_stage2_init(struct kvm_pgtable *pgt, struct kvm *kvm);*/ void kvm_pgtable_stage2_destroy (struct kvm_pgtable *pgt); +/** +* kvm_pgtable_stage2_map() - Install a mapping in a guest stage-2 page-table. +* @pgt: Page-table structure initialised by kvm_pgtable_stage2_init(). +* @addr: Intermediate physical address at which to place the mapping. +* @size: Size of the mapping. +* @phys: Physical address of the memory to map. +* @prot: Permissions and attributes for the mapping. +* @mc: Cache of pre-allocated GFP_PGTABLE_USER memory from which to +* allocate page-table pages. +* +* The offset of @addr within a page is ignored, @size is rounded-up to +* the next page boundary and @phys is rounded-down to the previous page +* boundary. +* +* If device attributes are not explicitly requested in @prot, then the +* mapping will be normal, cacheable. +* +* Note that this function will both coalesce existing table entries and split +* existing block mappings, relying on page-faults to fault back areas outside +* of the new mapping lazily. +* +* Return: 0 on success, negative error code on failure. +*/ +int kvm_pgtable_stage2_map (struct kvm_pgtable *pgt,u64 addr,u64 size, +u64 phys,enum kvm_pgtable_prot prot, +struct kvm_mmu_memory_cache *mc); + +/** +* kvm_pgtable_stage2_unmap() - Remove a mapping from a guest stage-2 page-table. +* @pgt: Page-table structure initialised by kvm_pgtable_stage2_init(). +* @addr: Intermediate physical address from which to remove the mapping. +* @size: Size of the mapping. +* +* The offset of @addr within a page is ignored and @size is rounded-up to +* the next page boundary. +* +* TLB invalidation is performed for each page-table entry cleared during the +* unmapping operation and the reference count for the page-table page +* containing the cleared entry is decremented, with unreferenced pages being +* freed. Unmapping a cacheable page will ensure that it is clean to the PoC if +* FWB is not supported by the CPU. +* +* Return: 0 on success, negative error code on failure. +*/ +int kvm_pgtable_stage2_unmap (struct kvm_pgtable *pgt,u64 addr,u64 size); +/** * kvm_pgtable_walk() - Walk a page-table. * @pgt: Page-table structure initialised by kvm_pgtable_*_init().
arch/arm64/kvm/hyp/pgtable.c +273 -0
289 lines not on this page · raw message
Signature · 6 lines
2.28.0.618.gf4bc123cb7-goog _______________________________________________ kvmarm mailing list [email protected] https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Re: [PATCH v5 06/21] KVM: arm64: Add support for stage-2 map()/unmap() in generic page-table
Hi Will,
Quoted 18 lines · Will Deacon
Add stage-2
map()andunmap()operations to the generic page-table code.Cc Marc Zyngier <[email protected]>Cc Quentin Perret <[email protected]>Reviewed-by Gavin Shan <[email protected]>Signed-off-by Will Deacon <[email protected]>--- arch/arm64/include/asm/kvm_pgtable.h | 46 +++++ arch/arm64/kvm/hyp/pgtable.c | 273 +++++++++++++++++++++++++++ 2 files changed, 319 insertions(+)arch/arm64/include/asm/kvm_pgtable.h +0
-0@@ -140,6 +140,52 @@ int kvm_pgtable_stage2_init(struct kvm_pgtable *pgt, struct kvm *kvm);*/ void kvm_pgtable_stage2_destroy (struct kvm_pgtable *pgt);
arch/arm64/include/asm/kvm_pgtable.h int kvm_pgtable_stage2_init(struct kvm_pgtable *pgt, struct kvm *kvm); · line 151
Quoted 10 lines
arch/arm64/include/asm/kvm_pgtable.h +9
-0+/** +* kvm_pgtable_stage2_map() - Install a mapping in a guest stage-2 page-table. +* @pgt: Page-table structure initialised by kvm_pgtable_stage2_init(). +* @addr: Intermediate physical address at which to place the mapping. +* @size: Size of the mapping. +* @phys: Physical address of the memory to map. +* @prot: Permissions and attributes for the mapping. +* @mc: Cache of pre-allocated GFP_PGTABLE_USER memory from which to +* allocate page-table pages.
In v5.9-rc5, kvm_mmu_topup_memory_cache() allocates GFP_KERNEL_ACCOUNT == GFP_KERNEL|__GFP_ACCOUNT memory, not GFP_PGTABLE_USER == GFP_KERNEL|__GFP_ZERO|__GFP_ACCOUNT.
Thanks,
Alex
_______________________________________________
kvmarm mailing list
[email protected]
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Will Deacon
maintainerPATCH v5 7/21 KVM: arm64: Convert kvm_phys_addr_ioremap() to generic page-table API
In reply to Will DeaconConvert kvm_phys_addr_ioremap() to use kvm_pgtable_stage2_map() instead of stage2_set_pte().
--- arch/arm64/kvm/mmu.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-)
arch/arm64/kvm/mmu.c +14 -16
@@ -1154,35 +1154,33 @@ static int stage2_pudp_test_and_clear_young(pud_t *pud)int kvm_phys_addr_ioremap (struct kvm *kvm,phys_addr_t guest_ipa,phys_addr_t pa,unsigned long size,bool writable) { -phys_addr_t addr, end; +phys_addr_t addr;int ret =0 ; -unsigned long pfn;struct kvm_mmu_memory_cache cache = {0 , __GFP_ZERO,NULL , }; +struct kvm_pgtable *pgt = kvm->arch.mmu.pgt; +enum kvm_pgtable_prot prot =KVM_PGTABLE_PROT_DEVICE | +KVM_PGTABLE_PROT_R | + (writable ?KVM_PGTABLE_PROT_W :0 ); - end = (guest_ipa + size +PAGE_SIZE -1 ) &PAGE_MASK ; - pfn =__phys_to_pfn (pa); - -for (addr = guest_ipa; addr < end; addr +=PAGE_SIZE ) { -pte_t pte =kvm_pfn_pte (pfn,PAGE_S2_DEVICE ); - -if (writable) - pte =kvm_s2pte_mkwrite (pte); + size +=offset_in_page (guest_ipa); + guest_ipa &=PAGE_MASK ; +for (addr = guest_ipa; addr < guest_ipa + size; addr +=PAGE_SIZE ) { ret =kvm_mmu_topup_memory_cache (&cache,kvm_mmu_cache_min_pages (kvm));if (ret) - goto out; +break ; +spin_lock (&kvm->mmu_lock); - ret =stage2_set_pte (&kvm->arch.mmu, &cache, addr, &pte, -KVM_S2PTE_FLAG_IS_IOMAP ); + ret =kvm_pgtable_stage2_map (pgt, addr,PAGE_SIZE , pa, prot, + &cache);spin_unlock (&kvm->mmu_lock);if (ret) - goto out; +break ; - pfn++; + pa +=PAGE_SIZE ; } -out:kvm_mmu_free_memory_cache (&cache);return ret; }
Signature · 6 lines
2.28.0.618.gf4bc123cb7-goog _______________________________________________ kvmarm mailing list [email protected] https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Will Deacon
maintainerPATCH v5 8/21 KVM: arm64: Convert kvm_set_spte_hva() to generic page-table API
In reply to Will DeaconConvert kvm_set_spte_hva() to use kvm_pgtable_stage2_map() instead of stage2_set_pte().
--- arch/arm64/kvm/mmu.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-)
arch/arm64/kvm/mmu.c +10 -13
@@ -1914,28 +1914,27 @@ int kvm_unmap_hva_range(struct kvm *kvm,static int kvm_set_spte_handler (struct kvm *kvm,gpa_t gpa,u64 size,void *data) { -pte_t *pte = (pte_t *)data; +kvm_pfn_t *pfn = (kvm_pfn_t *)data;WARN_ON (size !=PAGE_SIZE ); +/* -* We can always call stage2_set_pte with KVM_S2PTE_FLAG_LOGGING_ACTIVE -* flag clear because MMU notifiers will have unmapped a huge PMD before -* calling ->change_pte() (which in turn calls kvm_set_spte_hva()) and -* therefore stage2_set_pte() never needs to clear out a huge PMD -* through this calling path. +* The MMU notifiers will have unmapped a huge PMD before calling +* ->change_pte() (which in turn calls kvm_set_spte_hva()) and +* therefore we never need to clear out a huge PMD through this +* calling path and a memcache is not required. */ -stage2_set_pte (&kvm->arch.mmu,NULL , gpa, pte,0 ); +kvm_pgtable_stage2_map (kvm->arch.mmu.pgt, gpa,PAGE_SIZE , +__pfn_to_phys (*pfn),KVM_PGTABLE_PROT_R ,NULL );return 0 ; } -int kvm_set_spte_hva (struct kvm *kvm,unsigned long hva,pte_t pte) {unsigned long end = hva +PAGE_SIZE ;kvm_pfn_t pfn =pte_pfn (pte); -pte_t stage2_pte; -if (!kvm->arch.mmu.pgd) +if (!kvm->arch.mmu.pgt)return 0 ;trace_kvm_set_spte_hva (hva);
@@ -1945,9 +1944,7 @@ int kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte)* just like a translation fault and clean the cache to the PoC. */ clean_dcache_guest_page (pfn,PAGE_SIZE ); - stage2_pte =kvm_pfn_pte (pfn,PAGE_S2 ); -handle_hva_to_gpa (kvm, hva, end, &kvm_set_spte_handler, &stage2_pte); - +handle_hva_to_gpa (kvm, hva, end, &kvm_set_spte_handler, &pfn);return 0 ; }
Signature · 6 lines
2.28.0.618.gf4bc123cb7-goog _______________________________________________ kvmarm mailing list [email protected] https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Will Deacon
maintainerPATCH v5 9/21 KVM: arm64: Convert unmap_stage2_range() to generic page-table API
In reply to Will DeaconConvert unmap_stage2_range() to use kvm_pgtable_stage2_unmap() instead of walking the page-table directly.
--- arch/arm64/kvm/mmu.c | 62 ++++++++++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 25 deletions(-)
arch/arm64/kvm/mmu.c +37 -25
@@ -39,6 +39,38 @@ static bool is_iomap(unsigned long flags)return flags &KVM_S2PTE_FLAG_IS_IOMAP ; } +/* +* Release kvm_mmu_lock periodically if the memory region is large. Otherwise, +* we may see kernel panics with CONFIG_DETECT_HUNG_TASK, +* CONFIG_LOCKUP_DETECTOR, CONFIG_LOCKDEP. Additionally, holding the lock too +* long will also starve other vCPUs. We have to also make sure that the page +* tables are not freed while we released the lock. +*/ +static int stage2_apply_range (struct kvm *kvm,phys_addr_t addr, +phys_addr_t end, +int (*fn)(struct kvm_pgtable *,u64 ,u64 ), +bool resched) +{ +int ret; +u64 next; + +do { +struct kvm_pgtable *pgt = kvm->arch.mmu.pgt; +if (!pgt) +return -EINVAL ; + + next =stage2_pgd_addr_end (kvm, addr, end); + ret =fn (pgt, addr, next - addr); +if (ret) +break ; + +if (resched && next != end) +cond_resched_lock (&kvm->mmu_lock); + }while (addr = next, addr != end); + +return ret; +} +static bool memslot_is_logging (struct kvm_memory_slot *memslot) {return memslot->dirty_bitmap && !(memslot->flags &KVM_MEM_READONLY );
@@ -220,8 +252,8 @@ static inline void kvm_pgd_populate(pgd_t *pgdp, p4d_t *p4dp)* end up writing old data to disk. * * This is why right after unmapping a page/section and invalidating -* the corresponding TLBs, we call kvm_flush_dcache_p*() to make sure -* the IO subsystem will never hit in the cache. +* the corresponding TLBs, we flush to make sure the IO subsystem will +* never hit in the cache. * * This is all avoided on systems that have ARM64_HAS_STAGE2_FWB, as * we then fully enforce cacheability of RAM, no matter what the guest
@@ -344,32 +376,12 @@ static void __unmap_stage2_range(struct kvm_s2_mmu *mmu, phys_addr_t start, u64 bool may_block) {struct kvm *kvm = mmu->kvm; -pgd_t *pgd; -phys_addr_t addr = start, end = start + size; -phys_addr_t next; +phys_addr_t end = start + size;assert_spin_locked (&kvm->mmu_lock);WARN_ON (size & ~PAGE_MASK ); - - pgd = mmu->pgd +stage2_pgd_index (kvm, addr); -do { -/* -* Make sure the page table is still active, as another thread -* could have possibly freed the page table, while we released -* the lock. -*/ -if (!READ_ONCE (mmu->pgd)) -break ; - next =stage2_pgd_addr_end (kvm, addr, end); -if (!stage2_pgd_none (kvm, *pgd)) -unmap_stage2_p4ds (mmu, pgd, addr, next); -/* -* If the range is too large, release the kvm->mmu_lock -* to prevent starvation and lockup detector warnings. -*/ -if (may_block && next != end) -cond_resched_lock (&kvm->mmu_lock); - }while (pgd++, addr = next, addr != end); +WARN_ON (stage2_apply_range (kvm, start, end, kvm_pgtable_stage2_unmap, + may_block)); }static void unmap_stage2_range (struct kvm_s2_mmu *mmu,phys_addr_t start,u64 size)
Signature · 6 lines
2.28.0.618.gf4bc123cb7-goog _______________________________________________ kvmarm mailing list [email protected] https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Re: [PATCH v5 09/21] KVM: arm64: Convert unmap_stage2_range() to generic page-table API
Hi Will,
Quoted 2 lines · Will Deacon
Convert
unmap_stage2_range()to usekvm_pgtable_stage2_unmap()instead of walking the page-table directly.
Nitpick: the function name is __unmap_stage2_range() (above and in the subject); the two aren't equivalent because kvm_unmap_hva_handler() uses __unmap_stage2_range() directly.
Thanks,
Alex
_______________________________________________
kvmarm mailing list
[email protected]
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Will Deacon
maintainerPATCH v5 10/21 KVM: arm64: Add support for stage-2 page-aging in generic page-table
In reply to Will DeaconAdd stage-2 mkyoung(), mkold() and is_young() operations to the generic page-table code.
--- arch/arm64/include/asm/kvm_pgtable.h | 44 ++++++++++++++ arch/arm64/kvm/hyp/pgtable.c | 86 ++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+)
arch/arm64/include/asm/kvm_pgtable.h +44 -0
@@ -186,6 +186,50 @@ int kvm_pgtable_stage2_map(struct kvm_pgtable *pgt, u64 addr, u64 size,*/ int kvm_pgtable_stage2_unmap (struct kvm_pgtable *pgt,u64 addr,u64 size); +/** +* kvm_pgtable_stage2_mkyoung() - Set the access flag in a page-table entry. +* @pgt: Page-table structure initialised by kvm_pgtable_stage2_init(). +* @addr: Intermediate physical address to identify the page-table entry. +* +* The offset of @addr within a page is ignored. +* +* If there is a valid, leaf page-table entry used to translate @addr, then +* set the access flag in that entry. +* +* Return: The old page-table entry prior to setting the flag, 0 on failure. +*/ +kvm_pte_t kvm_pgtable_stage2_mkyoung (struct kvm_pgtable *pgt,u64 addr); + +/** +* kvm_pgtable_stage2_mkold() - Clear the access flag in a page-table entry. +* @pgt: Page-table structure initialised by kvm_pgtable_stage2_init(). +* @addr: Intermediate physical address to identify the page-table entry. +* +* The offset of @addr within a page is ignored. +* +* If there is a valid, leaf page-table entry used to translate @addr, then +* clear the access flag in that entry. +* +* Note that it is the caller's responsibility to invalidate the TLB after +* calling this function to ensure that the updated permissions are visible +* to the CPUs. +* +* Return: The old page-table entry prior to clearing the flag, 0 on failure. +*/ +kvm_pte_t kvm_pgtable_stage2_mkold (struct kvm_pgtable *pgt,u64 addr); + +/** +* kvm_pgtable_stage2_is_young() - Test whether a page-table entry has the +* access flag set. +* @pgt: Page-table structure initialised by kvm_pgtable_stage2_init(). +* @addr: Intermediate physical address to identify the page-table entry. +* +* The offset of @addr within a page is ignored. +* +* Return: True if the page-table entry has the access flag set, false otherwise. +*/ +bool kvm_pgtable_stage2_is_young (struct kvm_pgtable *pgt,u64 addr); +/** * kvm_pgtable_walk() - Walk a page-table. * @pgt: Page-table structure initialised by kvm_pgtable_*_init().
arch/arm64/kvm/hyp/pgtable.c +86 -0
92 lines not on this page · raw message
Signature · 6 lines
2.28.0.618.gf4bc123cb7-goog _______________________________________________ kvmarm mailing list [email protected] https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Will Deacon
maintainerPATCH v5 11/21 KVM: arm64: Convert page-aging and access faults to generic page-table API
In reply to Will DeaconConvert the page-aging functions and access fault handler to use the generic page-table code instead of walking the page-table directly.
--- arch/arm64/kvm/mmu.c | 74 ++++++++++---------------------------------- 1 file changed, 16 insertions(+), 58 deletions(-)
arch/arm64/kvm/mmu.c +16 -58
@@ -1706,46 +1706,23 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,return ret; } -/* -* Resolve the access fault by making the page young again. -* Note that because the faulting entry is guaranteed not to be -* cached in the TLB, we don't need to invalidate anything. -* Only the HW Access Flag updates are supported for Stage 2 (no DBM), -* so there is no need for atomic (pte|pmd)_mkyoung operations. -*/ +/* Resolve the access fault by making the page young again. */ static void handle_access_fault (struct kvm_vcpu *vcpu,phys_addr_t fault_ipa) { -pud_t *pud; -pmd_t *pmd; -pte_t *pte; -kvm_pfn_t pfn; -bool pfn_valid = false; +pte_t pte; +kvm_pte_t kpte; +struct kvm_s2_mmu *mmu;trace_kvm_access_fault (fault_ipa);spin_lock (&vcpu->kvm->mmu_lock); - -if (!stage2_get_leaf_entry (vcpu->arch.hw_mmu, fault_ipa, &pud, &pmd, &pte)) - goto out; - -if (pud) {/* HugeTLB */ - *pud =kvm_s2pud_mkyoung (*pud); - pfn =kvm_pud_pfn (*pud); - pfn_valid = true; - }else if (pmd) {/* THP, HugeTLB */ - *pmd =pmd_mkyoung (*pmd); - pfn =pmd_pfn (*pmd); - pfn_valid = true; - }else { - *pte =pte_mkyoung (*pte);/* Just a page... */ - pfn =pte_pfn (*pte); - pfn_valid = true; - } - -out: + mmu = vcpu->arch.hw_mmu; + kpte =kvm_pgtable_stage2_mkyoung (mmu->pgt, fault_ipa);spin_unlock (&vcpu->kvm->mmu_lock); -if (pfn_valid) -kvm_set_pfn_accessed (pfn); + + pte =__pte (kpte); +if (pte_valid (pte)) +kvm_set_pfn_accessed (pte_pfn (pte)); }/**
@@ -1962,38 +1939,19 @@ int kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte)static int kvm_age_hva_handler (struct kvm *kvm,gpa_t gpa,u64 size,void *data) { -pud_t *pud; -pmd_t *pmd; -pte_t *pte; +pte_t pte; +kvm_pte_t kpte;WARN_ON (size !=PAGE_SIZE && size !=PMD_SIZE && size !=PUD_SIZE ); -if (!stage2_get_leaf_entry (&kvm->arch.mmu, gpa, &pud, &pmd, &pte)) -return 0 ; - -if (pud) -return stage2_pudp_test_and_clear_young (pud); -else if (pmd) -return stage2_pmdp_test_and_clear_young (pmd); -else -return stage2_ptep_test_and_clear_young (pte); + kpte =kvm_pgtable_stage2_mkold (kvm->arch.mmu.pgt, gpa); + pte =__pte (kpte); +return pte_valid (pte) &&pte_young (pte); }static int kvm_test_age_hva_handler (struct kvm *kvm,gpa_t gpa,u64 size,void *data) { -pud_t *pud; -pmd_t *pmd; -pte_t *pte; -WARN_ON (size !=PAGE_SIZE && size !=PMD_SIZE && size !=PUD_SIZE ); -if (!stage2_get_leaf_entry (&kvm->arch.mmu, gpa, &pud, &pmd, &pte)) -return 0 ; - -if (pud) -return kvm_s2pud_young (*pud); -else if (pmd) -return pmd_young (*pmd); -else -return pte_young (*pte); +return kvm_pgtable_stage2_is_young (kvm->arch.mmu.pgt, gpa); }int kvm_age_hva (struct kvm *kvm,unsigned long start,unsigned long end)
Signature · 6 lines
2.28.0.618.gf4bc123cb7-goog _______________________________________________ kvmarm mailing list [email protected] https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Will Deacon
maintainerPATCH v5 12/21 KVM: arm64: Add support for stage-2 write-protect in generic page-table
In reply to Will DeaconFrom: Quentin Perret <[email protected]>
Add a stage-2 wrprotect() operation to the generic page-table code.
--- arch/arm64/include/asm/kvm_pgtable.h | 18 ++++++++++++++++++ arch/arm64/kvm/hyp/pgtable.c | 6 ++++++ 2 files changed, 24 insertions(+)
arch/arm64/include/asm/kvm_pgtable.h +18 -0
@@ -186,6 +186,24 @@ int kvm_pgtable_stage2_map(struct kvm_pgtable *pgt, u64 addr, u64 size,*/ int kvm_pgtable_stage2_unmap (struct kvm_pgtable *pgt,u64 addr,u64 size); +/** +* kvm_pgtable_stage2_wrprotect() - Write-protect guest stage-2 address range +* without TLB invalidation. +* @pgt: Page-table structure initialised by kvm_pgtable_stage2_init(). +* @addr: Intermediate physical address from which to write-protect, +* @size: Size of the range. +* +* The offset of @addr within a page is ignored and @size is rounded-up to +* the next page boundary. +* +* Note that it is the caller's responsibility to invalidate the TLB after +* calling this function to ensure that the updated permissions are visible +* to the CPUs. +* +* Return: 0 on success, negative error code on failure. +*/ +int kvm_pgtable_stage2_wrprotect (struct kvm_pgtable *pgt,u64 addr,u64 size); +/** * kvm_pgtable_stage2_mkyoung() - Set the access flag in a page-table entry. * @pgt: Page-table structure initialised by kvm_pgtable_stage2_init().
arch/arm64/kvm/hyp/pgtable.c +6 -0
@@ -746,6 +746,12 @@ static int stage2_update_leaf_attrs(struct kvm_pgtable *pgt, u64 addr,return 0 ; } +int kvm_pgtable_stage2_wrprotect (struct kvm_pgtable *pgt,u64 addr,u64 size) +{ +return stage2_update_leaf_attrs (pgt, addr, size,0 , +KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W ,NULL ); +} +kvm_pte_t kvm_pgtable_stage2_mkyoung (struct kvm_pgtable *pgt,u64 addr) {kvm_pte_t pte =0 ;
Signature · 6 lines
2.28.0.618.gf4bc123cb7-goog _______________________________________________ kvmarm mailing list [email protected] https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Will Deacon
maintainerPATCH v5 13/21 KVM: arm64: Convert write-protect operation to generic page-table API
In reply to Will DeaconFrom: Quentin Perret <[email protected]>
Convert stage2_wp_range() to call the kvm_pgtable_stage2_wrprotect() function of the generic page-table code instead of walking the page-table directly.
--- arch/arm64/kvm/mmu.c | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-)
arch/arm64/kvm/mmu.c +4 -21
@@ -71,6 +71,9 @@ static int stage2_apply_range(struct kvm *kvm, phys_addr_t addr,return ret; } +#define stage2_apply_range_resched (kvm, addr, end, fn) \ + stage2_apply_range(kvm, addr, end, fn, true) +static bool memslot_is_logging (struct kvm_memory_slot *memslot) {return memslot->dirty_bitmap && !(memslot->flags &KVM_MEM_READONLY );
@@ -1302,27 +1305,7 @@ static void stage2_wp_p4ds(struct kvm_s2_mmu *mmu, pgd_t *pgd,static void stage2_wp_range (struct kvm_s2_mmu *mmu,phys_addr_t addr,phys_addr_t end) {struct kvm *kvm = mmu->kvm; -pgd_t *pgd; -phys_addr_t next; - - pgd = mmu->pgd +stage2_pgd_index (kvm, addr); -do { -/* -* Release kvm_mmu_lock periodically if the memory region is -* large. Otherwise, we may see kernel panics with -* CONFIG_DETECT_HUNG_TASK, CONFIG_LOCKUP_DETECTOR, -* CONFIG_LOCKDEP. Additionally, holding the lock too long -* will also starve other vCPUs. We have to also make sure -* that the page tables are not freed while we released -* the lock. -*/ -cond_resched_lock (&kvm->mmu_lock); -if (!READ_ONCE (mmu->pgd)) -break ; - next =stage2_pgd_addr_end (kvm, addr, end); -if (stage2_pgd_present (kvm, *pgd)) -stage2_wp_p4ds (mmu, pgd, addr, next); - }while (pgd++, addr = next, addr != end); +stage2_apply_range_resched (kvm, addr, end, kvm_pgtable_stage2_wrprotect); }/**
Signature · 6 lines
2.28.0.618.gf4bc123cb7-goog _______________________________________________ kvmarm mailing list [email protected] https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Will Deacon
maintainerPATCH v5 14/21 KVM: arm64: Add support for stage-2 cache flushing in generic page-table
In reply to Will DeaconFrom: Quentin Perret <[email protected]>
Add support for cache flushing a range of the stage-2 address space to the generic page-table code.
--- arch/arm64/include/asm/kvm_pgtable.h | 15 +++++++++++++++ arch/arm64/kvm/hyp/pgtable.c | 26 ++++++++++++++++++++++++++ 2 files changed, 41 insertions(+)
arch/arm64/include/asm/kvm_pgtable.h +15 -0
@@ -248,6 +248,21 @@ kvm_pte_t kvm_pgtable_stage2_mkold(struct kvm_pgtable *pgt, u64 addr);*/ bool kvm_pgtable_stage2_is_young (struct kvm_pgtable *pgt,u64 addr); +/** +* kvm_pgtable_stage2_flush_range() - Clean and invalidate data cache to Point +* of Coherency for guest stage-2 address +* range. +* @pgt: Page-table structure initialised by kvm_pgtable_stage2_init(). +* @addr: Intermediate physical address from which to flush. +* @size: Size of the range. +* +* The offset of @addr within a page is ignored and @size is rounded-up to +* the next page boundary. +* +* Return: 0 on success, negative error code on failure. +*/ +int kvm_pgtable_stage2_flush (struct kvm_pgtable *pgt,u64 addr,u64 size); +/** * kvm_pgtable_walk() - Walk a page-table. * @pgt: Page-table structure initialised by kvm_pgtable_*_init().
arch/arm64/kvm/hyp/pgtable.c +26 -0
@@ -782,6 +782,32 @@ bool kvm_pgtable_stage2_is_young(struct kvm_pgtable *pgt, u64 addr)return pte &KVM_PTE_LEAF_ATTR_LO_S2_AF ; } +static int stage2_flush_walker (u64 addr,u64 end,u32 level,kvm_pte_t *ptep, +enum kvm_pgtable_walk_flags flag, +void *const arg) +{ +kvm_pte_t pte = *ptep; + +if (!kvm_pte_valid (pte) || !stage2_pte_cacheable (pte)) +return 0 ; + +stage2_flush_dcache (kvm_pte_follow (pte),kvm_granule_size (level)); +return 0 ; +} + +int kvm_pgtable_stage2_flush (struct kvm_pgtable *pgt,u64 addr,u64 size) +{ +struct kvm_pgtable_walker walker = { + .cb = stage2_flush_walker, + .flags =KVM_PGTABLE_WALK_LEAF , + }; + +if (cpus_have_const_cap (ARM64_HAS_STAGE2_FWB )) +return 0 ; + +return kvm_pgtable_walk (pgt, addr, size, &walker); +} +int kvm_pgtable_stage2_init (struct kvm_pgtable *pgt,struct kvm *kvm) {size_t pgd_sz;
Signature · 6 lines
2.28.0.618.gf4bc123cb7-goog _______________________________________________ kvmarm mailing list [email protected] https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Will Deacon
maintainerPATCH v5 15/21 KVM: arm64: Convert memslot cache-flushing code to generic page-table API
In reply to Will DeaconFrom: Quentin Perret <[email protected]>
Convert stage2_flush_memslot() to call the kvm_pgtable_stage2_flush() function of the generic page-table code instead of walking the page-table directly.
--- arch/arm64/kvm/mmu.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-)
arch/arm64/kvm/mmu.c +1 -12
@@ -460,21 +460,10 @@ static void stage2_flush_p4ds(struct kvm_s2_mmu *mmu, pgd_t *pgd,static void stage2_flush_memslot (struct kvm *kvm,struct kvm_memory_slot *memslot) { -struct kvm_s2_mmu *mmu = &kvm->arch.mmu;phys_addr_t addr = memslot->base_gfn <<PAGE_SHIFT ;phys_addr_t end = addr +PAGE_SIZE * memslot->npages; -phys_addr_t next; -pgd_t *pgd; - pgd = mmu->pgd +stage2_pgd_index (kvm, addr); -do { - next =stage2_pgd_addr_end (kvm, addr, end); -if (!stage2_pgd_none (kvm, *pgd)) -stage2_flush_p4ds (mmu, pgd, addr, next); - -if (next != end) -cond_resched_lock (&kvm->mmu_lock); - }while (pgd++, addr = next, addr != end); +stage2_apply_range_resched (kvm, addr, end, kvm_pgtable_stage2_flush); }/**
Signature · 6 lines
2.28.0.618.gf4bc123cb7-goog _______________________________________________ kvmarm mailing list [email protected] https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Will Deacon
maintainerPATCH v5 16/21 KVM: arm64: Add support for relaxing stage-2 perms in generic page-table code
In reply to Will DeaconAdd support for relaxing the permissions of a stage-2 mapping (i.e. adding additional permissions) to the generic page-table code.
--- arch/arm64/include/asm/kvm_pgtable.h | 19 +++++++++++++++++++ arch/arm64/kvm/hyp/pgtable.c | 20 ++++++++++++++++++++ 2 files changed, 39 insertions(+)
arch/arm64/include/asm/kvm_pgtable.h +19 -0
@@ -236,6 +236,25 @@ kvm_pte_t kvm_pgtable_stage2_mkyoung(struct kvm_pgtable *pgt, u64 addr);*/ kvm_pte_t kvm_pgtable_stage2_mkold (struct kvm_pgtable *pgt,u64 addr); +/** +* kvm_pgtable_stage2_relax_perms() - Relax the permissions enforced by a +* page-table entry. +* @pgt: Page-table structure initialised by kvm_pgtable_stage2_init(). +* @addr: Intermediate physical address to identify the page-table entry. +* @prot: Additional permissions to grant for the mapping. +* +* The offset of @addr within a page is ignored. +* +* If there is a valid, leaf page-table entry used to translate @addr, then +* relax the permissions in that entry according to the read, write and +* execute permissions specified by @prot. No permissions are removed, and +* TLB invalidation is performed after updating the entry. +* +* Return: 0 on success, negative error code on failure. +*/ +int kvm_pgtable_stage2_relax_perms (struct kvm_pgtable *pgt,u64 addr, +enum kvm_pgtable_prot prot); +/** * kvm_pgtable_stage2_is_young() - Test whether a page-table entry has the * access flag set.
arch/arm64/kvm/hyp/pgtable.c +20 -0
@@ -782,6 +782,26 @@ bool kvm_pgtable_stage2_is_young(struct kvm_pgtable *pgt, u64 addr)return pte &KVM_PTE_LEAF_ATTR_LO_S2_AF ; } +int kvm_pgtable_stage2_relax_perms (struct kvm_pgtable *pgt,u64 addr, +enum kvm_pgtable_prot prot) +{ +int ret; +kvm_pte_t set =0 , clr =0 ; + +if (prot &KVM_PGTABLE_PROT_R ) + set |=KVM_PTE_LEAF_ATTR_LO_S2_S2AP_R ; + +if (prot &KVM_PGTABLE_PROT_W ) + set |=KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W ; + +if (prot &KVM_PGTABLE_PROT_X ) + clr |=KVM_PTE_LEAF_ATTR_HI_S2_XN ; + + ret =stage2_update_leaf_attrs (pgt, addr,1 , set, clr,NULL ); +kvm_call_hyp (__kvm_tlb_flush_vmid_ipa, pgt->mmu, addr,0 ); +return ret; +} +static int stage2_flush_walker (u64 addr,u64 end,u32 level,kvm_pte_t *ptep,enum kvm_pgtable_walk_flags flag,void *const arg)
Signature · 6 lines
2.28.0.618.gf4bc123cb7-goog _______________________________________________ kvmarm mailing list [email protected] https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Re: [PATCH v5 16/21] KVM: arm64: Add support for relaxing stage-2 perms in generic page-table code
Hi Will,
Quoted 57 lines · Will Deacon
Add support for relaxing the permissions of a stage-2 mapping (i.e. adding additional permissions) to the generic page-table code.
Cc Marc Zyngier <[email protected]>Cc Quentin Perret <[email protected]>Reviewed-by Gavin Shan <[email protected]>Signed-off-by Will Deacon <[email protected]>--- arch/arm64/include/asm/kvm_pgtable.h | 19 +++++++++++++++++++ arch/arm64/kvm/hyp/pgtable.c | 20 ++++++++++++++++++++ 2 files changed, 39 insertions(+)arch/arm64/include/asm/kvm_pgtable.h +19
-0@@ -236,6 +236,25 @@ kvm_pte_t kvm_pgtable_stage2_mkyoung(struct kvm_pgtable *pgt, u64 addr);*/ kvm_pte_t kvm_pgtable_stage2_mkold (struct kvm_pgtable *pgt,u64 addr); +/** +* kvm_pgtable_stage2_relax_perms() - Relax the permissions enforced by a +* page-table entry. +* @pgt: Page-table structure initialised by kvm_pgtable_stage2_init(). +* @addr: Intermediate physical address to identify the page-table entry. +* @prot: Additional permissions to grant for the mapping. +* +* The offset of @addr within a page is ignored. +* +* If there is a valid, leaf page-table entry used to translate @addr, then +* relax the permissions in that entry according to the read, write and +* execute permissions specified by @prot. No permissions are removed, and +* TLB invalidation is performed after updating the entry. +* +* Return: 0 on success, negative error code on failure. +*/ +int kvm_pgtable_stage2_relax_perms (struct kvm_pgtable *pgt,u64 addr, +enum kvm_pgtable_prot prot); +/** * kvm_pgtable_stage2_is_young() - Test whether a page-table entry has the * access flag set. arch/arm64/kvm/hyp/pgtable.c +7
-0@@ -782,6 +782,26 @@ bool kvm_pgtable_stage2_is_young(struct kvm_pgtable *pgt, u64 addr)return pte &KVM_PTE_LEAF_ATTR_LO_S2_AF ; } +int kvm_pgtable_stage2_relax_perms (struct kvm_pgtable *pgt,u64 addr, +enum kvm_pgtable_prot prot) +{ +int ret; +kvm_pte_t set =0 , clr =0 ; + +if (prot &KVM_PGTABLE_PROT_R )
arch/arm64/kvm/hyp/pgtable.c bool kvm_pgtable_stage2_is_young(struct kvm_pgtable *pgt, u64 addr) · line 801
Quoted 10 lines
arch/arm64/kvm/hyp/pgtable.c +10
-0+ set |=KVM_PTE_LEAF_ATTR_LO_S2_S2AP_R ; + +if (prot &KVM_PGTABLE_PROT_W ) + set |=KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W ; + +if (prot &KVM_PGTABLE_PROT_X ) + clr |=KVM_PTE_LEAF_ATTR_HI_S2_XN ; + + ret =stage2_update_leaf_attrs (pgt, addr,1 , set, clr,NULL ); +kvm_call_hyp (__kvm_tlb_flush_vmid_ipa, pgt->mmu, addr,0 );
We know the level at which the entry is updated, as the visitor has a "level" parameter, I was wondering if it makes sense to do the TLBI invalidation there. Struct stage2_attr_data could have an extra field to control if the invalidation should be done in the visitor.
Thanks,
Alex
_______________________________________________
kvmarm mailing list
[email protected]
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Will Deacon
maintainerPATCH v5 17/21 KVM: arm64: Convert user_mem_abort() to generic page-table API
In reply to Will DeaconConvert user_mem_abort() to call kvm_pgtable_stage2_relax_perms() when handling a stage-2 permission fault and kvm_pgtable_stage2_map() when handling a stage-2 translation fault, rather than walking the page-table manually.
--- arch/arm64/kvm/mmu.c | 124 +++++++++++++++---------------------------- 1 file changed, 44 insertions(+), 80 deletions(-)
arch/arm64/kvm/mmu.c +44 -80
@@ -1499,18 +1499,19 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, {int ret;bool write_fault, writable, force_pte = false; -bool exec_fault, needs_exec; +bool exec_fault; +bool device = false;unsigned long mmu_seq; -gfn_t gfn = fault_ipa >>PAGE_SHIFT ;struct kvm *kvm = vcpu->kvm;struct kvm_mmu_memory_cache *memcache = &vcpu->arch.mmu_page_cache;struct vm_area_struct *vma;short vma_shift; +gfn_t gfn;kvm_pfn_t pfn; -pgprot_t mem_type =PAGE_S2 ;bool logging_active =memslot_is_logging (memslot); -unsigned long vma_pagesize, flags =0 ; -struct kvm_s2_mmu *mmu = vcpu->arch.hw_mmu; +unsigned long vma_pagesize; +enum kvm_pgtable_prot prot =KVM_PGTABLE_PROT_R ; +struct kvm_pgtable *pgt; write_fault =kvm_is_write_fault (vcpu); exec_fault =kvm_vcpu_trap_is_iabt (vcpu);
@@ -1543,22 +1544,24 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, vma_pagesize =PAGE_SIZE ; } -/* -* The stage2 has a minimum of 2 level table (For arm64 see -* kvm_arm_setup_stage2()). Hence, we are guaranteed that we can -* use PMD_SIZE huge mappings (even when the PMD is folded into PGD). -* As for PUD huge maps, we must make sure that we have at least -* 3 levels, i.e, PMD is not folded. -*/ -if (vma_pagesize ==PMD_SIZE || - (vma_pagesize ==PUD_SIZE &&kvm_stage2_has_pmd (kvm))) - gfn = (fault_ipa &huge_page_mask (hstate_vma (vma))) >>PAGE_SHIFT ; +if (vma_pagesize ==PMD_SIZE || vma_pagesize ==PUD_SIZE ) + fault_ipa &=huge_page_mask (hstate_vma (vma)); + + gfn = fault_ipa >>PAGE_SHIFT ;mmap_read_unlock (current->mm); -/* We need minimum second+third level pages */ - ret =kvm_mmu_topup_memory_cache (memcache,kvm_mmu_cache_min_pages (kvm)); -if (ret) -return ret; +/* +* Permission faults just need to update the existing leaf entry, +* and so normally don't require allocations from the memcache. The +* only exception to this is when dirty logging is enabled at runtime +* and a write fault needs to collapse a block entry into a table. +*/ +if (fault_status !=FSC_PERM || (logging_active && write_fault)) { + ret =kvm_mmu_topup_memory_cache (memcache, +kvm_mmu_cache_min_pages (kvm)); +if (ret) +return ret; + } mmu_seq = vcpu->kvm->mmu_notifier_seq;/*
@@ -1581,28 +1584,20 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,return -EFAULT ;if (kvm_is_device_pfn (pfn)) { - mem_type =PAGE_S2_DEVICE ; - flags |=KVM_S2PTE_FLAG_IS_IOMAP ; - }else if (logging_active) { -/* -* Faults on pages in a memslot with logging enabled -* should not be mapped with huge pages (it introduces churn -* and performance degradation), so force a pte mapping. -*/ - flags |=KVM_S2_FLAG_LOGGING_ACTIVE ; - + device = true; + }else if (logging_active && !write_fault) {/* * Only actually map the page as writable if this was a write * fault. */ -if (!write_fault) - writable = false; + writable = false; } -if (exec_fault &&is_iomap (flags)) +if (exec_fault && device)return -ENOEXEC ;spin_lock (&kvm->mmu_lock); + pgt = vcpu->arch.hw_mmu->pgt;if (mmu_notifier_retry (kvm, mmu_seq)) goto out_unlock;
@@ -1613,62 +1608,31 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,if (vma_pagesize ==PAGE_SIZE && !force_pte) vma_pagesize =transparent_hugepage_adjust (memslot, hva, &pfn, &fault_ipa); -if (writable) +if (writable) { + prot |=KVM_PGTABLE_PROT_W ;kvm_set_pfn_dirty (pfn); +mark_page_dirty (kvm, gfn); + } -if (fault_status !=FSC_PERM && !is_iomap (flags)) +if (fault_status !=FSC_PERM && !device)clean_dcache_guest_page (pfn, vma_pagesize); -if (exec_fault) +if (exec_fault) { + prot |=KVM_PGTABLE_PROT_X ;invalidate_icache_guest_page (pfn, vma_pagesize); + } -/* -* If we took an execution fault we have made the -* icache/dcache coherent above and should now let the s2 -* mapping be executable. -* -* Write faults (!exec_fault && FSC_PERM) are orthogonal to -* execute permissions, and we preserve whatever we have. -*/ - needs_exec = exec_fault || - (fault_status ==FSC_PERM && -stage2_is_exec (mmu, fault_ipa, vma_pagesize)); - -if (vma_pagesize ==PUD_SIZE ) { -pud_t new_pud =kvm_pfn_pud (pfn, mem_type); - - new_pud =kvm_pud_mkhuge (new_pud); -if (writable) - new_pud =kvm_s2pud_mkwrite (new_pud); - -if (needs_exec) - new_pud =kvm_s2pud_mkexec (new_pud); - - ret =stage2_set_pud_huge (mmu, memcache, fault_ipa, &new_pud); - }else if (vma_pagesize ==PMD_SIZE ) { -pmd_t new_pmd =kvm_pfn_pmd (pfn, mem_type); - - new_pmd =kvm_pmd_mkhuge (new_pmd); - -if (writable) - new_pmd =kvm_s2pmd_mkwrite (new_pmd); - -if (needs_exec) - new_pmd =kvm_s2pmd_mkexec (new_pmd); +if (device) + prot |=KVM_PGTABLE_PROT_DEVICE ; +else if (cpus_have_const_cap (ARM64_HAS_CACHE_DIC )) + prot |=KVM_PGTABLE_PROT_X ; - ret =stage2_set_pmd_huge (mmu, memcache, fault_ipa, &new_pmd); +if (fault_status ==FSC_PERM && !(logging_active && writable)) { + ret =kvm_pgtable_stage2_relax_perms (pgt, fault_ipa, prot); }else { -pte_t new_pte =kvm_pfn_pte (pfn, mem_type); - -if (writable) { - new_pte =kvm_s2pte_mkwrite (new_pte); -mark_page_dirty (kvm, gfn); - } - -if (needs_exec) - new_pte =kvm_s2pte_mkexec (new_pte); - - ret =stage2_set_pte (mmu, memcache, fault_ipa, &new_pte, flags); + ret =kvm_pgtable_stage2_map (pgt, fault_ipa, vma_pagesize, +__pfn_to_phys (pfn), prot, + memcache); } out_unlock:
Signature · 6 lines
2.28.0.618.gf4bc123cb7-goog _______________________________________________ kvmarm mailing list [email protected] https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Will Deacon
maintainerPATCH v5 18/21 KVM: arm64: Check the pgt instead of the pgd when modifying page-table
In reply to Will DeaconIn preparation for removing the 'pgd' field of 'struct kvm_s2_mmu', update the few remaining users to check the 'pgt' field instead.
--- arch/arm64/kvm/mmu.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
arch/arm64/kvm/mmu.c +3 -3
@@ -1829,7 +1829,7 @@ static int kvm_unmap_hva_handler(struct kvm *kvm, gpa_t gpa, u64 size, void *datint kvm_unmap_hva_range (struct kvm *kvm,unsigned long start,unsigned long end,unsigned flags) { -if (!kvm->arch.mmu.pgd) +if (!kvm->arch.mmu.pgt)return 0 ;trace_kvm_unmap_hva_range (start, end);
@@ -1892,7 +1892,7 @@ static int kvm_test_age_hva_handler(struct kvm *kvm, gpa_t gpa, u64 size, void *int kvm_age_hva (struct kvm *kvm,unsigned long start,unsigned long end) { -if (!kvm->arch.mmu.pgd) +if (!kvm->arch.mmu.pgt)return 0 ;trace_kvm_age_hva (start, end);return handle_hva_to_gpa (kvm, start, end, kvm_age_hva_handler,NULL );
@@ -1900,7 +1900,7 @@ int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end)int kvm_test_age_hva (struct kvm *kvm,unsigned long hva) { -if (!kvm->arch.mmu.pgd) +if (!kvm->arch.mmu.pgt)return 0 ;trace_kvm_test_age_hva (hva); return handle_hva_to_gpa(kvm, hva, hva + PAGE_SIZE,
Signature · 6 lines
2.28.0.618.gf4bc123cb7-goog _______________________________________________ kvmarm mailing list [email protected] https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Will Deacon
maintainerPATCH v5 19/21 KVM: arm64: Remove unused page-table code
In reply to Will DeaconNow that KVM is using the generic page-table code to manage the guest stage-2 page-tables, we can remove a bunch of unused macros, #defines and static inline functions from the old implementation.
--- arch/arm64/include/asm/kvm_mmu.h | 171 ------ arch/arm64/include/asm/pgtable-hwdef.h | 18 - arch/arm64/include/asm/pgtable-prot.h | 13 - arch/arm64/include/asm/stage2_pgtable.h | 215 ------- arch/arm64/kvm/mmu.c | 755 ------------------------ 5 files changed, 1172 deletions(-)
arch/arm64/include/asm/kvm_mmu.h +0 -171
@@ -107,12 +107,6 @@ static __always_inline unsigned long __kern_hyp_va(unsigned long v)#define kvm_phys_size (kvm) (_AC(1, ULL) << kvm_phys_shift(kvm))#define kvm_phys_mask (kvm) (kvm_phys_size(kvm) - _AC(1, ULL)) -static inline bool kvm_page_empty (void *ptr) -{ -struct page *ptr_page =virt_to_page (ptr); -return page_count (ptr_page) ==1 ; -} -#include <asm/kvm_pgtable.h> #include <asm/stage2_pgtable.h>
@@ -135,123 +129,6 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu);phys_addr_t kvm_mmu_get_httbr (void );phys_addr_t kvm_get_idmap_vector (void );int kvm_mmu_init (void ); -#define kvm_mk_pmd (ptep) \ - __pmd(__phys_to_pmd_val(__pa(ptep)) | PMD_TYPE_TABLE) -#define kvm_mk_pud (pmdp) \ - __pud(__phys_to_pud_val(__pa(pmdp)) | PMD_TYPE_TABLE) -#define kvm_mk_p4d (pmdp) \ - __p4d(__phys_to_p4d_val(__pa(pmdp)) | PUD_TYPE_TABLE) - -#define kvm_set_pud (pudp, pud) set_pud(pudp, pud) - -#define kvm_pfn_pte (pfn, prot) pfn_pte(pfn, prot) -#define kvm_pfn_pmd (pfn, prot) pfn_pmd(pfn, prot) -#define kvm_pfn_pud (pfn, prot) pfn_pud(pfn, prot) - -#define kvm_pud_pfn (pud) pud_pfn(pud) - -#define kvm_pmd_mkhuge (pmd) pmd_mkhuge(pmd) -#define kvm_pud_mkhuge (pud) pud_mkhuge(pud) - -static inline pte_t kvm_s2pte_mkwrite (pte_t pte) -{ -pte_val (pte) |=PTE_S2_RDWR ; -return pte; -} - -static inline pmd_t kvm_s2pmd_mkwrite (pmd_t pmd) -{ -pmd_val (pmd) |=PMD_S2_RDWR ; -return pmd; -} - -static inline pud_t kvm_s2pud_mkwrite (pud_t pud) -{ -pud_val (pud) |=PUD_S2_RDWR ; -return pud; -} - -static inline pte_t kvm_s2pte_mkexec (pte_t pte) -{ -pte_val (pte) &= ~PTE_S2_XN ; -return pte; -} - -static inline pmd_t kvm_s2pmd_mkexec (pmd_t pmd) -{ -pmd_val (pmd) &= ~PMD_S2_XN ; -return pmd; -} - -static inline pud_t kvm_s2pud_mkexec (pud_t pud) -{ -pud_val (pud) &= ~PUD_S2_XN ; -return pud; -} - -static inline void kvm_set_s2pte_readonly (pte_t *ptep) -{ -pteval_t old_pteval, pteval; - - pteval =READ_ONCE (pte_val (*ptep)); -do { - old_pteval = pteval; - pteval &= ~PTE_S2_RDWR ; - pteval |=PTE_S2_RDONLY ; - pteval =cmpxchg_relaxed (&pte_val (*ptep), old_pteval, pteval); - }while (pteval != old_pteval); -} - -static inline bool kvm_s2pte_readonly (pte_t *ptep) -{ -return (READ_ONCE (pte_val (*ptep)) &PTE_S2_RDWR ) ==PTE_S2_RDONLY ; -} - -static inline bool kvm_s2pte_exec (pte_t *ptep) -{ -return !(READ_ONCE (pte_val (*ptep)) &PTE_S2_XN ); -} - -static inline void kvm_set_s2pmd_readonly (pmd_t *pmdp) -{ -kvm_set_s2pte_readonly ((pte_t *)pmdp); -} - -static inline bool kvm_s2pmd_readonly (pmd_t *pmdp) -{ -return kvm_s2pte_readonly ((pte_t *)pmdp); -} - -static inline bool kvm_s2pmd_exec (pmd_t *pmdp) -{ -return !(READ_ONCE (pmd_val (*pmdp)) &PMD_S2_XN ); -} - -static inline void kvm_set_s2pud_readonly (pud_t *pudp) -{ -kvm_set_s2pte_readonly ((pte_t *)pudp); -} - -static inline bool kvm_s2pud_readonly (pud_t *pudp) -{ -return kvm_s2pte_readonly ((pte_t *)pudp); -} - -static inline bool kvm_s2pud_exec (pud_t *pudp) -{ -return !(READ_ONCE (pud_val (*pudp)) &PUD_S2_XN ); -} - -static inline pud_t kvm_s2pud_mkyoung (pud_t pud) -{ -return pud_mkyoung (pud); -} - -static inline bool kvm_s2pud_young (pud_t pud) -{ -return pud_young (pud); -} -struct kvm ;
@@ -293,30 +170,6 @@ static inline void __invalidate_icache_guest_page(kvm_pfn_t pfn, } } -static inline void __kvm_flush_dcache_pte (pte_t pte) -{ -if (!cpus_have_const_cap (ARM64_HAS_STAGE2_FWB )) { -struct page *page =pte_page (pte); -kvm_flush_dcache_to_poc (page_address (page),PAGE_SIZE ); - } -} - -static inline void __kvm_flush_dcache_pmd (pmd_t pmd) -{ -if (!cpus_have_const_cap (ARM64_HAS_STAGE2_FWB )) { -struct page *page =pmd_page (pmd); -kvm_flush_dcache_to_poc (page_address (page),PMD_SIZE ); - } -} - -static inline void __kvm_flush_dcache_pud (pud_t pud) -{ -if (!cpus_have_const_cap (ARM64_HAS_STAGE2_FWB )) { -struct page *page =pud_page (pud); -kvm_flush_dcache_to_poc (page_address (page),PUD_SIZE ); - } -} -void kvm_set_way_flush (struct kvm_vcpu *vcpu);void kvm_toggle_cache (struct kvm_vcpu *vcpu,bool was_enabled);
@@ -477,30 +330,6 @@ static inline int hyp_map_aux_data(void)#define kvm_phys_to_vttbr (addr) phys_to_ttbr(addr) -/* -* Get the magic number 'x' for VTTBR:BADDR of this KVM instance. -* With v8.2 LVA extensions, 'x' should be a minimum of 6 with -* 52bit IPS. -*/ -static inline int arm64_vttbr_x (u32 ipa_shift,u32 levels) -{ -int x =ARM64_VTTBR_X (ipa_shift, levels); - -return (IS_ENABLED (CONFIG_ARM64_PA_BITS_52 ) && x <6 ) ?6 : x; -} - -static inline u64 vttbr_baddr_mask (u32 ipa_shift,u32 levels) -{ -unsigned int x =arm64_vttbr_x (ipa_shift, levels); - -return GENMASK_ULL (PHYS_MASK_SHIFT -1 , x); -} - -static inline u64 kvm_vttbr_baddr_mask (struct kvm *kvm) -{ -return vttbr_baddr_mask (kvm_phys_shift (kvm),kvm_stage2_levels (kvm)); -} - static __always_inline u64 kvm_get_vttbr(struct kvm_s2_mmu *mmu) {struct kvm_vmid *vmid = &mmu->vmid;
arch/arm64/include/asm/pgtable-hwdef.h +0 -18
@@ -156,7 +156,6 @@#define PTE_CONT (_AT(pteval_t, 1) << 52)/* Contiguous range */ #define PTE_PXN (_AT(pteval_t, 1) << 53)/* Privileged XN */ #define PTE_UXN (_AT(pteval_t, 1) << 54)/* User XN */ -#define PTE_HYP_XN (_AT(pteval_t, 1) << 54)/* HYP XN */ #define PTE_ADDR_LOW (((_AT(pteval_t, 1) << (48 - PAGE_SHIFT)) - 1) << PAGE_SHIFT)#ifdef CONFIG_ARM64_PA_BITS_52
@@ -172,23 +171,6 @@#define PTE_ATTRINDX (t) (_AT(pteval_t, (t)) << 2)#define PTE_ATTRINDX_MASK (_AT(pteval_t, 7) << 2) -/* -* 2nd stage PTE definitions -*/ -#define PTE_S2_RDONLY (_AT(pteval_t, 1) << 6)/* HAP[2:1] */ -#define PTE_S2_RDWR (_AT(pteval_t, 3) << 6)/* HAP[2:1] */ -#define PTE_S2_XN (_AT(pteval_t, 2) << 53)/* XN[1:0] */ -#define PTE_S2_SW_RESVD (_AT(pteval_t, 15) << 55)/* Reserved for SW */ - -#define PMD_S2_RDONLY (_AT(pmdval_t, 1) << 6)/* HAP[2:1] */ -#define PMD_S2_RDWR (_AT(pmdval_t, 3) << 6)/* HAP[2:1] */ -#define PMD_S2_XN (_AT(pmdval_t, 2) << 53)/* XN[1:0] */ -#define PMD_S2_SW_RESVD (_AT(pmdval_t, 15) << 55)/* Reserved for SW */ - -#define PUD_S2_RDONLY (_AT(pudval_t, 1) << 6)/* HAP[2:1] */ -#define PUD_S2_RDWR (_AT(pudval_t, 3) << 6)/* HAP[2:1] */ -#define PUD_S2_XN (_AT(pudval_t, 2) << 53)/* XN[1:0] */ -/* * Memory Attribute override for Stage-2 (MemAttr[3:0]) */
arch/arm64/include/asm/pgtable-prot.h +0 -13
@@ -73,19 +73,6 @@ extern bool arm64_use_ng_mappings; __val; \ }) -#define PAGE_S2_XN \ - ({ \ - u64 __val; \ - if (cpus_have_const_cap(ARM64_HAS_CACHE_DIC)) \ - __val = 0; \ - else \ - __val = PTE_S2_XN; \ - __val; \ - }) - -#define PAGE_S2 __pgprot(_PROT_DEFAULT | PAGE_S2_MEMATTR(NORMAL) | PTE_S2_RDONLY | PAGE_S2_XN) -#define PAGE_S2_DEVICE __pgprot(_PROT_DEFAULT | PAGE_S2_MEMATTR(DEVICE_nGnRE) | PTE_S2_RDONLY | PTE_S2_XN) -#define PAGE_NONE __pgprot(((_PAGE_DEFAULT) & ~PTE_VALID) | PTE_PROT_NONE | PTE_RDONLY | PTE_NG | PTE_PXN | PTE_UXN)/* shared+writable pages are clean by default, hence PTE_RDONLY|PTE_WRITE */ #define PAGE_SHARED __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_RDONLY | PTE_NG | PTE_PXN | PTE_UXN | PTE_WRITE)
arch/arm64/include/asm/stage2_pgtable.h +0 -215
237 lines not on this page · raw message
arch/arm64/kvm/mmu.c +0 -755
796 lines not on this page · raw message
Signature · 6 lines
2.28.0.618.gf4bc123cb7-goog _______________________________________________ kvmarm mailing list [email protected] https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Will Deacon
maintainerPATCH v5 20/21 KVM: arm64: Remove unused 'pgd' field from 'struct kvm_s2_mmu'
In reply to Will DeaconThe stage-2 page-tables are entirely encapsulated by the 'pgt' field of 'struct kvm_s2_mmu', so remove the unused 'pgd' field.
--- arch/arm64/include/asm/kvm_host.h | 1 - arch/arm64/kvm/mmu.c | 2 -- 2 files changed, 3 deletions(-)
arch/arm64/include/asm/kvm_host.h +0 -1
@@ -79,7 +79,6 @@ struct kvm_s2_mmu {* for vEL1/EL0 with vHCR_EL2.VM == 0. In that case, we use the * canonical stage-2 page tables. */ -pgd_t *pgd;phys_addr_t pgd_phys;struct kvm_pgtable *pgt;
arch/arm64/kvm/mmu.c +0 -2
@@ -389,7 +389,6 @@ int kvm_init_stage2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu) mmu->kvm = kvm; mmu->pgt = pgt; mmu->pgd_phys =__pa (pgt->pgd); - mmu->pgd = (void *)pgt->pgd; mmu->vmid.vmid_gen =0 ;return 0 ;
@@ -475,7 +474,6 @@ void kvm_free_stage2_pgd(struct kvm_s2_mmu *mmu)spin_lock (&kvm->mmu_lock); pgt = mmu->pgt;if (pgt) { - mmu->pgd =NULL ; mmu->pgd_phys =0 ; mmu->pgt =NULL ;free_percpu (mmu->last_vcpu_ran);
Signature · 6 lines
2.28.0.618.gf4bc123cb7-goog _______________________________________________ kvmarm mailing list [email protected] https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Will Deacon
maintainerPATCH v5 21/21 KVM: arm64: Don't constrain maximum IPA size based on host configuration
In reply to Will DeaconNow that the guest stage-2 page-tables are managed independently from the host stage-1 page-tables, we can avoid constraining the IPA size based on the host and instead limit it only based on the PARange field of the ID_AA64MMFR0 register.
--- arch/arm64/kvm/reset.c | 40 ++++++---------------------------------- 1 file changed, 6 insertions(+), 34 deletions(-)
arch/arm64/kvm/reset.c +6 -34
@@ -339,7 +339,7 @@ u32 get_kvm_ipa_limit(void)int kvm_set_ipa_limit (void ) { -unsigned int ipa_max, pa_max, va_max, parange, tgran_2; +unsigned int parange, tgran_2;u64 mmfr0; mmfr0 =read_sanitised_ftr_reg (SYS_ID_AA64MMFR0_EL1 );
@@ -376,39 +376,11 @@ int kvm_set_ipa_limit(void)break ; } - pa_max =id_aa64mmfr0_parange_to_phys_shift (parange); - -/* Clamp the IPA limit to the PA size supported by the kernel */ - ipa_max = (pa_max >PHYS_MASK_SHIFT ) ?PHYS_MASK_SHIFT : pa_max; -/* -* Since our stage2 table is dependent on the stage1 page table code, -* we must always honor the following condition: -* -* Number of levels in Stage1 >= Number of levels in Stage2. -* -* So clamp the ipa limit further down to limit the number of levels. -* Since we can concatenate upto 16 tables at entry level, we could -* go upto 4bits above the maximum VA addressable with the current -* number of levels. -*/ - va_max =PGDIR_SHIFT +PAGE_SHIFT -3 ; - va_max +=4 ; - -if (va_max < ipa_max) - ipa_max = va_max; - -/* -* If the final limit is lower than the real physical address -* limit of the CPUs, report the reason. -*/ -if (ipa_max < pa_max) -pr_info ("kvm: Limiting the IPA size due to kernel %s Address limit\n" , - (va_max < pa_max) ?"Virtual" :"Physical" ); - -WARN (ipa_max <KVM_PHYS_SHIFT , -"KVM IPA limit (%d bit) is smaller than default size\n" , ipa_max); - kvm_ipa_limit = ipa_max; -kvm_info ("IPA Size Limit: %dbits\n" , kvm_ipa_limit); + kvm_ipa_limit =id_aa64mmfr0_parange_to_phys_shift (parange); +WARN (kvm_ipa_limit <KVM_PHYS_SHIFT , +"KVM IPA Size Limit (%d bits) is smaller than default size\n" , + kvm_ipa_limit); +kvm_info ("IPA Size Limit: %d bits\n" , kvm_ipa_limit);return 0 ; }
Signature · 6 lines
2.28.0.618.gf4bc123cb7-goog _______________________________________________ kvmarm mailing list [email protected] https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Marc Zyngier
maintainerQuoted 9 lines · Will Deacon
It's me again, with version five of the KVM page-table rework previously seen at:
v1: https://lore.kernel.org/r/[email protected]
v2: https://lore.kernel.org/r/[email protected]
v3: https://lore.kernel.org/r/[email protected]
v4: https://lore.kernel.org/r/[email protected][...]
As for last time, I've just pushed that it -next so that it simmers for a while.
[01/21] KVM: arm64: Remove kvm_mmu_free_memory_caches()
commit: 9af3e08baa7c20ee69b7fc18e720e08a091493b9
[02/21] KVM: arm64: Add stand-alone page-table walker infrastructure
commit: b1e57de62cfb4d05f45ab848bb893fbcff9557d3
[03/21] KVM: arm64: Add support for creating kernel-agnostic stage-1 page tables
commit: bb0e92cbbcd1f91411d0a7241f8febe2c8c5b078
[04/21] KVM: arm64: Use generic allocator for hyp stage-1 page-tables
commit: 0f9d09b8e29bc8166f6584279aedc4a7a4038f68
[05/21] KVM: arm64: Add support for creating kernel-agnostic stage-2 page tables
commit: 71233d05f4b5e3560f0d3d5607d01e9beff8dcbd
[06/21] KVM: arm64: Add support for stage-2 map()/unmap() in generic page-table
commit: 6d9d2115c48027132a69477c98d812be669f5b9b
[07/21] KVM: arm64: Convert kvm_phys_addr_ioremap() to generic page-table API
commit: 02bbd374ce4a8aad36c022fd1203cb9f11b52ee3
[08/21] KVM: arm64: Convert kvm_set_spte_hva() to generic page-table API
commit: e9edb17ae0a2634bfa5dac529229c06f97f2b669
[09/21] KVM: arm64: Convert unmap_stage2_range() to generic page-table API
commit: 52bae936f0e7be4b4c088505aecb8f04121f1dee
[10/21] KVM: arm64: Add support for stage-2 page-aging in generic page-table
commit: e0e5a07f3f5adca259ffa8ad3f4153ab448a4115
[11/21] KVM: arm64: Convert page-aging and access faults to generic page-table API
commit: ee8efad7994ce204806260bc0261c7e103f704c1
[12/21] KVM: arm64: Add support for stage-2 write-protect in generic page-table
commit: 73d49df2c3e7cad5bf64c92ec03ce9e3823898b9
[13/21] KVM: arm64: Convert write-protect operation to generic page-table API
commit: cc38d61cace392a5f064f2981ce6009bb158de21
[14/21] KVM: arm64: Add support for stage-2 cache flushing in generic page-table
commit: 93c66b40d728178722706a306df15ce92c819cd6
[15/21] KVM: arm64: Convert memslot cache-flushing code to generic page-table API
commit: 8d5207bef6913b5fac91cb58e509711e406c160d
[16/21] KVM: arm64: Add support for relaxing stage-2 perms in generic page-table code
commit: adcd4e23291e67575be0c8b08eed04fbe7fd9e77
[17/21] KVM: arm64: Convert user_mem_abort() to generic page-table API
commit: 6f745f1bb5bf2914be2344b0dd7781d0528b3e42
[18/21] KVM: arm64: Check the pgt instead of the pgd when modifying page-table
commit: 063deeb1f2c234ca5e9d156c7a86825fc5377477
[19/21] KVM: arm64: Remove unused page-table code
commit: 3f26ab58e3272ceada11279c2e90894d4995cf79
[20/21] KVM: arm64: Remove unused 'pgd' field from 'struct kvm_s2_mmu'
commit: 74cfa7ea66a7e54a5ea1d8ad1fb74a5e832ed867
[21/21] KVM: arm64: Don't constrain maximum IPA size based on host configuration
commit: c9b69a0cf0b4336fe7d2e35c46273debc68910fdCheers,
M.
Signature · 7 lines
Without deviation from the norm, progress is not possible. _______________________________________________ kvmarm mailing list [email protected] https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Hi Will,
Quoted 10 lines · Will Deacon
It's me again, with version five of the KVM page-table rework previously seen at:
v1: https://lore.kernel.org/r/[email protected]
v2: https://lore.kernel.org/r/[email protected]
v3: https://lore.kernel.org/r/[email protected]
v4: https://lore.kernel.org/r/[email protected]Changes since v4 include:
Quoted 8 lines
* Add comments to the kerneldoc describing alignment behaviour for addresses and size parameters
* Fix formatting of IPA size messages
* Fix handling of unaligned addresses inkvm_phys_addr_ioremap()
* Add DSB after zeroing stage-2 PGD pages
* Add reviewer tagsOnce again, thanks to Alex, Gavin and Andrew for their comments.
I didn't realize that there won't be another iteration of the series. I reviewed all the patches with the exception of patch #5 ("KVM: arm64: Use generic allocator for hyp stage-1 page-tables") because I don't know much about what needs to mapped at EL2 stage 1, everything else looks alright to me. If the commit message can be modified, you can add my Reviewed-by tag to the series (sans #5); it's fine if that's not possible.
Thanks,
Alex
Quoted 50 lines
Will
Cc Marc Zyngier <[email protected]>Cc Quentin Perret <[email protected]>Cc James Morse <[email protected]>Cc Suzuki Poulose <[email protected]>Cc Catalin Marinas <[email protected]>Cc Gavin Shan <[email protected]>Cc Alexandru Elisei <[email protected]>Cc Andrew Scull <[email protected]>--->8
Quentin Perret (4):
KVM: arm64: Add support for stage-2 write-protect in generic
page-table
KVM: arm64: Convert write-protect operation to generic page-table API
KVM: arm64: Add support for stage-2 cache flushing in generic
page-table
KVM: arm64: Convert memslot cache-flushing code to generic page-table
APIWill Deacon (17):
KVM: arm64: Removekvm_mmu_free_memory_caches()
KVM: arm64: Add stand-alone page-table walker infrastructure
KVM: arm64: Add support for creating kernel-agnostic stage-1 page
tables
KVM: arm64: Use generic allocator for hyp stage-1 page-tables
KVM: arm64: Add support for creating kernel-agnostic stage-2 page
tables
KVM: arm64: Add support for stage-2 map()/unmap() in generic
page-table
KVM: arm64: Convertkvm_phys_addr_ioremap()to generic page-table API
KVM: arm64: Convertkvm_set_spte_hva()to generic page-table API
KVM: arm64: Convertunmap_stage2_range()to generic page-table API
KVM: arm64: Add support for stage-2 page-aging in generic page-table
KVM: arm64: Convert page-aging and access faults to generic page-table
API
KVM: arm64: Add support for relaxing stage-2 perms in generic
page-table code
KVM: arm64: Convertuser_mem_abort()to generic page-table API
KVM: arm64: Check the pgt instead of the pgd when modifying page-table
KVM: arm64: Remove unused page-table code
KVM: arm64: Remove unused 'pgd' field from 'structkvm_s2_mmu'
KVM: arm64: Don't constrain maximum IPA size based on host
configuration
Quoted 15 lines
arch/arm64/include/asm/kvm_host.h | 2 +- arch/arm64/include/asm/kvm_mmu.h | 251 +--- arch/arm64/include/asm/kvm_pgtable.h | 309 ++++ arch/arm64/include/asm/pgtable-hwdef.h | 24 - arch/arm64/include/asm/pgtable-prot.h | 19 - arch/arm64/include/asm/stage2_pgtable.h | 215 --- arch/arm64/kvm/arm.c | 2 +- arch/arm64/kvm/hyp/Makefile | 2 +- arch/arm64/kvm/hyp/pgtable.c | 883 ++++++++++++ arch/arm64/kvm/mmu.c | 1748 ++++------------------- arch/arm64/kvm/reset.c | 40 +- 11 files changed, 1479 insertions(+), 2016 deletions(-) create mode 100644 arch/arm64/include/asm/kvm_pgtable.h create mode 100644 arch/arm64/kvm/hyp/pgtable.c
_______________________________________________
kvmarm mailing list
[email protected]
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Will Deacon
maintainerHi Alex,
Quoted 18 lines · Alexandru Elisei
Quoted 17 lines · Will Deacon
It's me again, with version five of the KVM page-table rework previously seen at:
v1: https://lore.kernel.org/r/[email protected]
v2: https://lore.kernel.org/r/[email protected]
v3: https://lore.kernel.org/r/[email protected]
v4: https://lore.kernel.org/r/[email protected]Changes since v4 include:
* Add comments to the kerneldoc describing alignment behaviour for addresses and size parameters
* Fix formatting of IPA size messages
* Fix handling of unaligned addresses inkvm_phys_addr_ioremap()
* Add DSB after zeroing stage-2 PGD pages
* Add reviewer tags
Quoted 8 lines
Quoted 1 line
Once again, thanks to Alex, Gavin and Andrew for their comments.
I didn't realize that there won't be another iteration of the series. I reviewed all the patches with the exception of patch #5 ("KVM: arm64: Use generic allocator for hyp stage-1 page-tables") because I don't know much about what needs to mapped at EL2 stage 1, everything else looks alright to me. If the commit message can be modified, you can add my Reviewed-by tag to the series (sans #5); it's fine if that's not possible.
The patches ended up in kvmarm/next as the remaining comments were pretty minor, so I've just been sending patches on top to clear up the leftovers (e.g. passing the TLBI level when handling a stage-2 permission fault).
Cheers for your review, the series definitely ended up in a much better shape for it. The hyp code is a walk in the park compared with the stage-2 parts, so don't worry about skipping that.
Will
_______________________________________________
kvmarm mailing list
[email protected]
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm