From: Andrew Cooper Date: Thu, 24 Dec 2015 23:36:47 +0000 (+0000) Subject: Introduce exec_user() to run a function at user privilege X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=c48628fd7bf055ac9fa2d6d764b7a215079edd67;p=people%2Froyger%2Fxen-test-framework.git Introduce exec_user() to run a function at user privilege Add a selftest to confirm functionality. Signed-off-by: Andrew Cooper --- diff --git a/arch/x86/entry_32.S b/arch/x86/entry_32.S index bda1150..2b08b49 100644 --- a/arch/x86/entry_32.S +++ b/arch/x86/entry_32.S @@ -1,4 +1,5 @@ #include +#include #include /* @@ -89,3 +90,25 @@ ENTRY(entry_ret_to_kernel) /* int $0x20 (return to kernel) */ mov 0*4(%esp), %eax /* Stash %eip from iret frame */ mov 3*4(%esp), %esp /* Load %esp from iret frame */ jmp *%eax /* Jump back */ + + +ENTRY(exec_user) /* void (*fn)(void) */ + + push $__USER_DS /* SS */ + push %esp + addl $4, (%esp) /* ESP */ + pushf /* EFLAGS */ + +#if defined(CONFIG_ENV_pv) /* PV guests see the real interrupt flag. Clobber it. */ + andl $~X86_EFLAGS_IF, (%esp) +#endif + + push $__USER_CS /* CS */ + push $1f /* EIP */ + + env_IRET /* Drop to user privilege. */ +1: + call *4(%esp) /* fn() */ + + int $0x20 /* Return to kernel privilege. */ + ret diff --git a/arch/x86/entry_64.S b/arch/x86/entry_64.S index e1b5baa..730ee5b 100644 --- a/arch/x86/entry_64.S +++ b/arch/x86/entry_64.S @@ -1,4 +1,5 @@ #include +#include #include /* @@ -102,3 +103,25 @@ ENTRY(entry_ret_to_kernel) /* int $0x20 (return to kernel) */ mov 0*8(%rsp), %rax /* Stash %rip from iret frame */ mov 3*8(%rsp), %rsp /* Load %esp from iret frame */ jmp *%rax /* Jump back */ + + +ENTRY(exec_user) /* void (*fn)(void) */ + + push $__USER_DS /* SS */ + push %rsp + addq $8, (%rsp) /* RSP */ + pushf /* RFLAGS */ + +#if defined(CONFIG_ENV_pv) /* PV guests see the real interrupt flag. Clobber it. */ + andq $~X86_EFLAGS_IF, (%rsp) +#endif + + push $__USER_CS /* CS */ + push $1f /* RIP */ + + env_IRETQ /* Drop to user privilege. */ +1: + call *%rdi /* fn() */ + + int $0x20 /* Return to kernel privilege. */ + ret diff --git a/include/xtf/lib.h b/include/xtf/lib.h index b4a7579..d18ac2b 100644 --- a/include/xtf/lib.h +++ b/include/xtf/lib.h @@ -18,6 +18,9 @@ void heapsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *), void (*swap)(void *, void *)); +/* Execute fn() at user privilege on the current stack. */ +void exec_user(void (*fn)(void)); + #endif /* XTF_LIB_H */ /* diff --git a/tests/selftest/main.c b/tests/selftest/main.c index 2595fba..45eb3bc 100644 --- a/tests/selftest/main.c +++ b/tests/selftest/main.c @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -130,6 +131,44 @@ static void test_exlog(void) xtf_exlog_stop(); } +static enum { + USER_not_seen, + USER_seen, + USER_bad_cs, +} seen_from_userspace = USER_not_seen; + +static void test_exec_user_cpl3(void) +{ + unsigned int cs = read_cs(); + + if ( (cs & 3) == 3 ) + seen_from_userspace = USER_seen; + else + seen_from_userspace = USER_bad_cs; +} + +static void test_exec_user(void) +{ + printk("Test: Userspace execution\n"); + + exec_user(test_exec_user_cpl3); + + switch ( seen_from_userspace ) + { + case USER_seen: + /* Success */ + break; + + case USER_not_seen: + xtf_failure("Fail: Did not execute function\n"); + break; + + case USER_bad_cs: + xtf_failure("Fail: Not at cpl3\n"); + break; + } +} + void test_main(void) { printk("XTF Selftests\n"); @@ -137,6 +176,7 @@ void test_main(void) test_int3_breakpoint(); test_extable(); test_exlog(); + test_exec_user(); xtf_success(); }