@@ -1541,21 +1541,38 @@ int kvm_write_guest(struct kvm *kvm, gpa_t gpa, const void *data,
15411541}
15421542
15431543int kvm_gfn_to_hva_cache_init (struct kvm * kvm , struct gfn_to_hva_cache * ghc ,
1544- gpa_t gpa )
1544+ gpa_t gpa , unsigned long len )
15451545{
15461546 struct kvm_memslots * slots = kvm_memslots (kvm );
15471547 int offset = offset_in_page (gpa );
1548- gfn_t gfn = gpa >> PAGE_SHIFT ;
1548+ gfn_t start_gfn = gpa >> PAGE_SHIFT ;
1549+ gfn_t end_gfn = (gpa + len - 1 ) >> PAGE_SHIFT ;
1550+ gfn_t nr_pages_needed = end_gfn - start_gfn + 1 ;
1551+ gfn_t nr_pages_avail ;
15491552
15501553 ghc -> gpa = gpa ;
15511554 ghc -> generation = slots -> generation ;
1552- ghc -> memslot = gfn_to_memslot (kvm , gfn );
1553- ghc -> hva = gfn_to_hva_many (ghc -> memslot , gfn , NULL );
1554- if (!kvm_is_error_hva (ghc -> hva ))
1555+ ghc -> len = len ;
1556+ ghc -> memslot = gfn_to_memslot (kvm , start_gfn );
1557+ ghc -> hva = gfn_to_hva_many (ghc -> memslot , start_gfn , & nr_pages_avail );
1558+ if (!kvm_is_error_hva (ghc -> hva ) && nr_pages_avail >= nr_pages_needed ) {
15551559 ghc -> hva += offset ;
1556- else
1557- return - EFAULT ;
1558-
1560+ } else {
1561+ /*
1562+ * If the requested region crosses two memslots, we still
1563+ * verify that the entire region is valid here.
1564+ */
1565+ while (start_gfn <= end_gfn ) {
1566+ ghc -> memslot = gfn_to_memslot (kvm , start_gfn );
1567+ ghc -> hva = gfn_to_hva_many (ghc -> memslot , start_gfn ,
1568+ & nr_pages_avail );
1569+ if (kvm_is_error_hva (ghc -> hva ))
1570+ return - EFAULT ;
1571+ start_gfn += nr_pages_avail ;
1572+ }
1573+ /* Use the slow path for cross page reads and writes. */
1574+ ghc -> memslot = NULL ;
1575+ }
15591576 return 0 ;
15601577}
15611578EXPORT_SYMBOL_GPL (kvm_gfn_to_hva_cache_init );
@@ -1566,8 +1583,13 @@ int kvm_write_guest_cached(struct kvm *kvm, struct gfn_to_hva_cache *ghc,
15661583 struct kvm_memslots * slots = kvm_memslots (kvm );
15671584 int r ;
15681585
1586+ BUG_ON (len > ghc -> len );
1587+
15691588 if (slots -> generation != ghc -> generation )
1570- kvm_gfn_to_hva_cache_init (kvm , ghc , ghc -> gpa );
1589+ kvm_gfn_to_hva_cache_init (kvm , ghc , ghc -> gpa , ghc -> len );
1590+
1591+ if (unlikely (!ghc -> memslot ))
1592+ return kvm_write_guest (kvm , ghc -> gpa , data , len );
15711593
15721594 if (kvm_is_error_hva (ghc -> hva ))
15731595 return - EFAULT ;
@@ -1587,8 +1609,13 @@ int kvm_read_guest_cached(struct kvm *kvm, struct gfn_to_hva_cache *ghc,
15871609 struct kvm_memslots * slots = kvm_memslots (kvm );
15881610 int r ;
15891611
1612+ BUG_ON (len > ghc -> len );
1613+
15901614 if (slots -> generation != ghc -> generation )
1591- kvm_gfn_to_hva_cache_init (kvm , ghc , ghc -> gpa );
1615+ kvm_gfn_to_hva_cache_init (kvm , ghc , ghc -> gpa , ghc -> len );
1616+
1617+ if (unlikely (!ghc -> memslot ))
1618+ return kvm_read_guest (kvm , ghc -> gpa , data , len );
15921619
15931620 if (kvm_is_error_hva (ghc -> hva ))
15941621 return - EFAULT ;
0 commit comments