x86: add a shared page indicating the need for an EOI notification
PATCH 1/2 x86: add a shared page indicating the need for an EOI notification
To simplify the interface for the guest, when a guest uses this new (sub-)hypercall, PHYSDEVOP_eoi behavior changes to unmask the corresponding event channel at once, avoiding the eventual need for a second hypercall from the guest.
Signed-off-by Jan Beulich <[email protected]>
xen/arch/x86/domain.c +8 -0
@@ -1823,6 +1823,14 @@ int domain_relinquish_resources(struct dunmap_vcpu_info (v); } +if ( d->arch.pirq_eoi_map ) + { +unsigned long mfn =unmap_domain_page_global (d->arch.pirq_eoi_map); + + d->arch.pirq_eoi_map =NULL ; +put_page_and_type (mfn_to_page (mfn)); + } + d->arch.relmem = RELMEM_xen;/* fallthrough */
xen/arch/x86/irq.c +56 -6
100 lines not on this page · raw message
xen/arch/x86/physdev.c +31 -0
@@ -191,10 +191,41 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_H ret = -EFAULT ;if (copy_from_guest (&eoi, arg,1 ) !=0 )break ; + ret = -EINVAL ; +if ( eoi.irq <0 || eoi.irq >=NR_IRQS ) +break ; +if ( v->domain->arch.pirq_eoi_map ) +evtchn_unmask (v->domain->pirq_to_evtchn[eoi.irq]); ret =pirq_guest_eoi (v->domain, eoi.irq);break ; } +case PHYSDEVOP_pirq_eoi_mfn: { +struct physdev_pirq_eoi_mfn info; + +BUILD_BUG_ON (NR_IRQS >PAGE_SIZE *8 ); + ret = -EFAULT ; +if (copy_from_guest (&info, arg,1 ) !=0 ) +break ; + ret = -EBUSY ; +if ( v->domain->arch.pirq_eoi_map ) +break ; + ret = -EINVAL ; +if ( !mfn_valid (info.mfn) || + !get_page_and_type (mfn_to_page (info.mfn), v->domain, + PGT_writable_page) ) +break ; + v->domain->arch.pirq_eoi_map =map_domain_page_global (info.mfn); +if ( v->domain->arch.pirq_eoi_map ) + ret =0 ; +else + { +put_page_and_type (mfn_to_page (info.mfn)); + ret = -ENOSPC ; + } +break ; + } +/* Legacy since 0x00030202. */ case PHYSDEVOP_IRQ_UNMASK_NOTIFY : { ret =pirq_guest_unmask (v->domain);
xen/arch/x86/x86_32/domain_page.c +5 -2
@@ -241,9 +241,9 @@ void *map_domain_page_global(unsigned loreturn (void *)va; } -void unmap_domain_page_global (const void *va) +unsigned long unmap_domain_page_global (const void *va) { -unsigned long __va = (unsigned long )va; +unsigned long __va = (unsigned long )va, mfn;l2_pgentry_t *pl2e;l1_pgentry_t *pl1e;unsigned int idx;
@@ -253,9 +253,12 @@ void unmap_domain_page_global(const void/* /First/, we zap the PTE. */ pl2e =virt_to_xen_l2e (__va); pl1e =l2e_to_l1e (*pl2e) +l1_table_offset (__va); + mfn =l1e_get_pfn (*pl1e);l1e_write (pl1e,l1e_empty ());/* /Second/, we add to the garbage map. */ idx = (__va -IOREMAP_VIRT_START ) >>PAGE_SHIFT ;set_bit (idx, garbage); + +return mfn; }
xen/arch/x86/x86_64/physdev.c +3 -0
@@ -18,6 +18,9 @@#define physdev_eoi compat_physdev_eoi#define physdev_eoi_t physdev_eoi_compat_t +#define physdev_pirq_eoi_mfn compat_physdev_pirq_eoi_mfn +#define physdev_pirq_eoi_mfn_t physdev_pirq_eoi_mfn_compat_t +#define physdev_set_iobitmap compat_physdev_set_iobitmap#define physdev_set_iobitmap_t physdev_set_iobitmap_compat_t
xen/common/event_channel.c +2 -3
@@ -762,10 +762,9 @@ long evtchn_bind_vcpu(unsigned int port, } -static long evtchn_unmask (evtchn_unmask_t *unmask) +int evtchn_unmask (unsigned int port) {struct domain *d = current->domain; -int port = unmask->port;struct vcpu *v;spin_lock (&d->event_lock);
@@ -916,7 +915,7 @@ long do_event_channel_op(int cmd, XEN_GUstruct evtchn_unmask unmask;if (copy_from_guest (&unmask, arg,1 ) !=0 )return -EFAULT ; - rc =evtchn_unmask (&unmask); + rc =evtchn_unmask (unmask.port);break ; }
xen/include/asm-x86/domain.h +2 -0
@@ -238,6 +238,8 @@ struct arch_domainint vector_pirq[NR_VECTORS ];s16 pirq_vector[NR_IRQS ]; +unsigned long *pirq_eoi_map; +/* Pseudophysical e820 map (XENMEM_memory_map). */ struct e820entry e820[3 ];unsigned int nr_e820;
xen/include/public/physdev.h +15 -0
@@ -41,6 +41,21 @@ typedef struct physdev_eoi physdev_eoi_tDEFINE_XEN_GUEST_HANDLE (physdev_eoi_t);/* +* Register a shared page for the hypervisor to indicate whether the guest +* must issue PHYSDEVOP_eoi. The semantics of PHYSDEVOP_eoi change slightly +* once the guest used this function in that the associated event channel +* will automatically get unmasked. The page registered is used as a bit +* array indexed by Xen's PIRQ value. +*/ +#define PHYSDEVOP_pirq_eoi_mfn 17 +struct physdev_pirq_eoi_mfn { +/* IN */ +xen_pfn_t mfn; +}; +typedef struct physdev_pirq_eoi_mfn physdev_pirq_eoi_mfn_t ; +DEFINE_XEN_GUEST_HANDLE (physdev_pirq_eoi_mfn_t); + +/* * Query the status of an IRQ line. * @arg == pointer to physdev_irq_status_query structure. */
xen/include/xen/domain_page.h +10 -3
@@ -32,7 +32,7 @@ void unmap_domain_page(const void *va);* mappings can also be unmapped from any context. */ void *map_domain_page_global (unsigned long mfn); -void unmap_domain_page_global (const void *va); +unsigned long unmap_domain_page_global (const void *va);#define DMCACHE_ENTRY_VALID 1U#define DMCACHE_ENTRY_HELD 2U
@@ -99,8 +99,15 @@ domain_mmap_cache_destroy(struct domain_#define map_domain_page (mfn) mfn_to_virt(mfn)#define unmap_domain_page (va) ((void)(va)) -#define map_domain_page_global (mfn) mfn_to_virt(mfn) -#define unmap_domain_page_global (va) ((void)(va)) +static inline void *map_domain_page_global (unsigned long mfn) +{ +return mfn_to_virt (mfn); +} + +static inline unsigned long unmap_domain_page_global (void *va) +{ +return virt_to_mfn (va); +}struct domain_mmap_cache { };
xen/include/xen/event.h +3 -0
@@ -44,6 +44,9 @@ int evtchn_send(struct domain *d, unsign/* Bind a local event-channel port to the specified VCPU. */ long evtchn_bind_vcpu (unsigned int port,unsigned int vcpu_id); +/* unmask the current domain's event-channel port. */ +int evtchn_unmask (unsigned int port); +/* Allocate/free a Xen-attached event channel port. */ int alloc_unbound_xen_event_channel (struct vcpu *local_vcpu,domid_t remote_domid);
xen/include/xen/irq.h +1 -0
@@ -22,6 +22,7 @@ struct irqaction#define IRQ_PENDING 4/* IRQ pending - replay on enable */ #define IRQ_REPLAY 8/* IRQ has been replayed but not acked yet */ #define IRQ_GUEST 16/* IRQ is handled by guest OS(es) */ +#define IRQ_GUEST_EOI_PENDING 32/* IRQ was disabled, pending a guest EOI */ #define IRQ_PER_CPU 256/* IRQ is per CPU */ /*