Skip to content

Commit 38d5df7

Browse files
yonghuahNanlinXie
authored andcommitted
hv:enable APICv-Posted Interrupt
to enable APICv Posted interrupt supported, following the specifications defined in Intel SDM Section #29.6, Volume3. Posted-interrupt processing is a feature by which a processor processes the virtual interrupts by recording them as pending on the virtual-APIC page. Injecting interrupts to VCPU from remote CPU without causing VM exit on the destination, following steps in SDM Section 29.6,volume3: Tracked-On: #1447 Signed-off-by: Yonghua Huang <yonghua.huang@intel.com> Acked-by: Eddie Dong <eddie.dong@intel.com>
1 parent a028567 commit 38d5df7

File tree

9 files changed

+80
-4
lines changed

9 files changed

+80
-4
lines changed

hypervisor/arch/x86/cpu.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,7 @@ static void bsp_boot_post(void)
483483

484484
timer_init();
485485
setup_notification();
486+
setup_posted_intr_notification();
486487
ptdev_init();
487488

488489
init_scheduler();
@@ -860,6 +861,10 @@ bool is_apicv_intr_delivery_supported(void)
860861
return ((cpu_caps.apicv_features & VAPIC_FEATURE_INTR_DELIVERY) != 0U);
861862
}
862863

864+
bool is_apicv_posted_intr_supported(void)
865+
{
866+
return ((cpu_caps.apicv_features & VAPIC_FEATURE_POST_INTR) != 0U);
867+
}
863868

864869
static void cpu_xsave_init(void)
865870
{

hypervisor/arch/x86/guest/vlapic.c

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,7 @@ vlapic_set_intr_ready(struct acrn_vlapic *vlapic, uint32_t vector, bool level)
460460
struct lapic_reg *irrptr, *tmrptr;
461461
uint32_t mask;
462462
uint32_t idx;
463+
int pending_intr;
463464

464465
ASSERT(vector <= NR_MAX_VECTOR,
465466
"invalid vector %u", vector);
@@ -480,7 +481,26 @@ vlapic_set_intr_ready(struct acrn_vlapic *vlapic, uint32_t vector, bool level)
480481
}
481482

482483
if (is_apicv_intr_delivery_supported()) {
483-
return apicv_set_intr_ready(vlapic, vector);
484+
pending_intr = apicv_set_intr_ready(vlapic, vector);
485+
if ((pending_intr != 0)
486+
&& is_apicv_posted_intr_supported()
487+
&& (get_cpu_id() != vlapic->vcpu->pcpu_id)) {
488+
/*
489+
* Send interrupt to vCPU via posted interrupt way:
490+
* 1. If target vCPU is in non-root mode(running),
491+
* send PI notification to vCPU and hardware will
492+
* sync PIR to vIRR automatically.
493+
* 2. If target vCPU is in root mode(isn't running),
494+
* record this request as ACRN_REQUEST_EVENT,then
495+
* will pick up the interrupt from PIR and inject
496+
* it to vCPU in next vmentry.
497+
*/
498+
bitmap_set_lock(ACRN_REQUEST_EVENT,
499+
&vlapic->vcpu->arch_vcpu.pending_req);
500+
vlapic_post_intr(vlapic->vcpu->pcpu_id);
501+
return 0;
502+
}
503+
return pending_intr;
484504
}
485505

486506
idx = vector >> 5U;
@@ -508,6 +528,20 @@ vlapic_set_intr_ready(struct acrn_vlapic *vlapic, uint32_t vector, bool level)
508528
return 1;
509529
}
510530

531+
/* Post an interrupt to the vcpu running on 'hostcpu'. */
532+
void vlapic_post_intr(uint16_t dest_pcpu_id)
533+
{
534+
send_single_ipi(dest_pcpu_id, VECTOR_POSTED_INTR);
535+
}
536+
537+
uint64_t apicv_get_pir_desc_paddr(struct vcpu *vcpu)
538+
{
539+
struct acrn_vlapic *vlapic;
540+
541+
vlapic = &vcpu->arch_vcpu.vlapic;
542+
return hva2hpa(&(vlapic->pir_desc));
543+
}
544+
511545
/**
512546
* @pre offset value shall be one of the folllowing values:
513547
* APIC_OFFSET_CMCI_LVT
@@ -1817,8 +1851,6 @@ vlapic_set_intr(struct vcpu *vcpu, uint32_t vector, bool level)
18171851
vlapic = vcpu_vlapic(vcpu);
18181852
if (vlapic_set_intr_ready(vlapic, vector, level) != 0) {
18191853
vcpu_make_request(vcpu, ACRN_REQUEST_EVENT);
1820-
} else {
1821-
ret = -ENODEV;
18221854
}
18231855

18241856
return ret;

hypervisor/arch/x86/irq.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ struct static_mapping_table {
2525
static struct static_mapping_table irq_static_mappings[NR_STATIC_MAPPINGS] = {
2626
{TIMER_IRQ, VECTOR_TIMER},
2727
{NOTIFY_IRQ, VECTOR_NOTIFY_VCPU},
28+
{POSTED_INTR_NOTIFY_IRQ, VECTOR_POSTED_INTR},
2829
};
2930

3031
/*

hypervisor/arch/x86/notify.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,3 +96,22 @@ void setup_notification(void)
9696
dev_dbg(ACRN_DBG_PTIRQ, "NOTIFY: irq[%d] setup vector %x",
9797
notification_irq, irq_to_vector(notification_irq));
9898
}
99+
100+
static void posted_intr_notification(__unused uint32_t irq, __unused void *data)
101+
{
102+
/* Dummy IRQ handler for case that Posted-Interrupt Notification
103+
* is sent to vCPU in root mode(isn't running),interrupt will be
104+
* picked up in next vmentry,do nothine here.
105+
*/
106+
}
107+
108+
/*pre-conditon: be called only by BSP initialization proccess*/
109+
void setup_posted_intr_notification(void)
110+
{
111+
if (request_irq(POSTED_INTR_NOTIFY_IRQ,
112+
posted_intr_notification,
113+
NULL, IRQF_NONE) < 0) {
114+
pr_err("Failed to setup posted-intr notification");
115+
return;
116+
}
117+
}

hypervisor/arch/x86/vmx.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -773,6 +773,10 @@ static void init_exec_ctrl(struct vcpu *vcpu)
773773
value32 = check_vmx_ctrl(MSR_IA32_VMX_PINBASED_CTLS,
774774
VMX_PINBASED_CTLS_IRQ_EXIT);
775775

776+
if (is_apicv_posted_intr_supported()) {
777+
value32 |= VMX_PINBASED_CTLS_POST_IRQ;
778+
}
779+
776780
exec_vmwrite32(VMX_PIN_VM_EXEC_CONTROLS, value32);
777781
pr_dbg("VMX_PIN_VM_EXEC_CONTROLS: 0x%x ", value32);
778782

@@ -864,6 +868,12 @@ static void init_exec_ctrl(struct vcpu *vcpu)
864868
exec_vmwrite64(VMX_EOI_EXIT3_FULL, 0UL);
865869

866870
exec_vmwrite16(VMX_GUEST_INTR_STATUS, 0U);
871+
if (is_apicv_posted_intr_supported()) {
872+
exec_vmwrite16(VMX_POSTED_INTR_VECTOR,
873+
VECTOR_POSTED_INTR);
874+
exec_vmwrite64(VMX_PIR_DESC_ADDR_FULL,
875+
apicv_get_pir_desc_paddr(vcpu));
876+
}
867877
}
868878

869879
/* Load EPTP execution control

hypervisor/include/arch/x86/cpu.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,7 @@ void cpu_do_idle(void);
318318
void cpu_dead(uint16_t pcpu_id);
319319
void trampoline_start16(void);
320320
bool is_apicv_intr_delivery_supported(void);
321+
bool is_apicv_posted_intr_supported(void);
321322
bool is_ept_supported(void);
322323
bool cpu_has_cap(uint32_t bit);
323324
void load_cpu_state_data(void);

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ int vlapic_pending_intr(struct acrn_vlapic *vlapic, uint32_t *vecptr);
122122
* block interrupt delivery).
123123
*/
124124
void vlapic_intr_accepted(struct acrn_vlapic *vlapic, uint32_t vector);
125+
void vlapic_post_intr(uint16_t dest_pcpu_id);
126+
uint64_t apicv_get_pir_desc_paddr(struct vcpu *vcpu);
125127

126128
struct acrn_vlapic *vm_lapic_from_pcpuid(struct vm *vm, uint16_t pcpu_id);
127129
int vlapic_rdmsr(struct vcpu *vcpu, uint32_t msr, uint64_t *rval);

hypervisor/include/arch/x86/irq.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#define VECTOR_TIMER 0xEFU
2121
#define VECTOR_NOTIFY_VCPU 0xF0U
22+
#define VECTOR_POSTED_INTR 0xF2U
2223
#define VECTOR_VIRT_IRQ_VHM 0xF7U
2324
#define VECTOR_SPURIOUS 0xFFU
2425
#define VECTOR_HYPERVISOR_CALLBACK_VHM 0xF3U
@@ -33,9 +34,10 @@
3334
#define NR_IRQS 256U
3435
#define IRQ_INVALID 0xffffffffU
3536

36-
#define NR_STATIC_MAPPINGS (2U)
37+
#define NR_STATIC_MAPPINGS (3U)
3738
#define TIMER_IRQ (NR_IRQS - 1U)
3839
#define NOTIFY_IRQ (NR_IRQS - 2U)
40+
#define POSTED_INTR_NOTIFY_IRQ (NR_IRQS - 3U)
3941

4042
#define DEFAULT_DEST_MODE IOAPIC_RTE_DESTLOG
4143
#define DEFAULT_DELIVERY_MODE IOAPIC_RTE_DELLOPRI
@@ -77,6 +79,7 @@ void partition_mode_dispatch_interrupt(struct intr_excp_ctx *ctx);
7779
#endif
7880

7981
void setup_notification(void);
82+
void setup_posted_intr_notification(void);
8083

8184
typedef void (*spurious_handler_t)(uint32_t vector);
8285
extern spurious_handler_t spurious_handler;

hypervisor/include/arch/x86/vmx.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
/* 16-bit control fields */
1111
#define VMX_VPID 0x00000000U
12+
#define VMX_POSTED_INTR_VECTOR 0x00000002U
1213
/* 16-bit guest-state fields */
1314
#define VMX_GUEST_ES_SEL 0x00000800U
1415
#define VMX_GUEST_CS_SEL 0x00000802U
@@ -48,6 +49,8 @@
4849
#define VMX_VIRTUAL_APIC_PAGE_ADDR_HIGH 0x00002013U
4950
#define VMX_APIC_ACCESS_ADDR_FULL 0x00002014U
5051
#define VMX_APIC_ACCESS_ADDR_HIGH 0x00002015U
52+
#define VMX_PIR_DESC_ADDR_FULL 0x00002016U
53+
#define VMX_PIR_DESC_ADDR_HIGH 0x00002017U
5154
#define VMX_EPT_POINTER_FULL 0x0000201AU
5255
#define VMX_EPT_POINTER_HIGH 0x0000201BU
5356
#define VMX_EOI_EXIT0_FULL 0x0000201CU

0 commit comments

Comments
 (0)