@@ -220,6 +220,15 @@ static int fixed_mtrr_seg_unit_range_index(int seg, int unit)
220220 return mtrr_seg -> range_start + 8 * unit ;
221221}
222222
223+ static int fixed_mtrr_seg_end_range_index (int seg )
224+ {
225+ struct fixed_mtrr_segment * mtrr_seg = & fixed_seg_table [seg ];
226+ int n ;
227+
228+ n = (mtrr_seg -> end - mtrr_seg -> start ) >> mtrr_seg -> range_shift ;
229+ return mtrr_seg -> range_start + n - 1 ;
230+ }
231+
223232static bool fixed_msr_to_range (u32 msr , u64 * start , u64 * end )
224233{
225234 int seg , unit ;
@@ -266,6 +275,14 @@ static int fixed_mtrr_addr_seg_to_range_index(u64 addr, int seg)
266275 return index ;
267276}
268277
278+ static u64 fixed_mtrr_range_end_addr (int seg , int index )
279+ {
280+ struct fixed_mtrr_segment * mtrr_seg = & fixed_seg_table [seg ];
281+ int pos = index - mtrr_seg -> range_start ;
282+
283+ return mtrr_seg -> start + ((pos + 1 ) << mtrr_seg -> range_shift );
284+ }
285+
269286static void var_mtrr_range (struct kvm_mtrr_range * range , u64 * start , u64 * end )
270287{
271288 u64 mask ;
@@ -409,6 +426,177 @@ void kvm_vcpu_mtrr_init(struct kvm_vcpu *vcpu)
409426 INIT_LIST_HEAD (& vcpu -> arch .mtrr_state .head );
410427}
411428
429+ struct mtrr_iter {
430+ /* input fields. */
431+ struct kvm_mtrr * mtrr_state ;
432+ u64 start ;
433+ u64 end ;
434+
435+ /* output fields. */
436+ int mem_type ;
437+ /* [start, end) is not fully covered in MTRRs? */
438+ bool partial_map ;
439+
440+ /* private fields. */
441+ union {
442+ /* used for fixed MTRRs. */
443+ struct {
444+ int index ;
445+ int seg ;
446+ };
447+
448+ /* used for var MTRRs. */
449+ struct {
450+ struct kvm_mtrr_range * range ;
451+ /* max address has been covered in var MTRRs. */
452+ u64 start_max ;
453+ };
454+ };
455+
456+ bool fixed ;
457+ };
458+
459+ static bool mtrr_lookup_fixed_start (struct mtrr_iter * iter )
460+ {
461+ int seg , index ;
462+
463+ if (!fixed_mtrr_is_enabled (iter -> mtrr_state ))
464+ return false;
465+
466+ seg = fixed_mtrr_addr_to_seg (iter -> start );
467+ if (seg < 0 )
468+ return false;
469+
470+ iter -> fixed = true;
471+ index = fixed_mtrr_addr_seg_to_range_index (iter -> start , seg );
472+ iter -> index = index ;
473+ iter -> seg = seg ;
474+ return true;
475+ }
476+
477+ static bool match_var_range (struct mtrr_iter * iter ,
478+ struct kvm_mtrr_range * range )
479+ {
480+ u64 start , end ;
481+
482+ var_mtrr_range (range , & start , & end );
483+ if (!(start >= iter -> end || end <= iter -> start )) {
484+ iter -> range = range ;
485+
486+ /*
487+ * the function is called when we do kvm_mtrr.head walking.
488+ * Range has the minimum base address which interleaves
489+ * [looker->start_max, looker->end).
490+ */
491+ iter -> partial_map |= iter -> start_max < start ;
492+
493+ /* update the max address has been covered. */
494+ iter -> start_max = max (iter -> start_max , end );
495+ return true;
496+ }
497+
498+ return false;
499+ }
500+
501+ static void __mtrr_lookup_var_next (struct mtrr_iter * iter )
502+ {
503+ struct kvm_mtrr * mtrr_state = iter -> mtrr_state ;
504+
505+ list_for_each_entry_continue (iter -> range , & mtrr_state -> head , node )
506+ if (match_var_range (iter , iter -> range ))
507+ return ;
508+
509+ iter -> range = NULL ;
510+ iter -> partial_map |= iter -> start_max < iter -> end ;
511+ }
512+
513+ static void mtrr_lookup_var_start (struct mtrr_iter * iter )
514+ {
515+ struct kvm_mtrr * mtrr_state = iter -> mtrr_state ;
516+
517+ iter -> fixed = false;
518+ iter -> start_max = iter -> start ;
519+ iter -> range = list_prepare_entry (iter -> range , & mtrr_state -> head , node );
520+
521+ __mtrr_lookup_var_next (iter );
522+ }
523+
524+ static void mtrr_lookup_fixed_next (struct mtrr_iter * iter )
525+ {
526+ /* terminate the lookup. */
527+ if (fixed_mtrr_range_end_addr (iter -> seg , iter -> index ) >= iter -> end ) {
528+ iter -> fixed = false;
529+ iter -> range = NULL ;
530+ return ;
531+ }
532+
533+ iter -> index ++ ;
534+
535+ /* have looked up for all fixed MTRRs. */
536+ if (iter -> index >= ARRAY_SIZE (iter -> mtrr_state -> fixed_ranges ))
537+ return mtrr_lookup_var_start (iter );
538+
539+ /* switch to next segment. */
540+ if (iter -> index > fixed_mtrr_seg_end_range_index (iter -> seg ))
541+ iter -> seg ++ ;
542+ }
543+
544+ static void mtrr_lookup_var_next (struct mtrr_iter * iter )
545+ {
546+ __mtrr_lookup_var_next (iter );
547+ }
548+
549+ static void mtrr_lookup_start (struct mtrr_iter * iter )
550+ {
551+ if (!mtrr_is_enabled (iter -> mtrr_state )) {
552+ iter -> partial_map = true;
553+ return ;
554+ }
555+
556+ if (!mtrr_lookup_fixed_start (iter ))
557+ mtrr_lookup_var_start (iter );
558+ }
559+
560+ static void mtrr_lookup_init (struct mtrr_iter * iter ,
561+ struct kvm_mtrr * mtrr_state , u64 start , u64 end )
562+ {
563+ iter -> mtrr_state = mtrr_state ;
564+ iter -> start = start ;
565+ iter -> end = end ;
566+ iter -> partial_map = false;
567+ iter -> fixed = false;
568+ iter -> range = NULL ;
569+
570+ mtrr_lookup_start (iter );
571+ }
572+
573+ static bool mtrr_lookup_okay (struct mtrr_iter * iter )
574+ {
575+ if (iter -> fixed ) {
576+ iter -> mem_type = iter -> mtrr_state -> fixed_ranges [iter -> index ];
577+ return true;
578+ }
579+
580+ if (iter -> range ) {
581+ iter -> mem_type = iter -> range -> base & 0xff ;
582+ return true;
583+ }
584+
585+ return false;
586+ }
587+
588+ static void mtrr_lookup_next (struct mtrr_iter * iter )
589+ {
590+ if (iter -> fixed )
591+ mtrr_lookup_fixed_next (iter );
592+ else
593+ mtrr_lookup_var_next (iter );
594+ }
595+
596+ #define mtrr_for_each_mem_type (_iter_ , _mtrr_ , _gpa_start_ , _gpa_end_ ) \
597+ for (mtrr_lookup_init(_iter_, _mtrr_, _gpa_start_, _gpa_end_); \
598+ mtrr_lookup_okay(_iter_); mtrr_lookup_next(_iter_))
599+
412600u8 kvm_mtrr_get_guest_memory_type (struct kvm_vcpu * vcpu , gfn_t gfn )
413601{
414602 struct kvm_mtrr * mtrr_state = & vcpu -> arch .mtrr_state ;
0 commit comments