Skip to content

Commit 5985c12

Browse files
mchinthwenlingz
authored andcommitted
HV:Added implementation for PMI handler function
irq.c/.h: Added new variables(ctx_rflags, ctx_rip, ctx_cs) in irq_desc On each interrupt this information is populated Added api's to access the irq_desc members profiling.c: profiling_pmi_handler:On each PMI generates gets the context and other information that caused it Tracked-On: #1409 Acked-by: Eddie Dong <eddie.dong@intel.com> Signed-off-by: Chinthapally, Manisha <manisha.chinthapally@intel.com>
1 parent a7cbee1 commit 5985c12

File tree

6 files changed

+219
-5
lines changed

6 files changed

+219
-5
lines changed

hypervisor/arch/x86/irq.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ static spinlock_t irq_alloc_spinlock = { .head = 0U, .tail = 0U, };
1212

1313
#define IRQ_ALLOC_BITMAP_SIZE INT_DIV_ROUNDUP(NR_IRQS, 64U)
1414
static uint64_t irq_alloc_bitmap[IRQ_ALLOC_BITMAP_SIZE];
15-
static struct irq_desc irq_desc_array[NR_IRQS];
15+
struct irq_desc irq_desc_array[NR_IRQS];
1616
static uint32_t vector_to_irq[NR_MAX_VECTOR + 1];
1717

1818
spurious_handler_t spurious_handler;
@@ -350,7 +350,12 @@ void dispatch_interrupt(const struct intr_excp_ctx *ctx)
350350
/* mask irq if possible */
351351
goto ERR;
352352
}
353-
353+
#ifdef PROFILING_ON
354+
/* Saves ctx info into irq_desc */
355+
desc->ctx_rip = ctx->rip;
356+
desc->ctx_rflags = ctx->rflags;
357+
desc->ctx_cs = ctx->cs;
358+
#endif
354359
handle_irq(desc);
355360
return;
356361
ERR:

hypervisor/arch/x86/virq.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,9 @@ int external_interrupt_vmexit_handler(struct vcpu *vcpu)
372372
}
373373

374374
ctx.vector = intr_info & 0xFFU;
375+
ctx.rip = vcpu_get_rip(vcpu);
376+
ctx.rflags = vcpu_get_rflags(vcpu);
377+
ctx.cs = exec_vmread32(VMX_GUEST_CS_SEL);
375378

376379
#ifdef CONFIG_PARTITION_MODE
377380
partition_mode_dispatch_interrupt(&ctx);

hypervisor/debug/profiling.c

Lines changed: 148 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
#define MAJOR_VERSION 1
1414
#define MINOR_VERSION 0
1515

16-
16+
#define LBR_NUM_REGISTERS 32U
17+
#define PERF_OVF_BIT_MASK 0xC0000070000000FULL
1718
#define LVT_PERFCTR_BIT_UNMASK 0xFFFEFFFFU
1819
#define LVT_PERFCTR_BIT_MASK 0x10000U
1920
#define VALID_DEBUGCTL_BIT_MASK 0x1801U
@@ -24,6 +25,8 @@ static bool in_pmu_profiling;
2425

2526
static uint32_t profiling_pmi_irq = IRQ_INVALID;
2627

28+
extern struct irq_desc irq_desc_array[NR_IRQS];
29+
2730
static void profiling_initialize_vmsw(void)
2831
{
2932
dev_dbg(ACRN_DBG_PROFILING, "%s: entering cpu%d",
@@ -324,9 +327,151 @@ static void profiling_handle_msrops(void)
324327
/*
325328
* Interrupt handler for performance monitoring interrupts
326329
*/
327-
static void profiling_pmi_handler(__unused unsigned int irq, __unused void *data)
330+
static void profiling_pmi_handler(unsigned int irq, __unused void *data)
328331
{
329-
/* to be implemented */
332+
uint64_t perf_ovf_status;
333+
uint32_t lvt_perf_ctr;
334+
uint32_t i;
335+
uint32_t group_id;
336+
struct profiling_msr_op *msrop = NULL;
337+
struct pmu_sample *psample = &(get_cpu_var(profiling_info.pmu_sample));
338+
struct sep_state *ss = &(get_cpu_var(profiling_info.sep_state));
339+
340+
if ((ss == NULL) || (psample == NULL)) {
341+
dev_dbg(ACRN_ERR_PROFILING, "%s: exiting cpu%d",
342+
__func__, get_cpu_id());
343+
return;
344+
}
345+
/* Stop all the counters first */
346+
msr_write(MSR_IA32_PERF_GLOBAL_CTRL, 0x0U);
347+
348+
group_id = ss->current_pmi_group_id;
349+
for (i = 0U; i < MAX_MSR_LIST_NUM; i++) {
350+
msrop = &(ss->pmi_entry_msr_list[group_id][i]);
351+
if (msrop != NULL) {
352+
if (msrop->msr_id == (uint32_t)-1) {
353+
break;
354+
}
355+
if (msrop->msr_op_type == (uint8_t)MSR_OP_WRITE) {
356+
msr_write(msrop->msr_id, msrop->value);
357+
}
358+
}
359+
}
360+
361+
ss->total_pmi_count++;
362+
perf_ovf_status = msr_read(MSR_IA32_PERF_GLOBAL_STATUS);
363+
lvt_perf_ctr = (uint32_t)msr_read(MSR_IA32_EXT_APIC_LVT_PMI);
364+
365+
if (perf_ovf_status == 0U) {
366+
goto reconfig;
367+
}
368+
369+
if ((perf_ovf_status & 0x80000000000000FULL) == 0U) {
370+
ss->nofrozen_pmi++;
371+
}
372+
373+
(void)memset(psample, 0U, sizeof(struct pmu_sample));
374+
375+
/* Attribute PMI to guest context */
376+
if ((get_cpu_var(profiling_info.vm_info).vmexit_reason
377+
== VMX_EXIT_REASON_EXTERNAL_INTERRUPT) &&
378+
((uint64_t)get_cpu_var(profiling_info.vm_info).external_vector
379+
== VECTOR_PMI)) {
380+
psample->csample.os_id
381+
=(uint32_t) get_cpu_var(profiling_info.vm_info).guest_vm_id;
382+
(void)memset(psample->csample.task, 0U, 16);
383+
psample->csample.cpu_id = get_cpu_id();
384+
psample->csample.process_id = 0U;
385+
psample->csample.task_id = 0U;
386+
psample->csample.overflow_status = perf_ovf_status;
387+
psample->csample.rip = get_cpu_var(profiling_info.vm_info).guest_rip;
388+
psample->csample.rflags
389+
= (uint32_t)get_cpu_var(profiling_info.vm_info).guest_rflags;
390+
psample->csample.cs
391+
= (uint32_t)get_cpu_var(profiling_info.vm_info).guest_cs;
392+
get_cpu_var(profiling_info.vm_info).vmexit_reason = 0U;
393+
get_cpu_var(profiling_info.vm_info).external_vector = -1;
394+
/* Attribute PMI to hypervisor context */
395+
} else {
396+
psample->csample.os_id = 0xFFFFFFFFU;
397+
(void)memcpy_s(psample->csample.task, 16, "VMM\0", 4);
398+
psample->csample.cpu_id = get_cpu_id();
399+
psample->csample.process_id = 0U;
400+
psample->csample.task_id = 0U;
401+
psample->csample.overflow_status = perf_ovf_status;
402+
psample->csample.rip = irq_desc_array[irq].ctx_rip;
403+
psample->csample.rflags
404+
= (uint32_t)irq_desc_array[irq].ctx_rflags;
405+
psample->csample.cs = (uint32_t)irq_desc_array[irq].ctx_cs;
406+
}
407+
408+
if ((sep_collection_switch &
409+
(1UL << (uint64_t)LBR_PMU_SAMPLING)) > 0UL) {
410+
psample->lsample.lbr_tos = msr_read(MSR_CORE_LASTBRANCH_TOS);
411+
for (i = 0U; i < LBR_NUM_REGISTERS; i++) {
412+
psample->lsample.lbr_from_ip[i]
413+
= msr_read(MSR_CORE_LASTBRANCH_0_FROM_IP + i);
414+
psample->lsample.lbr_to_ip[i]
415+
= msr_read(MSR_CORE_LASTBRANCH_0_TO_IP + i);
416+
}
417+
/* Generate core pmu sample and lbr data */
418+
(void)profiling_generate_data(COLLECT_PROFILE_DATA, LBR_PMU_SAMPLING);
419+
} else {
420+
/* Generate core pmu sample only */
421+
(void)profiling_generate_data(COLLECT_PROFILE_DATA, CORE_PMU_SAMPLING);
422+
}
423+
424+
/* Clear PERF_GLOBAL_OVF_STATUS bits */
425+
msr_write(MSR_IA32_PERF_GLOBAL_OVF_CTRL,
426+
perf_ovf_status & PERF_OVF_BIT_MASK);
427+
428+
ss->valid_pmi_count++;
429+
430+
group_id = ss->current_pmi_group_id;
431+
for (i = 0U; i < MAX_MSR_LIST_NUM; i++) {
432+
msrop = &(ss->pmi_exit_msr_list[group_id][i]);
433+
if (msrop != NULL) {
434+
if (msrop->msr_id == (uint32_t)-1) {
435+
break;
436+
}
437+
if (msrop->msr_op_type == (uint8_t)MSR_OP_WRITE) {
438+
if (msrop->reg_type != (uint8_t)PMU_MSR_DATA) {
439+
if (msrop->msr_id != MSR_IA32_PERF_GLOBAL_CTRL) {
440+
msr_write(msrop->msr_id, msrop->value);
441+
}
442+
}
443+
else {
444+
if (((perf_ovf_status >> msrop->param) & 0x1U) > 0U) {
445+
msr_write(msrop->msr_id, msrop->value);
446+
}
447+
}
448+
}
449+
}
450+
}
451+
452+
reconfig:
453+
454+
if (ss->pmu_state == PMU_RUNNING) {
455+
/* Unmask the interrupt */
456+
lvt_perf_ctr &= LVT_PERFCTR_BIT_UNMASK;
457+
msr_write(MSR_IA32_EXT_APIC_LVT_PMI, lvt_perf_ctr);
458+
group_id = ss->current_pmi_group_id;
459+
for (i = 0U; i < MAX_MSR_LIST_NUM; i++) {
460+
msrop = &(ss->pmi_start_msr_list[group_id][i]);
461+
if (msrop != NULL) {
462+
if (msrop->msr_id == (uint32_t)-1) {
463+
break;
464+
}
465+
if (msrop->msr_op_type == (uint8_t)MSR_OP_WRITE) {
466+
msr_write(msrop->msr_id, msrop->value);
467+
}
468+
}
469+
}
470+
} else {
471+
/* Mask the interrupt */
472+
lvt_perf_ctr |= LVT_PERFCTR_BIT_MASK;
473+
msr_write(MSR_IA32_EXT_APIC_LVT_PMI, lvt_perf_ctr);
474+
}
330475
}
331476

332477
/*

hypervisor/include/arch/x86/msr.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,16 @@
488488
#define MSR_ATOM_LER_TO_LIP 0x000001DEU
489489
/* Last exception record to linear IP */
490490

491+
#ifdef PROFILING_ON
492+
/* Core (and Goldmont) specific MSRs */
493+
#define MSR_CORE_LASTBRANCH_TOS 0x000001C9U
494+
/* Last branch record stack TOS */
495+
#define MSR_CORE_LASTBRANCH_0_FROM_IP 0x00000680U
496+
/* Last branch record 0 from IP */
497+
#define MSR_CORE_LASTBRANCH_0_TO_IP 0x000006C0U
498+
/* Last branch record 0 to IP */
499+
#endif
500+
491501
/* LINCROFT specific MSRs */
492502
#define MSR_LNC_BIOS_CACHE_AS_RAM 0x000002E0U /* Configure CAR */
493503

hypervisor/include/common/irq.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ struct irq_desc {
2424
uint32_t flags; /* flags for trigger mode/ptdev */
2525

2626
spinlock_t lock;
27+
#ifdef PROFILING_ON
28+
uint64_t ctx_rip;
29+
uint64_t ctx_rflags;
30+
uint64_t ctx_cs;
31+
#endif
2732
};
2833

2934
int32_t request_irq(uint32_t req_irq, irq_action_t action_fn, void *priv_data,

hypervisor/include/debug/profiling_internal.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ enum MSR_CMD_TYPE {
3333
MSR_OP_READ_CLEAR
3434
};
3535

36+
enum PMU_MSR_TYPE {
37+
PMU_MSR_CCCR = 0,
38+
PMU_MSR_ESCR,
39+
PMU_MSR_DATA
40+
};
3641
typedef enum IPI_COMMANDS {
3742
IPI_MSR_OP = 0,
3843
IPI_PMU_CONFIG,
@@ -212,6 +217,46 @@ struct sep_state {
212217
uint64_t saved_debugctl_value;
213218
} __aligned(8);
214219

220+
struct core_pmu_sample {
221+
/* context where PMI is triggered */
222+
uint32_t os_id;
223+
/* the task id */
224+
uint32_t task_id;
225+
/* instruction pointer */
226+
uint64_t rip;
227+
/* the task name */
228+
char task[16];
229+
/* physical cpu ID */
230+
uint32_t cpu_id;
231+
/* the process id */
232+
uint32_t process_id;
233+
/* perf global status msr value (for overflow status) */
234+
uint64_t overflow_status;
235+
/* rflags */
236+
uint32_t rflags;
237+
/* code segment */
238+
uint32_t cs;
239+
} __aligned(SEP_BUF_ENTRY_SIZE);
240+
241+
#define NUM_LBR_ENTRY 32
242+
243+
struct lbr_pmu_sample {
244+
/* LBR TOS */
245+
uint64_t lbr_tos;
246+
/* LBR FROM IP */
247+
uint64_t lbr_from_ip[NUM_LBR_ENTRY];
248+
/* LBR TO IP */
249+
uint64_t lbr_to_ip[NUM_LBR_ENTRY];
250+
/* LBR info */
251+
uint64_t lbr_info[NUM_LBR_ENTRY];
252+
} __aligned(SEP_BUF_ENTRY_SIZE);
253+
254+
struct pmu_sample {
255+
/* core pmu sample */
256+
struct core_pmu_sample csample;
257+
/* lbr pmu sample */
258+
struct lbr_pmu_sample lsample;
259+
} __aligned(SEP_BUF_ENTRY_SIZE);
215260

216261
struct vm_switch_trace {
217262
uint64_t vm_enter_tsc;
@@ -228,6 +273,7 @@ struct profiling_info_wrapper {
228273
struct sep_state sep_state;
229274
struct guest_vm_info vm_info;
230275
ipi_commands ipi_cmd;
276+
struct pmu_sample pmu_sample;
231277
struct vm_switch_trace vm_switch_trace;
232278
socwatch_state soc_state;
233279
struct sw_msr_op_info sw_msr_op_info;

0 commit comments

Comments
 (0)