Skip to content

Commit e1ad1ac

Browse files
Like XuPeter Zijlstra
authored andcommitted
perf/x86: Keep LBR records unchanged in host context for guest usage
When a guest wants to use the LBR registers, its hypervisor creates a guest LBR event and let host perf schedules it. The LBR records msrs are accessible to the guest when its guest LBR event is scheduled on by the perf subsystem. Before scheduling this event out, we should avoid host changes on IA32_DEBUGCTLMSR or LBR_SELECT. Otherwise, some unexpected branch operations may interfere with guest behavior, pollute LBR records, and even cause host branches leakage. In addition, the read operation on host is also avoidable. To ensure that guest LBR records are not lost during the context switch, the guest LBR event would enable the callstack mode which could save/restore guest unread LBR records with the help of intel_pmu_lbr_sched_task() naturally. However, the guest LBR_SELECT may changes for its own use and the host LBR event doesn't save/restore it. To ensure that we doesn't lost the guest LBR_SELECT value when the guest LBR event is running, the vlbr_constraint is bound up with a new constraint flag PERF_X86_EVENT_LBR_SELECT. Signed-off-by: Like Xu <[email protected]> Signed-off-by: Wei Wang <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent 097e431 commit e1ad1ac

File tree

3 files changed

+33
-7
lines changed

3 files changed

+33
-7
lines changed

arch/x86/events/intel/core.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2189,7 +2189,8 @@ static void intel_pmu_disable_event(struct perf_event *event)
21892189
} else if (idx == INTEL_PMC_IDX_FIXED_BTS) {
21902190
intel_pmu_disable_bts();
21912191
intel_pmu_drain_bts_buffer();
2192-
}
2192+
} else if (idx == INTEL_PMC_IDX_FIXED_VLBR)
2193+
intel_clear_masks(event, idx);
21932194

21942195
/*
21952196
* Needs to be called after x86_pmu_disable_event,
@@ -2271,7 +2272,8 @@ static void intel_pmu_enable_event(struct perf_event *event)
22712272
if (!__this_cpu_read(cpu_hw_events.enabled))
22722273
return;
22732274
intel_pmu_enable_bts(hwc->config);
2274-
}
2275+
} else if (idx == INTEL_PMC_IDX_FIXED_VLBR)
2276+
intel_set_masks(event, idx);
22752277
}
22762278

22772279
static void intel_pmu_add_event(struct perf_event *event)

arch/x86/events/intel/lbr.c

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,9 @@ static void __intel_pmu_lbr_restore(struct x86_perf_task_context *task_ctx)
383383

384384
wrmsrl(x86_pmu.lbr_tos, tos);
385385
task_ctx->lbr_stack_state = LBR_NONE;
386+
387+
if (cpuc->lbr_select)
388+
wrmsrl(MSR_LBR_SELECT, task_ctx->lbr_sel);
386389
}
387390

388391
static void __intel_pmu_lbr_save(struct x86_perf_task_context *task_ctx)
@@ -415,6 +418,9 @@ static void __intel_pmu_lbr_save(struct x86_perf_task_context *task_ctx)
415418

416419
cpuc->last_task_ctx = task_ctx;
417420
cpuc->last_log_id = ++task_ctx->log_id;
421+
422+
if (cpuc->lbr_select)
423+
rdmsrl(MSR_LBR_SELECT, task_ctx->lbr_sel);
418424
}
419425

420426
void intel_pmu_lbr_swap_task_ctx(struct perf_event_context *prev,
@@ -485,6 +491,9 @@ void intel_pmu_lbr_add(struct perf_event *event)
485491
if (!x86_pmu.lbr_nr)
486492
return;
487493

494+
if (event->hw.flags & PERF_X86_EVENT_LBR_SELECT)
495+
cpuc->lbr_select = 1;
496+
488497
cpuc->br_sel = event->hw.branch_reg.reg;
489498

490499
if (branch_user_callstack(cpuc->br_sel) && event->ctx->task_ctx_data) {
@@ -532,6 +541,9 @@ void intel_pmu_lbr_del(struct perf_event *event)
532541
task_ctx->lbr_callstack_users--;
533542
}
534543

544+
if (event->hw.flags & PERF_X86_EVENT_LBR_SELECT)
545+
cpuc->lbr_select = 0;
546+
535547
if (x86_pmu.intel_cap.pebs_baseline && event->attr.precise_ip > 0)
536548
cpuc->lbr_pebs_users--;
537549
cpuc->lbr_users--;
@@ -540,19 +552,27 @@ void intel_pmu_lbr_del(struct perf_event *event)
540552
perf_sched_cb_dec(event->ctx->pmu);
541553
}
542554

555+
static inline bool vlbr_exclude_host(void)
556+
{
557+
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
558+
559+
return test_bit(INTEL_PMC_IDX_FIXED_VLBR,
560+
(unsigned long *)&cpuc->intel_ctrl_guest_mask);
561+
}
562+
543563
void intel_pmu_lbr_enable_all(bool pmi)
544564
{
545565
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
546566

547-
if (cpuc->lbr_users)
567+
if (cpuc->lbr_users && !vlbr_exclude_host())
548568
__intel_pmu_lbr_enable(pmi);
549569
}
550570

551571
void intel_pmu_lbr_disable_all(void)
552572
{
553573
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
554574

555-
if (cpuc->lbr_users)
575+
if (cpuc->lbr_users && !vlbr_exclude_host())
556576
__intel_pmu_lbr_disable();
557577
}
558578

@@ -694,7 +714,8 @@ void intel_pmu_lbr_read(void)
694714
* This could be smarter and actually check the event,
695715
* but this simple approach seems to work for now.
696716
*/
697-
if (!cpuc->lbr_users || cpuc->lbr_users == cpuc->lbr_pebs_users)
717+
if (!cpuc->lbr_users || vlbr_exclude_host() ||
718+
cpuc->lbr_users == cpuc->lbr_pebs_users)
698719
return;
699720

700721
if (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_32)
@@ -1365,5 +1386,5 @@ int x86_perf_get_lbr(struct x86_pmu_lbr *lbr)
13651386
EXPORT_SYMBOL_GPL(x86_perf_get_lbr);
13661387

13671388
struct event_constraint vlbr_constraint =
1368-
FIXED_EVENT_CONSTRAINT(INTEL_FIXED_VLBR_EVENT,
1369-
(INTEL_PMC_IDX_FIXED_VLBR - INTEL_PMC_IDX_FIXED));
1389+
__EVENT_CONSTRAINT(INTEL_FIXED_VLBR_EVENT, (1ULL << INTEL_PMC_IDX_FIXED_VLBR),
1390+
FIXED_EVENT_FLAGS, 1, 0, PERF_X86_EVENT_LBR_SELECT);

arch/x86/events/perf_event.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ static inline bool constraint_match(struct event_constraint *c, u64 ecode)
7878
#define PERF_X86_EVENT_LARGE_PEBS 0x0400 /* use large PEBS */
7979
#define PERF_X86_EVENT_PEBS_VIA_PT 0x0800 /* use PT buffer for PEBS */
8080
#define PERF_X86_EVENT_PAIR 0x1000 /* Large Increment per Cycle */
81+
#define PERF_X86_EVENT_LBR_SELECT 0x2000 /* Save/Restore MSR_LBR_SELECT */
8182

8283
struct amd_nb {
8384
int nb_id; /* NorthBridge id */
@@ -237,6 +238,7 @@ struct cpu_hw_events {
237238
u64 br_sel;
238239
struct x86_perf_task_context *last_task_ctx;
239240
int last_log_id;
241+
int lbr_select;
240242

241243
/*
242244
* Intel host/guest exclude bits
@@ -722,6 +724,7 @@ struct x86_perf_task_context {
722724
u64 lbr_from[MAX_LBR_ENTRIES];
723725
u64 lbr_to[MAX_LBR_ENTRIES];
724726
u64 lbr_info[MAX_LBR_ENTRIES];
727+
u64 lbr_sel;
725728
int tos;
726729
int valid_lbrs;
727730
int lbr_callstack_users;

0 commit comments

Comments
 (0)