13
13
#define MAJOR_VERSION 1
14
14
#define MINOR_VERSION 0
15
15
16
+
17
+ #define LVT_PERFCTR_BIT_UNMASK 0xFFFEFFFFU
16
18
#define LVT_PERFCTR_BIT_MASK 0x10000U
19
+ #define VALID_DEBUGCTL_BIT_MASK 0x1801U
17
20
18
21
static uint64_t sep_collection_switch ;
22
+ static uint64_t socwatch_collection_switch ;
23
+ static bool in_pmu_profiling ;
19
24
20
25
static uint32_t profiling_pmi_irq = IRQ_INVALID ;
21
26
@@ -79,15 +84,131 @@ static void profiling_initialize_pmi(void)
79
84
*/
80
85
static void profiling_enable_pmu (void )
81
86
{
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 ());
83
154
}
84
155
85
156
/*
86
157
* Disable all Performance Monitoring Control registers
87
158
*/
88
159
static void profiling_disable_pmu (void )
89
160
{
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 ());
91
212
}
92
213
93
214
/*
@@ -106,6 +227,101 @@ static void profiling_pmi_handler(__unused unsigned int irq, __unused void *data
106
227
/* to be implemented */
107
228
}
108
229
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
+
109
325
/*
110
326
* Performs MSR operations on all the CPU's
111
327
*/
@@ -259,9 +475,115 @@ int32_t profiling_get_control(struct vm *vm, uint64_t addr)
259
475
/*
260
476
* Update the profiling type based on control switch
261
477
*/
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 )
263
479
{
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
+
265
587
return 0 ;
266
588
}
267
589
@@ -505,10 +827,16 @@ void profiling_setup(void)
505
827
profiling_pmi_irq = (uint32_t )retval ;
506
828
}
507
829
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
+
508
836
msr_write (MSR_IA32_EXT_APIC_LVT_PMI ,
509
837
VECTOR_PMI | LVT_PERFCTR_BIT_MASK );
510
838
511
839
dev_dbg (ACRN_DBG_PROFILING , "%s: exiting" , __func__ );
512
840
}
513
841
514
- #endif
842
+ #endif
0 commit comments