On Wed, Mar 06, 2019 at 05:00:15PM +1100, Suraj Jitindar Singh wrote: > Implement the function kvm_copy_guest() to be used to perform a memory > copy from one guest physical address to another of a variable length. > > This performs similar functionality as the kvm_read_guest() and > kvm_write_guest() functions, except both addresses point to guest memory. > This performs a copy in place using raw_copy_in_user() to avoid having to > buffer the data. > > The guest memory can reside in different memslots and the copy length > can span memslots. > > Signed-off-by: Suraj Jitindar Singh <sjitindarsingh@xxxxxxxxx> > > --- > > I suspect additional checking may be required around the raw_copy_in_user() > call. > > --- > include/linux/kvm_host.h | 1 + > virt/kvm/kvm_main.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 70 insertions(+) > ... > +static int next_segment_many(unsigned long len, int offset1, int offset2) > +{ > + int size = min(PAGE_SIZE - offset1, PAGE_SIZE - offset2); > + > + if (len > size) > + return size; > + else > + return len; > +} > + > +int kvm_copy_guest(struct kvm *kvm, gpa_t to, gpa_t from, unsigned long len) > +{ > + struct kvm_memory_slot *to_memslot = NULL; > + struct kvm_memory_slot *from_memslot = NULL; > + gfn_t to_gfn = to >> PAGE_SHIFT; > + gfn_t from_gfn = from >> PAGE_SHIFT; > + int seg; > + int to_offset = offset_in_page(to); > + int from_offset = offset_in_page(from); > + int ret; > + > + while ((seg = next_segment_many(len, to_offset, from_offset)) != 0) { > + if (!to_memslot || (to_gfn >= (to_memslot->base_gfn + > + to_memslot->npages))) > + to_memslot = gfn_to_memslot(kvm, to_gfn); > + if (!from_memslot || (from_gfn >= (from_memslot->base_gfn + > + from_memslot->npages))) > + from_memslot = gfn_to_memslot(kvm, from_gfn); > + > + ret = __kvm_copy_guest_page(to_memslot, to_gfn, to_offset, > + from_memslot, from_gfn, from_offset, > + seg); > + if (ret < 0) > + return ret; > + > + to_offset = (to_offset + seg) & (PAGE_SIZE - 1); > + from_offset = (from_offset + seg) & (PAGE_SIZE - 1); > + len -= seg; > + if (!to_offset) > + to_gfn += 1; > + if (!from_offset) > + from_gfn += 1; > + } > + return 0; > +} > +EXPORT_SYMBOL_GPL(kvm_copy_guest); Is there a need to support spanning multiple pages at this time? Your use case always accesses exactly a page and requires both dst and src to be page aligned. I.e. provide just kvm_copy_guest_page() for simplicity. > + > static int __kvm_gfn_to_hva_cache_init(struct kvm_memslots *slots, > struct gfn_to_hva_cache *ghc, > gpa_t gpa, unsigned long len) > -- > 2.13.6 >