From c3a84a8f7cedd97b34139cb6abde62f17b9d2b1c Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Thu, 22 Mar 2018 11:50:50 +0000 Subject: [PATCH] Rudimentary syscall handling for PV guests Signed-off-by: Andrew Cooper --- arch/x86/entry_32.S | 29 +++++++++++++++++++++++++ arch/x86/entry_64.S | 20 ++++++++++++++++++ arch/x86/include/arch/test.h | 26 +++++++++++++++++++++++ arch/x86/include/arch/xtf.h | 1 + arch/x86/pv/traps.c | 35 ++++++++++++++++++++++++++++++- arch/x86/traps.c | 5 +++++ include/xen/arch-x86/xen-x86_32.h | 3 +++ include/xen/arch-x86/xen-x86_64.h | 5 +++++ 8 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 arch/x86/include/arch/test.h diff --git a/arch/x86/entry_32.S b/arch/x86/entry_32.S index b49b0e7..9968b57 100644 --- a/arch/x86/entry_32.S +++ b/arch/x86/entry_32.S @@ -154,6 +154,35 @@ ENTRY(exec_user_stub) ENDFUNC(exec_user_stub) .popsection +#if defined(CONFIG_PV) +ENTRY(entry_SYSCALL) + push $0 + push $0x100 + + push %es + push %ds + + SAVE_ALL + + mov $__KERN_DS, %eax /* Restore data segments. */ + mov %eax, %ds + mov %eax, %es + + push %esp /* struct cpu_regs * */ + call do_syscall + add $4, %esp + + RESTORE_ALL + + pop %ds + pop %es + + add $8, %esp /* Pop error_code/entry_vector. */ + + jmp HYPERCALL_iret +ENDFUNC(entry_SYSCALL) +#endif + /* * Local variables: * tab-width: 8 diff --git a/arch/x86/entry_64.S b/arch/x86/entry_64.S index 756ccb1..5136dd6 100644 --- a/arch/x86/entry_64.S +++ b/arch/x86/entry_64.S @@ -148,6 +148,26 @@ ENTRY(exec_user_stub) ENDFUNC(exec_user_stub) .popsection +#if defined(CONFIG_PV) +ENTRY(entry_SYSCALL) + env_ADJUST_FRAME + + push $0 + movl $0x100, 4(%rsp) + + SAVE_ALL + + mov %rsp, %rdi /* struct cpu_regs * */ + call do_syscall + + RESTORE_ALL + + movq $VGCF_in_syscall, (%rsp) /* Clobber error_code/entry_vector */ + jmp HYPERCALL_iret + +ENDFUNC(entry_SYSCALL) +#endif /* CONFIG_PV */ + /* * Local variables: * tab-width: 8 diff --git a/arch/x86/include/arch/test.h b/arch/x86/include/arch/test.h new file mode 100644 index 0000000..a34cdbb --- /dev/null +++ b/arch/x86/include/arch/test.h @@ -0,0 +1,26 @@ +/** + * @file arch/x86/include/arch/test.h + * + * %x86 API for tests. + */ +#ifndef XTF_X86_TEST_H +#define XTF_X86_TEST_H + +#include + +/** + * May be implemented by a guest to handle SYSCALL invocations. + */ +void do_syscall(struct cpu_regs *regs); + +#endif /* XTF_X86_TEST_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/arch/x86/include/arch/xtf.h b/arch/x86/include/arch/xtf.h index 3609d5d..6cedf08 100644 --- a/arch/x86/include/arch/xtf.h +++ b/arch/x86/include/arch/xtf.h @@ -12,6 +12,7 @@ #include #include #include +#include #include extern char _end[]; diff --git a/arch/x86/pv/traps.c b/arch/x86/pv/traps.c index 1899d0b..92dca02 100644 --- a/arch/x86/pv/traps.c +++ b/arch/x86/pv/traps.c @@ -35,6 +35,8 @@ void entry_XM(void); void entry_VE(void); void entry_ret_to_kernel(void); +void entry_SYSCALL(void); + struct xen_trap_info pv_default_trap_info[] = { { X86_EXC_DE, 0|4, __KERN_CS, _u(entry_DE) }, @@ -108,7 +110,7 @@ static int __maybe_unused remap_linear_range(const void *start, const void *end, return ret; } -void arch_init_traps(void) +static void init_callbacks(void) { /* PV equivalent of `lidt`. */ int rc = hypercall_set_trap_table(pv_default_trap_info); @@ -116,6 +118,37 @@ void arch_init_traps(void) if ( rc ) panic("Failed to set trap table: %d\n", rc); + xen_callback_register_t cb; + +#ifdef __x86_64__ + cb = (xen_callback_register_t) { + .type = CALLBACKTYPE_syscall, + .flags = CALLBACKF_mask_events, + .address = INIT_XEN_CALLBACK(__KERN_CS, _u(entry_SYSCALL)), + }; + + rc = hypercall_register_callback(&cb); + if ( rc ) + panic("Failed to register syscall callback: %d\n", rc); +#endif + + cb = (xen_callback_register_t) { + .type = CALLBACKTYPE_syscall32, + .flags = CALLBACKF_mask_events, + .address = INIT_XEN_CALLBACK(__KERN_CS, _u(entry_SYSCALL)), + }; + + rc = hypercall_register_callback(&cb); + if ( rc ) + panic("Failed to register syscall32 callback: %d\n", rc); +} + +void arch_init_traps(void) +{ + int rc; + + init_callbacks(); + /* Register gdt[] with Xen. Need to map it read-only first. */ if ( remap_linear(gdt, PF_SYM(AD, P)) ) panic("Unable to remap gdt[] as read-only\n"); diff --git a/arch/x86/traps.c b/arch/x86/traps.c index 8fee587..b0a1f9b 100644 --- a/arch/x86/traps.c +++ b/arch/x86/traps.c @@ -68,6 +68,11 @@ void do_exception(struct cpu_regs *regs) } } +void __weak do_syscall(struct cpu_regs *regs) +{ + panic("Unhandled syscall\n"); +} + /* * Local variables: * mode: C diff --git a/include/xen/arch-x86/xen-x86_32.h b/include/xen/arch-x86/xen-x86_32.h index 63ff666..c8f5f17 100644 --- a/include/xen/arch-x86/xen-x86_32.h +++ b/include/xen/arch-x86/xen-x86_32.h @@ -85,6 +85,9 @@ struct xen_callback { }; typedef struct xen_callback xen_callback_t; +#define INIT_XEN_CALLBACK(_cs, _ip) \ + ((xen_callback_t){ .cs = _cs, .eip = _ip }) + #endif /* __ASSEMBLY__ */ #endif /* XEN_PUBLIC_ARCH_X86_XEN_X86_32_H */ diff --git a/include/xen/arch-x86/xen-x86_64.h b/include/xen/arch-x86/xen-x86_64.h index 8bc577f..30bc74d 100644 --- a/include/xen/arch-x86/xen-x86_64.h +++ b/include/xen/arch-x86/xen-x86_64.h @@ -17,6 +17,9 @@ #define MACH2PHYS_VIRT_START 0xFFFF800000000000UL +/* Guest exited in SYSCALL context? Return to guest with SYSRET? */ +#define VGCF_in_syscall 0x100 + #ifndef __ASSEMBLY__ /* Anonymous unions include all permissible names (e.g., al/ah/ax/eax/rax). */ @@ -90,6 +93,8 @@ struct arch_vcpu_info { typedef unsigned long xen_callback_t; +#define INIT_XEN_CALLBACK(_cs, _ip) (_ip) + #endif /* __ASSEMBLY__ */ #endif /* XEN_PUBLIC_ARCH_X86_XEN_X86_64_H */ -- 2.39.5