Skip to content

Commit

Permalink
x86/irq: allow setting IRQ permissions from GSI instead of pIRQ
Browse files Browse the repository at this point in the history
Some domains are not aware of the pIRQ abstraction layer that maps
interrupt sources into Xen space interrupt numbers.  pIRQs values are
only exposed to domains that have the option to route physical
interrupts over event channels.

This creates issues for PCI-passthrough from a PVH domain, as some of
the passthrough related hypercalls use pIRQ as references to physical
interrupts on the system.  One of such interfaces is
XEN_DOMCTL_irq_permission, used to grant or revoke access to
interrupts, takes a pIRQ as the reference to the interrupt to be
adjusted.

Since PVH doesn't manage interrupts in terms of pIRQs, introduce a new
hypercall that allows setting interrupt permissions based on GSI value
rather than pIRQ.

Note the GSI hypercall parameters is translated to an IRQ value (in
case there are ACPI overrides) before doing the checks.

Signed-off-by: Jiqian Chen <[email protected]>
Signed-off-by: Huang Rui <[email protected]>
Signed-off-by: Jiqian Chen <[email protected]>
Reviewed-by: Daniel P. Smith <[email protected]>
Acked-by: Jan Beulich <[email protected]>
  • Loading branch information
Jiqian Chen authored and jbeulich committed Sep 30, 2024
1 parent c353c47 commit d6e9a2a
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 4 deletions.
32 changes: 32 additions & 0 deletions xen/arch/x86/domctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include <asm/xstate.h>
#include <asm/psr.h>
#include <asm/cpu-policy.h>
#include <asm/io_apic.h>

static int update_domain_cpu_policy(struct domain *d,
xen_domctl_cpu_policy_t *xdpc)
Expand Down Expand Up @@ -237,6 +238,37 @@ long arch_do_domctl(
break;
}

case XEN_DOMCTL_gsi_permission:
{
int irq;
unsigned int gsi = domctl->u.gsi_permission.gsi;
uint32_t flags = domctl->u.gsi_permission.flags;

/* Check only valid bits are set */
ret = -EINVAL;
if ( flags & ~XEN_DOMCTL_GSI_ACTION_MASK )
break;

irq = gsi_2_irq(gsi);
if ( irq <= 0 )
{
ret = irq ?: -EACCES;
break;
}

ret = -EPERM;
if ( !irq_access_permitted(currd, irq) ||
xsm_irq_permission(XSM_HOOK, d, irq, flags) )
break;

if ( flags )
ret = irq_permit_access(d, irq);
else
ret = irq_deny_access(d, irq);

break;
}

case XEN_DOMCTL_getpageframeinfo3:
{
unsigned int num = domctl->u.getpageframeinfo3.num;
Expand Down
2 changes: 2 additions & 0 deletions xen/arch/x86/include/asm/io_apic.h
Original file line number Diff line number Diff line change
Expand Up @@ -213,5 +213,7 @@ unsigned highest_gsi(void);

int ioapic_guest_read( unsigned long physbase, unsigned int reg, u32 *pval);
int ioapic_guest_write(unsigned long physbase, unsigned int reg, u32 val);
int mp_find_ioapic(unsigned int gsi);
int gsi_2_irq(unsigned int gsi);

#endif
19 changes: 19 additions & 0 deletions xen/arch/x86/io_apic.c
Original file line number Diff line number Diff line change
Expand Up @@ -955,6 +955,25 @@ static int pin_2_irq(int idx, int apic, int pin)
return irq;
}

int gsi_2_irq(unsigned int gsi)
{
int ioapic, irq;
unsigned int pin;

if ( gsi > highest_gsi() )
return -ERANGE;

ioapic = mp_find_ioapic(gsi);
if ( ioapic < 0 )
return -EINVAL;

pin = gsi - io_apic_gsi_base(ioapic);

irq = apic_pin_2_gsi_irq(ioapic, pin);

return irq ?: -EINVAL;
}

static inline int IO_APIC_irq_trigger(int irq)
{
int apic, idx, pin;
Expand Down
7 changes: 3 additions & 4 deletions xen/arch/x86/mpparse.c
Original file line number Diff line number Diff line change
Expand Up @@ -842,8 +842,7 @@ static struct mp_ioapic_routing {
} mp_ioapic_routing[MAX_IO_APICS];


static int mp_find_ioapic (
int gsi)
int mp_find_ioapic(unsigned int gsi)
{
unsigned int i;

Expand All @@ -854,7 +853,7 @@ static int mp_find_ioapic (
return i;
}

printk(KERN_ERR "ERROR: Unable to locate IOAPIC for GSI %d\n", gsi);
printk(KERN_ERR "ERROR: Unable to locate IOAPIC for GSI %u\n", gsi);

return -1;
}
Expand Down Expand Up @@ -915,7 +914,7 @@ void __init mp_register_ioapic (
return;
}

unsigned __init highest_gsi(void)
unsigned highest_gsi(void)
{
unsigned x, res = 0;
for (x = 0; x < nr_ioapics; x++)
Expand Down
10 changes: 10 additions & 0 deletions xen/include/public/domctl.h
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,14 @@ struct xen_domctl_irq_permission {
uint8_t pad[3];
};

/* XEN_DOMCTL_gsi_permission */
struct xen_domctl_gsi_permission {
uint32_t gsi;
#define XEN_DOMCTL_GSI_REVOKE 0
#define XEN_DOMCTL_GSI_GRANT 1
#define XEN_DOMCTL_GSI_ACTION_MASK 1
uint32_t flags;
};

/* XEN_DOMCTL_iomem_permission */
struct xen_domctl_iomem_permission {
Expand Down Expand Up @@ -1306,6 +1314,7 @@ struct xen_domctl {
#define XEN_DOMCTL_get_paging_mempool_size 85
#define XEN_DOMCTL_set_paging_mempool_size 86
#define XEN_DOMCTL_dt_overlay 87
#define XEN_DOMCTL_gsi_permission 88
#define XEN_DOMCTL_gdbsx_guestmemio 1000
#define XEN_DOMCTL_gdbsx_pausevcpu 1001
#define XEN_DOMCTL_gdbsx_unpausevcpu 1002
Expand All @@ -1328,6 +1337,7 @@ struct xen_domctl {
struct xen_domctl_setdomainhandle setdomainhandle;
struct xen_domctl_setdebugging setdebugging;
struct xen_domctl_irq_permission irq_permission;
struct xen_domctl_gsi_permission gsi_permission;
struct xen_domctl_iomem_permission iomem_permission;
struct xen_domctl_ioport_permission ioport_permission;
struct xen_domctl_hypercall_init hypercall_init;
Expand Down
1 change: 1 addition & 0 deletions xen/xsm/flask/hooks.c
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,7 @@ static int cf_check flask_domctl(struct domain *d, unsigned int cmd,
case XEN_DOMCTL_shadow_op:
case XEN_DOMCTL_ioport_permission:
case XEN_DOMCTL_ioport_mapping:
case XEN_DOMCTL_gsi_permission:
#endif
#ifdef CONFIG_HAS_PASSTHROUGH
/*
Expand Down

0 comments on commit d6e9a2a

Please sign in to comment.