Skip to content

Commit 1786f62

Browse files
mchinthwenlingz
authored andcommitted
HV:Added support to setup tool & start/stop profing
profiling_set_control: Receives tool control information from guest and sets control switches accordingly, tool control information includes: type - sep/socwatch action - Start/stop feature - What to collect(core/lbr/vm switch) This function provides interface to start and stop profiling data collection profiling_start_pmu: Initialize sep state and enable PMU counters SMP calls profiling_enable_pmu profiling_stop_pmu: Reset sep state and Disable all the PMU counters SMP calls profiling_disable_pmu profiling_enable_pmu: Enable all the Performance Monitoring Control registers. Unmask LAPIC entry for PMC register to enable performance monitoring Walk through the entries and write to PMU control regiesters profiling_disable_pmu: Disable all Performance Monitoring Control registers Tracked-On: #1409 Acked-by: Eddie Dong <eddie.dong@intel.com> Signed-off-by: Chinthapally, Manisha <manisha.chinthapally@intel.com>
1 parent 898b9c8 commit 1786f62

File tree

2 files changed

+366
-5
lines changed

2 files changed

+366
-5
lines changed

hypervisor/debug/profiling.c

Lines changed: 333 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,14 @@
1313
#define MAJOR_VERSION 1
1414
#define MINOR_VERSION 0
1515

16+
17+
#define LVT_PERFCTR_BIT_UNMASK 0xFFFEFFFFU
1618
#define LVT_PERFCTR_BIT_MASK 0x10000U
19+
#define VALID_DEBUGCTL_BIT_MASK 0x1801U
1720

1821
static uint64_t sep_collection_switch;
22+
static uint64_t socwatch_collection_switch;
23+
static bool in_pmu_profiling;
1924

2025
static uint32_t profiling_pmi_irq = IRQ_INVALID;
2126

@@ -79,15 +84,131 @@ static void profiling_initialize_pmi(void)
7984
*/
8085
static void profiling_enable_pmu(void)
8186
{
82-
/* to be implemented */
87+
uint32_t lvt_perf_ctr;
88+
uint32_t i;
89+
uint32_t group_id;
90+
struct profiling_msr_op *msrop = NULL;
91+
struct sep_state *ss = &get_cpu_var(profiling_info.sep_state);
92+
93+
dev_dbg(ACRN_DBG_PROFILING, "%s: entering cpu%d",
94+
__func__, get_cpu_id());
95+
96+
if (ss == NULL) {
97+
dev_dbg(ACRN_ERR_PROFILING, "%s: exiting cpu%d",
98+
__func__, get_cpu_id());
99+
return;
100+
}
101+
102+
/* Unmask LAPIC LVT entry for PMC register */
103+
lvt_perf_ctr = (uint32_t) msr_read(MSR_IA32_EXT_APIC_LVT_PMI);
104+
dev_dbg(ACRN_DBG_PROFILING, "%s: 0x%x, 0x%llx",
105+
__func__, MSR_IA32_EXT_APIC_LVT_PMI, lvt_perf_ctr);
106+
lvt_perf_ctr &= LVT_PERFCTR_BIT_UNMASK;
107+
msr_write(MSR_IA32_EXT_APIC_LVT_PMI, lvt_perf_ctr);
108+
dev_dbg(ACRN_DBG_PROFILING, "%s: 0x%x, 0x%llx",
109+
__func__, MSR_IA32_EXT_APIC_LVT_PMI, lvt_perf_ctr);
110+
111+
if (ss->guest_debugctl_value != 0U) {
112+
/* Set the VM Exit MSR Load in VMCS */
113+
if (ss->vmexit_msr_cnt == 0) {
114+
ss->vmexit_msr_cnt = 1;
115+
ss->vmexit_msr_list[0].msr_idx
116+
= MSR_IA32_DEBUGCTL;
117+
ss->vmexit_msr_list[0].msr_data
118+
= ss->guest_debugctl_value &
119+
VALID_DEBUGCTL_BIT_MASK;
120+
121+
exec_vmwrite64(VMX_EXIT_MSR_LOAD_ADDR_FULL,
122+
hva2hpa(ss->vmexit_msr_list));
123+
exec_vmwrite(VMX_EXIT_MSR_LOAD_COUNT,
124+
(uint64_t)ss->vmexit_msr_cnt);
125+
}
126+
127+
/* VMCS GUEST field */
128+
ss->saved_debugctl_value
129+
= exec_vmread64(VMX_GUEST_IA32_DEBUGCTL_FULL);
130+
exec_vmwrite64(VMX_GUEST_IA32_DEBUGCTL_FULL,
131+
(ss->guest_debugctl_value & VALID_DEBUGCTL_BIT_MASK));
132+
}
133+
134+
group_id = ss->current_pmi_group_id;
135+
for (i = 0U; i < MAX_MSR_LIST_NUM; i++) {
136+
msrop = &(ss->pmi_start_msr_list[group_id][i]);
137+
if (msrop != NULL) {
138+
if (msrop->msr_id == (uint32_t)-1) {
139+
break;
140+
}
141+
if (msrop->msr_op_type == (uint8_t)MSR_OP_WRITE) {
142+
msr_write(msrop->msr_id, msrop->value);
143+
dev_dbg(ACRN_DBG_PROFILING,
144+
"%s: MSRWRITE cpu%d, msr_id=0x%x, msr_val=0x%llx",
145+
__func__, get_cpu_id(), msrop->msr_id, msrop->value);
146+
}
147+
}
148+
}
149+
150+
ss->pmu_state = PMU_RUNNING;
151+
152+
dev_dbg(ACRN_DBG_PROFILING, "%s: exiting cpu%d",
153+
__func__, get_cpu_id());
83154
}
84155

85156
/*
86157
* Disable all Performance Monitoring Control registers
87158
*/
88159
static void profiling_disable_pmu(void)
89160
{
90-
/* to be implemented */
161+
uint32_t lvt_perf_ctr;
162+
uint32_t i;
163+
uint32_t group_id;
164+
struct profiling_msr_op *msrop = NULL;
165+
struct sep_state *ss = &get_cpu_var(profiling_info.sep_state);
166+
167+
dev_dbg(ACRN_DBG_PROFILING, "%s: entering cpu%d",
168+
__func__, get_cpu_id());
169+
170+
if (ss == NULL) {
171+
dev_dbg(ACRN_ERR_PROFILING, "%s: exiting cpu%d",
172+
__func__, get_cpu_id());
173+
return;
174+
}
175+
176+
if (ss->vmexit_msr_cnt == 1) {
177+
/* Set the VM Exit MSR Load in VMCS */
178+
exec_vmwrite(VMX_EXIT_MSR_LOAD_COUNT, 0x0U);
179+
exec_vmwrite64(VMX_GUEST_IA32_DEBUGCTL_FULL,
180+
ss->saved_debugctl_value);
181+
182+
ss->vmexit_msr_cnt = 0;
183+
}
184+
185+
group_id = ss->current_pmi_group_id;
186+
for (i = 0U; i < MAX_MSR_LIST_NUM; i++) {
187+
msrop = &(ss->pmi_stop_msr_list[group_id][i]);
188+
if (msrop != NULL) {
189+
if (msrop->msr_id == (uint32_t)-1) {
190+
break;
191+
}
192+
if (msrop->msr_op_type == (uint8_t)MSR_OP_WRITE) {
193+
msr_write(msrop->msr_id, msrop->value);
194+
dev_dbg(ACRN_DBG_PROFILING,
195+
"%s: MSRWRITE cpu%d, msr_id=0x%x, msr_val=0x%llx",
196+
__func__, get_cpu_id(), msrop->msr_id, msrop->value);
197+
}
198+
}
199+
}
200+
201+
/* Mask LAPIC LVT entry for PMC register */
202+
lvt_perf_ctr = (uint32_t) msr_read(MSR_IA32_EXT_APIC_LVT_PMI);
203+
204+
lvt_perf_ctr |= LVT_PERFCTR_BIT_MASK;
205+
msr_write(MSR_IA32_EXT_APIC_LVT_PMI, lvt_perf_ctr);
206+
207+
208+
ss->pmu_state = PMU_SETUP;
209+
210+
dev_dbg(ACRN_DBG_PROFILING, "%s: exiting cpu%d",
211+
__func__, get_cpu_id());
91212
}
92213

93214
/*
@@ -106,6 +227,101 @@ static void profiling_pmi_handler(__unused unsigned int irq, __unused void *data
106227
/* to be implemented */
107228
}
108229

230+
/*
231+
* Initialize sep state and enable PMU counters
232+
*/
233+
void profiling_start_pmu(void)
234+
{
235+
uint16_t i;
236+
237+
dev_dbg(ACRN_DBG_PROFILING, "%s: entering", __func__);
238+
239+
if (in_pmu_profiling) {
240+
return;
241+
}
242+
243+
for (i = 0U; i < phys_cpu_num; i++) {
244+
if (per_cpu(profiling_info.sep_state, i).pmu_state != PMU_SETUP) {
245+
pr_err("%s: invalid pmu_state %u on cpu%d",
246+
__func__, get_cpu_var(profiling_info.sep_state).pmu_state, i);
247+
return;
248+
}
249+
}
250+
251+
for (i = 0U; i < phys_cpu_num; i++) {
252+
per_cpu(profiling_info.ipi_cmd, i) = IPI_PMU_START;
253+
per_cpu(profiling_info.sep_state, i).samples_logged = 0U;
254+
per_cpu(profiling_info.sep_state, i).samples_dropped = 0U;
255+
per_cpu(profiling_info.sep_state, i).valid_pmi_count = 0U;
256+
per_cpu(profiling_info.sep_state, i).total_pmi_count = 0U;
257+
per_cpu(profiling_info.sep_state, i).total_vmexit_count = 0U;
258+
per_cpu(profiling_info.sep_state, i).frozen_well = 0U;
259+
per_cpu(profiling_info.sep_state, i).frozen_delayed = 0U;
260+
per_cpu(profiling_info.sep_state, i).nofrozen_pmi = 0U;
261+
per_cpu(profiling_info.sep_state, i).pmu_state = PMU_RUNNING;
262+
}
263+
264+
smp_call_function(pcpu_active_bitmap, profiling_ipi_handler, NULL);
265+
266+
in_pmu_profiling = true;
267+
268+
dev_dbg(ACRN_DBG_PROFILING, "%s: done", __func__);
269+
}
270+
271+
/*
272+
* Reset sep state and Disable all the PMU counters
273+
*/
274+
void profiling_stop_pmu(void)
275+
{
276+
uint16_t i;
277+
278+
dev_dbg(ACRN_DBG_PROFILING, "%s: entering", __func__);
279+
280+
if (!in_pmu_profiling) {
281+
return;
282+
}
283+
284+
for (i = 0U; i < phys_cpu_num; i++) {
285+
per_cpu(profiling_info.ipi_cmd, i) = IPI_PMU_STOP;
286+
if (per_cpu(profiling_info.sep_state, i).pmu_state == PMU_RUNNING) {
287+
per_cpu(profiling_info.sep_state, i).pmu_state = PMU_SETUP;
288+
}
289+
290+
dev_dbg(ACRN_DBG_PROFILING,
291+
"%s: pmi_cnt[%d] = total:%u valid=%u, vmexit_cnt=%u",
292+
__func__, i, per_cpu(profiling_info.sep_state, i).total_pmi_count,
293+
per_cpu(profiling_info.sep_state, i).valid_pmi_count,
294+
per_cpu(profiling_info.sep_state, i).total_vmexit_count);
295+
296+
dev_dbg(ACRN_DBG_PROFILING,
297+
"%s: cpu%d frozen well:%u frozen delayed=%u, nofrozen_pmi=%u",
298+
__func__, i, per_cpu(profiling_info.sep_state, i).frozen_well,
299+
per_cpu(profiling_info.sep_state, i).frozen_delayed,
300+
per_cpu(profiling_info.sep_state, i).nofrozen_pmi);
301+
302+
dev_dbg(ACRN_DBG_PROFILING,
303+
"%s: cpu%d samples captured:%u samples dropped=%u",
304+
__func__, i, per_cpu(profiling_info.sep_state, i).samples_logged,
305+
per_cpu(profiling_info.sep_state, i).samples_dropped);
306+
307+
per_cpu(profiling_info.sep_state, i).samples_logged = 0U;
308+
per_cpu(profiling_info.sep_state, i).samples_dropped = 0U;
309+
per_cpu(profiling_info.sep_state, i).valid_pmi_count = 0U;
310+
per_cpu(profiling_info.sep_state, i).total_pmi_count = 0U;
311+
per_cpu(profiling_info.sep_state, i).total_vmexit_count = 0U;
312+
per_cpu(profiling_info.sep_state, i).frozen_well = 0U;
313+
per_cpu(profiling_info.sep_state, i).frozen_delayed = 0U;
314+
per_cpu(profiling_info.sep_state, i).nofrozen_pmi = 0U;
315+
}
316+
317+
smp_call_function(pcpu_active_bitmap, profiling_ipi_handler, NULL);
318+
319+
in_pmu_profiling = false;
320+
321+
dev_dbg(ACRN_DBG_PROFILING, "%s: done.", __func__);
322+
}
323+
324+
109325
/*
110326
* Performs MSR operations on all the CPU's
111327
*/
@@ -259,9 +475,115 @@ int32_t profiling_get_control(struct vm *vm, uint64_t addr)
259475
/*
260476
* Update the profiling type based on control switch
261477
*/
262-
int32_t profiling_set_control(__unused struct vm *vm, __unused uint64_t addr)
478+
int32_t profiling_set_control(struct vm *vm, uint64_t addr)
263479
{
264-
/* to be implemented */
480+
uint64_t old_switch;
481+
uint64_t new_switch;
482+
uint64_t i;
483+
484+
struct profiling_control prof_control;
485+
486+
(void)memset((void *)&prof_control, 0U, sizeof(prof_control));
487+
488+
dev_dbg(ACRN_DBG_PROFILING, "%s: entering", __func__);
489+
490+
if (copy_from_gpa(vm, &prof_control, addr, sizeof(prof_control)) != 0) {
491+
pr_err("%s: Unable to copy addr from vm\n", __func__);
492+
return -EINVAL;
493+
}
494+
495+
switch (prof_control.collector_id) {
496+
case COLLECT_PROFILE_DATA:
497+
old_switch = sep_collection_switch;
498+
new_switch = prof_control.switches;
499+
sep_collection_switch = prof_control.switches;
500+
501+
dev_dbg(ACRN_DBG_PROFILING,
502+
" old_switch: %llu sep_collection_switch: %llu!",
503+
old_switch, sep_collection_switch);
504+
505+
for (i = 0U; i < (uint64_t)MAX_SEP_FEATURE_ID; i++) {
506+
if ((new_switch ^ old_switch) & (0x1U << i)) {
507+
switch (i) {
508+
case CORE_PMU_SAMPLING:
509+
case CORE_PMU_COUNTING:
510+
if (new_switch & (0x1U << i)) {
511+
profiling_start_pmu();
512+
} else {
513+
profiling_stop_pmu();
514+
}
515+
break;
516+
case LBR_PMU_SAMPLING:
517+
break;
518+
case VM_SWITCH_TRACING:
519+
break;
520+
default:
521+
dev_dbg(ACRN_DBG_PROFILING,
522+
"%s: feature not supported %u",
523+
__func__, i);
524+
break;
525+
}
526+
}
527+
}
528+
break;
529+
case COLLECT_POWER_DATA:
530+
dev_dbg(ACRN_DBG_PROFILING,
531+
"%s: configuring socwatch", __func__);
532+
533+
socwatch_collection_switch = prof_control.switches;
534+
535+
dev_dbg(ACRN_DBG_PROFILING,
536+
"socwatch_collection_switch: %llu!",
537+
socwatch_collection_switch);
538+
539+
if (socwatch_collection_switch != 0UL) {
540+
dev_dbg(ACRN_DBG_PROFILING,
541+
"%s: socwatch start collection invoked!", __func__);
542+
for (i = 0U; i < (uint64_t)MAX_SOCWATCH_FEATURE_ID; i++) {
543+
if (socwatch_collection_switch & (0x1U << i)) {
544+
switch (i) {
545+
case SOCWATCH_COMMAND:
546+
break;
547+
case SOCWATCH_VM_SWITCH_TRACING:
548+
dev_dbg(ACRN_DBG_PROFILING,
549+
"%s: socwatch vm-switch feature requested!",
550+
__func__);
551+
break;
552+
default:
553+
dev_dbg(ACRN_DBG_PROFILING,
554+
"%s: socwatch feature not supported %u",
555+
__func__, i);
556+
break;
557+
}
558+
}
559+
}
560+
for (i = 0U; i < phys_cpu_num; i++) {
561+
per_cpu(profiling_info.soc_state, i)
562+
= SW_RUNNING;
563+
}
564+
} else { /* stop socwatch collection */
565+
dev_dbg(ACRN_DBG_PROFILING,
566+
"%s: socwatch stop collection invoked or collection switch not set!",
567+
__func__);
568+
for (i = 0U; i < phys_cpu_num; i++) {
569+
per_cpu(profiling_info.soc_state, i)
570+
= SW_STOPPED;
571+
}
572+
}
573+
break;
574+
default:
575+
pr_err("%s: unknown collector %d",
576+
__func__, prof_control.collector_id);
577+
break;
578+
}
579+
580+
if (copy_to_gpa(vm, &prof_control, addr, sizeof(prof_control)) != 0) {
581+
pr_err("%s: Unable to copy addr to vm\n", __func__);
582+
return -EINVAL;
583+
}
584+
585+
dev_dbg(ACRN_DBG_PROFILING, "%s: exiting", __func__);
586+
265587
return 0;
266588
}
267589

@@ -505,10 +827,16 @@ void profiling_setup(void)
505827
profiling_pmi_irq = (uint32_t)retval;
506828
}
507829

830+
per_cpu(profiling_info.sep_state, cpu).valid_pmi_count = 0U;
831+
per_cpu(profiling_info.sep_state, cpu).total_pmi_count = 0U;
832+
per_cpu(profiling_info.sep_state, cpu).total_vmexit_count = 0U;
833+
per_cpu(profiling_info.sep_state, cpu).pmu_state = PMU_INITIALIZED;
834+
per_cpu(profiling_info.sep_state, cpu).vmexit_msr_cnt = 0;
835+
508836
msr_write(MSR_IA32_EXT_APIC_LVT_PMI,
509837
VECTOR_PMI | LVT_PERFCTR_BIT_MASK);
510838

511839
dev_dbg(ACRN_DBG_PROFILING, "%s: exiting", __func__);
512840
}
513841

514-
#endif
842+
#endif

0 commit comments

Comments
 (0)