Skip to content

Commit

Permalink
Merge pull request torvalds#120 from ngkaho1234/fix-syscalls2
Browse files Browse the repository at this point in the history
lkl: fix syscalls with 64bit arguments.
  • Loading branch information
Octavian Purdila committed Mar 9, 2016
2 parents d863e04 + 7f139b2 commit ba2e263
Show file tree
Hide file tree
Showing 6 changed files with 273 additions and 16 deletions.
39 changes: 39 additions & 0 deletions arch/lkl/include/asm/syscalls_32.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#ifndef _ASM_SYSCALLS_32_H
#define _ASM_SYSCALLS_32_H

#include <linux/compiler.h>
#include <linux/linkage.h>
#include <linux/types.h>
#include <linux/signal.h>

#if __BITS_PER_LONG == 32

/* kernel/syscalls_32.c */
asmlinkage long sys32_truncate64(const char __user *, unsigned long, unsigned long);
asmlinkage long sys32_ftruncate64(unsigned int, unsigned long, unsigned long);

#ifdef CONFIG_MMU
struct mmap_arg_struct32;
asmlinkage long sys32_mmap(struct mmap_arg_struct32 __user *);
#endif

asmlinkage long sys32_wait4(pid_t, unsigned int __user *, int, struct rusage __user *);

asmlinkage long sys32_pread64(unsigned int, char __user *, u32, u32, u32);
asmlinkage long sys32_pwrite64(unsigned int, const char __user *, u32, u32, u32);

long sys32_fadvise64_64(int, __u32, __u32, __u32, __u32, int);

asmlinkage ssize_t sys32_readahead(int, unsigned, unsigned, size_t);
asmlinkage long sys32_sync_file_range(int, unsigned, unsigned,
unsigned, unsigned, unsigned int);
asmlinkage long sys32_sync_file_range2(int, unsigned int,
unsigned, unsigned,
unsigned, unsigned);
asmlinkage long sys32_fadvise64(int, unsigned, unsigned, size_t, int);
asmlinkage long sys32_fallocate(int, int, unsigned,
unsigned, unsigned, unsigned);

#endif /* __BITS_PER_LONG */

#endif /* _ASM_SYSCALLS_32_H */
30 changes: 30 additions & 0 deletions arch/lkl/include/asm/unistd_32.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#include <asm/bitsperlong.h>

#ifndef __SYSCALL
#define __SYSCALL(x, y)
#endif

#if __BITS_PER_LONG == 32
__SYSCALL(__NR3264_truncate, sys32_truncate64)
__SYSCALL(__NR3264_ftruncate, sys32_ftruncate64)

#ifdef CONFIG_MMU
__SYSCALL(__NR3264_mmap, sys32_mmap)
#endif

__SYSCALL(__NR_wait4, sys32_wait4)

__SYSCALL(__NR_pread64, sys32_pread64)
__SYSCALL(__NR_pwrite64, sys32_pwrite64)

__SYSCALL(__NR_readahead, sys32_readahead)
#ifdef __ARCH_WANT_SYNC_FILE_RANGE2
__SYSCALL(__NR_sync_file_range2, sys32_sync_file_range2)
#else
__SYSCALL(__NR_sync_file_range, sys32_sync_file_range)
#endif
/* mm/fadvise.c */
__SYSCALL(__NR3264_fadvise64, sys32_fadvise64_64)
__SYSCALL(__NR_fallocate, sys32_fallocate)

#endif
36 changes: 36 additions & 0 deletions arch/lkl/include/uapi/asm/syscalls.h
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ long lkl_sys_halt(void);
#define __MAP(n,...) __MAP##n(__VA_ARGS__)

#define __SC_LONG(t, a) (long)a
#define __SC_TABLE(t, a) {sizeof(t), (long long)(a)}
#define __SC_DECL(t, a) t a

#define LKL_SYSCALL0(name) \
Expand All @@ -232,13 +233,39 @@ long lkl_sys_halt(void);
return lkl_syscall(__lkl__NR##name, params); \
}

#if __BITS_PER_LONG == 32
#define LKL_SYSCALLx(x, name, ...) \
static inline \
long lkl_sys##name(__MAP(x, __SC_DECL, __VA_ARGS__)) \
{ \
struct { \
unsigned int size; \
long long value; \
} lkl_params[x] = { __MAP(x, __SC_TABLE, __VA_ARGS__) }; \
long params[6], i, k; \
for (i = k = 0;i < x && k < 6;i++, k++) { \
if (lkl_params[i].size > sizeof(long) && \
k + 1 < 6) { \
params[k] = \
(long)(lkl_params[i].value & (-1UL)); \
k++; \
params[k] = \
(long)(lkl_params[i].value >> __BITS_PER_LONG); \
} else { \
params[k] = (long)(lkl_params[i].value); \
} \
} \
return lkl_syscall(__lkl__NR##name, params); \
}
#else
#define LKL_SYSCALLx(x, name, ...) \
static inline \
long lkl_sys##name(__MAP(x, __SC_DECL, __VA_ARGS__)) \
{ \
long params[6] = { __MAP(x, __SC_LONG, __VA_ARGS__) }; \
return lkl_syscall(__lkl__NR##name, params); \
}
#endif

#define SYSCALL_DEFINE0(name, ...) LKL_SYSCALL0(name)
#define SYSCALL_DEFINE1(name, ...) LKL_SYSCALLx(1, name, __VA_ARGS__)
Expand All @@ -248,6 +275,15 @@ long lkl_sys_halt(void);
#define SYSCALL_DEFINE5(name, ...) LKL_SYSCALLx(5, name, __VA_ARGS__)
#define SYSCALL_DEFINE6(name, ...) LKL_SYSCALLx(6, name, __VA_ARGS__)

#if __BITS_PER_LONG == 32
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpointer-to-int-cast"
#endif

#include <asm/syscall_defs.h>

#if __BITS_PER_LONG == 32
#pragma GCC diagnostic pop
#endif

#endif
2 changes: 1 addition & 1 deletion arch/lkl/kernel/Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
extra-y := vmlinux.lds

obj-y = setup.o threads.o irq.o time.o syscalls.o misc.o mem.o console.o
obj-y = setup.o threads.o irq.o time.o syscalls.o misc.o mem.o console.o syscalls_32.o
22 changes: 7 additions & 15 deletions arch/lkl/kernel/syscalls.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <linux/kthread.h>
#include <asm/host_ops.h>
#include <asm/syscalls.h>
#include <asm/syscalls_32.h>

struct syscall_thread_data;
static asmlinkage long sys_create_syscall_thread(struct syscall_thread_data *);
Expand All @@ -23,6 +24,10 @@ typedef long (*syscall_handler_t)(long arg1, ...);
syscall_handler_t syscall_table[__NR_syscalls] = {
[0 ... __NR_syscalls - 1] = (syscall_handler_t)sys_ni_syscall,
#include <asm/unistd.h>

#if __BITS_PER_LONG == 32
#include <asm/unistd_32.h>
#endif
};

struct syscall {
Expand Down Expand Up @@ -54,10 +59,11 @@ static long run_syscall(struct syscall *s)

if (s->no < 0 || s->no >= __NR_syscalls)
ret = -ENOSYS;
else
else {
ret = syscall_table[s->no](s->params[0], s->params[1],
s->params[2], s->params[3],
s->params[4], s->params[5]);
}
s->ret = ret;

task_work_run();
Expand Down Expand Up @@ -319,20 +325,6 @@ long lkl_syscall(long no, long *params)
return __lkl_syscall(data, no, params);
}

asmlinkage
ssize_t sys_lkl_pwrite64(unsigned int fd, const char *buf, size_t count,
off_t pos_hi, off_t pos_lo)
{
return sys_pwrite64(fd, buf, count, ((loff_t)pos_hi << 32) + pos_lo);
}

asmlinkage
ssize_t sys_lkl_pread64(unsigned int fd, char *buf, size_t count,
off_t pos_hi, off_t pos_lo)
{
return sys_pread64(fd, buf, count, ((loff_t)pos_hi << 32) + pos_lo);
}

static asmlinkage long
sys_create_syscall_thread(struct syscall_thread_data *data)
{
Expand Down
160 changes: 160 additions & 0 deletions arch/lkl/kernel/syscalls_32.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
/*
* sys_ia32.c: Conversion between 32bit and 64bit native syscalls. Based on
* sys_sparc32
*
* Copyright (C) 2000 VA Linux Co
* Copyright (C) 2000 Don Dugger <n0ano@valinux.com>
* Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com>
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 2000 Hewlett-Packard Co.
* Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com>
* Copyright (C) 2000,2001,2002 Andi Kleen, SuSE Labs (x86-64 port)
*
* These routines maintain argument size conversion between 32bit and 64bit
* environment. In 2.5 most of this should be moved to a generic directory.
*
* This file assumes that there is a hole at the end of user address space.
*
* Some of the functions are LE specific currently. These are
* hopefully all marked. This should be fixed.
*/

#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/signal.h>
#include <linux/syscalls.h>
#include <linux/times.h>
#include <linux/utsname.h>
#include <linux/mm.h>
#include <linux/uio.h>
#include <linux/poll.h>
#include <linux/personality.h>
#include <linux/stat.h>
#include <linux/rwsem.h>
#include <linux/compat.h>
#include <linux/vfs.h>
#include <linux/ptrace.h>
#include <linux/highuid.h>
#include <linux/sysctl.h>
#include <linux/slab.h>
#include <asm/types.h>
#include <linux/atomic.h>
#include <asm/syscalls_32.h>

#define AA(__x) ((unsigned long)(__x))

#if __BITS_PER_LONG == 32

asmlinkage long sys32_truncate64(const char __user *filename,
unsigned long offset_low,
unsigned long offset_high)
{
return sys_truncate64(filename, ((loff_t) offset_high << 32) | offset_low);
}

asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long offset_low,
unsigned long offset_high)
{
return sys_ftruncate64(fd, ((loff_t) offset_high << 32) | offset_low);
}

#ifdef CONFIG_MMU
/*
* Linux/i386 didn't use to be able to handle more than
* 4 system call parameters, so these system calls used a memory
* block for parameter passing..
*/

struct mmap_arg_struct32 {
unsigned int addr;
unsigned int len;
unsigned int prot;
unsigned int flags;
unsigned int fd;
unsigned int offset;
};

asmlinkage long sys32_mmap(struct mmap_arg_struct32 __user *arg)
{
struct mmap_arg_struct32 a;

if (copy_from_user(&a, arg, sizeof(a)))
return -EFAULT;

if (a.offset & ~PAGE_MASK)
return -EINVAL;

return sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd,
a.offset>>PAGE_SHIFT);
}
#endif

asmlinkage long sys32_wait4(pid_t pid, unsigned int __user *stat_addr,
int options, struct rusage __user *ru)
{
return sys_wait4(pid, stat_addr, options, ru);
}

asmlinkage long sys32_pread64(unsigned int fd, char __user *ubuf, u32 count,
u32 poslo, u32 poshi)
{
return sys_pread64(fd, ubuf, count,
((loff_t)AA(poshi) << 32) | AA(poslo));
}

asmlinkage long sys32_pwrite64(unsigned int fd, const char __user *ubuf,
u32 count, u32 poslo, u32 poshi)
{
return sys_pwrite64(fd, ubuf, count,
((loff_t)AA(poshi) << 32) | AA(poslo));
}


/*
* Some system calls that need sign extended arguments. This could be
* done by a generic wrapper.
*/
long sys32_fadvise64_64(int fd, __u32 offset_low, __u32 offset_high,
__u32 len_low, __u32 len_high, int advice)
{
return sys_fadvise64_64(fd,
(((u64)offset_high)<<32) | offset_low,
(((u64)len_high)<<32) | len_low,
advice);
}

asmlinkage ssize_t sys32_readahead(int fd, unsigned off_lo, unsigned off_hi,
size_t count)
{
return sys_readahead(fd, ((u64)off_hi << 32) | off_lo, count);
}

asmlinkage long sys32_sync_file_range(int fd, unsigned off_low, unsigned off_hi,
unsigned n_low, unsigned n_hi, unsigned int flags)
{
return sys_sync_file_range(fd,
((u64)off_hi << 32) | off_low,
((u64)n_hi << 32) | n_low, flags);
}

asmlinkage long sys32_sync_file_range2(int fd, unsigned int flags,
unsigned off_low, unsigned off_hi,
unsigned n_low, unsigned n_hi)
{
return sys_sync_file_range(fd,
((u64)off_hi << 32) | off_low,
((u64)n_hi << 32) | n_low, flags);
}

asmlinkage long sys32_fallocate(int fd, int mode, unsigned offset_lo,
unsigned offset_hi, unsigned len_lo,
unsigned len_hi)
{
return sys_fallocate(fd, mode, ((u64)offset_hi << 32) | offset_lo,
((u64)len_hi << 32) | len_lo);
}

#endif

0 comments on commit ba2e263

Please sign in to comment.