diff --git a/arch/x86/entry.S b/arch/x86/entry.S index fd11abec..40b9a803 100644 --- a/arch/x86/entry.S +++ b/arch/x86/entry.S @@ -29,8 +29,26 @@ #include #include +.macro _handle_usermode cr3 + testb $0x3, 8(%_ASM_SP) + jz 1f /* skip if from kernel mode */ + SET_CR3 \cr3 + swapgs + 1: +.endm + +.macro from_usermode + _handle_usermode cr3 +.endm + +.macro to_usermode + _handle_usermode user_cr3 +.endm + .macro exception_handler sym vec has_error_code ENTRY(entry_\sym) + from_usermode + .if \has_error_code == 0 push $0 .endif @@ -42,10 +60,14 @@ END_FUNC(entry_\sym) .macro interrupt_handler sym func ENTRY(asm_interrupt_handler_\sym) + from_usermode + cld SAVE_ALL_REGS call \func RESTORE_ALL_REGS + + to_usermode IRET END_FUNC(asm_interrupt_handler_\sym) .endm @@ -87,6 +109,8 @@ ENTRY(handle_exception) #else add $4, %_ASM_SP #endif + + to_usermode IRET END_FUNC(handle_exception) @@ -97,17 +121,22 @@ interrupt_handler keyboard keyboard_interrupt_handler interrupt_handler acpi acpi_interrupt_handler #endif -ENTRY(usermode_call_asm) +ENTRY(enter_usermode) /* FIXME: Add 32-bit support */ /* will be restored on entering back in kernel mode */ + SAVE_ALL_REGS PUSHF - mov %_ASM_SP, %gs:(%rdx) + /* Save stack pointer onto per-cpu */ + mov %_ASM_SP, %gs:(%_ASM_DX) + + /* Move to user stack */ + mov %_ASM_CX, %_ASM_SP /* SS + SP */ push $__USER_DS - push %gs:(%rcx) + push %_ASM_CX /* EFLAGS */ PUSHF @@ -118,8 +147,9 @@ ENTRY(usermode_call_asm) pushq $__USER_CS push $usermode_stub + to_usermode IRET -END_FUNC(usermode_call_asm) +END_FUNC(enter_usermode) SECTION(.text.user, "ax", 16) ENTRY(usermode_stub) @@ -130,7 +160,10 @@ ENTRY(usermode_stub) xchg %_ASM_DI, %_ASM_SI call *%_ASM_SI - int $X86_RET2KERN_INT + /* sys_exit */ + mov %_ASM_AX, %_ASM_DI + xor %_ASM_AX, %_ASM_AX + syscall END_FUNC(usermode_stub) SECTION(.data.rmode, "aw", 16) diff --git a/arch/x86/traps.c b/arch/x86/traps.c index 46285ae0..824ef311 100644 --- a/arch/x86/traps.c +++ b/arch/x86/traps.c @@ -1,4 +1,5 @@ /* + * Copyright © 2022 Open Source Security, Inc. * Copyright © 2020 Amazon.com, Inc. or its affiliates. * Copyright © 2014,2015 Citrix Systems Ltd. * All Rights Reserved. @@ -26,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -33,6 +35,7 @@ #include #include #include +#include #include @@ -40,14 +43,6 @@ extern void asm_interrupt_handler_uart(void); extern void asm_interrupt_handler_keyboard(void); extern void asm_interrupt_handler_timer(void); -static void ret2kern_handler(void) { - /* clang-format off */ - asm volatile("mov %%gs:%[sp], %%" STR(_ASM_SP) "\n" - "POPF \n" - :: [ sp ] "m"(ACCESS_ONCE(PERCPU_VAR(ret2kern_sp)))); - /* clang-format on */ -} - static void init_tss(percpu_t *percpu) { #if defined(__i386__) percpu->tss_df.iopb = sizeof(percpu->tss_df); @@ -153,10 +148,6 @@ void init_traps(const cpu_t *cpu) { set_intr_gate(&percpu->idt[X86_EX_DF], __KERN_CS, _ul(entry_DF), GATE_DPL0, GATE_PRESENT, 1); #endif - /* User mode return to kernel handler */ - set_intr_gate(&percpu->idt[X86_RET2KERN_INT], __KERN_CS, _ul(ret2kern_handler), GATE_DPL3, GATE_PRESENT, 0); - /* clang-format on */ - set_intr_gate(&percpu->idt[COM1_IRQ0_OFFSET], __KERN_CS, _ul(asm_interrupt_handler_uart), GATE_DPL0, GATE_PRESENT, 0); set_intr_gate(&percpu->idt[COM2_IRQ0_OFFSET], __KERN_CS, @@ -174,6 +165,8 @@ void init_traps(const cpu_t *cpu) { init_gdt(percpu); wrmsr(MSR_TSC_AUX, cpu->id); + + init_usermode(percpu); } static void dump_general_regs(const struct cpu_regs *regs) { @@ -306,7 +299,7 @@ static bool extables_fixup(struct cpu_regs *regs) { void do_exception(struct cpu_regs *regs) { static char ec_str[32], panic_str[128]; - if (extables_fixup(regs)) + if (!from_usermode(regs->cs) && extables_fixup(regs)) return; dump_regs(regs); @@ -320,5 +313,11 @@ void do_exception(struct cpu_regs *regs) { exception_names[regs->vector], ec_str, regs->cs, regs->_ASM_IP, regs->ss, regs->_ASM_SP); + /* Handle user tasks' exceptions */ + if (from_usermode(regs->cs)) { + printk("Task exception: %s\n", panic_str); + goto_syscall_exit(-EFAULT); + } + panic(panic_str); } diff --git a/common/kernel.c b/common/kernel.c index 500096b1..ff74ef9a 100644 --- a/common/kernel.c +++ b/common/kernel.c @@ -35,14 +35,6 @@ #include #endif -extern int usermode_call_asm(user_func_t fn, void *fn_arg, unsigned long ret2kern_sp, - unsigned long user_stack); - -int usermode_call(user_func_t fn, void *fn_arg) { - return usermode_call_asm(fn, fn_arg, PERCPU_OFFSET(ret2kern_sp), - PERCPU_OFFSET(user_stack)); -} - static void __noreturn echo_loop(void) { while (1) { io_delay(); diff --git a/common/percpu.c b/common/percpu.c index 56841ee5..f933746b 100644 --- a/common/percpu.c +++ b/common/percpu.c @@ -49,11 +49,10 @@ percpu_t *get_percpu_page(unsigned int cpu) { /* Per CPU page must be identity mapped, * because GDT descriptor has 32-bit base. */ - percpu = get_free_page(GFP_IDENT | GFP_KERNEL); + percpu = get_free_page(GFP_IDENT | GFP_KERNEL | GFP_USER); BUG_ON(!percpu); percpu->cpu_id = cpu; - percpu->user_stack = get_free_page_top(GFP_USER); list_add(&percpu->list, &percpu_frames); return percpu; diff --git a/common/sched.c b/common/sched.c index 3a2a9b18..e35d4961 100644 --- a/common/sched.c +++ b/common/sched.c @@ -32,10 +32,12 @@ #include #include #include +#include #include #include +#include static tid_t next_tid; @@ -96,7 +98,10 @@ static void destroy_task(task_t *task) { spin_lock(&task->cpu->lock); list_unlink(&task->list); + if (task->stack) + put_page_top(task->stack); spin_unlock(&task->cpu->lock); + kfree(task); } @@ -111,6 +116,8 @@ static int prepare_task(task_t *task, const char *name, task_func_t func, void * task->func = func; task->arg = arg; task->type = type; + if (task->type == TASK_TYPE_USER) + task->stack = get_free_page_top(GFP_USER); set_task_state(task, TASK_STATE_READY); return ESUCCESS; } @@ -178,7 +185,11 @@ static void run_task(task_t *task) { printk("CPU[%u]: Running task %s[%u]\n", task->cpu->id, task->name, task->id); set_task_state(task, TASK_STATE_RUNNING); - task->result = task->func(task->arg); + if (task->type == TASK_TYPE_USER) + task->result = enter_usermode(task->func, task->arg, + PERCPU_OFFSET(usermode_private), task->stack); + else + task->result = task->func(task->arg); set_task_state(task, TASK_STATE_DONE); } diff --git a/common/usermode.c b/common/usermode.c new file mode 100644 index 00000000..45915c36 --- /dev/null +++ b/common/usermode.c @@ -0,0 +1,249 @@ +/* + * Copyright © 2022 Open Source Security, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include + +static inline void syscall_save(void) { + /* clang-format off */ + asm volatile( + "push %%" STR(_ASM_CX) "\n" + "push %%r11" + ::: "memory" + ); + /* clang-format on */ +} + +static inline void syscall_restore(void) { + /* clang-format off */ + asm volatile( + "pop %%r11\n" + "pop %%" STR(_ASM_CX) + ::: "memory" + ); + /* clang-format on */ +} + +static inline long syscall_return(long return_code) { + register long ret asm(STR(_ASM_AX)) = return_code; + return ret; +} + +static inline void stack_switch(void) { + /* clang-format off */ + asm volatile( + "xchg %%gs:%[private], %%" STR(_ASM_SP) "\n" + ::[private] "m"(ACCESS_ONCE(PERCPU_VAR(usermode_private))) + ); + /* clang-format on */ +} + +static inline void switch_address_space(const cr3_t *cr3) { + /* clang-format off */ + asm volatile( + "push %%" STR(_ASM_AX) "\n" + "mov %[cr3], %%" STR(_ASM_AX) "\n" + "mov %%" STR(_ASM_AX) ", %%cr3\n" + "pop %%" STR(_ASM_AX) "\n" + :: [cr3] "m" (*cr3) + : STR(_ASM_AX) + ); + /* clang-format on */ +} + +static inline void _sys_exit(void) { + /* clang-format off */ + asm volatile ( + "mov %%" STR(_ASM_DI)", %%gs:%[private]\n" + POPF() + RESTORE_ALL_REGS() + "mov %%gs:%[private], %%" STR(_ASM_AX) "\n" + "ret\n" + :: [ private ] "m"(ACCESS_ONCE(PERCPU_VAR(usermode_private))) + : STR(_ASM_AX) + ); + /* clang-format on */ +} + +void __naked syscall_handler(void) { + register unsigned long syscall_nr asm(STR(_ASM_AX)); + register unsigned long param1 asm(STR(_ASM_DI)); + (void) param1; + register unsigned long param2 asm(STR(_ASM_SI)); + (void) param2; + register unsigned long param3 asm(STR(_ASM_BX)); + (void) param3; + register unsigned long param4 asm(STR(_ASM_DX)); + (void) param4; + + SAVE_CLOBBERED_REGS(); + switch_address_space(&cr3); + swapgs(); + stack_switch(); + syscall_save(); + + switch (syscall_nr) { + case SYSCALL_EXIT: + syscall_restore(); + _sys_exit(); + UNREACHABLE(); + + case SYSCALL_PRINTF: + printk(_ptr(param1), param2, param3, param4); + syscall_return(0); + break; + + case SYSCALL_MMAP: { + void *va = _ptr(param1); + unsigned int order = _u(param2); + frame_t *frame; + + frame = get_free_frames(order); + if (!va) + va = mfn_to_virt_user(frame->mfn); + + va = vmap_user(va, frame->mfn, order, L4_PROT_USER, L3_PROT_USER, L2_PROT_USER, + L1_PROT_USER); + syscall_return(_ul(va)); + } break; + + case SYSCALL_MUNMAP: { + void *va = _ptr(param1); + unsigned int order = _u(param2); + + vunmap_user(va, order); + } break; + + default: + printk("Unknown syscall: %lu\n", syscall_nr); + syscall_return(-1L); + break; + } + + syscall_restore(); + stack_switch(); + swapgs(); + switch_address_space(&user_cr3); + + RESTORE_CLOBBERED_REGS(); + + sysret(); +} + +static void init_syscall(void) { + msr_star_t star; + + star.eip = _u(_ul(&syscall_handler)); + star.kern_cs = __KERN_CS64; + star.user_cs = __USER_CS64; + + wrmsr(MSR_STAR, star.reg); + wrmsr(MSR_LSTAR, _ul(&syscall_handler)); + /* FIXME: Add compat support */ + wrmsr(MSR_CSTAR, _ul(NULL)); + + wrmsr(MSR_FMASK, X86_EFLAGS_CF | X86_EFLAGS_PF | X86_EFLAGS_AF | X86_EFLAGS_ZF | + X86_EFLAGS_SF | X86_EFLAGS_TF | X86_EFLAGS_IF | X86_EFLAGS_DF | + X86_EFLAGS_OF | X86_EFLAGS_ID | X86_EFLAGS_NT | X86_EFLAGS_RF | + X86_EFLAGS_AC | X86_EFLAGS_IOPL); + + wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_SCE); +} + +void init_usermode(percpu_t *percpu) { + vmap_user_4k(&cr3, virt_to_mfn(&cr3), L1_PROT); + vmap_user_4k(&enter_usermode, virt_to_mfn(&enter_usermode), L1_PROT); + vmap_user_4k(&syscall_handler, virt_to_mfn(&syscall_handler), L1_PROT); + + init_syscall(); +} + +static inline void __user_text sys_exit(unsigned long exit_code) { + asm volatile("syscall" ::"A"(SYSCALL_EXIT), "D"(exit_code) : STR(_ASM_CX), "r11"); +} + +static inline long __user_text sys_printf(const char *fmt, unsigned long arg1, + unsigned long arg2, unsigned long arg3) { + register unsigned long rax asm(STR(_ASM_AX)); + + /* clang-format off */ + asm volatile( + "syscall" + : "=A"(rax) + : "0"(SYSCALL_PRINTF), "D"(fmt), "S"(arg1), "b"(arg2), "d"(arg3) + : STR(_ASM_CX), "r11" + ); + /* clang-format on */ + + return rax; +} + +static inline long __user_text sys_mmap(void *va, unsigned long order) { + register unsigned long rax asm(STR(_ASM_AX)); + + /* clang-format off */ + asm volatile( + "syscall" + : "=A"(rax) + : "0"(SYSCALL_MMAP), "D"(va), "S"(order) + : STR(_ASM_CX), "r11" + ); + /* clang-format on */ + + return rax; +} + +static inline long __user_text sys_munmap(void *va, unsigned long order) { + register unsigned long rax asm(STR(_ASM_AX)); + + /* clang-format off */ + asm volatile( + "syscall" + ::"A"(SYSCALL_MUNMAP), "D"(va), "S"(order) + : STR(_ASM_CX), "r11" + ); + /* clang-format on */ + + return rax; +} + +void __user_text exit(unsigned long exit_code) { + sys_exit(exit_code); +} + +void __user_text printf(const char *fmt, unsigned long arg1, unsigned long arg2, + unsigned long arg3) { + sys_printf(fmt, arg1, arg2, arg3); +} + +void *__user_text mmap(void *va, unsigned long order) { + return _ptr(sys_mmap(va, order)); +} + +void __user_text munmap(void *va, unsigned long order) { + sys_munmap(va, order); +} diff --git a/include/arch/x86/asm-macros.h b/include/arch/x86/asm-macros.h index eb1a857f..e04d0007 100644 --- a/include/arch/x86/asm-macros.h +++ b/include/arch/x86/asm-macros.h @@ -261,34 +261,43 @@ name ## _end: #if defined(__x86_64__) #define SAVE_CLOBBERED_REGS64() \ - "push %%r8\n" \ - "push %%r9\n" \ - "push %%r10\n" \ - "push %%r11\n" \ + asm volatile ( \ + "push %%r8\n" \ + "push %%r9\n" \ + "push %%r10\n" \ + "push %%r11\n" \ + ::: "memory") #define RESTORE_CLOBBERED_REGS64() \ - "pop %%" STR(r11) "\n" \ - "pop %%" STR(r10) "\n" \ - "pop %%" STR(r9) "\n" \ - "pop %%" STR(r8) "\n" + asm volatile ( \ + "pop %%" STR(r11) "\n" \ + "pop %%" STR(r10) "\n" \ + "pop %%" STR(r9) "\n" \ + "pop %%" STR(r8) "\n" \ + ::: "r8", "r9", "r10", "r11") #else #define SAVE_CLOBBERED_REGS64() #define RESTORE_CLOBBERED_REGS64() #endif -#define SAVE_CLOBBERED_REGS() \ - "push %%" STR(_ASM_CX) "\n" \ - "push %%" STR(_ASM_DX) "\n" \ - "push %%" STR(_ASM_SI) "\n" \ - "push %%" STR(_ASM_DI) "\n" \ +#define SAVE_CLOBBERED_REGS() \ + asm volatile ( \ + "push %%" STR(_ASM_CX) "\n" \ + "push %%" STR(_ASM_DX) "\n" \ + "push %%" STR(_ASM_SI) "\n" \ + "push %%" STR(_ASM_DI) "\n" \ + ::: "memory"); \ SAVE_CLOBBERED_REGS64() -#define RESTORE_CLOBBERED_REGS() \ - RESTORE_CLOBBERED_REGS64() \ - "pop %%" STR(_ASM_DI) "\n" \ - "pop %%" STR(_ASM_SI) "\n" \ - "pop %%" STR(_ASM_DX) "\n" \ - "pop %%" STR(_ASM_CX) "\n" \ +#define RESTORE_CLOBBERED_REGS() \ + RESTORE_CLOBBERED_REGS64(); \ + asm volatile ( \ + "pop %%" STR(_ASM_DI) "\n" \ + "pop %%" STR(_ASM_SI) "\n" \ + "pop %%" STR(_ASM_DX) "\n" \ + "pop %%" STR(_ASM_CX) "\n" \ + ::: STR(_ASM_DI), STR(_ASM_SI), \ + STR(_ASM_DX), STR(_ASM_CX)) /* clang-format on */ #if defined(__x86_64__) diff --git a/include/arch/x86/processor.h b/include/arch/x86/processor.h index 06d5cae5..0c67aa62 100644 --- a/include/arch/x86/processor.h +++ b/include/arch/x86/processor.h @@ -271,6 +271,16 @@ struct cpu_regs { }; typedef struct cpu_regs cpu_regs_t; +union msr_star { + uint64_t reg; + struct __packed { + uint32_t eip; + uint16_t kern_cs; + uint16_t user_cs; + }; +}; +typedef union msr_star msr_star_t; + static inline bool has_error_code(uint32_t vector) { return !!((1U << vector) & X86_EX_HAS_ERROR_CODE); } diff --git a/include/arch/x86/traps.h b/include/arch/x86/traps.h index cd5dc680..c731580e 100644 --- a/include/arch/x86/traps.h +++ b/include/arch/x86/traps.h @@ -30,8 +30,6 @@ #define MAX_INT 256 -#define X86_RET2KERN_INT 32 - #ifndef __ASSEMBLY__ #include diff --git a/include/ktf.h b/include/ktf.h index 500cc215..fa651b93 100644 --- a/include/ktf.h +++ b/include/ktf.h @@ -38,12 +38,8 @@ typedef uint16_t io_port_t; -typedef int (*user_func_t)(void *arg); - extern bool opt_debug; -extern int usermode_call(user_func_t fn, void *fn_arg); - extern void kernel_main(void) __noreturn; extern unsigned long test_main(void *unused); diff --git a/include/percpu.h b/include/percpu.h index 06fe7cbb..b6891499 100644 --- a/include/percpu.h +++ b/include/percpu.h @@ -57,8 +57,7 @@ struct percpu { x86_tss_t tss_df __aligned(16); #endif - unsigned long ret2kern_sp; - void *user_stack; + unsigned long usermode_private; } __aligned(PAGE_SIZE); typedef struct percpu percpu_t; diff --git a/include/sched.h b/include/sched.h index 8f433c20..d40af72e 100644 --- a/include/sched.h +++ b/include/sched.h @@ -68,6 +68,7 @@ struct task { task_state_t state; cpu_t *cpu; + void *stack; const char *name; task_func_t func; diff --git a/include/usermode.h b/include/usermode.h new file mode 100644 index 00000000..5e9b9461 --- /dev/null +++ b/include/usermode.h @@ -0,0 +1,64 @@ +/* + * Copyright © 2022 Open Source Security, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef KTF_USERMODE_H +#define KTF_USERMODE_H + +#define SYSCALL_EXIT 0 +#define SYSCALL_PRINTF 1 +#define SYSCALL_MMAP 2 +#define SYSCALL_MUNMAP 3 + +#ifndef __ASSEMBLY__ +#include +#include + +/* Static declarations */ + +static inline bool from_usermode(uint16_t cs) { + return (cs & 0x3) != 0; +} + +static inline void goto_syscall_exit(long exit_code) { + swapgs(); + asm volatile("jmp syscall_handler" ::"A"(SYSCALL_EXIT), "D"(exit_code)); +} + +/* External declarations */ + +extern unsigned long enter_usermode(task_func_t fn, void *fn_arg, + unsigned long usermode_private, void *user_stack); +extern void __naked syscall_handler(void); + +extern void init_usermode(percpu_t *percpu); + +extern void __user_text exit(unsigned long exit_code); +extern void __user_text printf(const char *fmt, unsigned long arg1, unsigned long arg2, + unsigned long arg3); +extern void *__user_text mmap(void *va, unsigned long order); +extern void __user_text munmap(void *va, unsigned long order); + +#endif /* __ASSEMBLY__ */ + +#endif /* KTF_USERMODE_H */ diff --git a/tests/unittests.c b/tests/unittests.c index 779d6dda..b9f162c8 100644 --- a/tests/unittests.c +++ b/tests/unittests.c @@ -22,6 +22,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include #include #include #include @@ -30,8 +31,9 @@ #include #include #include +#include -#include +#include static char opt_string[4]; string_cmd("string", opt_string); @@ -64,13 +66,35 @@ static void cpu_freq_expect(const char *cpu_str, uint64_t expectation) { return; } -static int __user_text func(void *arg) { +static unsigned long test_kernel_task_func(void *arg) { + printk("CPU[%u]: Executing %s\n", smp_processor_id(), __func__); + return _ul(arg); +} + +static unsigned long __user_text test_user_task_func1(void *arg) { + static char *fmt_printf __user_data = "printf: %u %x %d\n"; + + printf(fmt_printf, 1234, 0x41414141, 9); + printf(fmt_printf, 1235, 0x42424242, -9); + + exit(9); return 0; } -int unit_tests(void *_unused) { - usermode_call(func, NULL); +static unsigned long __user_text test_user_task_func2(void *arg) { + static char *fmt_mmap __user_data = "mmap: %lx\n"; + void *va; + + va = mmap(_ptr(0xfff80000), PAGE_ORDER_4K); + printf(fmt_mmap, _ul(va), 0, 0); + memset(va, 0xcc, 0x1000); + ((void (*)(void)) va)(); + + return 0; +} + +int unit_tests(void *_unused) { printk("\nLet the UNITTESTs begin\n"); printk("Commandline parsing: %s\n", kernel_cmdline); @@ -138,6 +162,18 @@ int unit_tests(void *_unused) { cpu_freq_expect("Prototyp Amazing Foo One @ 1GHz", 1000000000); cpu_freq_expect("Prototyp Amazing Foo Two @ 1.00GHz", 1000000000); + task_t *task1, *task2, *task_user1, *task_user2; + + task1 = new_kernel_task("test1", test_kernel_task_func, _ptr(98)); + task2 = new_kernel_task("test2", test_kernel_task_func, _ptr(-99)); + task_user1 = new_user_task("test1 user", test_user_task_func1, NULL); + task_user2 = new_user_task("test2 user", test_user_task_func2, NULL); + + schedule_task(task1, get_bsp_cpu()); + schedule_task(task2, get_cpu(1)); + schedule_task(task_user1, get_bsp_cpu()); + schedule_task(task_user2, get_cpu(1)); + printk("Long mode to real mode transition:\n"); long_to_real();