diff --git a/hypervisor/arch/x86/guest/vmcall.c b/hypervisor/arch/x86/guest/vmcall.c index 93bad22241..b47aa51dcb 100644 --- a/hypervisor/arch/x86/guest/vmcall.c +++ b/hypervisor/arch/x86/guest/vmcall.c @@ -99,6 +99,12 @@ int vmcall_vmexit_handler(struct vcpu *vcpu) ret = hcall_pulse_irqline(vm, (uint16_t)param1, param2); break; + case HC_SET_IRQLINE: + /* param1: vmid */ + ret = hcall_set_irqline(vm, (uint16_t)param1, + (struct acrn_irqline_ops *)¶m2); + break; + case HC_INJECT_MSI: /* param1: vmid */ ret = hcall_inject_msi(vm, (uint16_t)param1, param2); diff --git a/hypervisor/common/hypercall.c b/hypervisor/common/hypercall.c index a0da1bac9d..476f3ffaf0 100644 --- a/hypervisor/common/hypercall.c +++ b/hypervisor/common/hypercall.c @@ -71,22 +71,19 @@ int32_t hcall_get_api_version(struct vm *vm, uint64_t param) *@pre Pointer vm shall point to VM0 */ static void -handle_vpic_irqline(struct vm *vm, uint32_t irq, enum irq_mode mode) +handle_vpic_irqline(struct vm *vm, uint32_t irq, uint32_t operation) { - - switch (mode) { - case IRQ_ASSERT: + switch (operation) { + case GSI_SET_HIGH: vpic_assert_irq(vm, irq); break; - case IRQ_DEASSERT: + case GSI_SET_LOW: vpic_deassert_irq(vm, irq); break; - case IRQ_PULSE: + case GSI_RAISING_PULSE: vpic_pulse_irq(vm, irq); default: /* - * In this switch statement, mode shall either be IRQ_ASSERT or - * IRQ_DEASSERT or IRQ_PULSE. * Gracefully return if prior case clauses have not been met. */ break; @@ -97,22 +94,20 @@ handle_vpic_irqline(struct vm *vm, uint32_t irq, enum irq_mode mode) *@pre Pointer vm shall point to VM0 */ static void -handle_vioapic_irqline(struct vm *vm, uint32_t irq, enum irq_mode mode) +handle_vioapic_irqline(struct vm *vm, uint32_t irq, uint32_t operation) { - switch (mode) { - case IRQ_ASSERT: + switch (operation) { + case GSI_SET_HIGH: vioapic_assert_irq(vm, irq); break; - case IRQ_DEASSERT: + case GSI_SET_LOW: vioapic_deassert_irq(vm, irq); break; - case IRQ_PULSE: + case GSI_RAISING_PULSE: vioapic_pulse_irq(vm, irq); break; default: /* - * In this switch statement, mode shall either be IRQ_ASSERT or - * IRQ_DEASSERT or IRQ_PULSE. * Gracefully return if prior case clauses have not been met. */ break; @@ -124,7 +119,7 @@ handle_vioapic_irqline(struct vm *vm, uint32_t irq, enum irq_mode mode) */ static int32_t handle_virt_irqline(struct vm *vm, uint16_t target_vmid, - struct acrn_irqline *param, enum irq_mode mode) + struct acrn_irqline *param, uint32_t operation) { int32_t ret = 0; uint32_t intr_type; @@ -152,19 +147,19 @@ handle_virt_irqline(struct vm *vm, uint16_t target_vmid, switch (intr_type) { case ACRN_INTR_TYPE_ISA: /* Call vpic for pic injection */ - handle_vpic_irqline(target_vm, param->pic_irq, mode); + handle_vpic_irqline(target_vm, param->pic_irq, operation); /* call vioapic for ioapic injection if ioapic_irq != ~0U*/ if (param->ioapic_irq != (~0U)) { /* handle IOAPIC irqline */ handle_vioapic_irqline(target_vm, - param->ioapic_irq, mode); + param->ioapic_irq, operation); } break; case ACRN_INTR_TYPE_IOAPIC: /* handle IOAPIC irqline */ handle_vioapic_irqline(target_vm, - param->ioapic_irq, mode); + param->ioapic_irq, operation); break; default: dev_dbg(ACRN_DBG_HYCALL, "vINTR inject failed. type=%d", @@ -309,7 +304,7 @@ int32_t hcall_assert_irqline(struct vm *vm, uint16_t vmid, uint64_t param) pr_err("%s: Unable copy param to vm\n", __func__); return -1; } - ret = handle_virt_irqline(vm, vmid, &irqline, IRQ_ASSERT); + ret = handle_virt_irqline(vm, vmid, &irqline, GSI_SET_HIGH); return ret; } @@ -326,7 +321,7 @@ int32_t hcall_deassert_irqline(struct vm *vm, uint16_t vmid, uint64_t param) pr_err("%s: Unable copy param to vm\n", __func__); return -1; } - ret = handle_virt_irqline(vm, vmid, &irqline, IRQ_DEASSERT); + ret = handle_virt_irqline(vm, vmid, &irqline, GSI_SET_LOW); return ret; } @@ -343,11 +338,38 @@ int32_t hcall_pulse_irqline(struct vm *vm, uint16_t vmid, uint64_t param) pr_err("%s: Unable copy param to vm\n", __func__); return -1; } - ret = handle_virt_irqline(vm, vmid, &irqline, IRQ_PULSE); + ret = handle_virt_irqline(vm, vmid, &irqline, GSI_RAISING_PULSE); return ret; } +/** + *@pre Pointer vm shall point to VM0 + */ +int32_t hcall_set_irqline(struct vm *vm, uint16_t vmid, + struct acrn_irqline_ops *ops) +{ + struct vm *target_vm = get_vm_from_vmid(vmid); + + if (target_vm == NULL) { + return -EINVAL; + } + + if (ops->nr_gsi >= vioapic_pincount(vm)) { + return -EINVAL; + } + + if (ops->nr_gsi < vpic_pincount()) { + /* Call vpic for pic injection */ + handle_vpic_irqline(target_vm, ops->nr_gsi, ops->op); + } + + /* handle IOAPIC irqline */ + handle_vioapic_irqline(target_vm, ops->nr_gsi, ops->op); + + return 0; +} + /** *@pre Pointer vm shall point to VM0 */ diff --git a/hypervisor/include/common/hypercall.h b/hypervisor/include/common/hypercall.h index 81588279d1..2760f0995f 100644 --- a/hypervisor/include/common/hypercall.h +++ b/hypervisor/include/common/hypercall.h @@ -184,6 +184,23 @@ int32_t hcall_deassert_irqline(struct vm *vm, uint16_t vmid, uint64_t param); */ int32_t hcall_pulse_irqline(struct vm *vm, uint16_t vmid, uint64_t param); + +/** + * @brief set or clear IRQ line + * + * Set or clear a virtual IRQ line for a VM, which could be from ISA + * or IOAPIC, normally it triggers an edge IRQ. + * The function will return -1 if the target VM does not exist. + * + * @param vm Pointer to VM data structure + * @param vmid ID of the VM + * @irq_req: request command for IRQ set or clear + * + * @pre Pointer vm shall point to VM0 + * @return 0 on success, non-zero on error. + */ +int32_t hcall_set_irqline(struct vm *vm, uint16_t vmid, + struct acrn_irqline_ops *ops); /** * @brief inject MSI interrupt * diff --git a/hypervisor/include/common/irq.h b/hypervisor/include/common/irq.h index d2b1307bd8..7d4b160c80 100644 --- a/hypervisor/include/common/irq.h +++ b/hypervisor/include/common/irq.h @@ -11,11 +11,6 @@ #define IRQF_LEVEL (1U << 1U) /* 1: level trigger; 0: edge trigger */ #define IRQF_PT (1U << 2U) /* 1: for passthrough dev */ -enum irq_mode { - IRQ_PULSE, - IRQ_ASSERT, - IRQ_DEASSERT, -}; typedef void (*irq_action_t)(uint32_t irq, void *priv_data); diff --git a/hypervisor/include/public/acrn_common.h b/hypervisor/include/public/acrn_common.h index c4e1536fe7..b631041131 100644 --- a/hypervisor/include/public/acrn_common.h +++ b/hypervisor/include/public/acrn_common.h @@ -264,6 +264,22 @@ struct acrn_set_ioreq_buffer { /** Interrupt type for acrn_irqline: inject interrupt to both PIC and IOAPIC */ #define ACRN_INTR_TYPE_IOAPIC 1U +/** Operation types for setting IRQ line */ +#define GSI_SET_HIGH 0U +#define GSI_SET_LOW 1U +#define GSI_RAISING_PULSE 2U +#define GSI_FALLING_PULSE 3U + +/** + * @brief Info to Set/Clear/Pulse a virtual IRQ line for a VM + * + * the parameter for HC_SET_IRQLINE hypercall + */ +struct acrn_irqline_ops { + uint32_t nr_gsi; + uint32_t op; +} __aligned(8); + /** * @brief Info to assert/deassert/pulse a virtual IRQ line for a VM * diff --git a/hypervisor/include/public/acrn_hv_defs.h b/hypervisor/include/public/acrn_hv_defs.h index 32686a4ea4..a845391dc4 100644 --- a/hypervisor/include/public/acrn_hv_defs.h +++ b/hypervisor/include/public/acrn_hv_defs.h @@ -45,6 +45,7 @@ #define HC_PULSE_IRQLINE BASE_HC_ID(HC_ID, HC_ID_IRQ_BASE + 0x02UL) #define HC_INJECT_MSI BASE_HC_ID(HC_ID, HC_ID_IRQ_BASE + 0x03UL) #define HC_VM_INTR_MONITOR BASE_HC_ID(HC_ID, HC_ID_IRQ_BASE + 0x04UL) +#define HC_SET_IRQLINE BASE_HC_ID(HC_ID, HC_ID_IRQ_BASE + 0x05UL) /* DM ioreq management */ #define HC_ID_IOREQ_BASE 0x30UL