How ACRN pass-thru LAPIC?

LAPIC Passthrough Based on vLAPIC

LAPIC passthrough is supported based on vLAPIC, the guest OS first boots with vLAPIC in xAPIC mode and then switches to x2APIC mode to enable the LAPIC passthrough.

In case of LAPIC passthrough based on vLAPIC, the system will have the following characteristics.

  • IRQs received by the LAPIC can be handled by the Guest VM without vmexit
  • Guest VM always see virtual LAPIC IDs for security consideration
  • most MSRs are directly accessible from Guest VM except for XAPICID, LDR and ICR. Write operations to ICR will be trapped to avoid malicious IPIs. Read operations to XAPIC and LDR will be trapped in order to make the Guest VM always see the virtual LAPIC IDs instead of the physical ones.

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*
* After switch to x2apic mode, most MSRs are passthrough to guest, but vlapic is still valid
* for virtualization of some MSRs for security consideration:
* - XAPICID/LDR: Read to XAPICID/LDR need to be trapped to guarantee guest always see right vlapic_id.
* - ICR: Write to ICR need to be trapped to avoid milicious IPI.
*/

/**
* @pre vcpu != NULL
*/
void update_msr_bitmap_x2apic_passthru(struct acrn_vcpu *vcpu)
{
uint8_t *msr_bitmap = vcpu->arch.msr_bitmap;

intercept_x2apic_msrs(msr_bitmap, INTERCEPT_DISABLE);
enable_msr_interception(msr_bitmap, MSR_IA32_EXT_XAPICID, INTERCEPT_READ);
enable_msr_interception(msr_bitmap, MSR_IA32_EXT_APIC_LDR, INTERCEPT_READ);
enable_msr_interception(msr_bitmap, MSR_IA32_EXT_APIC_ICR, INTERCEPT_WRITE);
set_tsc_msr_interception(vcpu, exec_vmread64(VMX_TSC_OFFSET_FULL) != 0UL);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int32_t vlapic_x2apic_write(struct acrn_vcpu *vcpu, uint32_t msr, uint64_t val)
{
struct acrn_vlapic *vlapic;
uint32_t offset;
int32_t error = -1;

/*
* If vLAPIC is in xAPIC mode and guest tries to access x2APIC MSRs
* inject a GP to guest
*/
vlapic = vcpu_vlapic(vcpu);
if (is_x2apic_enabled(vlapic)) {
if (is_lapic_pt_configured(vcpu->vm)) {
switch (msr) {
case MSR_IA32_EXT_APIC_ICR:
error = vlapic_x2apic_pt_icr_access(vcpu, val);
break;
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
int32_t vlapic_x2apic_read(struct acrn_vcpu *vcpu, uint32_t msr, uint64_t *val)
{
struct acrn_vlapic *vlapic;
uint32_t offset;
int32_t error = -1;

/*
* If vLAPIC is in xAPIC mode and guest tries to access x2APIC MSRs
* inject a GP to guest
*/
vlapic = vcpu_vlapic(vcpu);
if (is_x2apic_enabled(vlapic)) {
if (is_lapic_pt_configured(vcpu->vm)) {
switch (msr) {
case MSR_IA32_EXT_APIC_LDR:
case MSR_IA32_EXT_XAPICID:
offset = x2apic_msr_to_regoff(msr);
error = vlapic_read(vlapic, offset, val);
break;
default:
pr_err("%s: unexpected MSR[0x%x] read with lapic_pt", __func__, msr);
break;
}
} else {
offset = x2apic_msr_to_regoff(msr);
if (vlapic->ops->x2apic_read_msr_may_valid(offset)) {
error = vlapic_read(vlapic, offset, val);
}
}
}

return error;
}

参考资料:

  1. LAPIC Passthrough Based on vLAPIC