Commit 0e97e2a2 authored by Andi Kleen's avatar Andi Kleen Committed by Linus Torvalds

[PATCH] x86-64 IA32 emulation updates

Some bugfixes for the 32bit emulation for x86-64 and make it all compile
again.

Has rewritten ioctl registration code and some other updates.  New
system calls are supported.

It unfortunately broke some time ago by binfmt_elf changes for all
shared linked libraries.  Will fix that later.
parent fb06dbb1
...@@ -2,17 +2,10 @@ ...@@ -2,17 +2,10 @@
# Makefile for the ia32 kernel emulation subsystem. # Makefile for the ia32 kernel emulation subsystem.
# #
USE_STANDARD_AS_RULE := true
export-objs := ia32_ioctl.o sys_ia32.o export-objs := ia32_ioctl.o sys_ia32.o
all: ia32.o
O_TARGET := ia32.o
obj-$(CONFIG_IA32_EMULATION) := ia32entry.o sys_ia32.o ia32_ioctl.o \ obj-$(CONFIG_IA32_EMULATION) := ia32entry.o sys_ia32.o ia32_ioctl.o \
ia32_signal.o \ ia32_signal.o \
ia32_binfmt.o fpu32.o socket32.o ptrace32.o ipc32.o ia32_binfmt.o fpu32.o socket32.o ptrace32.o ipc32.o
clean::
include $(TOPDIR)/Rules.make include $(TOPDIR)/Rules.make
...@@ -58,6 +58,8 @@ struct timeval32 ...@@ -58,6 +58,8 @@ struct timeval32
int tv_sec, tv_usec; int tv_sec, tv_usec;
}; };
#define jiffies_to_timeval(a,b) do { (b)->tv_usec = 0; (b)->tv_sec = (a)/HZ; }while(0)
struct elf_prstatus struct elf_prstatus
{ {
struct elf_siginfo pr_info; /* Info associated with signal */ struct elf_siginfo pr_info; /* Info associated with signal */
...@@ -162,6 +164,7 @@ do { \ ...@@ -162,6 +164,7 @@ do { \
#define ELF_PLAT_INIT(r) elf32_init(r) #define ELF_PLAT_INIT(r) elf32_init(r)
#define setup_arg_pages(bprm) ia32_setup_arg_pages(bprm) #define setup_arg_pages(bprm) ia32_setup_arg_pages(bprm)
int ia32_setup_arg_pages(struct linux_binprm *bprm);
#undef start_thread #undef start_thread
#define start_thread(regs,new_rip,new_rsp) do { \ #define start_thread(regs,new_rip,new_rsp) do { \
......
This diff is collapsed.
...@@ -81,11 +81,11 @@ sys32_sigsuspend(int history0, int history1, old_sigset_t mask, struct pt_regs r ...@@ -81,11 +81,11 @@ sys32_sigsuspend(int history0, int history1, old_sigset_t mask, struct pt_regs r
sigset_t saveset; sigset_t saveset;
mask &= _BLOCKABLE; mask &= _BLOCKABLE;
spin_lock_irq(&current->sigmask_lock); spin_lock_irq(&current->sig->siglock);
saveset = current->blocked; saveset = current->blocked;
siginitset(&current->blocked, mask); siginitset(&current->blocked, mask);
recalc_sigpending(); recalc_sigpending();
spin_unlock_irq(&current->sigmask_lock); spin_unlock_irq(&current->sig->siglock);
regs.rax = -EINTR; regs.rax = -EINTR;
while (1) { while (1) {
...@@ -170,10 +170,7 @@ ia32_restore_sigcontext(struct pt_regs *regs, struct sigcontext_ia32 *sc, unsign ...@@ -170,10 +170,7 @@ ia32_restore_sigcontext(struct pt_regs *regs, struct sigcontext_ia32 *sc, unsign
asm volatile("movl %%" #seg ",%0" : "=r" (cur)); \ asm volatile("movl %%" #seg ",%0" : "=r" (cur)); \
if (pre != cur) loadsegment(seg,pre); } if (pre != cur) loadsegment(seg,pre); }
/* Reload fs and gs if they have changed in the signal handler. /* Reload fs and gs if they have changed in the signal handler. */
This does not handle long fs/gs base changes in the handler, but does not clobber
them at least in the normal case. */
{ {
unsigned short gs; unsigned short gs;
...@@ -181,11 +178,18 @@ ia32_restore_sigcontext(struct pt_regs *regs, struct sigcontext_ia32 *sc, unsign ...@@ -181,11 +178,18 @@ ia32_restore_sigcontext(struct pt_regs *regs, struct sigcontext_ia32 *sc, unsign
load_gs_index(gs); load_gs_index(gs);
} }
RELOAD_SEG(fs); RELOAD_SEG(fs);
RELOAD_SEG(ds);
RELOAD_SEG(es);
COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx); COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
COPY(dx); COPY(cx); COPY(ip); COPY(dx); COPY(cx); COPY(ip);
/* Don't touch extended registers */ /* Don't touch extended registers */
err |= __get_user(regs->cs, &sc->cs);
regs->cs |= 2;
err |= __get_user(regs->ss, &sc->ss);
regs->ss |= 2;
{ {
unsigned int tmpflags; unsigned int tmpflags;
err |= __get_user(tmpflags, &sc->eflags); err |= __get_user(tmpflags, &sc->eflags);
...@@ -231,10 +235,10 @@ asmlinkage int sys32_sigreturn(struct pt_regs regs) ...@@ -231,10 +235,10 @@ asmlinkage int sys32_sigreturn(struct pt_regs regs)
goto badframe; goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE); sigdelsetmask(&set, ~_BLOCKABLE);
spin_lock_irq(&current->sigmask_lock); spin_lock_irq(&current->sig->siglock);
current->blocked = set; current->blocked = set;
recalc_sigpending(); recalc_sigpending();
spin_unlock_irq(&current->sigmask_lock); spin_unlock_irq(&current->sig->siglock);
if (ia32_restore_sigcontext(&regs, &frame->sc, &eax)) if (ia32_restore_sigcontext(&regs, &frame->sc, &eax))
goto badframe; goto badframe;
...@@ -258,10 +262,10 @@ asmlinkage int sys32_rt_sigreturn(struct pt_regs regs) ...@@ -258,10 +262,10 @@ asmlinkage int sys32_rt_sigreturn(struct pt_regs regs)
goto badframe; goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE); sigdelsetmask(&set, ~_BLOCKABLE);
spin_lock_irq(&current->sigmask_lock); spin_lock_irq(&current->sig->siglock);
current->blocked = set; current->blocked = set;
recalc_sigpending(); recalc_sigpending();
spin_unlock_irq(&current->sigmask_lock); spin_unlock_irq(&current->sig->siglock);
if (ia32_restore_sigcontext(&regs, &frame->uc.uc_mcontext, &eax)) if (ia32_restore_sigcontext(&regs, &frame->uc.uc_mcontext, &eax))
goto badframe; goto badframe;
...@@ -299,6 +303,10 @@ ia32_setup_sigcontext(struct sigcontext_ia32 *sc, struct _fpstate_ia32 *fpstate, ...@@ -299,6 +303,10 @@ ia32_setup_sigcontext(struct sigcontext_ia32 *sc, struct _fpstate_ia32 *fpstate,
err |= __put_user(tmp, (unsigned int *)&sc->gs); err |= __put_user(tmp, (unsigned int *)&sc->gs);
__asm__("movl %%fs,%0" : "=r"(tmp): "0"(tmp)); __asm__("movl %%fs,%0" : "=r"(tmp): "0"(tmp));
err |= __put_user(tmp, (unsigned int *)&sc->fs); err |= __put_user(tmp, (unsigned int *)&sc->fs);
__asm__("movl %%ds,%0" : "=r"(tmp): "0"(tmp));
err |= __put_user(tmp, (unsigned int *)&sc->ds);
__asm__("movl %%es,%0" : "=r"(tmp): "0"(tmp));
err |= __put_user(tmp, (unsigned int *)&sc->es);
err |= __put_user((u32)regs->rdi, &sc->edi); err |= __put_user((u32)regs->rdi, &sc->edi);
err |= __put_user((u32)regs->rsi, &sc->esi); err |= __put_user((u32)regs->rsi, &sc->esi);
...@@ -308,6 +316,8 @@ ia32_setup_sigcontext(struct sigcontext_ia32 *sc, struct _fpstate_ia32 *fpstate, ...@@ -308,6 +316,8 @@ ia32_setup_sigcontext(struct sigcontext_ia32 *sc, struct _fpstate_ia32 *fpstate,
err |= __put_user((u32)regs->rdx, &sc->edx); err |= __put_user((u32)regs->rdx, &sc->edx);
err |= __put_user((u32)regs->rcx, &sc->ecx); err |= __put_user((u32)regs->rcx, &sc->ecx);
err |= __put_user((u32)regs->rax, &sc->eax); err |= __put_user((u32)regs->rax, &sc->eax);
err |= __put_user((u32)regs->cs, &sc->cs);
err |= __put_user((u32)regs->ss, &sc->ss);
err |= __put_user(current->thread.trap_no, &sc->trapno); err |= __put_user(current->thread.trap_no, &sc->trapno);
err |= __put_user(current->thread.error_code, &sc->err); err |= __put_user(current->thread.error_code, &sc->err);
err |= __put_user((u32)regs->rip, &sc->eip); err |= __put_user((u32)regs->rip, &sc->eip);
...@@ -406,8 +416,13 @@ void ia32_setup_frame(int sig, struct k_sigaction *ka, ...@@ -406,8 +416,13 @@ void ia32_setup_frame(int sig, struct k_sigaction *ka,
regs->rsp = (unsigned long) frame; regs->rsp = (unsigned long) frame;
regs->rip = (unsigned long) ka->sa.sa_handler; regs->rip = (unsigned long) ka->sa.sa_handler;
asm volatile("movl %0,%%ds" :: "r" (__USER32_DS));
asm volatile("movl %0,%%es" :: "r" (__USER32_DS));
regs->cs = __USER32_CS;
regs->ss = __USER32_DS;
set_fs(USER_DS); set_fs(USER_DS);
// XXX: cs
regs->eflags &= ~TF_MASK; regs->eflags &= ~TF_MASK;
#if DEBUG_SIG #if DEBUG_SIG
...@@ -479,8 +494,13 @@ void ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, ...@@ -479,8 +494,13 @@ void ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
regs->rsp = (unsigned long) frame; regs->rsp = (unsigned long) frame;
regs->rip = (unsigned long) ka->sa.sa_handler; regs->rip = (unsigned long) ka->sa.sa_handler;
asm volatile("movl %0,%%ds" :: "r" (__USER32_DS));
asm volatile("movl %0,%%es" :: "r" (__USER32_DS));
regs->cs = __USER32_CS;
regs->ss = __USER32_DS;
set_fs(USER_DS); set_fs(USER_DS);
// XXX: cs
regs->eflags &= ~TF_MASK; regs->eflags &= ~TF_MASK;
#if DEBUG_SIG #if DEBUG_SIG
......
...@@ -171,7 +171,7 @@ ia32_sys_call_table: ...@@ -171,7 +171,7 @@ ia32_sys_call_table:
.quad sys_umount /* new_umount */ .quad sys_umount /* new_umount */
.quad ni_syscall /* old lock syscall holder */ .quad ni_syscall /* old lock syscall holder */
.quad sys32_ioctl .quad sys32_ioctl
.quad sys32_fcntl /* 55 */ .quad sys32_fcntl64 /* 55 */
.quad ni_syscall /* old mpx syscall holder */ .quad ni_syscall /* old mpx syscall holder */
.quad sys_setpgid .quad sys_setpgid
.quad ni_syscall /* old ulimit syscall holder */ .quad ni_syscall /* old ulimit syscall holder */
...@@ -319,15 +319,15 @@ ia32_sys_call_table: ...@@ -319,15 +319,15 @@ ia32_sys_call_table:
.quad sys_getgid /* 200 */ .quad sys_getgid /* 200 */
.quad sys_geteuid .quad sys_geteuid
.quad sys_getegid .quad sys_getegid
.quad sys32_setreuid .quad sys_setreuid
.quad sys32_setregid .quad sys_setregid
.quad sys32_getgroups /* 205 */ .quad sys_getgroups /* 205 */
.quad sys32_setgroups .quad sys_setgroups
.quad sys_fchown .quad sys_fchown
.quad sys32_setresuid .quad sys_setresuid
.quad sys32_getresuid .quad sys_getresuid
.quad sys32_setresgid /* 210 */ .quad sys_setresgid /* 210 */
.quad sys32_getresgid .quad sys_getresgid
.quad sys_chown .quad sys_chown
.quad sys_setuid .quad sys_setuid
.quad sys_setgid .quad sys_setgid
...@@ -356,9 +356,19 @@ ia32_sys_call_table: ...@@ -356,9 +356,19 @@ ia32_sys_call_table:
.quad sys_fremovexattr .quad sys_fremovexattr
.quad sys_tkill /* 238 */ .quad sys_tkill /* 238 */
.quad sys_sendfile64 .quad sys_sendfile64
.quad sys_futex .quad sys_futex /* 240 */
.quad sys32_sched_setaffinity .quad sys32_sched_setaffinity
.quad sys32_sched_getaffinity .quad sys32_sched_getaffinity
.quad sys_set_thread_area
.quad sys_get_thread_area
.quad sys32_io_setup
.quad sys_io_destroy
.quad sys_io_getevents
.quad sys_io_submit
.quad sys_io_cancel
.quad sys_ni_syscall /* 250 alloc_huge_pages */
.quad sys_ni_syscall /* free_huge_pages */
.quad sys_ni_syscall /* exit_group */
ia32_syscall_end: ia32_syscall_end:
.rept IA32_NR_syscalls-(ia32_syscall_end-ia32_sys_call_table)/8 .rept IA32_NR_syscalls-(ia32_syscall_end-ia32_sys_call_table)/8
.quad ni_syscall .quad ni_syscall
......
...@@ -152,8 +152,8 @@ struct shm_info32 { ...@@ -152,8 +152,8 @@ struct shm_info32 {
}; };
struct ipc_kludge { struct ipc_kludge {
struct msgbuf *msgp; u32 msgp;
int msgtyp; s32 msgtyp;
}; };
...@@ -268,14 +268,19 @@ semctl32 (int first, int second, int third, void *uptr) ...@@ -268,14 +268,19 @@ semctl32 (int first, int second, int third, void *uptr)
return err; return err;
} }
#define MAXBUF (64*1024)
static int static int
do_sys32_msgsnd (int first, int second, int third, void *uptr) do_sys32_msgsnd (int first, int second, int third, void *uptr)
{ {
struct msgbuf *p = kmalloc(second + sizeof(struct msgbuf) + 4, GFP_USER); struct msgbuf *p;
struct msgbuf32 *up = (struct msgbuf32 *)uptr; struct msgbuf32 *up = (struct msgbuf32 *)uptr;
mm_segment_t old_fs; mm_segment_t old_fs;
int err; int err;
if (second >= MAXBUF-sizeof(struct msgbuf))
return -EINVAL;
p = kmalloc(second + sizeof(struct msgbuf), GFP_USER);
if (!p) if (!p)
return -ENOMEM; return -ENOMEM;
err = get_user(p->mtype, &up->mtype); err = get_user(p->mtype, &up->mtype);
...@@ -312,13 +317,15 @@ do_sys32_msgrcv (int first, int second, int msgtyp, int third, int version, void ...@@ -312,13 +317,15 @@ do_sys32_msgrcv (int first, int second, int msgtyp, int third, int version, void
uptr = (void *)A(ipck.msgp); uptr = (void *)A(ipck.msgp);
msgtyp = ipck.msgtyp; msgtyp = ipck.msgtyp;
} }
if (second >= MAXBUF-sizeof(struct msgbuf))
return -EINVAL;
err = -ENOMEM; err = -ENOMEM;
p = kmalloc(second + sizeof(struct msgbuf) + 4, GFP_USER); p = kmalloc(second + sizeof(struct msgbuf), GFP_USER);
if (!p) if (!p)
goto out; goto out;
old_fs = get_fs(); old_fs = get_fs();
set_fs(KERNEL_DS); set_fs(KERNEL_DS);
err = sys_msgrcv(first, p, second + 4, msgtyp, third); err = sys_msgrcv(first, p, second, msgtyp, third);
set_fs(old_fs); set_fs(old_fs);
if (err < 0) if (err < 0)
goto free_then_out; goto free_then_out;
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <asm/i387.h> #include <asm/i387.h>
#include <asm/fpu32.h> #include <asm/fpu32.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/ptrace.h>
#define R32(l,q) \ #define R32(l,q) \
case offsetof(struct user32, regs.l): stack[offsetof(struct pt_regs, q)/8] = val; break case offsetof(struct user32, regs.l): stack[offsetof(struct pt_regs, q)/8] = val; break
...@@ -35,20 +36,32 @@ static int putreg32(struct task_struct *child, unsigned regno, u32 val) ...@@ -35,20 +36,32 @@ static int putreg32(struct task_struct *child, unsigned regno, u32 val)
switch (regno) { switch (regno) {
case offsetof(struct user32, regs.fs): case offsetof(struct user32, regs.fs):
if (val && (val & 3) != 3) return -EIO;
child->thread.fs = val; child->thread.fs = val;
break; break;
case offsetof(struct user32, regs.gs): case offsetof(struct user32, regs.gs):
if (val && (val & 3) != 3) return -EIO;
child->thread.gs = val; child->thread.gs = val;
break; break;
case offsetof(struct user32, regs.ds): case offsetof(struct user32, regs.ds):
if (val && (val & 3) != 3) return -EIO;
child->thread.ds = val; child->thread.ds = val;
break; break;
case offsetof(struct user32, regs.es): case offsetof(struct user32, regs.es):
if (val && (val & 3) != 3) return -EIO;
child->thread.es = val; child->thread.es = val;
break; break;
R32(cs, cs); case offsetof(struct user32, regs.ss):
R32(ss, ss); if ((val & 3) != 3) return -EIO;
stack[offsetof(struct pt_regs, ss)/8] = val;
break;
case offsetof(struct user32, regs.cs):
if ((val & 3) != 3) return -EIO;
stack[offsetof(struct pt_regs, cs)/8] = val;
break;
R32(ebx, rbx); R32(ebx, rbx);
R32(ecx, rcx); R32(ecx, rcx);
R32(edx, rdx); R32(edx, rdx);
......
...@@ -57,6 +57,7 @@ ...@@ -57,6 +57,7 @@
#include <linux/ipc.h> #include <linux/ipc.h>
#include <linux/rwsem.h> #include <linux/rwsem.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/aio_abi.h>
#include <asm/mman.h> #include <asm/mman.h>
#include <asm/types.h> #include <asm/types.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
...@@ -1288,37 +1289,71 @@ static inline int put_flock(struct flock *kfl, struct flock32 *ufl) ...@@ -1288,37 +1289,71 @@ static inline int put_flock(struct flock *kfl, struct flock32 *ufl)
extern asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg); extern asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg);
asmlinkage long sys32_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg) static inline int get_flock64(struct ia32_flock64 *fl32, struct flock *fl64)
{ {
switch (cmd) { if (access_ok(fl32, sizeof(struct ia32_flock64), VERIFY_WRITE)) {
case F_GETLK: int ret = __get_user(fl64->l_type, &fl32->l_type);
case F_SETLK: ret |= __get_user(fl64->l_whence, &fl32->l_whence);
case F_SETLKW: ret |= __get_user(fl64->l_start, &fl32->l_start);
{ ret |= __get_user(fl64->l_len, &fl32->l_len);
struct flock f; ret |= __get_user(fl64->l_pid, &fl32->l_pid);
mm_segment_t old_fs; return ret;
long ret;
if (get_flock(&f, (struct flock32 *)arg))
return -EFAULT;
old_fs = get_fs(); set_fs (KERNEL_DS);
ret = sys_fcntl(fd, cmd, (unsigned long)&f);
set_fs (old_fs);
if (ret) return ret;
if (put_flock(&f, (struct flock32 *)arg))
return -EFAULT;
return 0;
} }
default: return -EFAULT;
return sys_fcntl(fd, cmd, (unsigned long)arg); }
static inline int put_flock64(struct ia32_flock64 *fl32, struct flock *fl64)
{
if (access_ok(fl32, sizeof(struct ia32_flock64), VERIFY_WRITE)) {
int ret = __put_user(fl64->l_type, &fl32->l_type);
ret |= __put_user(fl64->l_whence, &fl32->l_whence);
ret |= __put_user(fl64->l_start, &fl32->l_start);
ret |= __put_user(fl64->l_len, &fl32->l_len);
ret |= __put_user(fl64->l_pid, &fl32->l_pid);
return ret;
} }
return -EFAULT;
} }
asmlinkage long sys32_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg) asmlinkage long sys32_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg)
{ {
if (cmd >= F_GETLK64 && cmd <= F_SETLKW64) struct flock fl64;
return sys_fcntl(fd, cmd + F_GETLK - F_GETLK64, arg); mm_segment_t oldfs = get_fs();
return sys32_fcntl(fd, cmd, arg); int ret = 0, origcmd;
unsigned long origarg;
origcmd = cmd;
origarg = arg;
switch (cmd) {
case F_GETLK:
case F_SETLK:
case F_SETLKW:
ret = get_flock(&fl64, (struct flock32 *)arg);
arg = (unsigned long) &fl64;
set_fs(KERNEL_DS);
break;
case F_GETLK64:
cmd = F_GETLK;
goto cnv64;
case F_SETLK64:
cmd = F_SETLK;
goto cnv64;
case F_SETLKW64:
cmd = F_SETLKW;
cnv64:
ret = get_flock64((struct ia32_flock64 *)arg, &fl64);
arg = (unsigned long)&fl64;
set_fs(KERNEL_DS);
break;
}
if (!ret)
ret = sys_fcntl(fd, cmd, arg);
set_fs(oldfs);
if (origcmd == F_GETLK && !ret)
ret = put_flock(&fl64, (struct flock32 *)origarg);
else if (cmd == F_GETLK && !ret)
ret = put_flock64((struct ia32_flock64 *)origarg, &fl64);
return ret;
} }
int sys32_ni_syscall(int call) int sys32_ni_syscall(int call)
...@@ -1362,42 +1397,6 @@ sys32_utime(char * filename, struct utimbuf32 *times) ...@@ -1362,42 +1397,6 @@ sys32_utime(char * filename, struct utimbuf32 *times)
return ret; return ret;
} }
/*
* Ooo, nasty. We need here to frob 32-bit unsigned longs to
* 64-bit unsigned longs.
*/
static inline int
get_fd_set32(unsigned long n, unsigned long *fdset, u32 *ufdset)
{
if (ufdset) {
unsigned long odd;
if (verify_area(VERIFY_READ, ufdset, n*sizeof(u32)))
return -EFAULT;
odd = n & 1UL;
n &= ~1UL;
while (n) {
unsigned long h, l;
__get_user(l, ufdset);
__get_user(h, ufdset+1);
ufdset += 2;
*fdset++ = h << 32 | l;
n -= 2;
}
if (odd)
__get_user(*fdset, ufdset);
} else {
/* Tricky, must clear full unsigned long in the
* kernel fdset at the end, this makes sure that
* actually happens.
*/
memset(fdset, 0, ((n + 1) & ~1)*sizeof(u32));
}
return 0;
}
extern asmlinkage long sys_sysfs(int option, unsigned long arg1, extern asmlinkage long sys_sysfs(int option, unsigned long arg1,
unsigned long arg2); unsigned long arg2);
...@@ -1704,136 +1703,6 @@ sys32_rt_sigqueueinfo(int pid, int sig, siginfo_t32 *uinfo) ...@@ -1704,136 +1703,6 @@ sys32_rt_sigqueueinfo(int pid, int sig, siginfo_t32 *uinfo)
return ret; return ret;
} }
extern asmlinkage long sys_setreuid(uid_t ruid, uid_t euid);
asmlinkage long sys32_setreuid(__kernel_uid_t32 ruid, __kernel_uid_t32 euid)
{
uid_t sruid, seuid;
sruid = (ruid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)ruid);
seuid = (euid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)euid);
return sys_setreuid(sruid, seuid);
}
extern asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid);
asmlinkage long
sys32_setresuid(__kernel_uid_t32 ruid, __kernel_uid_t32 euid,
__kernel_uid_t32 suid)
{
uid_t sruid, seuid, ssuid;
sruid = (ruid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)ruid);
seuid = (euid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)euid);
ssuid = (suid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)suid);
return sys_setresuid(sruid, seuid, ssuid);
}
extern asmlinkage long sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid);
asmlinkage long
sys32_getresuid(__kernel_uid_t32 *ruid, __kernel_uid_t32 *euid,
__kernel_uid_t32 *suid)
{
uid_t a, b, c;
int ret;
mm_segment_t old_fs = get_fs();
set_fs (KERNEL_DS);
ret = sys_getresuid(&a, &b, &c);
set_fs (old_fs);
if (put_user (a, ruid) || put_user (b, euid) || put_user (c, suid))
return -EFAULT;
return ret;
}
extern asmlinkage long sys_setregid(gid_t rgid, gid_t egid);
asmlinkage long
sys32_setregid(__kernel_gid_t32 rgid, __kernel_gid_t32 egid)
{
gid_t srgid, segid;
srgid = (rgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)rgid);
segid = (egid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)egid);
return sys_setregid(srgid, segid);
}
extern asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid);
asmlinkage long
sys32_setresgid(__kernel_gid_t32 rgid, __kernel_gid_t32 egid,
__kernel_gid_t32 sgid)
{
gid_t srgid, segid, ssgid;
srgid = (rgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)rgid);
segid = (egid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)egid);
ssgid = (sgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)sgid);
return sys_setresgid(srgid, segid, ssgid);
}
extern asmlinkage long sys_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid);
asmlinkage long
sys32_getresgid(__kernel_gid_t32 *rgid, __kernel_gid_t32 *egid,
__kernel_gid_t32 *sgid)
{
gid_t a, b, c;
int ret;
mm_segment_t old_fs = get_fs();
set_fs (KERNEL_DS);
ret = sys_getresgid(&a, &b, &c);
set_fs (old_fs);
if (!ret) {
ret = put_user (a, rgid);
ret |= put_user (b, egid);
ret |= put_user (c, sgid);
}
return ret;
}
extern asmlinkage long sys_getgroups(int gidsetsize, gid_t *grouplist);
asmlinkage long
sys32_getgroups(int gidsetsize, __kernel_gid_t32 *grouplist)
{
gid_t gl[NGROUPS];
int ret, i;
mm_segment_t old_fs = get_fs ();
set_fs (KERNEL_DS);
ret = sys_getgroups(gidsetsize, gl);
set_fs (old_fs);
if (gidsetsize && ret > 0 && ret <= NGROUPS)
for (i = 0; i < ret; i++, grouplist++)
if (put_user (gl[i], grouplist))
return -EFAULT;
return ret;
}
extern asmlinkage long sys_setgroups(int gidsetsize, gid_t *grouplist);
asmlinkage long
sys32_setgroups(int gidsetsize, __kernel_gid_t32 *grouplist)
{
gid_t gl[NGROUPS];
int ret, i;
mm_segment_t old_fs = get_fs ();
if ((unsigned) gidsetsize > NGROUPS)
return -EINVAL;
for (i = 0; i < gidsetsize; i++, grouplist++)
if (get_user (gl[i], grouplist))
return -EFAULT;
set_fs (KERNEL_DS);
ret = sys_setgroups(gidsetsize, gl);
set_fs (old_fs);
return ret;
}
extern void check_pending(int signum); extern void check_pending(int signum);
asmlinkage long sys_utimes(char *, struct timeval *); asmlinkage long sys_utimes(char *, struct timeval *);
...@@ -1943,7 +1812,7 @@ sys32_newuname(struct new_utsname * name) ...@@ -1943,7 +1812,7 @@ sys32_newuname(struct new_utsname * name)
int ret = sys_newuname(name); int ret = sys_newuname(name);
if (current->personality == PER_LINUX32 && !ret) { if (current->personality == PER_LINUX32 && !ret) {
ret = copy_to_user(name->machine, "i386\0\0", 8); ret = copy_to_user(name->machine, "i686\0\0", 6);
} }
return ret; return ret;
} }
...@@ -2164,7 +2033,7 @@ int sys32_uname(struct old_utsname * name) ...@@ -2164,7 +2033,7 @@ int sys32_uname(struct old_utsname * name)
err=copy_to_user(name, &system_utsname, sizeof (*name)); err=copy_to_user(name, &system_utsname, sizeof (*name));
up_read(&uts_sem); up_read(&uts_sem);
if (current->personality == PER_LINUX32) if (current->personality == PER_LINUX32)
err |= copy_to_user(&name->machine, "i386", 5); err |= copy_to_user(&name->machine, "i686", 5);
return err?-EFAULT:0; return err?-EFAULT:0;
} }
...@@ -2270,16 +2139,17 @@ int sys32_execve(char *name, u32 argv, u32 envp, struct pt_regs regs) ...@@ -2270,16 +2139,17 @@ int sys32_execve(char *name, u32 argv, u32 envp, struct pt_regs regs)
asmlinkage int sys32_fork(struct pt_regs regs) asmlinkage int sys32_fork(struct pt_regs regs)
{ {
struct task_struct *p; struct task_struct *p;
p = do_fork(SIGCHLD, regs.rsp, &regs, 0); p = do_fork(SIGCHLD, regs.rsp, &regs, 0, NULL);
return IS_ERR(p) ? PTR_ERR(p) : p->pid; return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
asmlinkage int sys32_clone(unsigned int clone_flags, unsigned int newsp, struct pt_regs regs) asmlinkage int sys32_clone(unsigned int clone_flags, unsigned int newsp, struct pt_regs regs)
{ {
struct task_struct *p; struct task_struct *p;
int *user_tid = (int *)regs.rdx;
if (!newsp) if (!newsp)
newsp = regs.rsp; newsp = regs.rsp;
p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, &regs, 0); p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, &regs, 0, user_tid);
return IS_ERR(p) ? PTR_ERR(p) : p->pid; return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
...@@ -2296,7 +2166,7 @@ asmlinkage int sys32_clone(unsigned int clone_flags, unsigned int newsp, struct ...@@ -2296,7 +2166,7 @@ asmlinkage int sys32_clone(unsigned int clone_flags, unsigned int newsp, struct
asmlinkage int sys32_vfork(struct pt_regs regs) asmlinkage int sys32_vfork(struct pt_regs regs)
{ {
struct task_struct *p; struct task_struct *p;
p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.rsp, &regs, 0); p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.rsp, &regs, 0, NULL);
return IS_ERR(p) ? PTR_ERR(p) : p->pid; return IS_ERR(p) ? PTR_ERR(p) : p->pid;
} }
...@@ -2695,10 +2565,26 @@ int sys32_sched_getaffinity(pid_t pid, unsigned int len, ...@@ -2695,10 +2565,26 @@ int sys32_sched_getaffinity(pid_t pid, unsigned int len,
return err; return err;
} }
extern long sys_io_setup(unsigned nr_reqs, aio_context_t *ctx);
long sys32_io_setup(unsigned nr_reqs, u32 *ctx32p)
{
long ret;
aio_context_t ctx64;
mm_segment_t oldfs = get_fs();
set_fs(KERNEL_DS);
ret = sys_io_setup(nr_reqs, &ctx64);
set_fs(oldfs);
/* truncating is ok because it's a user address */
if (!ret)
ret = put_user((u32)ctx64, ctx32p);
return ret;
}
struct exec_domain ia32_exec_domain = { struct exec_domain ia32_exec_domain = {
name: "linux/x86", .name = "linux/x86",
pers_low: PER_LINUX32, .pers_low = PER_LINUX32,
pers_high: PER_LINUX32, .pers_high = PER_LINUX32,
}; };
static int __init ia32_init (void) static int __init ia32_init (void)
......
...@@ -249,7 +249,17 @@ ...@@ -249,7 +249,17 @@
#define __NR_ia32_futex 240 #define __NR_ia32_futex 240
#define __NR_ia32_sched_setaffinity 241 #define __NR_ia32_sched_setaffinity 241
#define __NR_ia32_sched_getaffinity 242 #define __NR_ia32_sched_getaffinity 242
#define __NR_ia32_set_thread_area 243
#define __NR_ia32_get_thread_area 244
#define __NR_ia32_io_setup 245
#define __NR_ia32_io_destroy 246
#define __NR_ia32_io_getevents 247
#define __NR_ia32_io_submit 248
#define __NR_ia32_io_cancel 249
#define __NR_ia32_alloc_hugepages 250
#define __NR_ia32_free_hugepages 251
#define __NR_ia32_exit_group 252
#define IA32_NR_syscalls 243 /* must be > than biggest syscall! */ #define IA32_NR_syscalls 260 /* must be > than biggest syscall! */
#endif /* _ASM_X86_64_IA32_UNISTD_H_ */ #endif /* _ASM_X86_64_IA32_UNISTD_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment