On Mon, Sep 13, 2021 at 01:01:29PM -0700, Sohil Mehta wrote:
Add a registration syscall for a task to register itself as a user interrupt sender using the uintr_fd generated by the receiver. A task can register multiple uintr_fds. Each unique successful connection creates a new entry in the User Interrupt Target Table (UITT).
Each entry in the UITT table is referred by the UITT index (uipi_index). The uipi_index returned during the registration syscall lets a sender generate a user IPI using the 'SENDUIPI <uipi_index>' instruction.
Also, add a sender unregister syscall to unregister a particular task from the uintr_fd. Calling close on the uintr_fd will disconnect all threads in a sender process from that FD.
Currently, the UITT size is arbitrarily chosen as 256 entries corresponding to a 4KB page. Based on feedback and usage data this can either be increased/decreased or made dynamic later.
Architecturally, the UITT table can be unique for each thread or shared across threads of the same thread group. The current implementation keeps the UITT as unique for the each thread. This makes the kernel implementation relatively simple and only threads that use uintr get setup with the related structures. However, this means that the uipi_index for each thread would be inconsistent wrt to other threads. (Executing 'SENDUIPI 2' on threads of the same process could generate different user interrupts.)
Alternatively, the benefit of sharing the UITT table is that all threads would see the same view of the UITT table. Also the kernel UITT memory allocation would be more efficient if multiple threads connect to the same uintr_fd. However, this would mean the kernel needs to keep the UITT table size MISC_MSR[] in sync across these threads. Also the UPID/UITT teardown flows might need additional consideration.
Signed-off-by: Sohil Mehta sohil.mehta@intel.com
arch/x86/include/asm/processor.h | 2 + arch/x86/include/asm/uintr.h | 15 ++ arch/x86/kernel/process.c | 1 + arch/x86/kernel/uintr_core.c | 355 ++++++++++++++++++++++++++++++- arch/x86/kernel/uintr_fd.c | 133 ++++++++++++ 5 files changed, 495 insertions(+), 11 deletions(-)
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index d229bfac8b4f..3482c3182e39 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -10,6 +10,7 @@ struct mm_struct; struct io_bitmap; struct vm86; struct uintr_receiver; +struct uintr_sender; #include <asm/math_emu.h> #include <asm/segment.h> @@ -533,6 +534,7 @@ struct thread_struct { #ifdef CONFIG_X86_USER_INTERRUPTS /* User Interrupt state*/ struct uintr_receiver *ui_recv;
- struct uintr_sender *ui_send;
#endif /* Floating point and extended processor state */ diff --git a/arch/x86/include/asm/uintr.h b/arch/x86/include/asm/uintr.h index 1f00e2a63da4..ef3521dd7fb9 100644 --- a/arch/x86/include/asm/uintr.h +++ b/arch/x86/include/asm/uintr.h @@ -8,6 +8,7 @@ struct uintr_upid_ctx { struct task_struct *task; /* Receiver task */ struct uintr_upid *upid; refcount_t refs;
- bool receiver_active; /* Flag for UPID being mapped to a receiver */
}; struct uintr_receiver_info { @@ -16,12 +17,26 @@ struct uintr_receiver_info { u64 uvec; /* Vector number */ }; +struct uintr_sender_info {
- struct list_head node;
- struct uintr_uitt_ctx *uitt_ctx;
- struct task_struct *task;
- struct uintr_upid_ctx *r_upid_ctx; /* Receiver's UPID context */
- struct callback_head twork; /* Task work head */
- unsigned int uitt_index;
+};
bool uintr_arch_enabled(void); int do_uintr_register_handler(u64 handler); int do_uintr_unregister_handler(void); int do_uintr_register_vector(struct uintr_receiver_info *r_info); void do_uintr_unregister_vector(struct uintr_receiver_info *r_info); +int do_uintr_register_sender(struct uintr_receiver_info *r_info,
struct uintr_sender_info *s_info);
+void do_uintr_unregister_sender(struct uintr_receiver_info *r_info,
struct uintr_sender_info *s_info);
void uintr_free(struct task_struct *task); /* TODO: Inline the context switch related functions */ diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 83677f76bd7b..9db33e467b30 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -92,6 +92,7 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) #ifdef CONFIG_X86_USER_INTERRUPTS /* User Interrupt state is unique for each task */ dst->thread.ui_recv = NULL;
- dst->thread.ui_send = NULL;
#endif return fpu_clone(dst); diff --git a/arch/x86/kernel/uintr_core.c b/arch/x86/kernel/uintr_core.c index 9dcb9f60e5bc..8f331c5fe0cf 100644 --- a/arch/x86/kernel/uintr_core.c +++ b/arch/x86/kernel/uintr_core.c @@ -21,6 +21,11 @@ #include <asm/msr-index.h> #include <asm/uintr.h> +/*
- Each UITT entry is 16 bytes in size.
- Current UITT table size is set as 4KB (256 * 16 bytes)
- */
+#define UINTR_MAX_UITT_NR 256 #define UINTR_MAX_UVEC_NR 64 /* User Posted Interrupt Descriptor (UPID) */ @@ -44,6 +49,27 @@ struct uintr_receiver { u64 uvec_mask; /* track active vector per bit */ }; +/* User Interrupt Target Table Entry (UITTE) */ +struct uintr_uitt_entry {
- u8 valid; /* bit 0: valid, bit 1-7: reserved */
Do you check that the other bits are set to 0?
- u8 user_vec;
- u8 reserved[6];
What is this reserved for?
- u64 target_upid_addr;
If this is a pointer, why not say it is a pointer?
+} __packed __aligned(16);
+struct uintr_uitt_ctx {
- struct uintr_uitt_entry *uitt;
- /* Protect UITT */
- spinlock_t uitt_lock;
- refcount_t refs;
Again, a kref please.
thanks,
greg k-h