Skip to content

Commit a90e001

Browse files
author
Marc Zyngier
committed
Merge branch kvm-arm64/pkvm-np-thp-6.16 into kvmarm-master/next
* kvm-arm64/pkvm-np-thp-6.16: (21 commits) : . : Large mapping support for non-protected pKVM guests, courtesy of : Vincent Donnefort. From the cover letter: : : "This series adds support for stage-2 huge mappings (PMD_SIZE) to pKVM : np-guests, that is installing PMD-level mappings in the stage-2, : whenever the stage-1 is backed by either Hugetlbfs or THPs." : . KVM: arm64: np-guest CMOs with PMD_SIZE fixmap KVM: arm64: Stage-2 huge mappings for np-guests KVM: arm64: Add a range to pkvm_mappings KVM: arm64: Convert pkvm_mappings to interval tree KVM: arm64: Add a range to __pkvm_host_test_clear_young_guest() KVM: arm64: Add a range to __pkvm_host_wrprotect_guest() KVM: arm64: Add a range to __pkvm_host_unshare_guest() KVM: arm64: Add a range to __pkvm_host_share_guest() KVM: arm64: Introduce for_each_hyp_page KVM: arm64: Handle huge mappings for np-guest CMOs KVM: arm64: Extend pKVM selftest for np-guests KVM: arm64: Selftest for pKVM transitions KVM: arm64: Don't WARN from __pkvm_host_share_guest() KVM: arm64: Add .hyp.data section KVM: arm64: Unconditionally cross check hyp state KVM: arm64: Defer EL2 stage-1 mapping on share KVM: arm64: Move hyp state to hyp_vmemmap KVM: arm64: Introduce {get,set}_host_state() helpers KVM: arm64: Use 0b11 for encoding PKVM_NOPAGE KVM: arm64: Fix pKVM page-tracking comments ... Signed-off-by: Marc Zyngier <maz@kernel.org>
2 parents 67bd641 + c353fde commit a90e001

File tree

19 files changed

+730
-245
lines changed

19 files changed

+730
-245
lines changed

arch/arm64/include/asm/kvm_host.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -971,20 +971,22 @@ struct kvm_vcpu_arch {
971971
#define vcpu_sve_zcr_elx(vcpu) \
972972
(unlikely(is_hyp_ctxt(vcpu)) ? ZCR_EL2 : ZCR_EL1)
973973

974-
#define vcpu_sve_state_size(vcpu) ({ \
974+
#define sve_state_size_from_vl(sve_max_vl) ({ \
975975
size_t __size_ret; \
976-
unsigned int __vcpu_vq; \
976+
unsigned int __vq; \
977977
\
978-
if (WARN_ON(!sve_vl_valid((vcpu)->arch.sve_max_vl))) { \
978+
if (WARN_ON(!sve_vl_valid(sve_max_vl))) { \
979979
__size_ret = 0; \
980980
} else { \
981-
__vcpu_vq = vcpu_sve_max_vq(vcpu); \
982-
__size_ret = SVE_SIG_REGS_SIZE(__vcpu_vq); \
981+
__vq = sve_vq_from_vl(sve_max_vl); \
982+
__size_ret = SVE_SIG_REGS_SIZE(__vq); \
983983
} \
984984
\
985985
__size_ret; \
986986
})
987987

988+
#define vcpu_sve_state_size(vcpu) sve_state_size_from_vl((vcpu)->arch.sve_max_vl)
989+
988990
#define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE | \
989991
KVM_GUESTDBG_USE_SW_BP | \
990992
KVM_GUESTDBG_USE_HW | \

arch/arm64/include/asm/kvm_pgtable.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ typedef u64 kvm_pte_t;
5959

6060
#define KVM_PHYS_INVALID (-1ULL)
6161

62+
#define KVM_PTE_TYPE BIT(1)
63+
#define KVM_PTE_TYPE_BLOCK 0
64+
#define KVM_PTE_TYPE_PAGE 1
65+
#define KVM_PTE_TYPE_TABLE 1
66+
6267
#define KVM_PTE_LEAF_ATTR_LO GENMASK(11, 2)
6368

6469
#define KVM_PTE_LEAF_ATTR_LO_S1_ATTRIDX GENMASK(4, 2)
@@ -413,7 +418,7 @@ static inline bool kvm_pgtable_walk_lock_held(void)
413418
*/
414419
struct kvm_pgtable {
415420
union {
416-
struct rb_root pkvm_mappings;
421+
struct rb_root_cached pkvm_mappings;
417422
struct {
418423
u32 ia_bits;
419424
s8 start_level;

arch/arm64/include/asm/kvm_pkvm.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,12 @@ static inline unsigned long host_s2_pgtable_pages(void)
135135
return res;
136136
}
137137

138+
#ifdef CONFIG_NVHE_EL2_DEBUG
139+
static inline unsigned long pkvm_selftest_pages(void) { return 32; }
140+
#else
141+
static inline unsigned long pkvm_selftest_pages(void) { return 0; }
142+
#endif
143+
138144
#define KVM_FFA_MBOX_NR_PAGES 1
139145

140146
static inline unsigned long hyp_ffa_proxy_pages(void)
@@ -167,6 +173,8 @@ struct pkvm_mapping {
167173
struct rb_node node;
168174
u64 gfn;
169175
u64 pfn;
176+
u64 nr_pages;
177+
u64 __subtree_last; /* Internal member for interval tree */
170178
};
171179

172180
int pkvm_pgtable_stage2_init(struct kvm_pgtable *pgt, struct kvm_s2_mmu *mmu,

arch/arm64/include/asm/sections.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ extern char __alt_instructions[], __alt_instructions_end[];
1111
extern char __hibernate_exit_text_start[], __hibernate_exit_text_end[];
1212
extern char __hyp_idmap_text_start[], __hyp_idmap_text_end[];
1313
extern char __hyp_text_start[], __hyp_text_end[];
14+
extern char __hyp_data_start[], __hyp_data_end[];
1415
extern char __hyp_rodata_start[], __hyp_rodata_end[];
1516
extern char __hyp_reloc_begin[], __hyp_reloc_end[];
1617
extern char __hyp_bss_start[], __hyp_bss_end[];

arch/arm64/kernel/image-vars.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ KVM_NVHE_ALIAS(__hyp_text_start);
127127
KVM_NVHE_ALIAS(__hyp_text_end);
128128
KVM_NVHE_ALIAS(__hyp_bss_start);
129129
KVM_NVHE_ALIAS(__hyp_bss_end);
130+
KVM_NVHE_ALIAS(__hyp_data_start);
131+
KVM_NVHE_ALIAS(__hyp_data_end);
130132
KVM_NVHE_ALIAS(__hyp_rodata_start);
131133
KVM_NVHE_ALIAS(__hyp_rodata_end);
132134

arch/arm64/kernel/vmlinux.lds.S

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
*(__kvm_ex_table) \
1414
__stop___kvm_ex_table = .;
1515

16-
#define HYPERVISOR_DATA_SECTIONS \
16+
#define HYPERVISOR_RODATA_SECTIONS \
1717
HYP_SECTION_NAME(.rodata) : { \
1818
. = ALIGN(PAGE_SIZE); \
1919
__hyp_rodata_start = .; \
@@ -23,6 +23,15 @@
2323
__hyp_rodata_end = .; \
2424
}
2525

26+
#define HYPERVISOR_DATA_SECTION \
27+
HYP_SECTION_NAME(.data) : { \
28+
. = ALIGN(PAGE_SIZE); \
29+
__hyp_data_start = .; \
30+
*(HYP_SECTION_NAME(.data)) \
31+
. = ALIGN(PAGE_SIZE); \
32+
__hyp_data_end = .; \
33+
}
34+
2635
#define HYPERVISOR_PERCPU_SECTION \
2736
. = ALIGN(PAGE_SIZE); \
2837
HYP_SECTION_NAME(.data..percpu) : { \
@@ -51,7 +60,8 @@
5160
#define SBSS_ALIGN PAGE_SIZE
5261
#else /* CONFIG_KVM */
5362
#define HYPERVISOR_EXTABLE
54-
#define HYPERVISOR_DATA_SECTIONS
63+
#define HYPERVISOR_RODATA_SECTIONS
64+
#define HYPERVISOR_DATA_SECTION
5565
#define HYPERVISOR_PERCPU_SECTION
5666
#define HYPERVISOR_RELOC_SECTION
5767
#define SBSS_ALIGN 0
@@ -190,7 +200,7 @@ SECTIONS
190200
/* everything from this point to __init_begin will be marked RO NX */
191201
RO_DATA(PAGE_SIZE)
192202

193-
HYPERVISOR_DATA_SECTIONS
203+
HYPERVISOR_RODATA_SECTIONS
194204

195205
.got : { *(.got) }
196206
/*
@@ -295,6 +305,8 @@ SECTIONS
295305
_sdata = .;
296306
RW_DATA(L1_CACHE_BYTES, PAGE_SIZE, THREAD_ALIGN)
297307

308+
HYPERVISOR_DATA_SECTION
309+
298310
/*
299311
* Data written with the MMU off but read with the MMU on requires
300312
* cache lines to be invalidated, discarding up to a Cache Writeback

arch/arm64/kvm/arm.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2604,6 +2604,13 @@ static int __init init_hyp_mode(void)
26042604
goto out_err;
26052605
}
26062606

2607+
err = create_hyp_mappings(kvm_ksym_ref(__hyp_data_start),
2608+
kvm_ksym_ref(__hyp_data_end), PAGE_HYP);
2609+
if (err) {
2610+
kvm_err("Cannot map .hyp.data section\n");
2611+
goto out_err;
2612+
}
2613+
26072614
err = create_hyp_mappings(kvm_ksym_ref(__hyp_rodata_start),
26082615
kvm_ksym_ref(__hyp_rodata_end), PAGE_HYP_RO);
26092616
if (err) {

arch/arm64/kvm/hyp/include/nvhe/mem_protect.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,12 @@ int __pkvm_host_donate_hyp(u64 pfn, u64 nr_pages);
3939
int __pkvm_hyp_donate_host(u64 pfn, u64 nr_pages);
4040
int __pkvm_host_share_ffa(u64 pfn, u64 nr_pages);
4141
int __pkvm_host_unshare_ffa(u64 pfn, u64 nr_pages);
42-
int __pkvm_host_share_guest(u64 pfn, u64 gfn, struct pkvm_hyp_vcpu *vcpu,
42+
int __pkvm_host_share_guest(u64 pfn, u64 gfn, u64 nr_pages, struct pkvm_hyp_vcpu *vcpu,
4343
enum kvm_pgtable_prot prot);
44-
int __pkvm_host_unshare_guest(u64 gfn, struct pkvm_hyp_vm *hyp_vm);
44+
int __pkvm_host_unshare_guest(u64 gfn, u64 nr_pages, struct pkvm_hyp_vm *hyp_vm);
4545
int __pkvm_host_relax_perms_guest(u64 gfn, struct pkvm_hyp_vcpu *vcpu, enum kvm_pgtable_prot prot);
46-
int __pkvm_host_wrprotect_guest(u64 gfn, struct pkvm_hyp_vm *hyp_vm);
47-
int __pkvm_host_test_clear_young_guest(u64 gfn, bool mkold, struct pkvm_hyp_vm *vm);
46+
int __pkvm_host_wrprotect_guest(u64 gfn, u64 nr_pages, struct pkvm_hyp_vm *hyp_vm);
47+
int __pkvm_host_test_clear_young_guest(u64 gfn, u64 nr_pages, bool mkold, struct pkvm_hyp_vm *vm);
4848
int __pkvm_host_mkyoung_guest(u64 gfn, struct pkvm_hyp_vcpu *vcpu);
4949

5050
bool addr_is_memory(phys_addr_t phys);
@@ -67,4 +67,10 @@ static __always_inline void __load_host_stage2(void)
6767
else
6868
write_sysreg(0, vttbr_el2);
6969
}
70+
71+
#ifdef CONFIG_NVHE_EL2_DEBUG
72+
void pkvm_ownership_selftest(void *base);
73+
#else
74+
static inline void pkvm_ownership_selftest(void *base) { }
75+
#endif
7076
#endif /* __KVM_NVHE_MEM_PROTECT__ */

arch/arm64/kvm/hyp/include/nvhe/memory.h

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,30 @@
88
#include <linux/types.h>
99

1010
/*
11-
* Bits 0-1 are reserved to track the memory ownership state of each page:
12-
* 00: The page is owned exclusively by the page-table owner.
13-
* 01: The page is owned by the page-table owner, but is shared
14-
* with another entity.
15-
* 10: The page is shared with, but not owned by the page-table owner.
16-
* 11: Reserved for future use (lending).
11+
* Bits 0-1 are used to encode the memory ownership state of each page from the
12+
* point of view of a pKVM "component" (host, hyp, guest, ... see enum
13+
* pkvm_component_id):
14+
* 00: The page is owned and exclusively accessible by the component;
15+
* 01: The page is owned and accessible by the component, but is also
16+
* accessible by another component;
17+
* 10: The page is accessible but not owned by the component;
18+
* The storage of this state depends on the component: either in the
19+
* hyp_vmemmap for the host and hyp states or in PTE software bits for guests.
1720
*/
1821
enum pkvm_page_state {
1922
PKVM_PAGE_OWNED = 0ULL,
2023
PKVM_PAGE_SHARED_OWNED = BIT(0),
2124
PKVM_PAGE_SHARED_BORROWED = BIT(1),
22-
__PKVM_PAGE_RESERVED = BIT(0) | BIT(1),
2325

24-
/* Meta-states which aren't encoded directly in the PTE's SW bits */
25-
PKVM_NOPAGE = BIT(2),
26+
/*
27+
* 'Meta-states' are not stored directly in PTE SW bits for guest
28+
* states, but inferred from the context (e.g. invalid PTE entries).
29+
* For the host and hyp, meta-states are stored directly in the
30+
* struct hyp_page.
31+
*/
32+
PKVM_NOPAGE = BIT(0) | BIT(1),
2633
};
27-
#define PKVM_PAGE_META_STATES_MASK (~__PKVM_PAGE_RESERVED)
34+
#define PKVM_PAGE_STATE_MASK (BIT(0) | BIT(1))
2835

2936
#define PKVM_PAGE_STATE_PROT_MASK (KVM_PGTABLE_PROT_SW0 | KVM_PGTABLE_PROT_SW1)
3037
static inline enum kvm_pgtable_prot pkvm_mkstate(enum kvm_pgtable_prot prot,
@@ -44,8 +51,15 @@ struct hyp_page {
4451
u16 refcount;
4552
u8 order;
4653

47-
/* Host (non-meta) state. Guarded by the host stage-2 lock. */
48-
enum pkvm_page_state host_state : 8;
54+
/* Host state. Guarded by the host stage-2 lock. */
55+
unsigned __host_state : 4;
56+
57+
/*
58+
* Complement of the hyp state. Guarded by the hyp stage-1 lock. We use
59+
* the complement so that the initial 0 in __hyp_state_comp (due to the
60+
* entire vmemmap starting off zeroed) encodes PKVM_NOPAGE.
61+
*/
62+
unsigned __hyp_state_comp : 4;
4963

5064
u32 host_share_guest_count;
5165
};
@@ -82,6 +96,26 @@ static inline struct hyp_page *hyp_phys_to_page(phys_addr_t phys)
8296
#define hyp_page_to_virt(page) __hyp_va(hyp_page_to_phys(page))
8397
#define hyp_page_to_pool(page) (((struct hyp_page *)page)->pool)
8498

99+
static inline enum pkvm_page_state get_host_state(struct hyp_page *p)
100+
{
101+
return p->__host_state;
102+
}
103+
104+
static inline void set_host_state(struct hyp_page *p, enum pkvm_page_state state)
105+
{
106+
p->__host_state = state;
107+
}
108+
109+
static inline enum pkvm_page_state get_hyp_state(struct hyp_page *p)
110+
{
111+
return p->__hyp_state_comp ^ PKVM_PAGE_STATE_MASK;
112+
}
113+
114+
static inline void set_hyp_state(struct hyp_page *p, enum pkvm_page_state state)
115+
{
116+
p->__hyp_state_comp = state ^ PKVM_PAGE_STATE_MASK;
117+
}
118+
85119
/*
86120
* Refcounting for 'struct hyp_page'.
87121
* hyp_pool::lock must be held if atomic access to the refcount is required.

arch/arm64/kvm/hyp/include/nvhe/mm.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,11 @@
1313
extern struct kvm_pgtable pkvm_pgtable;
1414
extern hyp_spinlock_t pkvm_pgd_lock;
1515

16-
int hyp_create_pcpu_fixmap(void);
16+
int hyp_create_fixmap(void);
1717
void *hyp_fixmap_map(phys_addr_t phys);
1818
void hyp_fixmap_unmap(void);
19+
void *hyp_fixblock_map(phys_addr_t phys, size_t *size);
20+
void hyp_fixblock_unmap(void);
1921

2022
int hyp_create_idmap(u32 hyp_va_bits);
2123
int hyp_map_vectors(void);

0 commit comments

Comments
 (0)