Skip to content

Commit f571c09

Browse files
Xiao Guangrongbonzini
authored andcommitted
KVM: MTRR: introduce mtrr_for_each_mem_type
It walks all MTRRs and gets all the memory cache type setting for the specified range also it checks if the range is fully covered by MTRRs Signed-off-by: Xiao Guangrong <[email protected]> [Adjust for range_size->range_shift change. - Paolo] Signed-off-by: Paolo Bonzini <[email protected]>
1 parent f7bfb57 commit f571c09

File tree

1 file changed

+188
-0
lines changed

1 file changed

+188
-0
lines changed

arch/x86/kvm/mtrr.c

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
223232
static 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+
269286
static 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+
412600
u8 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

Comments
 (0)