From mboxrd@z Thu Jan 1 00:00:00 1970 From: Arbel Moshe Subject: [PATCH 1/5] x86: Add utility to run function in User Mode Date: Sun, 24 Dec 2017 12:07:57 +0200 Message-ID: <20171224100801.145806-2-arbel.moshe@oracle.com> References: <20171224100801.145806-1-arbel.moshe@oracle.com> Cc: idan.brown@oracle.com, liran.alon@oracle.com, Arbel Moshe , Konrad Rzeszutek Wilk To: pbonzini@redhat.com, rkrcmar@redhat.com, kvm@vger.kernel.org Return-path: Received: from userp2120.oracle.com ([156.151.31.85]:32904 "EHLO userp2120.oracle.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751323AbdLXKIy (ORCPT ); Sun, 24 Dec 2017 05:08:54 -0500 In-Reply-To: <20171224100801.145806-1-arbel.moshe@oracle.com> Sender: kvm-owner@vger.kernel.org List-ID: Add usermode util that enables running a function in user mode. In addition, it enables catching an exception which is raised from the user-mode function. Signed-off-by: Arbel Moshe Reviewed-by: Liran Alon Signed-off-by: Konrad Rzeszutek Wilk --- lib/x86/usermode.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/x86/usermode.h | 30 ++++++++++++++ x86/Makefile.common | 1 + 3 files changed, 144 insertions(+) create mode 100644 lib/x86/usermode.c create mode 100644 lib/x86/usermode.h diff --git a/lib/x86/usermode.c b/lib/x86/usermode.c new file mode 100644 index 0000000..323d84d --- /dev/null +++ b/lib/x86/usermode.c @@ -0,0 +1,113 @@ +#include "x86/msr.h" +#include "x86/processor.h" +#include "x86/apic-defs.h" +#include "x86/apic.h" +#include "x86/desc.h" +#include "x86/isr.h" +#include "alloc.h" +#include "setjmp.h" +#include "usermode.h" + +#include "libcflat.h" +#include + +#define USERMODE_STACK_SIZE 0x2000 +#define RET_TO_KERNEL_IRQ 0x20 + +jmp_buf jmpbuf; + +static void restore_exec_to_jmpbuf(void) +{ + longjmp(jmpbuf, 1); +} + +static void restore_exec_to_jmpbuf_exception_handler(struct ex_regs *regs) +{ + /* longjmp must happen after iret, so do not do it now. */ + regs->rip = (unsigned long)&restore_exec_to_jmpbuf; + regs->cs = KERNEL_CS; +} + +uint64_t run_in_user(usermode_func func, unsigned int fault_vector, + uint64_t arg1, uint64_t arg2, uint64_t arg3, + uint64_t arg4, bool *raised_vector) +{ + extern char ret_to_kernel; + uint64_t rax = 0; + static unsigned char user_stack[USERMODE_STACK_SIZE]; + + *raised_vector = 0; + set_idt_entry(RET_TO_KERNEL_IRQ, &ret_to_kernel, 3); + handle_exception(fault_vector, + restore_exec_to_jmpbuf_exception_handler); + + if (setjmp(jmpbuf) != 0) { + *raised_vector = 1; + return 0; + } + + asm volatile ( + /* Backing Up Stack in rdi */ + "mov %%rsp, %%rdi\n\t" + /* Load user_ds to DS and ES */ + "mov %[user_ds], %%ax\n\t" + "mov %%ax, %%ds\n\t" + "mov %%ax, %%es\n\t" + /* IRET into user mode */ + "pushq %[user_ds]\n\t" + "pushq %[user_stack_top]\n\t" + "pushfq\n\t" + "pushq %[user_cs]\n\t" + "pushq $user_mode\n\t" + "iretq\n" + + "user_mode:\n\t" + /* Back up registers before invoking func */ + "push %%rbx\n\t" + "push %%rcx\n\t" + "push %%rdx\n\t" + "push %%r8\n\t" + "push %%r9\n\t" + "push %%r10\n\t" + "push %%r11\n\t" + "push %%rdi\n\t" + "push %%rsi\n\t" + /* Call user mode function */ + "mov %[arg1], %%rdi\n\t" + "mov %[arg2], %%rsi\n\t" + "mov %[arg3], %%rdx\n\t" + "mov %[arg4], %%rcx\n\t" + "call %[func]\n\t" + /* Restore registers */ + "pop %%rsi\n\t" + "pop %%rdi\n\t" + "pop %%r11\n\t" + "pop %%r10\n\t" + "pop %%r9\n\t" + "pop %%r8\n\t" + "pop %%rdx\n\t" + "pop %%rcx\n\t" + "pop %%rbx\n\t" + /* Return to kernel via system call */ + "int %[kernel_entry_vector]\n\t" + /* Kernel Mode */ + "ret_to_kernel:\n\t" + "mov %%rdi, %%rsp\n\t" + : + "+a"(rax) + : + [arg1]"m"(arg1), + [arg2]"m"(arg2), + [arg3]"m"(arg3), + [arg4]"m"(arg4), + [func]"m"(func), + [user_ds]"i"(USER_DS), + [user_cs]"i"(USER_CS), + [user_stack_top]"r"(user_stack + + sizeof(user_stack)), + [kernel_entry_vector]"i"(RET_TO_KERNEL_IRQ) + : + "rsi", "rdi", "rcx", "rdx"); + + return rax; +} diff --git a/lib/x86/usermode.h b/lib/x86/usermode.h new file mode 100644 index 0000000..4e005e6 --- /dev/null +++ b/lib/x86/usermode.h @@ -0,0 +1,30 @@ +#ifndef _USERMODE_H_ +#define _USERMODE_H_ + +#include "x86/msr.h" +#include "x86/processor.h" +#include "x86/apic-defs.h" +#include "x86/apic.h" +#include "x86/desc.h" +#include "x86/isr.h" +#include "alloc.h" +#include "setjmp.h" + +#include "libcflat.h" +#include + +typedef uint64_t (*usermode_func)(void); + +/* + * Run function in user mode + * Supports running functions with up to 4 arguments. + * fault_vector: exception vector that might get thrown during the function. + * raised_vector: outputs true if exception occurred. + * + * returns: return value returned by function, or 0 if an exception occurred. + */ +uint64_t run_in_user(usermode_func func, unsigned int fault_vector, + uint64_t arg1, uint64_t arg2, uint64_t arg3, + uint64_t arg4, bool *raised_vector); + +#endif diff --git a/x86/Makefile.common b/x86/Makefile.common index 5f7eac4..8a9d245 100644 --- a/x86/Makefile.common +++ b/x86/Makefile.common @@ -19,6 +19,7 @@ cflatobjs += lib/x86/desc.o cflatobjs += lib/x86/isr.o cflatobjs += lib/x86/acpi.o cflatobjs += lib/x86/stack.o +cflatobjs += lib/x86/usermode.o OBJDIRS += lib/x86 -- 2.14.1