Skip to content

Commit d5d8184

Browse files
author
Christoffer Dall
committed
KVM: ARM: Memory virtualization setup
This commit introduces the framework for guest memory management through the use of 2nd stage translation. Each VM has a pointer to a level-1 table (the pgd field in struct kvm_arch) which is used for the 2nd stage translations. Entries are added when handling guest faults (later patch) and the table itself can be allocated and freed through the following functions implemented in arch/arm/kvm/arm_mmu.c: - kvm_alloc_stage2_pgd(struct kvm *kvm); - kvm_free_stage2_pgd(struct kvm *kvm); Each entry in TLBs and caches are tagged with a VMID identifier in addition to ASIDs. The VMIDs are assigned consecutively to VMs in the order that VMs are executed, and caches and tlbs are invalidated when the VMID space has been used to allow for more than 255 simultaenously running guests. The 2nd stage pgd is allocated in kvm_arch_init_vm(). The table is freed in kvm_arch_destroy_vm(). Both functions are called from the main KVM code. We pre-allocate page table memory to be able to synchronize using a spinlock and be called under rcu_read_lock from the MMU notifiers. We steal the mmu_memory_cache implementation from x86 and adapt for our specific usage. We support MMU notifiers (thanks to Marc Zyngier) through kvm_unmap_hva and kvm_set_spte_hva. Finally, define kvm_phys_addr_ioremap() to map a device at a guest IPA, which is used by VGIC support to map the virtual CPU interface registers to the guest. This support is added by Marc Zyngier. Reviewed-by: Will Deacon <[email protected]> Reviewed-by: Marcelo Tosatti <[email protected]> Signed-off-by: Marc Zyngier <[email protected]> Signed-off-by: Christoffer Dall <[email protected]>
1 parent 342cd0a commit d5d8184

File tree

8 files changed

+488
-2
lines changed

8 files changed

+488
-2
lines changed

arch/arm/include/asm/kvm_asm.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
#define ARM_EXCEPTION_HVC 7
5858

5959
#ifndef __ASSEMBLY__
60+
struct kvm;
6061
struct kvm_vcpu;
6162

6263
extern char __kvm_hyp_init[];
@@ -71,6 +72,7 @@ extern char __kvm_hyp_code_start[];
7172
extern char __kvm_hyp_code_end[];
7273

7374
extern void __kvm_flush_vm_context(void);
75+
extern void __kvm_tlb_flush_vmid(struct kvm *kvm);
7476

7577
extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
7678
#endif

arch/arm/include/asm/kvm_host.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,4 +112,22 @@ struct kvm_one_reg;
112112
int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
113113
int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
114114
u64 kvm_call_hyp(void *hypfn, ...);
115+
116+
#define KVM_ARCH_WANT_MMU_NOTIFIER
117+
struct kvm;
118+
int kvm_unmap_hva(struct kvm *kvm, unsigned long hva);
119+
int kvm_unmap_hva_range(struct kvm *kvm,
120+
unsigned long start, unsigned long end);
121+
void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
122+
123+
/* We do not have shadow page tables, hence the empty hooks */
124+
static inline int kvm_age_hva(struct kvm *kvm, unsigned long hva)
125+
{
126+
return 0;
127+
}
128+
129+
static inline int kvm_test_age_hva(struct kvm *kvm, unsigned long hva)
130+
{
131+
return 0;
132+
}
115133
#endif /* __ARM_KVM_HOST_H__ */

arch/arm/include/asm/kvm_mmu.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,15 @@ int create_hyp_mappings(void *from, void *to);
2323
int create_hyp_io_mappings(void *from, void *to, phys_addr_t);
2424
void free_hyp_pmds(void);
2525

26+
int kvm_alloc_stage2_pgd(struct kvm *kvm);
27+
void kvm_free_stage2_pgd(struct kvm *kvm);
28+
int kvm_phys_addr_ioremap(struct kvm *kvm, phys_addr_t guest_ipa,
29+
phys_addr_t pa, unsigned long size);
30+
31+
int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run);
32+
33+
void kvm_mmu_free_memory_caches(struct kvm_vcpu *vcpu);
34+
2635
phys_addr_t kvm_mmu_get_httbr(void);
2736
int kvm_mmu_init(void);
2837
void kvm_clear_hyp_idmap(void);

arch/arm/kvm/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ config KVM_ARM_HOST
3636
bool "KVM host support for ARM cpus."
3737
depends on KVM
3838
depends on MMU
39+
select MMU_NOTIFIER
3940
---help---
4041
Provides host support for ARM processors.
4142

arch/arm/kvm/arm.c

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,33 @@ void kvm_arch_sync_events(struct kvm *kvm)
8181
{
8282
}
8383

84+
/**
85+
* kvm_arch_init_vm - initializes a VM data structure
86+
* @kvm: pointer to the KVM struct
87+
*/
8488
int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
8589
{
90+
int ret = 0;
91+
8692
if (type)
8793
return -EINVAL;
8894

89-
return 0;
95+
ret = kvm_alloc_stage2_pgd(kvm);
96+
if (ret)
97+
goto out_fail_alloc;
98+
99+
ret = create_hyp_mappings(kvm, kvm + 1);
100+
if (ret)
101+
goto out_free_stage2_pgd;
102+
103+
/* Mark the initial VMID generation invalid */
104+
kvm->arch.vmid_gen = 0;
105+
106+
return ret;
107+
out_free_stage2_pgd:
108+
kvm_free_stage2_pgd(kvm);
109+
out_fail_alloc:
110+
return ret;
90111
}
91112

92113
int kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf)
@@ -104,10 +125,16 @@ int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages)
104125
return 0;
105126
}
106127

128+
/**
129+
* kvm_arch_destroy_vm - destroy the VM data structure
130+
* @kvm: pointer to the KVM struct
131+
*/
107132
void kvm_arch_destroy_vm(struct kvm *kvm)
108133
{
109134
int i;
110135

136+
kvm_free_stage2_pgd(kvm);
137+
111138
for (i = 0; i < KVM_MAX_VCPUS; ++i) {
112139
if (kvm->vcpus[i]) {
113140
kvm_arch_vcpu_free(kvm->vcpus[i]);
@@ -196,7 +223,13 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id)
196223
if (err)
197224
goto free_vcpu;
198225

226+
err = create_hyp_mappings(vcpu, vcpu + 1);
227+
if (err)
228+
goto vcpu_uninit;
229+
199230
return vcpu;
231+
vcpu_uninit:
232+
kvm_vcpu_uninit(vcpu);
200233
free_vcpu:
201234
kmem_cache_free(kvm_vcpu_cache, vcpu);
202235
out:
@@ -210,6 +243,8 @@ int kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
210243

211244
void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu)
212245
{
246+
kvm_mmu_free_memory_caches(vcpu);
247+
kmem_cache_free(kvm_vcpu_cache, vcpu);
213248
}
214249

215250
void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)

arch/arm/kvm/interrupts.S

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,13 @@ __kvm_hyp_code_start:
3232
/********************************************************************
3333
* Flush per-VMID TLBs
3434
*/
35+
ENTRY(__kvm_tlb_flush_vmid)
36+
bx lr
37+
ENDPROC(__kvm_tlb_flush_vmid)
38+
39+
/********************************************************************
40+
* Flush TLBs and instruction caches of current CPU for all VMIDs
41+
*/
3542
ENTRY(__kvm_flush_vm_context)
3643
bx lr
3744
ENDPROC(__kvm_flush_vm_context)

0 commit comments

Comments
 (0)