94
94
#define PRIO (x ) ((x) >> 4)
95
95
96
96
#define VLAPIC_VERSION (16)
97
- #define VLAPIC_MAXLVT_ENTRIES (APIC_LVT_CMCI)
98
97
99
98
#define x2apic (vlapic ) (((vlapic)->msr_apicbase & APICBASE_X2APIC) ? 1 : 0)
100
99
@@ -212,20 +211,6 @@ vlapic_timer_divisor(uint32_t dcr)
212
211
}
213
212
}
214
213
215
- static void
216
- vlapic_mask_lvts (struct vlapic * vlapic )
217
- {
218
- struct LAPIC * lapic = vlapic -> apic_page ;
219
-
220
- lapic -> lvt_cmci |= APIC_LVT_M ;
221
- lapic -> lvt_timer |= APIC_LVT_M ;
222
- lapic -> lvt_thermal |= APIC_LVT_M ;
223
- lapic -> lvt_pcint |= APIC_LVT_M ;
224
- lapic -> lvt_lint0 |= APIC_LVT_M ;
225
- lapic -> lvt_lint1 |= APIC_LVT_M ;
226
- lapic -> lvt_error |= APIC_LVT_M ;
227
- }
228
-
229
214
#if 0
230
215
static inline void
231
216
vlapic_dump_lvt (uint32_t offset , uint32_t * lvt )
@@ -304,32 +289,6 @@ vlapic_esr_write_handler(struct vlapic *vlapic)
304
289
vlapic -> esr_pending = 0 ;
305
290
}
306
291
307
- static void
308
- vlapic_reset (struct vlapic * vlapic )
309
- {
310
- struct LAPIC * lapic ;
311
-
312
- lapic = vlapic -> apic_page ;
313
- bzero (lapic , sizeof (struct LAPIC ));
314
-
315
- lapic -> id = vlapic_get_id (vlapic );
316
- lapic -> version = VLAPIC_VERSION ;
317
- lapic -> version |= (VLAPIC_MAXLVT_ENTRIES << MAXLVTSHIFT );
318
- lapic -> dfr = 0xffffffff ;
319
- lapic -> svr = APIC_SVR_VECTOR ;
320
- vlapic_mask_lvts (vlapic );
321
-
322
- lapic -> dcr_timer = 0 ;
323
- vlapic_dcr_write_handler (vlapic );
324
-
325
- if (vlapic -> vcpuid == 0 )
326
- vlapic -> boot_state = BS_RUNNING ; /* BSP */
327
- else
328
- vlapic -> boot_state = BS_INIT ; /* AP */
329
-
330
- vlapic -> svr_last = lapic -> svr ;
331
- }
332
-
333
292
void
334
293
vlapic_set_intr_ready (struct vlapic * vlapic , int vector , bool level )
335
294
{
@@ -388,24 +347,65 @@ vlapic_get_lvtptr(struct vlapic *vlapic, uint32_t offset)
388
347
}
389
348
}
390
349
350
+ static __inline int
351
+ lvt_off_to_idx (uint32_t offset )
352
+ {
353
+ int index ;
354
+
355
+ switch (offset ) {
356
+ case APIC_OFFSET_CMCI_LVT :
357
+ index = APIC_LVT_CMCI ;
358
+ break ;
359
+ case APIC_OFFSET_TIMER_LVT :
360
+ index = APIC_LVT_TIMER ;
361
+ break ;
362
+ case APIC_OFFSET_THERM_LVT :
363
+ index = APIC_LVT_THERMAL ;
364
+ break ;
365
+ case APIC_OFFSET_PERF_LVT :
366
+ index = APIC_LVT_PMC ;
367
+ break ;
368
+ case APIC_OFFSET_LINT0_LVT :
369
+ index = APIC_LVT_LINT0 ;
370
+ break ;
371
+ case APIC_OFFSET_LINT1_LVT :
372
+ index = APIC_LVT_LINT1 ;
373
+ break ;
374
+ case APIC_OFFSET_ERROR_LVT :
375
+ index = APIC_LVT_ERROR ;
376
+ break ;
377
+ default :
378
+ index = -1 ;
379
+ break ;
380
+ }
381
+ KASSERT (index >= 0 && index <= VLAPIC_MAXLVT_INDEX , ("lvt_off_to_idx: "
382
+ "invalid lvt index %d for offset %#x" , index , offset ));
383
+
384
+ return (index );
385
+ }
386
+
391
387
static __inline uint32_t
392
388
vlapic_get_lvt (struct vlapic * vlapic , uint32_t offset )
393
389
{
390
+ int idx ;
391
+ uint32_t val ;
394
392
395
- return (* vlapic_get_lvtptr (vlapic , offset ));
393
+ idx = lvt_off_to_idx (offset );
394
+ val = atomic_load_acq_32 (& vlapic -> lvt_last [idx ]);
395
+ return (val );
396
396
}
397
397
398
- static void
399
- vlapic_set_lvt (struct vlapic * vlapic , uint32_t offset , uint32_t val )
398
+ void
399
+ vlapic_lvt_write_handler (struct vlapic * vlapic , uint32_t offset )
400
400
{
401
- uint32_t * lvtptr , mask ;
401
+ uint32_t * lvtptr , mask , val ;
402
402
struct LAPIC * lapic ;
403
+ int idx ;
403
404
404
405
lapic = vlapic -> apic_page ;
405
406
lvtptr = vlapic_get_lvtptr (vlapic , offset );
406
-
407
- if (offset == APIC_OFFSET_TIMER_LVT )
408
- VLAPIC_TIMER_LOCK (vlapic );
407
+ val = * lvtptr ;
408
+ idx = lvt_off_to_idx (offset );
409
409
410
410
if (!(lapic -> svr & APIC_SVR_ENABLE ))
411
411
val |= APIC_LVT_M ;
@@ -424,10 +424,36 @@ vlapic_set_lvt(struct vlapic *vlapic, uint32_t offset, uint32_t val)
424
424
mask |= APIC_LVT_DM ;
425
425
break ;
426
426
}
427
- * lvtptr = val & mask ;
427
+ val &= mask ;
428
+ * lvtptr = val ;
429
+ atomic_store_rel_32 (& vlapic -> lvt_last [idx ], val );
430
+ }
431
+
432
+ static void
433
+ vlapic_mask_lvts (struct vlapic * vlapic )
434
+ {
435
+ struct LAPIC * lapic = vlapic -> apic_page ;
436
+
437
+ lapic -> lvt_cmci |= APIC_LVT_M ;
438
+ vlapic_lvt_write_handler (vlapic , APIC_OFFSET_CMCI_LVT );
439
+
440
+ lapic -> lvt_timer |= APIC_LVT_M ;
441
+ vlapic_lvt_write_handler (vlapic , APIC_OFFSET_TIMER_LVT );
442
+
443
+ lapic -> lvt_thermal |= APIC_LVT_M ;
444
+ vlapic_lvt_write_handler (vlapic , APIC_OFFSET_THERM_LVT );
445
+
446
+ lapic -> lvt_pcint |= APIC_LVT_M ;
447
+ vlapic_lvt_write_handler (vlapic , APIC_OFFSET_PERF_LVT );
448
+
449
+ lapic -> lvt_lint0 |= APIC_LVT_M ;
450
+ vlapic_lvt_write_handler (vlapic , APIC_OFFSET_LINT0_LVT );
451
+
452
+ lapic -> lvt_lint1 |= APIC_LVT_M ;
453
+ vlapic_lvt_write_handler (vlapic , APIC_OFFSET_LINT1_LVT );
428
454
429
- if ( offset == APIC_OFFSET_TIMER_LVT )
430
- VLAPIC_TIMER_UNLOCK (vlapic );
455
+ lapic -> lvt_error |= APIC_LVT_M ;
456
+ vlapic_lvt_write_handler (vlapic , APIC_OFFSET_ERROR_LVT );
431
457
}
432
458
433
459
static int
@@ -648,7 +674,7 @@ vlapic_fire_cmci(struct vlapic *vlapic)
648
674
}
649
675
}
650
676
651
- static VMM_STAT_ARRAY (LVTS_TRIGGERRED , VLAPIC_MAXLVT_ENTRIES ,
677
+ static VMM_STAT_ARRAY (LVTS_TRIGGERRED , VLAPIC_MAXLVT_INDEX + 1 ,
652
678
"lvts triggered ") ;
653
679
654
680
int
@@ -1166,6 +1192,11 @@ vlapic_read(struct vlapic *vlapic, uint64_t offset, uint64_t *data, bool *retu)
1166
1192
case APIC_OFFSET_CMCI_LVT :
1167
1193
case APIC_OFFSET_TIMER_LVT ... APIC_OFFSET_ERROR_LVT :
1168
1194
* data = vlapic_get_lvt (vlapic , offset );
1195
+ #ifdef INVARIANTS
1196
+ reg = vlapic_get_lvtptr (vlapic , offset );
1197
+ KASSERT (* data == * reg , ("inconsistent lvt value at "
1198
+ "offset %#lx: %#lx/%#x" , offset , * data , * reg ));
1199
+ #endif
1169
1200
break ;
1170
1201
case APIC_OFFSET_TIMER_ICR :
1171
1202
* data = lapic -> icr_timer ;
@@ -1190,6 +1221,7 @@ int
1190
1221
vlapic_write (struct vlapic * vlapic , uint64_t offset , uint64_t data , bool * retu )
1191
1222
{
1192
1223
struct LAPIC * lapic = vlapic -> apic_page ;
1224
+ uint32_t * regptr ;
1193
1225
int retval ;
1194
1226
1195
1227
KASSERT ((offset & 0xf ) == 0 && offset < PAGE_SIZE ,
@@ -1238,7 +1270,9 @@ vlapic_write(struct vlapic *vlapic, uint64_t offset, uint64_t data, bool *retu)
1238
1270
break ;
1239
1271
case APIC_OFFSET_CMCI_LVT :
1240
1272
case APIC_OFFSET_TIMER_LVT ... APIC_OFFSET_ERROR_LVT :
1241
- vlapic_set_lvt (vlapic , offset , data );
1273
+ regptr = vlapic_get_lvtptr (vlapic , offset );
1274
+ * regptr = data ;
1275
+ vlapic_lvt_write_handler (vlapic , offset );
1242
1276
break ;
1243
1277
case APIC_OFFSET_TIMER_ICR :
1244
1278
lapic -> icr_timer = data ;
@@ -1269,6 +1303,32 @@ vlapic_write(struct vlapic *vlapic, uint64_t offset, uint64_t data, bool *retu)
1269
1303
return (retval );
1270
1304
}
1271
1305
1306
+ static void
1307
+ vlapic_reset (struct vlapic * vlapic )
1308
+ {
1309
+ struct LAPIC * lapic ;
1310
+
1311
+ lapic = vlapic -> apic_page ;
1312
+ bzero (lapic , sizeof (struct LAPIC ));
1313
+
1314
+ lapic -> id = vlapic_get_id (vlapic );
1315
+ lapic -> version = VLAPIC_VERSION ;
1316
+ lapic -> version |= (VLAPIC_MAXLVT_INDEX << MAXLVTSHIFT );
1317
+ lapic -> dfr = 0xffffffff ;
1318
+ lapic -> svr = APIC_SVR_VECTOR ;
1319
+ vlapic_mask_lvts (vlapic );
1320
+
1321
+ lapic -> dcr_timer = 0 ;
1322
+ vlapic_dcr_write_handler (vlapic );
1323
+
1324
+ if (vlapic -> vcpuid == 0 )
1325
+ vlapic -> boot_state = BS_RUNNING ; /* BSP */
1326
+ else
1327
+ vlapic -> boot_state = BS_INIT ; /* AP */
1328
+
1329
+ vlapic -> svr_last = lapic -> svr ;
1330
+ }
1331
+
1272
1332
void
1273
1333
vlapic_init (struct vlapic * vlapic )
1274
1334
{
0 commit comments