summaryrefslogtreecommitdiff
path: root/arch/x86/include
diff options
context:
space:
mode:
authorSohil Mehta <[email protected]>2021-05-25 16:57:40 -0700
committerSohil Mehta <[email protected]>2021-09-12 19:22:18 -0700
commit34777dfbdf50046a33d6426f454eeedcc88d33fd (patch)
tree9ce5db98583d741418f14e60d01d0e5182761aa4 /arch/x86/include
parent1b1294ead936c822ae184c7857f1818a300b8f24 (diff)
x86/uintr: Introduce uintr_wait() syscall
Add a new system call to allow applications to block in the kernel and wait for user interrupts. <The current implementation doesn't support waking up from other blocking system calls like sleep(), read(), epoll(), etc. uintr_wait() is a placeholder syscall while we decide on that behaviour.> When the application makes this syscall the notification vector is switched to a new kernel vector. Any new SENDUIPI will invoke the kernel interrupt which is then used to wake up the process. Currently, the task wait list is global one. To make the implementation scalable there is a need to move to a distributed per-cpu wait list. Signed-off-by: Sohil Mehta <[email protected]>
Diffstat (limited to 'arch/x86/include')
-rw-r--r--arch/x86/include/asm/hardirq.h1
-rw-r--r--arch/x86/include/asm/idtentry.h1
-rw-r--r--arch/x86/include/asm/irq_vectors.h3
-rw-r--r--arch/x86/include/asm/uintr.h22
4 files changed, 26 insertions, 1 deletions
diff --git a/arch/x86/include/asm/hardirq.h b/arch/x86/include/asm/hardirq.h
index 279afc01f1ac..a4623fdb65a1 100644
--- a/arch/x86/include/asm/hardirq.h
+++ b/arch/x86/include/asm/hardirq.h
@@ -22,6 +22,7 @@ typedef struct {
#endif
#ifdef CONFIG_X86_USER_INTERRUPTS
unsigned int uintr_spurious_count;
+ unsigned int uintr_kernel_notifications;
#endif
unsigned int x86_platform_ipis; /* arch dependent */
unsigned int apic_perf_irqs;
diff --git a/arch/x86/include/asm/idtentry.h b/arch/x86/include/asm/idtentry.h
index 5929a6f9eeee..0ac7ef592283 100644
--- a/arch/x86/include/asm/idtentry.h
+++ b/arch/x86/include/asm/idtentry.h
@@ -673,6 +673,7 @@ DECLARE_IDTENTRY_SYSVEC(POSTED_INTR_NESTED_VECTOR, sysvec_kvm_posted_intr_nested
#ifdef CONFIG_X86_USER_INTERRUPTS
DECLARE_IDTENTRY_SYSVEC(UINTR_NOTIFICATION_VECTOR, sysvec_uintr_spurious_interrupt);
+DECLARE_IDTENTRY_SYSVEC(UINTR_KERNEL_VECTOR, sysvec_uintr_kernel_notification);
#endif
#if IS_ENABLED(CONFIG_HYPERV)
diff --git a/arch/x86/include/asm/irq_vectors.h b/arch/x86/include/asm/irq_vectors.h
index d26faa504931..1d289b3ee0da 100644
--- a/arch/x86/include/asm/irq_vectors.h
+++ b/arch/x86/include/asm/irq_vectors.h
@@ -106,8 +106,9 @@
/* Vector for User interrupt notifications */
#define UINTR_NOTIFICATION_VECTOR 0xec
+#define UINTR_KERNEL_VECTOR 0xeb
-#define LOCAL_TIMER_VECTOR 0xeb
+#define LOCAL_TIMER_VECTOR 0xea
#define NR_VECTORS 256
diff --git a/arch/x86/include/asm/uintr.h b/arch/x86/include/asm/uintr.h
index ef3521dd7fb9..64113ef523ca 100644
--- a/arch/x86/include/asm/uintr.h
+++ b/arch/x86/include/asm/uintr.h
@@ -4,11 +4,29 @@
#ifdef CONFIG_X86_USER_INTERRUPTS
+/* User Posted Interrupt Descriptor (UPID) */
+struct uintr_upid {
+ struct {
+ u8 status; /* bit 0: ON, bit 1: SN, bit 2-7: reserved */
+ u8 reserved1; /* Reserved */
+ u8 nv; /* Notification vector */
+ u8 reserved2; /* Reserved */
+ u32 ndst; /* Notification destination */
+ } nc __packed; /* Notification control */
+ u64 puir; /* Posted user interrupt requests */
+} __aligned(64);
+
+/* UPID Notification control status */
+#define UPID_ON 0x0 /* Outstanding notification */
+#define UPID_SN 0x1 /* Suppressed notification */
+
struct uintr_upid_ctx {
+ struct list_head node;
struct task_struct *task; /* Receiver task */
struct uintr_upid *upid;
refcount_t refs;
bool receiver_active; /* Flag for UPID being mapped to a receiver */
+ bool waiting;
};
struct uintr_receiver_info {
@@ -43,11 +61,15 @@ void uintr_free(struct task_struct *task);
void switch_uintr_prepare(struct task_struct *prev);
void switch_uintr_return(void);
+int uintr_receiver_wait(void);
+void uintr_wake_up_process(void);
+
#else /* !CONFIG_X86_USER_INTERRUPTS */
static inline void uintr_free(struct task_struct *task) {}
static inline void switch_uintr_prepare(struct task_struct *prev) {}
static inline void switch_uintr_return(void) {}
+static inline void uintr_wake_up_process(void) {}
#endif /* CONFIG_X86_USER_INTERRUPTS */