From: Haiwei Li <haiwei.li@xxxxxxxxx> Guest memory operations like read_gva/write_gva/read_gpa/write_gpa only support doing address translation for current page. It's not correct if such operation access data over current page. Fix above issue for these functions by doing address translation per page granularity. Signed-off-by: Haiwei Li <haiwei.li@xxxxxxxxx> --- arch/x86/kvm/vmx/pkvm/hyp/memory.c | 65 ++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 21 deletions(-) diff --git a/arch/x86/kvm/vmx/pkvm/hyp/memory.c b/arch/x86/kvm/vmx/pkvm/hyp/memory.c index e99fa72cedac..a42669ccf89c 100644 --- a/arch/x86/kvm/vmx/pkvm/hyp/memory.c +++ b/arch/x86/kvm/vmx/pkvm/hyp/memory.c @@ -110,27 +110,47 @@ int gva2gpa(struct kvm_vcpu *vcpu, gva_t gva, gpa_t *gpa, return check_translation(vcpu, _gpa, prot, access, exception); } -/* only support host VM now */ -static int copy_gva(struct kvm_vcpu *vcpu, gva_t gva, void *addr, - unsigned int bytes, struct x86_exception *exception, bool from_guest) +static inline int __copy_gpa(struct kvm_vcpu *vcpu, void *addr, gpa_t gpa, + unsigned int size, unsigned int pg_size, + bool from_guest) { - u32 access = VMX_AR_DPL(vmcs_read32(GUEST_SS_AR_BYTES)) == 3 ? PFERR_USER_MASK : 0; - gpa_t gpa; + unsigned int len, offset_in_pg; void *hva; - int ret; - /*FIXME: need check the gva per page granularity */ - ret = gva2gpa(vcpu, gva, &gpa, access, exception); - if (ret) - return ret; + offset_in_pg = (unsigned int)gpa & (pg_size - 1); + len = (size > (pg_size - offset_in_pg)) ? (pg_size - offset_in_pg) : size; hva = host_gpa2hva(gpa); if (from_guest) - memcpy(addr, hva, bytes); + memcpy(addr, hva, len); else - memcpy(hva, addr, bytes); + memcpy(hva, addr, len); - return bytes; + return len; +} + +/* only support host VM now */ +static int copy_gva(struct kvm_vcpu *vcpu, gva_t gva, void *addr, + unsigned int bytes, struct x86_exception *exception, bool from_guest) +{ + u32 access = VMX_AR_DPL(vmcs_read32(GUEST_SS_AR_BYTES)) == 3 ? PFERR_USER_MASK : 0; + gpa_t gpa; + unsigned int len; + int ret = 0; + + while ((bytes > 0) && (ret == 0)) { + ret = gva2gpa(vcpu, gva, &gpa, access, exception); + if (ret >= 0) { + len = __copy_gpa(vcpu, addr, gpa, bytes, PAGE_SIZE, from_guest); + if (len == 0) + return -EINVAL; + gva += len; + addr += len; + bytes -= len; + } + } + + return ret; } int read_gva(struct kvm_vcpu *vcpu, gva_t gva, void *addr, @@ -149,15 +169,18 @@ int write_gva(struct kvm_vcpu *vcpu, gva_t gva, void *addr, static int copy_gpa(struct kvm_vcpu *vcpu, gpa_t gpa, void *addr, unsigned int bytes, bool from_guest) { - void *hva; - - hva = host_gpa2hva(gpa); - if (from_guest) - memcpy(addr, hva, bytes); - else - memcpy(hva, addr, bytes); + unsigned int len; + + while (bytes > 0) { + len = __copy_gpa(vcpu, addr, gpa, bytes, PAGE_SIZE, from_guest); + if (len == 0) + return -EINVAL; + gpa += len; + addr += len; + bytes -= len; + } - return bytes; + return 0; } int read_gpa(struct kvm_vcpu *vcpu, gpa_t gpa, void *addr, unsigned int bytes) -- 2.25.1