Skip to content

Commit 56acaac

Browse files
lifeixEddie Dong
authored andcommitted
hv: vlapic: add TPR below threshold implement
Add TPR below threshold implement for "Virtual-interrupt delivery" not support. Windows will use it to delay interrupt handle. Complete all the interrupts in IRR as long as they are higher priority than current TPR. Once current IRR priority is less than current TPR enable TPR threshold to IRR, so that if guest reduces the TPR threshold, it would be good to take below TPR threshold exit and let interrupts to go thru. Tracked-On: #1842 Signed-off-by: Zheng, Gen <gen.zheng@intel.com> Signed-off-by: Li, Fei1 <fei1.li@intel.com>
1 parent a4c9cb9 commit 56acaac

File tree

3 files changed

+63
-23
lines changed

3 files changed

+63
-23
lines changed

hypervisor/arch/x86/guest/virq.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,8 @@ static int32_t vcpu_inject_vlapic_int(struct acrn_vcpu *vcpu)
174174
}
175175
}
176176

177+
vlapic_update_tpr_threshold(vlapic);
178+
177179
return ret;
178180
}
179181

hypervisor/arch/x86/guest/vlapic.c

Lines changed: 59 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1316,6 +1316,28 @@ vlapic_icrlo_write_handler(struct acrn_vlapic *vlapic)
13161316
return ret; /* handled completely in the kernel */
13171317
}
13181318

1319+
static inline uint32_t vlapic_find_highest_irr(const struct acrn_vlapic *vlapic)
1320+
{
1321+
const struct lapic_regs *lapic = &(vlapic->apic_page);
1322+
uint32_t i, val, bitpos, vec = 0U;
1323+
const struct lapic_reg *irrptr;
1324+
1325+
irrptr = &lapic->irr[0];
1326+
1327+
/* i ranges effectively from 7 to 1 */
1328+
for (i = 8U; i > 1U; ) {
1329+
i--;
1330+
val = atomic_load32(&irrptr[i].v);
1331+
if (val != 0U) {
1332+
bitpos = (uint32_t)fls32(val);
1333+
vec = (i * 32U) + bitpos;
1334+
break;
1335+
}
1336+
}
1337+
1338+
return vec;
1339+
}
1340+
13191341
/**
13201342
* @brief Find a deliverable virtual interrupts for vLAPIC in irr.
13211343
*
@@ -1330,32 +1352,20 @@ vlapic_icrlo_write_handler(struct acrn_vlapic *vlapic)
13301352
* result of calling this function.
13311353
* This function is only for case that APICv/VID is NOT supported.
13321354
*/
1333-
bool
1334-
vlapic_find_deliverable_intr(const struct acrn_vlapic *vlapic, uint32_t *vecptr)
1355+
bool vlapic_find_deliverable_intr(const struct acrn_vlapic *vlapic, uint32_t *vecptr)
13351356
{
13361357
const struct lapic_regs *lapic = &(vlapic->apic_page);
1337-
uint32_t i, vector, val, bitpos;
1338-
const struct lapic_reg *irrptr;
1358+
uint32_t vec;
13391359
bool ret = false;
13401360

1341-
irrptr = &lapic->irr[0];
1342-
1343-
/* i ranges effectively from 7 to 0 */
1344-
for (i = 8U; i > 0U; ) {
1345-
i--;
1346-
val = atomic_load32(&irrptr[i].v);
1347-
bitpos = (uint32_t)fls32(val);
1348-
if (bitpos != INVALID_BIT_INDEX) {
1349-
vector = (i * 32U) + bitpos;
1350-
if (prio(vector) > prio(lapic->ppr.v)) {
1351-
if (vecptr != NULL) {
1352-
*vecptr = vector;
1353-
}
1354-
ret = true;
1355-
}
1356-
break;
1361+
vec = vlapic_find_highest_irr(vlapic);
1362+
if (prio(vec) > prio(lapic->ppr.v)) {
1363+
ret = true;
1364+
if (vecptr != NULL) {
1365+
*vecptr = vec;
13571366
}
13581367
}
1368+
13591369
return ret;
13601370
}
13611371

@@ -2419,8 +2429,35 @@ int32_t apic_write_vmexit_handler(struct acrn_vcpu *vcpu)
24192429
return err;
24202430
}
24212431

2422-
int32_t tpr_below_threshold_vmexit_handler(__unused struct acrn_vcpu *vcpu)
2432+
/*
2433+
* TPR threshold (32 bits). Bits 3:0 of this field determine the threshold
2434+
* below which bits 7:4 of VTPR (see Section 29.1.1) cannot fall.
2435+
*/
2436+
void vlapic_update_tpr_threshold(const struct acrn_vlapic *vlapic)
24232437
{
2424-
pr_err("Unhandled %s.", __func__);
2438+
uint32_t irr, tpr, threshold;
2439+
2440+
tpr = vlapic->apic_page.tpr.v;
2441+
tpr = ((tpr & 0xf0U) >> 4U);
2442+
irr = vlapic_find_highest_irr(vlapic);
2443+
irr >>= 4U;
2444+
threshold = (irr > tpr) ? 0U : irr;
2445+
2446+
exec_vmwrite32(VMX_TPR_THRESHOLD, threshold);
2447+
}
2448+
2449+
int32_t tpr_below_threshold_vmexit_handler(struct acrn_vcpu *vcpu)
2450+
{
2451+
struct acrn_vlapic *vlapic = vcpu_vlapic(vcpu);
2452+
2453+
vlapic_update_ppr(vlapic);
2454+
/*
2455+
* Once we come here, the vTPR must small than IRR.
2456+
* set TPR threshold to 0 to bypass VM-Execution Control Fields check
2457+
* since vcpu_inject_vlapic_int will update TPR threshold aright.
2458+
*/
2459+
exec_vmwrite32(VMX_TPR_THRESHOLD, 0U);
2460+
vcpu_make_request(vcpu, ACRN_REQUEST_EVENT);
2461+
24252462
return 0;
24262463
}

hypervisor/include/arch/x86/guest/vlapic.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,8 @@ void vlapic_apicv_inject_pir(struct acrn_vlapic *vlapic);
234234
int32_t apic_access_vmexit_handler(struct acrn_vcpu *vcpu);
235235
int32_t apic_write_vmexit_handler(struct acrn_vcpu *vcpu);
236236
int32_t veoi_vmexit_handler(struct acrn_vcpu *vcpu);
237-
int32_t tpr_below_threshold_vmexit_handler(__unused struct acrn_vcpu *vcpu);
237+
void vlapic_update_tpr_threshold(const struct acrn_vlapic *vlapic);
238+
int32_t tpr_below_threshold_vmexit_handler(struct acrn_vcpu *vcpu);
238239
void vlapic_calc_dest(struct acrn_vm *vm, uint64_t *dmask, uint32_t dest, bool phys, bool lowprio);
239240
void vlapic_calc_dest_lapic_pt(struct acrn_vm *vm, uint64_t *dmask, uint32_t dest, bool phys);
240241

0 commit comments

Comments
 (0)