kernel: allow up to 6 arguments for system calls

A quick look at "man syscall" shows that in Linux, all architectures
support at least 6 argument system calls, with a few supporting 7. We
can at least do 6 in Zephyr.

x86 port modified to use EBP register to carry the 6th system call
argument.

Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
This commit is contained in:
Andrew Boie 2017-09-19 09:59:42 -07:00 committed by Andrew Boie
commit 1956f09590
5 changed files with 43 additions and 14 deletions

View file

@ -35,6 +35,7 @@ _id_ok:
* for _k_syscall_handler_t functions * for _k_syscall_handler_t functions
*/ */
push %esp /* ssf */ push %esp /* ssf */
push %ebp /* arg6 */
push %edi /* arg5 */ push %edi /* arg5 */
push %ebx /* arg4 */ push %ebx /* arg4 */
#ifndef CONFIG_X86_IAMCU #ifndef CONFIG_X86_IAMCU
@ -63,11 +64,11 @@ _id_ok:
pop %ebx pop %ebx
pop %edi pop %edi
#ifndef CONFIG_X86_IAMCU #ifndef CONFIG_X86_IAMCU
/* Discard ssf, no free register to pop it into so we add instead */ /* Discard ssf and arg6 */
add $4, %esp add $8, %esp
#else #else
xor %edx, %edx /* Clean EDX */ pop %ecx /* Clean ECX and get arg6 off the stack */
pop %ecx /* Clean ECX and get ssf arg off the stack */ pop %edx /* Clean EDX and get ssf off the stack */
#endif #endif
iret iret

View file

@ -560,6 +560,26 @@ extern struct task_state_segment _main_tss;
* the entry stub clobbers EDX and ECX on IAMCU systems * the entry stub clobbers EDX and ECX on IAMCU systems
*/ */
static inline u32_t _arch_syscall_invoke6(u32_t arg1, u32_t arg2, u32_t arg3,
u32_t arg4, u32_t arg5, u32_t arg6,
u32_t call_id)
{
u32_t ret;
__asm__ volatile("push %%ebp\n\t"
"mov %[arg6], %%ebp\n\t"
"int $0x80\n\t"
"pop %%ebp\n\t"
: "=a" (ret)
#ifdef CONFIG_X86_IAMCU
, "=d" (arg2), "=c" (arg3)
#endif
: "S" (call_id), "a" (arg1), "d" (arg2),
"c" (arg3), "b" (arg4), "D" (arg5),
[arg6] "r" (arg6));
return ret;
}
static inline u32_t _arch_syscall_invoke5(u32_t arg1, u32_t arg2, u32_t arg3, static inline u32_t _arch_syscall_invoke5(u32_t arg1, u32_t arg2, u32_t arg3,
u32_t arg4, u32_t arg5, u32_t call_id) u32_t arg4, u32_t arg5, u32_t call_id)
{ {

View file

@ -3917,6 +3917,10 @@ static inline int _is_user_context(void)
} }
/* Interfaces for invoking system calls */ /* Interfaces for invoking system calls */
static inline u32_t _arch_syscall_invoke6(u32_t arg1, u32_t arg2, u32_t arg3,
u32_t arg4, u32_t arg5, u32_t arg6,
u32_t call_id);
static inline u32_t _arch_syscall_invoke5(u32_t arg1, u32_t arg2, u32_t arg3, static inline u32_t _arch_syscall_invoke5(u32_t arg1, u32_t arg2, u32_t arg3,
u32_t arg4, u32_t arg5, u32_t arg4, u32_t arg5,
u32_t call_id); u32_t call_id);

View file

@ -31,8 +31,8 @@
* - Many kernel calls do no sanity checking of parameters other than * - Many kernel calls do no sanity checking of parameters other than
* assertions. The handler must check all of these conditions using * assertions. The handler must check all of these conditions using
* _SYSCALL_ASSERT() * _SYSCALL_ASSERT()
* - If the system call has more then 5 arguments, then arg5 will be a pointer * - If the system call has more than 6 arguments, then arg6 will be a pointer
* to some struct containing arguments 5+. The struct itself needs to be * to some struct containing arguments 6+. The struct itself needs to be
* validated like any other buffer passed in from userspace, and its members * validated like any other buffer passed in from userspace, and its members
* individually validated (if necessary) and then passed to the real * individually validated (if necessary) and then passed to the real
* implementation like normal arguments * implementation like normal arguments
@ -47,6 +47,7 @@
* @param arg3 system call argument 3 * @param arg3 system call argument 3
* @param arg4 system call argument 4 * @param arg4 system call argument 4
* @param arg5 system call argument 5 * @param arg5 system call argument 5
* @param arg6 system call argument 6
* @param ssf System call stack frame pointer. Used to generate kernel oops * @param ssf System call stack frame pointer. Used to generate kernel oops
* via _arch_syscall_oops_at(). Contents are arch-specific. * via _arch_syscall_oops_at(). Contents are arch-specific.
* @return system call return value, or 0 if the system call implementation * @return system call return value, or 0 if the system call implementation
@ -54,7 +55,8 @@
* *
*/ */
typedef u32_t (*_k_syscall_handler_t)(u32_t arg1, u32_t arg2, u32_t arg3, typedef u32_t (*_k_syscall_handler_t)(u32_t arg1, u32_t arg2, u32_t arg3,
u32_t arg4, u32_t arg5, void *ssf); u32_t arg4, u32_t arg5, u32_t arg6,
void *ssf);
extern const _k_syscall_handler_t _k_syscall_table[K_SYSCALL_LIMIT]; extern const _k_syscall_handler_t _k_syscall_table[K_SYSCALL_LIMIT];
@ -94,18 +96,20 @@ extern const _k_syscall_handler_t _k_syscall_table[K_SYSCALL_LIMIT];
/* Convenience macros for handler implementations */ /* Convenience macros for handler implementations */
#define _SYSCALL_ARG0 ARG_UNUSED(arg1); ARG_UNUSED(arg2); ARG_UNUSED(arg3); \ #define _SYSCALL_ARG0 ARG_UNUSED(arg1); ARG_UNUSED(arg2); ARG_UNUSED(arg3); \
ARG_UNUSED(arg4); ARH_UNUSED(arg5) ARG_UNUSED(arg4); ARH_UNUSED(arg5); ARG_UNUSED(arg6)
#define _SYSCALL_ARG1 ARG_UNUSED(arg2); ARG_UNUSED(arg3); ARG_UNUSED(arg4); \ #define _SYSCALL_ARG1 ARG_UNUSED(arg2); ARG_UNUSED(arg3); ARG_UNUSED(arg4); \
ARG_UNUSED(arg5) ARG_UNUSED(arg5); ARG_UNUSED(arg6)
#define _SYSCALL_ARG2 ARG_UNUSED(arg3); ARG_UNUSED(arg4); ARG_UNUSED(arg5) #define _SYSCALL_ARG2 ARG_UNUSED(arg3); ARG_UNUSED(arg4); ARG_UNUSED(arg5); \
ARG_UNUSED(arg6)
#define _SYSCALL_ARG3 ARG_UNUSED(arg4); ARG_UNUSED(arg5) #define _SYSCALL_ARG3 ARG_UNUSED(arg4); ARG_UNUSED(arg5); ARG_UNUSED(arg6)
#define _SYSCALL_ARG4 ARG_UNUSED(arg5)
#define _SYSCALL_ARG4 ARG_UNUSED(arg5); ARG_UNUSED(arg6)
#define _SYSCALL_ARG5 ARG_UNUSED(arg6)
#endif /* _ASMLANGUAGE */ #endif /* _ASMLANGUAGE */
#endif /* _ZEPHYR_SYSCALL_H_ */ #endif /* _ZEPHYR_SYSCALL_H_ */

View file

@ -183,7 +183,7 @@ void _k_object_init(void *object)
} }
static u32_t _syscall_bad_handler(u32_t bad_id, u32_t arg2, u32_t arg3, static u32_t _syscall_bad_handler(u32_t bad_id, u32_t arg2, u32_t arg3,
u32_t arg4, u32_t arg5, void *ssf) u32_t arg4, u32_t arg5, u32_t arg6, void *ssf)
{ {
printk("Bad system call id %u invoked\n", bad_id); printk("Bad system call id %u invoked\n", bad_id);
_arch_syscall_oops(ssf); _arch_syscall_oops(ssf);