Module: xenomai-3 Branch: master Commit: 6db20901963d634b9786467c711c2ba526db48a2 URL: http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=6db20901963d634b9786467c711c2ba526db48a2
Author: Philippe Gerum <r...@xenomai.org> Date: Tue Feb 3 16:19:39 2015 +0100 cobalt/x86_64: fix register trashing upon MAYDAY diversion --- kernel/cobalt/arch/x86/mayday.c | 73 ++++++++++++++++++++++++++++++++++++--- kernel/cobalt/posix/syscall.c | 1 - 2 files changed, 68 insertions(+), 6 deletions(-) diff --git a/kernel/cobalt/arch/x86/mayday.c b/kernel/cobalt/arch/x86/mayday.c index 4b986c9..62c5eea 100644 --- a/kernel/cobalt/arch/x86/mayday.c +++ b/kernel/cobalt/arch/x86/mayday.c @@ -67,27 +67,81 @@ static inline void setup_mayday64(void *page) /* * We want this code to appear at the top of the MAYDAY page: * + * 50 push %rax + * 41 53 push %r11 + * 51 push %rcx * b8 2b 02 00 0c mov $<mux_code>,%eax * 0f 05 syscall - * 0f 0b ud2a + * 59 pop %rcx + * 41 5b pop %r11 + * 48 87 04 24 xchg %rax,(%rsp) + * c3 retq * - * We intentionally don't mess with EFLAGS here, so that we - * don't have to save/restore it in handle/fixup code. + * The flow for a MAYDAY diversion on x86_64 is as follows: + * + * [runaway code] + * <watchdog/timer IRQ entry> + * [%orig_rip = %rip, %rip = &mayday_page] ; handle_mayday + * <watchdog/timer IRQ exit> + * + * [mayday_page trampoline] + * <MAYDAY syscall> ; relax + fixup_mayday + * [%rax = %orig_rip] + * ret-to-runaway-code + * + * [runaway code] + * ... + * + * We must take care of preserving %rcx and %r11 which are + * clobbered by the kernel when handling a syscall in long + * mode. This is required because the runaway thread code did + * not actually plan for running the MAYDAY syscall - we + * forced it to do so, by diverting the return path of the + * watchdog/timer IRQ which preempted it. + * + * On x86_64, we want the MAYDAY syscall to return to us, so + * that we can restore the clobbered registers, prior to + * branching back to the user code. fixup_mayday ensures that + * the original %rip is returned from the MAYDAY syscall in + * %rax, therefore we have to save the latter across the + * syscall as well. + * + * In addition, we intentionally don't mess with EFLAGS here, + * so that we don't have to save/restore it in handle/fixup + * code. */ static const struct __attribute__ ((__packed__)) { + u8 push_rax; + u16 push_r11; + u8 push_rcx; struct __attribute__ ((__packed__)) { u8 op; u32 imm; } mov_eax; u16 syscall; - u16 bug; + u8 pop_rcx; + u16 pop_r11; + struct __attribute__ ((__packed__)) { + u16 op; + u16 spec; + } xchg_rax_tos; + u8 retq; } code = { + .push_rax = 0x50, + .push_r11 = 0x5341, + .push_rcx = 0x51, .mov_eax = { .op = 0xb8, .imm = __xn_syscode(sc_cobalt_mayday) }, .syscall = 0x050f, - .bug = 0x0b0f, + .pop_rcx = 0x59, + .pop_r11 = 0x5b41, + .xchg_rax_tos = { + .op = 0x8748, + .spec = 0x2404 + }, + .retq = 0xc3, }; memcpy(page, &code, sizeof(code)); @@ -145,7 +199,16 @@ void xnarch_handle_mayday(struct xnarchtcb *tcb, struct pt_regs *regs, void xnarch_fixup_mayday(struct xnarchtcb *tcb, struct pt_regs *regs) { +#ifdef CONFIG_X86_64 + if (IS_ENABLED(CONFIG_XENO_ARCH_SYS3264) && + test_thread_flag(TIF_IA32)) { + regs->ip = tcb->mayday.ip; + regs->ax = tcb->mayday.ax; + } else + regs->ax = tcb->mayday.ip; +#else regs->ip = tcb->mayday.ip; regs->ax = tcb->mayday.ax; +#endif regs->sp = tcb->mayday.sp; } diff --git a/kernel/cobalt/posix/syscall.c b/kernel/cobalt/posix/syscall.c index 03ec81d..6a9a02c 100644 --- a/kernel/cobalt/posix/syscall.c +++ b/kernel/cobalt/posix/syscall.c @@ -272,7 +272,6 @@ static COBALT_SYSCALL(mayday, oneway, int, (void)) * did. */ return __xn_reg_rval(regs); - } static void stringify_feature_set(unsigned long fset, char *buf, int size) _______________________________________________ Xenomai-git mailing list Xenomai-git@xenomai.org http://www.xenomai.org/mailman/listinfo/xenomai-git