Module: xenomai-3 Branch: next Commit: 367867fafbd9174fec9cfcae06979911e3a78c50 URL: http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=367867fafbd9174fec9cfcae06979911e3a78c50
Author: Philippe Gerum <r...@xenomai.org> Date: Thu Oct 16 14:20:49 2014 +0200 cobalt: fixup generic 32bit syscall support --- include/cobalt/kernel/rtdm/fd.h | 25 +++++- include/cobalt/uapi/syscall.h | 2 +- kernel/cobalt/Kconfig | 3 - kernel/cobalt/debug.c | 26 +----- kernel/cobalt/debug.h | 4 +- .../cobalt/include/asm-generic/xenomai/syscall.h | 5 ++ .../cobalt/include/asm-generic/xenomai/syscall32.h | 6 +- kernel/cobalt/posix/syscall.c | 88 +++++++++++++++----- kernel/cobalt/rtdm/fd.c | 45 +++++++++- 9 files changed, 146 insertions(+), 58 deletions(-) diff --git a/include/cobalt/kernel/rtdm/fd.h b/include/cobalt/kernel/rtdm/fd.h index cf47fcb..51609b3 100644 --- a/include/cobalt/kernel/rtdm/fd.h +++ b/include/cobalt/kernel/rtdm/fd.h @@ -24,6 +24,7 @@ #include <linux/socket.h> #include <linux/file.h> #include <cobalt/kernel/tree.h> +#include <asm-generic/xenomai/syscall.h> struct vm_area_struct; struct rtdm_fd; @@ -299,30 +300,48 @@ struct rtdm_fd { unsigned int refs; int minor; int oflags; +#ifdef CONFIG_COMPAT + int compat; +#endif struct list_head cleanup; }; #define RTDM_FD_MAGIC 0x52544446 +#define RTDM_FD_COMPAT __COBALT_COMPAT_BIT +#define RTDM_FD_COMPATX __COBALT_COMPATX_BIT + int __rtdm_anon_getfd(const char *name, int flags); void __rtdm_anon_putfd(int ufd); -static inline struct cobalt_ppd *rtdm_fd_owner(struct rtdm_fd *fd) +static inline struct cobalt_ppd *rtdm_fd_owner(const struct rtdm_fd *fd) { return fd->owner; } -static inline int rtdm_fd_minor(struct rtdm_fd *fd) +static inline int rtdm_fd_minor(const struct rtdm_fd *fd) { return fd->minor; } -static inline int rtdm_fd_flags(struct rtdm_fd *fd) +static inline int rtdm_fd_flags(const struct rtdm_fd *fd) { return fd->oflags; } +#ifdef CONFIG_COMPAT +static inline int rtdm_fd_compat(const struct rtdm_fd *fd) +{ + return fd->compat; +} +#else +static inline int rtdm_fd_compat(const struct rtdm_fd *fd) +{ + return 0; +} +#endif + int rtdm_fd_enter(struct rtdm_fd *rtdm_fd, int ufd, unsigned int magic, struct rtdm_fd_ops *ops); diff --git a/include/cobalt/uapi/syscall.h b/include/cobalt/uapi/syscall.h index 59d90e5..aa364a1 100644 --- a/include/cobalt/uapi/syscall.h +++ b/include/cobalt/uapi/syscall.h @@ -120,6 +120,6 @@ #define sc_cobalt_extend 97 #define sc_cobalt_sysconf 98 -#define __NR_COBALT_SYSCALLS 100 +#define __NR_COBALT_SYSCALLS 128 /* Power of 2 */ #endif /* !_COBALT_UAPI_SYSCALL_H */ diff --git a/kernel/cobalt/Kconfig b/kernel/cobalt/Kconfig index c4185b2..2e49d37 100644 --- a/kernel/cobalt/Kconfig +++ b/kernel/cobalt/Kconfig @@ -257,9 +257,6 @@ config XENO_OPT_VFILE depends on PROC_FS default y -config XENO_OPT_SYS3264 - bool - endmenu menu "Sizes and static limits" diff --git a/kernel/cobalt/debug.c b/kernel/cobalt/debug.c index a809dc9..ad72a3e 100644 --- a/kernel/cobalt/debug.c +++ b/kernel/cobalt/debug.c @@ -111,7 +111,6 @@ out: */ #define RELAX_SPOTNR 128 #define RELAX_HSLOTS (1 << 8) -#define RELAX_CALLDEPTH SIGSHADOW_BACKTRACE_DEPTH struct relax_record { /* Number of hits for this location */ @@ -124,7 +123,7 @@ struct relax_record { struct backtrace { unsigned long pc; const char *mapname; - } backtrace[RELAX_CALLDEPTH]; + } backtrace[SIGSHADOW_BACKTRACE_DEPTH]; /* Program hash value of the caller. */ u32 proghash; /* Pid of the caller. */ @@ -201,10 +200,9 @@ void xndebug_notify_relax(struct xnthread *thread, int reason) sigshadow_int(SIGSHADOW_ACTION_BACKTRACE, reason)); } -void xndebug_trace_relax(int nr, unsigned long __user *u_backtrace, +void xndebug_trace_relax(int nr, unsigned long *backtrace, int reason) { - unsigned long backtrace[RELAX_CALLDEPTH]; struct relax_record *p, **h; struct vm_area_struct *vma; struct xnthread *thread; @@ -220,25 +218,7 @@ void xndebug_trace_relax(int nr, unsigned long __user *u_backtrace, thread = xnthread_current(); if (thread == NULL) return; /* Can't be, right? What a mess. */ - /* - * In case backtrace() in userland is broken or fails. We may - * want to know about this in kernel space however, for future - * use. - */ - if (nr <= 0) - return; - /* - * We may omit the older frames if we can't store the full - * backtrace. - */ - if (nr > RELAX_CALLDEPTH) - nr = RELAX_CALLDEPTH; - /* - * Fetch the backtrace array, filled with PC values as seen - * from the relaxing thread in user-space. This can't fail - */ - if (__xn_safe_copy_from_user(backtrace, u_backtrace, nr * sizeof(pc))) - return; + /* * We compute PC values relative to the base of the shared * executable mappings we find in the backtrace, which makes diff --git a/kernel/cobalt/debug.h b/kernel/cobalt/debug.h index 6cb6ad5..2af4fcb 100644 --- a/kernel/cobalt/debug.h +++ b/kernel/cobalt/debug.h @@ -54,7 +54,7 @@ static inline void xndebug_shadow_init(struct xnthread *thread) #ifdef CONFIG_XENO_OPT_DEBUG_TRACE_RELAX void xndebug_notify_relax(struct xnthread *thread, int reason); -void xndebug_trace_relax(int nr, unsigned long __user *u_backtrace, +void xndebug_trace_relax(int nr, unsigned long *backtrace, int reason); #else static inline @@ -62,7 +62,7 @@ void xndebug_notify_relax(struct xnthread *thread, int reason) { } static inline -void xndebug_trace_relax(int nr, unsigned long __user *u_backtrace, +void xndebug_trace_relax(int nr, unsigned long *backtrace, int reason) { /* Simply ignore. */ diff --git a/kernel/cobalt/include/asm-generic/xenomai/syscall.h b/kernel/cobalt/include/asm-generic/xenomai/syscall.h index eae4a68..8a00008 100644 --- a/kernel/cobalt/include/asm-generic/xenomai/syscall.h +++ b/kernel/cobalt/include/asm-generic/xenomai/syscall.h @@ -65,4 +65,9 @@ static inline int __xn_safe_strncpy_from_user(char *dst, return __xn_strncpy_from_user(dst, src, count); } +/* 32bit syscall emulation */ +#define __COBALT_COMPAT_BIT 0x1 +/* 32bit syscall emulation - extended form */ +#define __COBALT_COMPATX_BIT 0x2 + #endif /* !_COBALT_ASM_GENERIC_SYSCALL_H */ diff --git a/kernel/cobalt/include/asm-generic/xenomai/syscall32.h b/kernel/cobalt/include/asm-generic/xenomai/syscall32.h index 1ffc546..b0c6f4a 100644 --- a/kernel/cobalt/include/asm-generic/xenomai/syscall32.h +++ b/kernel/cobalt/include/asm-generic/xenomai/syscall32.h @@ -19,8 +19,12 @@ #ifndef _COBALT_ASM_GENERIC_SYSCALL32_H #define _COBALT_ASM_GENERIC_SYSCALL32_H +#define __COBALT_CALL32_INITHAND(__handler) + +#define __COBALT_CALL32_INITMODE(__mode) + #define __COBALT_CALL32_ENTRY(__name, __handler) -#define COBALT_SYSCALL32x_DECL(__name, __type, __args) +#define __COBALT_CALL_COMPAT(__reg) 0 #endif /* !_COBALT_ASM_GENERIC_SYSCALL32_H */ diff --git a/kernel/cobalt/posix/syscall.c b/kernel/cobalt/posix/syscall.c index 550f57a..ae879fc 100644 --- a/kernel/cobalt/posix/syscall.c +++ b/kernel/cobalt/posix/syscall.c @@ -132,7 +132,7 @@ static int handle_head_syscall(struct ipipe_domain *ipd, struct pt_regs *regs) } handler = cobalt_syscalls[nr]; - sysflags = cobalt_sysmodes[nr]; + sysflags = cobalt_sysmodes[nr & (__NR_COBALT_SYSCALLS - 1)]; /* * Executing Cobalt services requires CAP_SYS_NICE, except for @@ -313,7 +313,7 @@ static int handle_root_syscall(struct ipipe_domain *ipd, struct pt_regs *regs) /* Processing a Xenomai syscall. */ handler = cobalt_syscalls[nr]; - sysflags = cobalt_sysmodes[nr]; + sysflags = cobalt_sysmodes[nr & (__NR_COBALT_SYSCALLS - 1)]; if ((sysflags & __xn_exec_conforming) != 0) sysflags |= (thread ? __xn_exec_histage : __xn_exec_lostage); @@ -512,7 +512,32 @@ static COBALT_SYSCALL(backtrace, current, int, (int nr, unsigned long __user *u_backtrace, int reason)) { - xndebug_trace_relax(nr, u_backtrace, reason); + unsigned long backtrace[SIGSHADOW_BACKTRACE_DEPTH]; + int ret; + + /* + * In case backtrace() in userland is broken or fails. We may + * want to know about this in kernel space however, for future + * use. + */ + if (nr <= 0) + return 0; + /* + * We may omit the older frames if we can't store the full + * backtrace. + */ + if (nr > SIGSHADOW_BACKTRACE_DEPTH) + nr = SIGSHADOW_BACKTRACE_DEPTH; + /* + * Fetch the backtrace array, filled with PC values as seen + * from the relaxing thread in user-space. This can't fail + */ + ret = __xn_safe_copy_from_user(backtrace, u_backtrace, nr * sizeof(long)); + if (ret) + return ret; + + xndebug_trace_relax(nr, backtrace, reason); + return 0; } @@ -722,17 +747,17 @@ static int cobalt_ni(void) * returning -ENOSYS, as the table may be sparse. * * - then __COBALT_CALL_ENTRY() produces a native call entry - * (e.g. pure 64bit call handler for a 64bit architecture), and - * optionally a set of 32bit syscall entries offset by an + * (e.g. pure 64bit call handler for a 64bit architecture), optionally + * followed by a set of 32bit syscall entries offset by an * arch-specific base index, which default to the native calls. These - * nitty-gritty details are defined by <asm/xenomai/syscall32.h>. 32bit - * architectures - or 64bit ones for which we don't support any 32bit - * ABI model - will simply define __COBALT_CALL32_ENTRY() as an empty - * macro. + * nitty-gritty details are defined by + * <asm/xenomai/syscall32.h>. 32bit architectures - or 64bit ones for + * which we don't support any 32bit ABI model - will simply define + * __COBALT_CALL32_ENTRY() as an empty macro. * - * - finally, pure 32bit call entries are generated per-architecture, - * by including <asm/xenomai/syscall32-table.h>, overriding the - * default handlers installed during the previous step. + * - finally, 32bit thunk entries are generated per-architecture, by + * including <asm/xenomai/syscall32-table.h>, overriding the default + * handlers installed during the previous step. * * For instance, with CONFIG_X86_X32 support enabled in an x86_64 * kernel, sc_cobalt_mq_timedreceive would appear twice in the table, @@ -744,7 +769,7 @@ static int cobalt_ni(void) * * cobalt32x_mq_timedreceive() would do the required thunking for * dealing with the 32<->64bit conversion of arguments. On the other - * hand, sc_cobalt_sched_yield - which do not require any thunking - + * hand, sc_cobalt_sched_yield - which do not require any thunk - * would also appear twice, but both entries would point at the native * syscall implementation: * @@ -762,21 +787,38 @@ static int cobalt_ni(void) * routines it may need for handing 32bit calls over their respective * 64bit implementation. * - * By convention, there is NO 32bit-specific syscall, which means that + * By convention, there is NO pure 32bit syscall, which means that * each 32bit syscall defined by a compat ABI interface MUST match a * native (64bit) syscall. This is important as we share the call * modes (i.e. __xn_exec_ bits) between all ABI models. * * --rpm */ -#define __syshand__(__name) ((cobalt_syshand)(cobalt_ ## __name)) -#define __COBALT_CALL_ENTRY(__name) [sc_cobalt_ ## __name] = __syshand__(__name) \ - __COBALT_CALL32_ENTRY(__name, __syshand__(__name)) -#define __COBALT_MODE(__name, __mode) [sc_cobalt_ ## __name] = __xn_exec_##__mode -#define __COBALT_NI __syshand__(ni) +#define __syshand__(__name) ((cobalt_syshand)(cobalt_ ## __name)) + +#define __COBALT_NI __syshand__(ni) + +#define __COBALT_CALL_NI \ + [0 ... __NR_COBALT_SYSCALLS-1] = __COBALT_NI \ + __COBALT_CALL32_INITHAND(__COBALT_NI) + +#define __COBALT_CALL_NFLAGS \ + [0 ... __NR_COBALT_SYSCALLS-1] = 0 \ + __COBALT_CALL32_INITMODE(0) + +#define __COBALT_CALL_ENTRY(__name) \ + [sc_cobalt_ ## __name] = __syshand__(__name) \ + __COBALT_CALL32_ENTRY(__name, __syshand__(__name)) + +#define __COBALT_MODE(__name, __mode) \ + [sc_cobalt_ ## __name] = __xn_exec_##__mode + +#ifdef CONFIG_XENO_ARCH_SYS3264 +#include "syscall32.h" +#endif static const cobalt_syshand cobalt_syscalls[] = { - [0 ... __NR_COBALT_SYSCALLS-1] = __COBALT_NI, + __COBALT_CALL_NI, __COBALT_CALL_ENTRY(thread_create), __COBALT_CALL_ENTRY(thread_getpid), __COBALT_CALL_ENTRY(thread_setschedparam_ex), @@ -873,14 +915,14 @@ static const cobalt_syshand cobalt_syscalls[] = { __COBALT_CALL_ENTRY(backtrace), __COBALT_CALL_ENTRY(serialdbg), __COBALT_CALL_ENTRY(sysconf), - __COBALT_CALL_ENTRY(sysctl), -#ifdef CONFIG_XENO_OPT_SYS3264 + __COBALT_CALL_ENTRY(sysctl) +#ifdef CONFIG_XENO_ARCH_SYS3264 #include <asm/xenomai/syscall32-table.h> #endif }; static const int cobalt_sysmodes[] = { - [0 ... __NR_COBALT_SYSCALLS-1] = 0, + __COBALT_CALL_NFLAGS, __COBALT_MODE(thread_create, init), __COBALT_MODE(thread_getpid, current), __COBALT_MODE(thread_setschedparam_ex, conforming), diff --git a/kernel/cobalt/rtdm/fd.c b/kernel/cobalt/rtdm/fd.c index f75c7e5..61ace15 100644 --- a/kernel/cobalt/rtdm/fd.c +++ b/kernel/cobalt/rtdm/fd.c @@ -31,6 +31,7 @@ #include <rtdm/fd.h> #include "internal.h" #include "posix/process.h" +#include "posix/syscall.h" DEFINE_PRIVATE_XNLOCK(fdtree_lock); static LIST_HEAD(rtdm_fd_cleanup_queue); @@ -115,6 +116,29 @@ static struct rtdm_fd *fetch_fd(struct cobalt_ppd *p, int ufd) } \ while (0) +#ifdef CONFIG_COMPAT + +static inline void set_compat_bit(struct rtdm_fd *fd) +{ + struct pt_regs *regs; + + if (cobalt_ppd_get(0) == &__xnsys_global_ppd) + fd->compat = 0; + else { + regs = task_pt_regs(current); + XENO_BUGON(COBALT, !__xn_syscall_p(regs)); + fd->compat = __COBALT_CALL_COMPAT(__xn_reg_sys(regs)); + } +} + +#else /* !CONFIG_COMPAT */ + +static inline void set_compat_bit(struct rtdm_fd *fd) +{ +} + +#endif /* !CONFIG_COMPAT */ + int rtdm_fd_enter(struct rtdm_fd *fd, int ufd, unsigned int magic, struct rtdm_fd_ops *ops) { @@ -146,6 +170,7 @@ int rtdm_fd_enter(struct rtdm_fd *fd, int ufd, unsigned int magic, fd->ops = ops; fd->owner = ppd; fd->refs = 1; + set_compat_bit(fd); idx->fd = fd; @@ -332,8 +357,8 @@ EXPORT_SYMBOL_GPL(rtdm_fd_unlock); int rtdm_fd_ioctl(int ufd, unsigned int request, ...) { - void __user *arg; struct rtdm_fd *fd; + void __user *arg; va_list args; int err, ret; @@ -347,6 +372,8 @@ int rtdm_fd_ioctl(int ufd, unsigned int request, ...) goto out; } + set_compat_bit(fd); + trace_cobalt_fd_ioctl(current, fd, ufd, request); if (ipipe_root_p) @@ -384,6 +411,8 @@ rtdm_fd_read(int ufd, void __user *buf, size_t size) goto out; } + set_compat_bit(fd); + trace_cobalt_fd_read(current, fd, ufd, size); if (ipipe_root_p) @@ -415,6 +444,8 @@ ssize_t rtdm_fd_write(int ufd, const void __user *buf, size_t size) goto out; } + set_compat_bit(fd); + trace_cobalt_fd_write(current, fd, ufd, size); if (ipipe_root_p) @@ -446,6 +477,8 @@ ssize_t rtdm_fd_recvmsg(int ufd, struct msghdr *msg, int flags) goto out; } + set_compat_bit(fd); + trace_cobalt_fd_recvmsg(current, fd, ufd, flags); if (ipipe_root_p) @@ -454,7 +487,7 @@ ssize_t rtdm_fd_recvmsg(int ufd, struct msghdr *msg, int flags) err = fd->ops->recvmsg_rt(fd, msg, flags); if (!XENO_ASSERT(COBALT, !spltest())) - splnone(); + splnone(); rtdm_fd_put(fd); out: @@ -476,6 +509,8 @@ ssize_t rtdm_fd_sendmsg(int ufd, const struct msghdr *msg, int flags) goto out; } + set_compat_bit(fd); + trace_cobalt_fd_sendmsg(current, fd, ufd, flags); if (ipipe_root_p) @@ -527,6 +562,8 @@ ebadf: return -EBADF; } + set_compat_bit(fd); + trace_cobalt_fd_close(current, fd, ufd, fd->refs); /* @@ -557,6 +594,8 @@ int rtdm_fd_mmap(int ufd, struct _rtdm_mmap_request *rma, goto out; } + set_compat_bit(fd); + trace_cobalt_fd_mmap(current, fd, ufd, rma); if (rma->flags & (MAP_FIXED|MAP_ANONYMOUS)) { @@ -616,6 +655,8 @@ int rtdm_fd_select(int ufd, struct xnselector *selector, if (IS_ERR(fd)) return PTR_ERR(fd); + set_compat_bit(fd); + rc = fd->ops->select(fd, selector, type, ufd); if (!XENO_ASSERT(COBALT, !spltest())) _______________________________________________ Xenomai-git mailing list Xenomai-git@xenomai.org http://www.xenomai.org/mailman/listinfo/xenomai-git