mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2026-01-05 23:57:10 +00:00
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: projectacrn#1409 Acked-by: Eddie Dong <eddie.dong@intel.com> Signed-off-by: Chinthapally, Manisha <manisha.chinthapally@intel.com>
This commit is contained in:
committed by
wenlingz
parent
a7cbee1802
commit
5985c1216e
@@ -13,7 +13,8 @@
|
||||
#define MAJOR_VERSION 1
|
||||
#define MINOR_VERSION 0
|
||||
|
||||
|
||||
#define LBR_NUM_REGISTERS 32U
|
||||
#define PERF_OVF_BIT_MASK 0xC0000070000000FULL
|
||||
#define LVT_PERFCTR_BIT_UNMASK 0xFFFEFFFFU
|
||||
#define LVT_PERFCTR_BIT_MASK 0x10000U
|
||||
#define VALID_DEBUGCTL_BIT_MASK 0x1801U
|
||||
@@ -24,6 +25,8 @@ static bool in_pmu_profiling;
|
||||
|
||||
static uint32_t profiling_pmi_irq = IRQ_INVALID;
|
||||
|
||||
extern struct irq_desc irq_desc_array[NR_IRQS];
|
||||
|
||||
static void profiling_initialize_vmsw(void)
|
||||
{
|
||||
dev_dbg(ACRN_DBG_PROFILING, "%s: entering cpu%d",
|
||||
@@ -324,9 +327,151 @@ static void profiling_handle_msrops(void)
|
||||
/*
|
||||
* Interrupt handler for performance monitoring interrupts
|
||||
*/
|
||||
static void profiling_pmi_handler(__unused unsigned int irq, __unused void *data)
|
||||
static void profiling_pmi_handler(unsigned int irq, __unused void *data)
|
||||
{
|
||||
/* to be implemented */
|
||||
uint64_t perf_ovf_status;
|
||||
uint32_t lvt_perf_ctr;
|
||||
uint32_t i;
|
||||
uint32_t group_id;
|
||||
struct profiling_msr_op *msrop = NULL;
|
||||
struct pmu_sample *psample = &(get_cpu_var(profiling_info.pmu_sample));
|
||||
struct sep_state *ss = &(get_cpu_var(profiling_info.sep_state));
|
||||
|
||||
if ((ss == NULL) || (psample == NULL)) {
|
||||
dev_dbg(ACRN_ERR_PROFILING, "%s: exiting cpu%d",
|
||||
__func__, get_cpu_id());
|
||||
return;
|
||||
}
|
||||
/* Stop all the counters first */
|
||||
msr_write(MSR_IA32_PERF_GLOBAL_CTRL, 0x0U);
|
||||
|
||||
group_id = ss->current_pmi_group_id;
|
||||
for (i = 0U; i < MAX_MSR_LIST_NUM; i++) {
|
||||
msrop = &(ss->pmi_entry_msr_list[group_id][i]);
|
||||
if (msrop != NULL) {
|
||||
if (msrop->msr_id == (uint32_t)-1) {
|
||||
break;
|
||||
}
|
||||
if (msrop->msr_op_type == (uint8_t)MSR_OP_WRITE) {
|
||||
msr_write(msrop->msr_id, msrop->value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ss->total_pmi_count++;
|
||||
perf_ovf_status = msr_read(MSR_IA32_PERF_GLOBAL_STATUS);
|
||||
lvt_perf_ctr = (uint32_t)msr_read(MSR_IA32_EXT_APIC_LVT_PMI);
|
||||
|
||||
if (perf_ovf_status == 0U) {
|
||||
goto reconfig;
|
||||
}
|
||||
|
||||
if ((perf_ovf_status & 0x80000000000000FULL) == 0U) {
|
||||
ss->nofrozen_pmi++;
|
||||
}
|
||||
|
||||
(void)memset(psample, 0U, sizeof(struct pmu_sample));
|
||||
|
||||
/* Attribute PMI to guest context */
|
||||
if ((get_cpu_var(profiling_info.vm_info).vmexit_reason
|
||||
== VMX_EXIT_REASON_EXTERNAL_INTERRUPT) &&
|
||||
((uint64_t)get_cpu_var(profiling_info.vm_info).external_vector
|
||||
== VECTOR_PMI)) {
|
||||
psample->csample.os_id
|
||||
=(uint32_t) get_cpu_var(profiling_info.vm_info).guest_vm_id;
|
||||
(void)memset(psample->csample.task, 0U, 16);
|
||||
psample->csample.cpu_id = get_cpu_id();
|
||||
psample->csample.process_id = 0U;
|
||||
psample->csample.task_id = 0U;
|
||||
psample->csample.overflow_status = perf_ovf_status;
|
||||
psample->csample.rip = get_cpu_var(profiling_info.vm_info).guest_rip;
|
||||
psample->csample.rflags
|
||||
= (uint32_t)get_cpu_var(profiling_info.vm_info).guest_rflags;
|
||||
psample->csample.cs
|
||||
= (uint32_t)get_cpu_var(profiling_info.vm_info).guest_cs;
|
||||
get_cpu_var(profiling_info.vm_info).vmexit_reason = 0U;
|
||||
get_cpu_var(profiling_info.vm_info).external_vector = -1;
|
||||
/* Attribute PMI to hypervisor context */
|
||||
} else {
|
||||
psample->csample.os_id = 0xFFFFFFFFU;
|
||||
(void)memcpy_s(psample->csample.task, 16, "VMM\0", 4);
|
||||
psample->csample.cpu_id = get_cpu_id();
|
||||
psample->csample.process_id = 0U;
|
||||
psample->csample.task_id = 0U;
|
||||
psample->csample.overflow_status = perf_ovf_status;
|
||||
psample->csample.rip = irq_desc_array[irq].ctx_rip;
|
||||
psample->csample.rflags
|
||||
= (uint32_t)irq_desc_array[irq].ctx_rflags;
|
||||
psample->csample.cs = (uint32_t)irq_desc_array[irq].ctx_cs;
|
||||
}
|
||||
|
||||
if ((sep_collection_switch &
|
||||
(1UL << (uint64_t)LBR_PMU_SAMPLING)) > 0UL) {
|
||||
psample->lsample.lbr_tos = msr_read(MSR_CORE_LASTBRANCH_TOS);
|
||||
for (i = 0U; i < LBR_NUM_REGISTERS; i++) {
|
||||
psample->lsample.lbr_from_ip[i]
|
||||
= msr_read(MSR_CORE_LASTBRANCH_0_FROM_IP + i);
|
||||
psample->lsample.lbr_to_ip[i]
|
||||
= msr_read(MSR_CORE_LASTBRANCH_0_TO_IP + i);
|
||||
}
|
||||
/* Generate core pmu sample and lbr data */
|
||||
(void)profiling_generate_data(COLLECT_PROFILE_DATA, LBR_PMU_SAMPLING);
|
||||
} else {
|
||||
/* Generate core pmu sample only */
|
||||
(void)profiling_generate_data(COLLECT_PROFILE_DATA, CORE_PMU_SAMPLING);
|
||||
}
|
||||
|
||||
/* Clear PERF_GLOBAL_OVF_STATUS bits */
|
||||
msr_write(MSR_IA32_PERF_GLOBAL_OVF_CTRL,
|
||||
perf_ovf_status & PERF_OVF_BIT_MASK);
|
||||
|
||||
ss->valid_pmi_count++;
|
||||
|
||||
group_id = ss->current_pmi_group_id;
|
||||
for (i = 0U; i < MAX_MSR_LIST_NUM; i++) {
|
||||
msrop = &(ss->pmi_exit_msr_list[group_id][i]);
|
||||
if (msrop != NULL) {
|
||||
if (msrop->msr_id == (uint32_t)-1) {
|
||||
break;
|
||||
}
|
||||
if (msrop->msr_op_type == (uint8_t)MSR_OP_WRITE) {
|
||||
if (msrop->reg_type != (uint8_t)PMU_MSR_DATA) {
|
||||
if (msrop->msr_id != MSR_IA32_PERF_GLOBAL_CTRL) {
|
||||
msr_write(msrop->msr_id, msrop->value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (((perf_ovf_status >> msrop->param) & 0x1U) > 0U) {
|
||||
msr_write(msrop->msr_id, msrop->value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reconfig:
|
||||
|
||||
if (ss->pmu_state == PMU_RUNNING) {
|
||||
/* Unmask the interrupt */
|
||||
lvt_perf_ctr &= LVT_PERFCTR_BIT_UNMASK;
|
||||
msr_write(MSR_IA32_EXT_APIC_LVT_PMI, lvt_perf_ctr);
|
||||
group_id = ss->current_pmi_group_id;
|
||||
for (i = 0U; i < MAX_MSR_LIST_NUM; i++) {
|
||||
msrop = &(ss->pmi_start_msr_list[group_id][i]);
|
||||
if (msrop != NULL) {
|
||||
if (msrop->msr_id == (uint32_t)-1) {
|
||||
break;
|
||||
}
|
||||
if (msrop->msr_op_type == (uint8_t)MSR_OP_WRITE) {
|
||||
msr_write(msrop->msr_id, msrop->value);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Mask the interrupt */
|
||||
lvt_perf_ctr |= LVT_PERFCTR_BIT_MASK;
|
||||
msr_write(MSR_IA32_EXT_APIC_LVT_PMI, lvt_perf_ctr);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user