Message ID | 20211111141352.26311-6-chao.p.peng@linux.intel.com (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | KVM: mm: fd-based approach for supporting KVM guest private memory | expand |
On 11.11.2021 16.13, Chao Peng wrote: > Currently support to exit to userspace for private/shared memory > conversion. > > Signed-off-by: Sean Christopherson <seanjc@google.com> > Signed-off-by: Yu Zhang <yu.c.zhang@linux.intel.com> > Signed-off-by: Chao Peng <chao.p.peng@linux.intel.com> > --- > arch/x86/kvm/mmu/mmu.c | 20 ++++++++++++++++++++ > include/uapi/linux/kvm.h | 15 +++++++++++++++ > 2 files changed, 35 insertions(+) > > diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c > index af5ecf4ef62a..780868888aa8 100644 > --- a/arch/x86/kvm/mmu/mmu.c > +++ b/arch/x86/kvm/mmu/mmu.c > @@ -3950,6 +3950,17 @@ static bool try_async_pf(struct kvm_vcpu *vcpu, bool prefault, gfn_t gfn, > > slot = __kvm_vcpu_gfn_to_memslot(vcpu, gfn, private); > > + /* > + * Exit to userspace to map the requested private/shared memory region > + * if there is no memslot and (a) the access is private or (b) there is > + * an existing private memslot. Emulated MMIO must be accessed through > + * shared GPAs, thus a memslot miss on a private GPA is always handled > + * as an implicit conversion "request". > + */ > + if (!slot && > + (private || __kvm_vcpu_gfn_to_memslot(vcpu, gfn, true))) > + goto out_convert; > + > /* Don't expose aliases for no slot GFNs or private memslots */ > if ((cr2_or_gpa & vcpu_gpa_stolen_mask(vcpu)) && > !kvm_is_visible_memslot(slot)) { > @@ -3994,6 +4005,15 @@ static bool try_async_pf(struct kvm_vcpu *vcpu, bool prefault, gfn_t gfn, > *pfn = __gfn_to_pfn_memslot(slot, gfn, false, NULL, > write, writable, hva); > return false; > + > +out_convert: > + vcpu->run->exit_reason = KVM_EXIT_MEMORY_ERROR; > + vcpu->run->mem.type = private ? KVM_EXIT_MEM_MAP_PRIVATE > + : KVM_EXIT_MEM_MAP_SHARE; > + vcpu->run->mem.u.map.gpa = cr2_or_gpa; > + vcpu->run->mem.u.map.size = PAGE_SIZE; > + return true; > + > I think this does just retry, no exit to user space? > } > > static int direct_page_fault(struct kvm_vcpu *vcpu, gpa_t gpa, u32 error_code, > diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h > index 8d20caae9180..470c472a9451 100644 > --- a/include/uapi/linux/kvm.h > +++ b/include/uapi/linux/kvm.h > @@ -233,6 +233,18 @@ struct kvm_xen_exit { > } u; > }; > > +struct kvm_memory_exit { > +#define KVM_EXIT_MEM_MAP_SHARE 1 > +#define KVM_EXIT_MEM_MAP_PRIVATE 2 > + __u32 type; > + union { > + struct { > + __u64 gpa; > + __u64 size; > + } map; > + } u; > +}; > + > #define KVM_S390_GET_SKEYS_NONE 1 > #define KVM_S390_SKEYS_MAX 1048576 > > @@ -272,6 +284,7 @@ struct kvm_xen_exit { > #define KVM_EXIT_X86_BUS_LOCK 33 > #define KVM_EXIT_XEN 34 > #define KVM_EXIT_TDVMCALL 35 > +#define KVM_EXIT_MEMORY_ERROR 36 > > /* For KVM_EXIT_INTERNAL_ERROR */ > /* Emulate instruction failed. */ > @@ -455,6 +468,8 @@ struct kvm_run { > __u64 subfunc; > __u64 param[4]; > } tdvmcall; > + /* KVM_EXIT_MEMORY_ERROR */ > + struct kvm_memory_exit mem; > /* Fix the size of the union. */ > char padding[256]; > };
On Thu, Nov 11, 2021 at 05:08:47PM +0200, Mika Penttilä wrote: > > > On 11.11.2021 16.13, Chao Peng wrote: > > Currently support to exit to userspace for private/shared memory > > conversion. > > > > Signed-off-by: Sean Christopherson <seanjc@google.com> > > Signed-off-by: Yu Zhang <yu.c.zhang@linux.intel.com> > > Signed-off-by: Chao Peng <chao.p.peng@linux.intel.com> > > --- > > arch/x86/kvm/mmu/mmu.c | 20 ++++++++++++++++++++ > > include/uapi/linux/kvm.h | 15 +++++++++++++++ > > 2 files changed, 35 insertions(+) > > > > diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c > > index af5ecf4ef62a..780868888aa8 100644 > > --- a/arch/x86/kvm/mmu/mmu.c > > +++ b/arch/x86/kvm/mmu/mmu.c > > @@ -3950,6 +3950,17 @@ static bool try_async_pf(struct kvm_vcpu *vcpu, bool prefault, gfn_t gfn, > > slot = __kvm_vcpu_gfn_to_memslot(vcpu, gfn, private); > > + /* > > + * Exit to userspace to map the requested private/shared memory region > > + * if there is no memslot and (a) the access is private or (b) there is > > + * an existing private memslot. Emulated MMIO must be accessed through > > + * shared GPAs, thus a memslot miss on a private GPA is always handled > > + * as an implicit conversion "request". > > + */ > > + if (!slot && > > + (private || __kvm_vcpu_gfn_to_memslot(vcpu, gfn, true))) > > + goto out_convert; > > + > > /* Don't expose aliases for no slot GFNs or private memslots */ > > if ((cr2_or_gpa & vcpu_gpa_stolen_mask(vcpu)) && > > !kvm_is_visible_memslot(slot)) { > > @@ -3994,6 +4005,15 @@ static bool try_async_pf(struct kvm_vcpu *vcpu, bool prefault, gfn_t gfn, > > *pfn = __gfn_to_pfn_memslot(slot, gfn, false, NULL, > > write, writable, hva); > > return false; > > + > > +out_convert: > > + vcpu->run->exit_reason = KVM_EXIT_MEMORY_ERROR; > > + vcpu->run->mem.type = private ? KVM_EXIT_MEM_MAP_PRIVATE > > + : KVM_EXIT_MEM_MAP_SHARE; > > + vcpu->run->mem.u.map.gpa = cr2_or_gpa; > > + vcpu->run->mem.u.map.size = PAGE_SIZE; > > + return true; > > + > I think this does just retry, no exit to user space? Good catch, thanks. Chao > > > > > > } > > static int direct_page_fault(struct kvm_vcpu *vcpu, gpa_t gpa, u32 error_code, > > diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h > > index 8d20caae9180..470c472a9451 100644 > > --- a/include/uapi/linux/kvm.h > > +++ b/include/uapi/linux/kvm.h > > @@ -233,6 +233,18 @@ struct kvm_xen_exit { > > } u; > > }; > > +struct kvm_memory_exit { > > +#define KVM_EXIT_MEM_MAP_SHARE 1 > > +#define KVM_EXIT_MEM_MAP_PRIVATE 2 > > + __u32 type; > > + union { > > + struct { > > + __u64 gpa; > > + __u64 size; > > + } map; > > + } u; > > +}; > > + > > #define KVM_S390_GET_SKEYS_NONE 1 > > #define KVM_S390_SKEYS_MAX 1048576 > > @@ -272,6 +284,7 @@ struct kvm_xen_exit { > > #define KVM_EXIT_X86_BUS_LOCK 33 > > #define KVM_EXIT_XEN 34 > > #define KVM_EXIT_TDVMCALL 35 > > +#define KVM_EXIT_MEMORY_ERROR 36 > > /* For KVM_EXIT_INTERNAL_ERROR */ > > /* Emulate instruction failed. */ > > @@ -455,6 +468,8 @@ struct kvm_run { > > __u64 subfunc; > > __u64 param[4]; > > } tdvmcall; > > + /* KVM_EXIT_MEMORY_ERROR */ > > + struct kvm_memory_exit mem; > > /* Fix the size of the union. */ > > char padding[256]; > > }; >
diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index af5ecf4ef62a..780868888aa8 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -3950,6 +3950,17 @@ static bool try_async_pf(struct kvm_vcpu *vcpu, bool prefault, gfn_t gfn, slot = __kvm_vcpu_gfn_to_memslot(vcpu, gfn, private); + /* + * Exit to userspace to map the requested private/shared memory region + * if there is no memslot and (a) the access is private or (b) there is + * an existing private memslot. Emulated MMIO must be accessed through + * shared GPAs, thus a memslot miss on a private GPA is always handled + * as an implicit conversion "request". + */ + if (!slot && + (private || __kvm_vcpu_gfn_to_memslot(vcpu, gfn, true))) + goto out_convert; + /* Don't expose aliases for no slot GFNs or private memslots */ if ((cr2_or_gpa & vcpu_gpa_stolen_mask(vcpu)) && !kvm_is_visible_memslot(slot)) { @@ -3994,6 +4005,15 @@ static bool try_async_pf(struct kvm_vcpu *vcpu, bool prefault, gfn_t gfn, *pfn = __gfn_to_pfn_memslot(slot, gfn, false, NULL, write, writable, hva); return false; + +out_convert: + vcpu->run->exit_reason = KVM_EXIT_MEMORY_ERROR; + vcpu->run->mem.type = private ? KVM_EXIT_MEM_MAP_PRIVATE + : KVM_EXIT_MEM_MAP_SHARE; + vcpu->run->mem.u.map.gpa = cr2_or_gpa; + vcpu->run->mem.u.map.size = PAGE_SIZE; + return true; + } static int direct_page_fault(struct kvm_vcpu *vcpu, gpa_t gpa, u32 error_code, diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 8d20caae9180..470c472a9451 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -233,6 +233,18 @@ struct kvm_xen_exit { } u; }; +struct kvm_memory_exit { +#define KVM_EXIT_MEM_MAP_SHARE 1 +#define KVM_EXIT_MEM_MAP_PRIVATE 2 + __u32 type; + union { + struct { + __u64 gpa; + __u64 size; + } map; + } u; +}; + #define KVM_S390_GET_SKEYS_NONE 1 #define KVM_S390_SKEYS_MAX 1048576 @@ -272,6 +284,7 @@ struct kvm_xen_exit { #define KVM_EXIT_X86_BUS_LOCK 33 #define KVM_EXIT_XEN 34 #define KVM_EXIT_TDVMCALL 35 +#define KVM_EXIT_MEMORY_ERROR 36 /* For KVM_EXIT_INTERNAL_ERROR */ /* Emulate instruction failed. */ @@ -455,6 +468,8 @@ struct kvm_run { __u64 subfunc; __u64 param[4]; } tdvmcall; + /* KVM_EXIT_MEMORY_ERROR */ + struct kvm_memory_exit mem; /* Fix the size of the union. */ char padding[256]; };