aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86_64/ia32
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/x86_64/ia32
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'arch/x86_64/ia32')
-rw-r--r--arch/x86_64/ia32/Makefile32
-rw-r--r--arch/x86_64/ia32/fpu32.c184
-rw-r--r--arch/x86_64/ia32/ia32_aout.c529
-rw-r--r--arch/x86_64/ia32/ia32_binfmt.c434
-rw-r--r--arch/x86_64/ia32/ia32_ioctl.c201
-rw-r--r--arch/x86_64/ia32/ia32_signal.c621
-rw-r--r--arch/x86_64/ia32/ia32entry.S602
-rw-r--r--arch/x86_64/ia32/ipc32.c57
-rw-r--r--arch/x86_64/ia32/ptrace32.c379
-rw-r--r--arch/x86_64/ia32/sys_ia32.c1050
-rw-r--r--arch/x86_64/ia32/syscall32.c111
-rw-r--r--arch/x86_64/ia32/tls32.c163
-rw-r--r--arch/x86_64/ia32/vsyscall-sigreturn.S120
-rw-r--r--arch/x86_64/ia32/vsyscall-syscall.S68
-rw-r--r--arch/x86_64/ia32/vsyscall-sysenter.S94
-rw-r--r--arch/x86_64/ia32/vsyscall.lds77
16 files changed, 4722 insertions, 0 deletions
diff --git a/arch/x86_64/ia32/Makefile b/arch/x86_64/ia32/Makefile
new file mode 100644
index 000000000000..a12b19da4b59
--- /dev/null
+++ b/arch/x86_64/ia32/Makefile
@@ -0,0 +1,32 @@
1#
2# Makefile for the ia32 kernel emulation subsystem.
3#
4
5obj-$(CONFIG_IA32_EMULATION) := ia32entry.o sys_ia32.o ia32_ioctl.o \
6 ia32_signal.o tls32.o \
7 ia32_binfmt.o fpu32.o ptrace32.o syscall32.o
8
9sysv-$(CONFIG_SYSVIPC) := ipc32.o
10obj-$(CONFIG_IA32_EMULATION) += $(sysv-y)
11
12obj-$(CONFIG_IA32_AOUT) += ia32_aout.o
13
14$(obj)/syscall32.o: $(src)/syscall32.c \
15 $(foreach F,sysenter syscall,$(obj)/vsyscall-$F.so)
16
17# Teach kbuild about targets
18targets := $(foreach F,sysenter syscall,vsyscall-$F.o vsyscall-$F.so)
19
20# The DSO images are built using a special linker script
21quiet_cmd_syscall = SYSCALL $@
22 cmd_syscall = $(CC) -m32 -nostdlib -shared -s \
23 -Wl,-soname=linux-gate.so.1 -o $@ \
24 -Wl,-T,$(filter-out FORCE,$^)
25
26$(obj)/vsyscall-sysenter.so $(obj)/vsyscall-syscall.so: \
27$(obj)/vsyscall-%.so: $(src)/vsyscall.lds $(obj)/vsyscall-%.o FORCE
28 $(call if_changed,syscall)
29
30AFLAGS_vsyscall-sysenter.o = -m32
31AFLAGS_vsyscall-syscall.o = -m32
32CFLAGS_ia32_ioctl.o += -Ifs/
diff --git a/arch/x86_64/ia32/fpu32.c b/arch/x86_64/ia32/fpu32.c
new file mode 100644
index 000000000000..1c23095f1813
--- /dev/null
+++ b/arch/x86_64/ia32/fpu32.c
@@ -0,0 +1,184 @@
1/*
2 * Copyright 2002 Andi Kleen, SuSE Labs.
3 * FXSAVE<->i387 conversion support. Based on code by Gareth Hughes.
4 * This is used for ptrace, signals and coredumps in 32bit emulation.
5 * $Id: fpu32.c,v 1.1 2002/03/21 14:16:32 ak Exp $
6 */
7
8#include <linux/sched.h>
9#include <asm/sigcontext32.h>
10#include <asm/processor.h>
11#include <asm/uaccess.h>
12#include <asm/i387.h>
13
14static inline unsigned short twd_i387_to_fxsr(unsigned short twd)
15{
16 unsigned int tmp; /* to avoid 16 bit prefixes in the code */
17
18 /* Transform each pair of bits into 01 (valid) or 00 (empty) */
19 tmp = ~twd;
20 tmp = (tmp | (tmp>>1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */
21 /* and move the valid bits to the lower byte. */
22 tmp = (tmp | (tmp >> 1)) & 0x3333; /* 00VV00VV00VV00VV */
23 tmp = (tmp | (tmp >> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */
24 tmp = (tmp | (tmp >> 4)) & 0x00ff; /* 00000000VVVVVVVV */
25 return tmp;
26}
27
28static inline unsigned long twd_fxsr_to_i387(struct i387_fxsave_struct *fxsave)
29{
30 struct _fpxreg *st = NULL;
31 unsigned long tos = (fxsave->swd >> 11) & 7;
32 unsigned long twd = (unsigned long) fxsave->twd;
33 unsigned long tag;
34 unsigned long ret = 0xffff0000;
35 int i;
36
37#define FPREG_ADDR(f, n) ((void *)&(f)->st_space + (n) * 16);
38
39 for (i = 0 ; i < 8 ; i++) {
40 if (twd & 0x1) {
41 st = FPREG_ADDR( fxsave, (i - tos) & 7 );
42
43 switch (st->exponent & 0x7fff) {
44 case 0x7fff:
45 tag = 2; /* Special */
46 break;
47 case 0x0000:
48 if ( !st->significand[0] &&
49 !st->significand[1] &&
50 !st->significand[2] &&
51 !st->significand[3] ) {
52 tag = 1; /* Zero */
53 } else {
54 tag = 2; /* Special */
55 }
56 break;
57 default:
58 if (st->significand[3] & 0x8000) {
59 tag = 0; /* Valid */
60 } else {
61 tag = 2; /* Special */
62 }
63 break;
64 }
65 } else {
66 tag = 3; /* Empty */
67 }
68 ret |= (tag << (2 * i));
69 twd = twd >> 1;
70 }
71 return ret;
72}
73
74
75static inline int convert_fxsr_from_user(struct i387_fxsave_struct *fxsave,
76 struct _fpstate_ia32 __user *buf)
77{
78 struct _fpxreg *to;
79 struct _fpreg __user *from;
80 int i;
81 u32 v;
82 int err = 0;
83
84#define G(num,val) err |= __get_user(val, num + (u32 __user *)buf)
85 G(0, fxsave->cwd);
86 G(1, fxsave->swd);
87 G(2, fxsave->twd);
88 fxsave->twd = twd_i387_to_fxsr(fxsave->twd);
89 G(3, fxsave->rip);
90 G(4, v);
91 fxsave->fop = v>>16; /* cs ignored */
92 G(5, fxsave->rdp);
93 /* 6: ds ignored */
94#undef G
95 if (err)
96 return -1;
97
98 to = (struct _fpxreg *)&fxsave->st_space[0];
99 from = &buf->_st[0];
100 for (i = 0 ; i < 8 ; i++, to++, from++) {
101 if (__copy_from_user(to, from, sizeof(*from)))
102 return -1;
103 }
104 return 0;
105}
106
107
108static inline int convert_fxsr_to_user(struct _fpstate_ia32 __user *buf,
109 struct i387_fxsave_struct *fxsave,
110 struct pt_regs *regs,
111 struct task_struct *tsk)
112{
113 struct _fpreg __user *to;
114 struct _fpxreg *from;
115 int i;
116 u16 cs,ds;
117 int err = 0;
118
119 if (tsk == current) {
120 /* should be actually ds/cs at fpu exception time,
121 but that information is not available in 64bit mode. */
122 asm("movw %%ds,%0 " : "=r" (ds));
123 asm("movw %%cs,%0 " : "=r" (cs));
124 } else { /* ptrace. task has stopped. */
125 ds = tsk->thread.ds;
126 cs = regs->cs;
127 }
128
129#define P(num,val) err |= __put_user(val, num + (u32 __user *)buf)
130 P(0, (u32)fxsave->cwd | 0xffff0000);
131 P(1, (u32)fxsave->swd | 0xffff0000);
132 P(2, twd_fxsr_to_i387(fxsave));
133 P(3, (u32)fxsave->rip);
134 P(4, cs | ((u32)fxsave->fop) << 16);
135 P(5, fxsave->rdp);
136 P(6, 0xffff0000 | ds);
137#undef P
138
139 if (err)
140 return -1;
141
142 to = &buf->_st[0];
143 from = (struct _fpxreg *) &fxsave->st_space[0];
144 for ( i = 0 ; i < 8 ; i++, to++, from++ ) {
145 if (__copy_to_user(to, from, sizeof(*to)))
146 return -1;
147 }
148 return 0;
149}
150
151int restore_i387_ia32(struct task_struct *tsk, struct _fpstate_ia32 __user *buf, int fsave)
152{
153 clear_fpu(tsk);
154 if (!fsave) {
155 if (__copy_from_user(&tsk->thread.i387.fxsave,
156 &buf->_fxsr_env[0],
157 sizeof(struct i387_fxsave_struct)))
158 return -1;
159 tsk->thread.i387.fxsave.mxcsr &= mxcsr_feature_mask;
160 set_stopped_child_used_math(tsk);
161 }
162 return convert_fxsr_from_user(&tsk->thread.i387.fxsave, buf);
163}
164
165int save_i387_ia32(struct task_struct *tsk,
166 struct _fpstate_ia32 __user *buf,
167 struct pt_regs *regs,
168 int fsave)
169{
170 int err = 0;
171
172 init_fpu(tsk);
173 if (convert_fxsr_to_user(buf, &tsk->thread.i387.fxsave, regs, tsk))
174 return -1;
175 if (fsave)
176 return 0;
177 err |= __put_user(tsk->thread.i387.fxsave.swd, &buf->status);
178 if (fsave)
179 return err ? -1 : 1;
180 err |= __put_user(X86_FXSR_MAGIC, &buf->magic);
181 err |= __copy_to_user(&buf->_fxsr_env[0], &tsk->thread.i387.fxsave,
182 sizeof(struct i387_fxsave_struct));
183 return err ? -1 : 1;
184}
diff --git a/arch/x86_64/ia32/ia32_aout.c b/arch/x86_64/ia32/ia32_aout.c
new file mode 100644
index 000000000000..1965efc974dc
--- /dev/null
+++ b/arch/x86_64/ia32/ia32_aout.c
@@ -0,0 +1,529 @@
1/*
2 * a.out loader for x86-64
3 *
4 * Copyright (C) 1991, 1992, 1996 Linus Torvalds
5 * Hacked together by Andi Kleen
6 */
7
8#include <linux/module.h>
9
10#include <linux/time.h>
11#include <linux/kernel.h>
12#include <linux/mm.h>
13#include <linux/mman.h>
14#include <linux/a.out.h>
15#include <linux/errno.h>
16#include <linux/signal.h>
17#include <linux/string.h>
18#include <linux/fs.h>
19#include <linux/file.h>
20#include <linux/stat.h>
21#include <linux/fcntl.h>
22#include <linux/ptrace.h>
23#include <linux/user.h>
24#include <linux/slab.h>
25#include <linux/binfmts.h>
26#include <linux/personality.h>
27#include <linux/init.h>
28
29#include <asm/system.h>
30#include <asm/uaccess.h>
31#include <asm/pgalloc.h>
32#include <asm/cacheflush.h>
33#include <asm/user32.h>
34#include <asm/ia32.h>
35
36#undef WARN_OLD
37#undef CORE_DUMP /* probably broken */
38
39extern int ia32_setup_arg_pages(struct linux_binprm *bprm,
40 unsigned long stack_top, int exec_stack);
41
42static int load_aout_binary(struct linux_binprm *, struct pt_regs * regs);
43static int load_aout_library(struct file*);
44
45#if CORE_DUMP
46static int aout_core_dump(long signr, struct pt_regs * regs, struct file *file);
47
48/*
49 * fill in the user structure for a core dump..
50 */
51static void dump_thread32(struct pt_regs * regs, struct user32 * dump)
52{
53 u32 fs,gs;
54
55/* changed the size calculations - should hopefully work better. lbt */
56 dump->magic = CMAGIC;
57 dump->start_code = 0;
58 dump->start_stack = regs->rsp & ~(PAGE_SIZE - 1);
59 dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT;
60 dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1))) >> PAGE_SHIFT;
61 dump->u_dsize -= dump->u_tsize;
62 dump->u_ssize = 0;
63 dump->u_debugreg[0] = current->thread.debugreg0;
64 dump->u_debugreg[1] = current->thread.debugreg1;
65 dump->u_debugreg[2] = current->thread.debugreg2;
66 dump->u_debugreg[3] = current->thread.debugreg3;
67 dump->u_debugreg[4] = 0;
68 dump->u_debugreg[5] = 0;
69 dump->u_debugreg[6] = current->thread.debugreg6;
70 dump->u_debugreg[7] = current->thread.debugreg7;
71
72 if (dump->start_stack < 0xc0000000)
73 dump->u_ssize = ((unsigned long) (0xc0000000 - dump->start_stack)) >> PAGE_SHIFT;
74
75 dump->regs.ebx = regs->rbx;
76 dump->regs.ecx = regs->rcx;
77 dump->regs.edx = regs->rdx;
78 dump->regs.esi = regs->rsi;
79 dump->regs.edi = regs->rdi;
80 dump->regs.ebp = regs->rbp;
81 dump->regs.eax = regs->rax;
82 dump->regs.ds = current->thread.ds;
83 dump->regs.es = current->thread.es;
84 asm("movl %%fs,%0" : "=r" (fs)); dump->regs.fs = fs;
85 asm("movl %%gs,%0" : "=r" (gs)); dump->regs.gs = gs;
86 dump->regs.orig_eax = regs->orig_rax;
87 dump->regs.eip = regs->rip;
88 dump->regs.cs = regs->cs;
89 dump->regs.eflags = regs->eflags;
90 dump->regs.esp = regs->rsp;
91 dump->regs.ss = regs->ss;
92
93#if 1 /* FIXME */
94 dump->u_fpvalid = 0;
95#else
96 dump->u_fpvalid = dump_fpu (regs, &dump->i387);
97#endif
98}
99
100#endif
101
102static struct linux_binfmt aout_format = {
103 .module = THIS_MODULE,
104 .load_binary = load_aout_binary,
105 .load_shlib = load_aout_library,
106#if CORE_DUMP
107 .core_dump = aout_core_dump,
108#endif
109 .min_coredump = PAGE_SIZE
110};
111
112static void set_brk(unsigned long start, unsigned long end)
113{
114 start = PAGE_ALIGN(start);
115 end = PAGE_ALIGN(end);
116 if (end <= start)
117 return;
118 down_write(&current->mm->mmap_sem);
119 do_brk(start, end - start);
120 up_write(&current->mm->mmap_sem);
121}
122
123#if CORE_DUMP
124/*
125 * These are the only things you should do on a core-file: use only these
126 * macros to write out all the necessary info.
127 */
128
129static int dump_write(struct file *file, const void *addr, int nr)
130{
131 return file->f_op->write(file, addr, nr, &file->f_pos) == nr;
132}
133
134#define DUMP_WRITE(addr, nr) \
135 if (!dump_write(file, (void *)(addr), (nr))) \
136 goto end_coredump;
137
138#define DUMP_SEEK(offset) \
139if (file->f_op->llseek) { \
140 if (file->f_op->llseek(file,(offset),0) != (offset)) \
141 goto end_coredump; \
142} else file->f_pos = (offset)
143
144/*
145 * Routine writes a core dump image in the current directory.
146 * Currently only a stub-function.
147 *
148 * Note that setuid/setgid files won't make a core-dump if the uid/gid
149 * changed due to the set[u|g]id. It's enforced by the "current->mm->dumpable"
150 * field, which also makes sure the core-dumps won't be recursive if the
151 * dumping of the process results in another error..
152 */
153
154static int aout_core_dump(long signr, struct pt_regs * regs, struct file *file)
155{
156 mm_segment_t fs;
157 int has_dumped = 0;
158 unsigned long dump_start, dump_size;
159 struct user32 dump;
160# define START_DATA(u) (u.u_tsize << PAGE_SHIFT)
161# define START_STACK(u) (u.start_stack)
162
163 fs = get_fs();
164 set_fs(KERNEL_DS);
165 has_dumped = 1;
166 current->flags |= PF_DUMPCORE;
167 strncpy(dump.u_comm, current->comm, sizeof(current->comm));
168 dump.u_ar0 = (u32)(((unsigned long)(&dump.regs)) - ((unsigned long)(&dump)));
169 dump.signal = signr;
170 dump_thread32(regs, &dump);
171
172/* If the size of the dump file exceeds the rlimit, then see what would happen
173 if we wrote the stack, but not the data area. */
174 if ((dump.u_dsize+dump.u_ssize+1) * PAGE_SIZE >
175 current->signal->rlim[RLIMIT_CORE].rlim_cur)
176 dump.u_dsize = 0;
177
178/* Make sure we have enough room to write the stack and data areas. */
179 if ((dump.u_ssize+1) * PAGE_SIZE >
180 current->signal->rlim[RLIMIT_CORE].rlim_cur)
181 dump.u_ssize = 0;
182
183/* make sure we actually have a data and stack area to dump */
184 set_fs(USER_DS);
185 if (!access_ok(VERIFY_READ, (void *) (unsigned long)START_DATA(dump), dump.u_dsize << PAGE_SHIFT))
186 dump.u_dsize = 0;
187 if (!access_ok(VERIFY_READ, (void *) (unsigned long)START_STACK(dump), dump.u_ssize << PAGE_SHIFT))
188 dump.u_ssize = 0;
189
190 set_fs(KERNEL_DS);
191/* struct user */
192 DUMP_WRITE(&dump,sizeof(dump));
193/* Now dump all of the user data. Include malloced stuff as well */
194 DUMP_SEEK(PAGE_SIZE);
195/* now we start writing out the user space info */
196 set_fs(USER_DS);
197/* Dump the data area */
198 if (dump.u_dsize != 0) {
199 dump_start = START_DATA(dump);
200 dump_size = dump.u_dsize << PAGE_SHIFT;
201 DUMP_WRITE(dump_start,dump_size);
202 }
203/* Now prepare to dump the stack area */
204 if (dump.u_ssize != 0) {
205 dump_start = START_STACK(dump);
206 dump_size = dump.u_ssize << PAGE_SHIFT;
207 DUMP_WRITE(dump_start,dump_size);
208 }
209/* Finally dump the task struct. Not be used by gdb, but could be useful */
210 set_fs(KERNEL_DS);
211 DUMP_WRITE(current,sizeof(*current));
212end_coredump:
213 set_fs(fs);
214 return has_dumped;
215}
216#endif
217
218/*
219 * create_aout_tables() parses the env- and arg-strings in new user
220 * memory and creates the pointer tables from them, and puts their
221 * addresses on the "stack", returning the new stack pointer value.
222 */
223static u32 __user *create_aout_tables(char __user *p, struct linux_binprm *bprm)
224{
225 u32 __user *argv;
226 u32 __user *envp;
227 u32 __user *sp;
228 int argc = bprm->argc;
229 int envc = bprm->envc;
230
231 sp = (u32 __user *) ((-(unsigned long)sizeof(u32)) & (unsigned long) p);
232 sp -= envc+1;
233 envp = sp;
234 sp -= argc+1;
235 argv = sp;
236 put_user((unsigned long) envp,--sp);
237 put_user((unsigned long) argv,--sp);
238 put_user(argc,--sp);
239 current->mm->arg_start = (unsigned long) p;
240 while (argc-->0) {
241 char c;
242 put_user((u32)(unsigned long)p,argv++);
243 do {
244 get_user(c,p++);
245 } while (c);
246 }
247 put_user(NULL,argv);
248 current->mm->arg_end = current->mm->env_start = (unsigned long) p;
249 while (envc-->0) {
250 char c;
251 put_user((u32)(unsigned long)p,envp++);
252 do {
253 get_user(c,p++);
254 } while (c);
255 }
256 put_user(NULL,envp);
257 current->mm->env_end = (unsigned long) p;
258 return sp;
259}
260
261/*
262 * These are the functions used to load a.out style executables and shared
263 * libraries. There is no binary dependent code anywhere else.
264 */
265
266static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
267{
268 struct exec ex;
269 unsigned long error;
270 unsigned long fd_offset;
271 unsigned long rlim;
272 int retval;
273
274 ex = *((struct exec *) bprm->buf); /* exec-header */
275 if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC &&
276 N_MAGIC(ex) != QMAGIC && N_MAGIC(ex) != NMAGIC) ||
277 N_TRSIZE(ex) || N_DRSIZE(ex) ||
278 i_size_read(bprm->file->f_dentry->d_inode) < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
279 return -ENOEXEC;
280 }
281
282 fd_offset = N_TXTOFF(ex);
283
284 /* Check initial limits. This avoids letting people circumvent
285 * size limits imposed on them by creating programs with large
286 * arrays in the data or bss.
287 */
288 rlim = current->signal->rlim[RLIMIT_DATA].rlim_cur;
289 if (rlim >= RLIM_INFINITY)
290 rlim = ~0;
291 if (ex.a_data + ex.a_bss > rlim)
292 return -ENOMEM;
293
294 /* Flush all traces of the currently running executable */
295 retval = flush_old_exec(bprm);
296 if (retval)
297 return retval;
298
299 regs->cs = __USER32_CS;
300 regs->r8 = regs->r9 = regs->r10 = regs->r11 = regs->r12 =
301 regs->r13 = regs->r14 = regs->r15 = 0;
302
303 /* OK, This is the point of no return */
304 set_personality(PER_LINUX);
305 set_thread_flag(TIF_IA32);
306 clear_thread_flag(TIF_ABI_PENDING);
307
308 current->mm->end_code = ex.a_text +
309 (current->mm->start_code = N_TXTADDR(ex));
310 current->mm->end_data = ex.a_data +
311 (current->mm->start_data = N_DATADDR(ex));
312 current->mm->brk = ex.a_bss +
313 (current->mm->start_brk = N_BSSADDR(ex));
314 current->mm->free_area_cache = TASK_UNMAPPED_BASE;
315
316 set_mm_counter(current->mm, rss, 0);
317 current->mm->mmap = NULL;
318 compute_creds(bprm);
319 current->flags &= ~PF_FORKNOEXEC;
320
321 if (N_MAGIC(ex) == OMAGIC) {
322 unsigned long text_addr, map_size;
323 loff_t pos;
324
325 text_addr = N_TXTADDR(ex);
326
327 pos = 32;
328 map_size = ex.a_text+ex.a_data;
329
330 down_write(&current->mm->mmap_sem);
331 error = do_brk(text_addr & PAGE_MASK, map_size);
332 up_write(&current->mm->mmap_sem);
333
334 if (error != (text_addr & PAGE_MASK)) {
335 send_sig(SIGKILL, current, 0);
336 return error;
337 }
338
339 error = bprm->file->f_op->read(bprm->file, (char *)text_addr,
340 ex.a_text+ex.a_data, &pos);
341 if ((signed long)error < 0) {
342 send_sig(SIGKILL, current, 0);
343 return error;
344 }
345
346 flush_icache_range(text_addr, text_addr+ex.a_text+ex.a_data);
347 } else {
348#ifdef WARN_OLD
349 static unsigned long error_time, error_time2;
350 if ((ex.a_text & 0xfff || ex.a_data & 0xfff) &&
351 (N_MAGIC(ex) != NMAGIC) && (jiffies-error_time2) > 5*HZ)
352 {
353 printk(KERN_NOTICE "executable not page aligned\n");
354 error_time2 = jiffies;
355 }
356
357 if ((fd_offset & ~PAGE_MASK) != 0 &&
358 (jiffies-error_time) > 5*HZ)
359 {
360 printk(KERN_WARNING
361 "fd_offset is not page aligned. Please convert program: %s\n",
362 bprm->file->f_dentry->d_name.name);
363 error_time = jiffies;
364 }
365#endif
366
367 if (!bprm->file->f_op->mmap||((fd_offset & ~PAGE_MASK) != 0)) {
368 loff_t pos = fd_offset;
369 down_write(&current->mm->mmap_sem);
370 do_brk(N_TXTADDR(ex), ex.a_text+ex.a_data);
371 up_write(&current->mm->mmap_sem);
372 bprm->file->f_op->read(bprm->file,(char *)N_TXTADDR(ex),
373 ex.a_text+ex.a_data, &pos);
374 flush_icache_range((unsigned long) N_TXTADDR(ex),
375 (unsigned long) N_TXTADDR(ex) +
376 ex.a_text+ex.a_data);
377 goto beyond_if;
378 }
379
380 down_write(&current->mm->mmap_sem);
381 error = do_mmap(bprm->file, N_TXTADDR(ex), ex.a_text,
382 PROT_READ | PROT_EXEC,
383 MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE | MAP_32BIT,
384 fd_offset);
385 up_write(&current->mm->mmap_sem);
386
387 if (error != N_TXTADDR(ex)) {
388 send_sig(SIGKILL, current, 0);
389 return error;
390 }
391
392 down_write(&current->mm->mmap_sem);
393 error = do_mmap(bprm->file, N_DATADDR(ex), ex.a_data,
394 PROT_READ | PROT_WRITE | PROT_EXEC,
395 MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE | MAP_32BIT,
396 fd_offset + ex.a_text);
397 up_write(&current->mm->mmap_sem);
398 if (error != N_DATADDR(ex)) {
399 send_sig(SIGKILL, current, 0);
400 return error;
401 }
402 }
403beyond_if:
404 set_binfmt(&aout_format);
405
406 set_brk(current->mm->start_brk, current->mm->brk);
407
408 retval = ia32_setup_arg_pages(bprm, IA32_STACK_TOP, EXSTACK_DEFAULT);
409 if (retval < 0) {
410 /* Someone check-me: is this error path enough? */
411 send_sig(SIGKILL, current, 0);
412 return retval;
413 }
414
415 current->mm->start_stack =
416 (unsigned long)create_aout_tables((char __user *)bprm->p, bprm);
417 /* start thread */
418 asm volatile("movl %0,%%fs" :: "r" (0)); \
419 asm volatile("movl %0,%%es; movl %0,%%ds": :"r" (__USER32_DS));
420 load_gs_index(0);
421 (regs)->rip = ex.a_entry;
422 (regs)->rsp = current->mm->start_stack;
423 (regs)->eflags = 0x200;
424 (regs)->cs = __USER32_CS;
425 (regs)->ss = __USER32_DS;
426 set_fs(USER_DS);
427 if (unlikely(current->ptrace & PT_PTRACED)) {
428 if (current->ptrace & PT_TRACE_EXEC)
429 ptrace_notify ((PTRACE_EVENT_EXEC << 8) | SIGTRAP);
430 else
431 send_sig(SIGTRAP, current, 0);
432 }
433 return 0;
434}
435
436static int load_aout_library(struct file *file)
437{
438 struct inode * inode;
439 unsigned long bss, start_addr, len;
440 unsigned long error;
441 int retval;
442 struct exec ex;
443
444 inode = file->f_dentry->d_inode;
445
446 retval = -ENOEXEC;
447 error = kernel_read(file, 0, (char *) &ex, sizeof(ex));
448 if (error != sizeof(ex))
449 goto out;
450
451 /* We come in here for the regular a.out style of shared libraries */
452 if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != QMAGIC) || N_TRSIZE(ex) ||
453 N_DRSIZE(ex) || ((ex.a_entry & 0xfff) && N_MAGIC(ex) == ZMAGIC) ||
454 i_size_read(inode) < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
455 goto out;
456 }
457
458 if (N_FLAGS(ex))
459 goto out;
460
461 /* For QMAGIC, the starting address is 0x20 into the page. We mask
462 this off to get the starting address for the page */
463
464 start_addr = ex.a_entry & 0xfffff000;
465
466 if ((N_TXTOFF(ex) & ~PAGE_MASK) != 0) {
467 loff_t pos = N_TXTOFF(ex);
468
469#ifdef WARN_OLD
470 static unsigned long error_time;
471 if ((jiffies-error_time) > 5*HZ)
472 {
473 printk(KERN_WARNING
474 "N_TXTOFF is not page aligned. Please convert library: %s\n",
475 file->f_dentry->d_name.name);
476 error_time = jiffies;
477 }
478#endif
479 down_write(&current->mm->mmap_sem);
480 do_brk(start_addr, ex.a_text + ex.a_data + ex.a_bss);
481 up_write(&current->mm->mmap_sem);
482
483 file->f_op->read(file, (char *)start_addr,
484 ex.a_text + ex.a_data, &pos);
485 flush_icache_range((unsigned long) start_addr,
486 (unsigned long) start_addr + ex.a_text + ex.a_data);
487
488 retval = 0;
489 goto out;
490 }
491 /* Now use mmap to map the library into memory. */
492 down_write(&current->mm->mmap_sem);
493 error = do_mmap(file, start_addr, ex.a_text + ex.a_data,
494 PROT_READ | PROT_WRITE | PROT_EXEC,
495 MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_32BIT,
496 N_TXTOFF(ex));
497 up_write(&current->mm->mmap_sem);
498 retval = error;
499 if (error != start_addr)
500 goto out;
501
502 len = PAGE_ALIGN(ex.a_text + ex.a_data);
503 bss = ex.a_text + ex.a_data + ex.a_bss;
504 if (bss > len) {
505 down_write(&current->mm->mmap_sem);
506 error = do_brk(start_addr + len, bss - len);
507 up_write(&current->mm->mmap_sem);
508 retval = error;
509 if (error != start_addr + len)
510 goto out;
511 }
512 retval = 0;
513out:
514 return retval;
515}
516
517static int __init init_aout_binfmt(void)
518{
519 return register_binfmt(&aout_format);
520}
521
522static void __exit exit_aout_binfmt(void)
523{
524 unregister_binfmt(&aout_format);
525}
526
527module_init(init_aout_binfmt);
528module_exit(exit_aout_binfmt);
529MODULE_LICENSE("GPL");
diff --git a/arch/x86_64/ia32/ia32_binfmt.c b/arch/x86_64/ia32/ia32_binfmt.c
new file mode 100644
index 000000000000..93d568dfa762
--- /dev/null
+++ b/arch/x86_64/ia32/ia32_binfmt.c
@@ -0,0 +1,434 @@
1/*
2 * Written 2000,2002 by Andi Kleen.
3 *
4 * Loosely based on the sparc64 and IA64 32bit emulation loaders.
5 * This tricks binfmt_elf.c into loading 32bit binaries using lots
6 * of ugly preprocessor tricks. Talk about very very poor man's inheritance.
7 */
8#include <linux/types.h>
9#include <linux/config.h>
10#include <linux/stddef.h>
11#include <linux/rwsem.h>
12#include <linux/sched.h>
13#include <linux/compat.h>
14#include <linux/string.h>
15#include <linux/binfmts.h>
16#include <linux/mm.h>
17#include <linux/security.h>
18
19#include <asm/segment.h>
20#include <asm/ptrace.h>
21#include <asm/processor.h>
22#include <asm/user32.h>
23#include <asm/sigcontext32.h>
24#include <asm/fpu32.h>
25#include <asm/i387.h>
26#include <asm/uaccess.h>
27#include <asm/ia32.h>
28#include <asm/vsyscall32.h>
29
30#define ELF_NAME "elf/i386"
31
32#define AT_SYSINFO 32
33#define AT_SYSINFO_EHDR 33
34
35int sysctl_vsyscall32 = 1;
36
37#define ARCH_DLINFO do { \
38 if (sysctl_vsyscall32) { \
39 NEW_AUX_ENT(AT_SYSINFO, (u32)(u64)VSYSCALL32_VSYSCALL); \
40 NEW_AUX_ENT(AT_SYSINFO_EHDR, VSYSCALL32_BASE); \
41 } \
42} while(0)
43
44struct file;
45struct elf_phdr;
46
47#define IA32_EMULATOR 1
48
49#define ELF_ET_DYN_BASE (TASK_UNMAPPED_32 + 0x1000000)
50
51#undef ELF_ARCH
52#define ELF_ARCH EM_386
53
54#undef ELF_CLASS
55#define ELF_CLASS ELFCLASS32
56
57#define ELF_DATA ELFDATA2LSB
58
59#define USE_ELF_CORE_DUMP 1
60
61/* Overwrite elfcore.h */
62#define _LINUX_ELFCORE_H 1
63typedef unsigned int elf_greg_t;
64
65#define ELF_NGREG (sizeof (struct user_regs_struct32) / sizeof(elf_greg_t))
66typedef elf_greg_t elf_gregset_t[ELF_NGREG];
67
68/*
69 * These macros parameterize elf_core_dump in fs/binfmt_elf.c to write out
70 * extra segments containing the vsyscall DSO contents. Dumping its
71 * contents makes post-mortem fully interpretable later without matching up
72 * the same kernel and hardware config to see what PC values meant.
73 * Dumping its extra ELF program headers includes all the other information
74 * a debugger needs to easily find how the vsyscall DSO was being used.
75 */
76#define ELF_CORE_EXTRA_PHDRS (VSYSCALL32_EHDR->e_phnum)
77#define ELF_CORE_WRITE_EXTRA_PHDRS \
78do { \
79 const struct elf32_phdr *const vsyscall_phdrs = \
80 (const struct elf32_phdr *) (VSYSCALL32_BASE \
81 + VSYSCALL32_EHDR->e_phoff); \
82 int i; \
83 Elf32_Off ofs = 0; \
84 for (i = 0; i < VSYSCALL32_EHDR->e_phnum; ++i) { \
85 struct elf32_phdr phdr = vsyscall_phdrs[i]; \
86 if (phdr.p_type == PT_LOAD) { \
87 BUG_ON(ofs != 0); \
88 ofs = phdr.p_offset = offset; \
89 phdr.p_memsz = PAGE_ALIGN(phdr.p_memsz); \
90 phdr.p_filesz = phdr.p_memsz; \
91 offset += phdr.p_filesz; \
92 } \
93 else \
94 phdr.p_offset += ofs; \
95 phdr.p_paddr = 0; /* match other core phdrs */ \
96 DUMP_WRITE(&phdr, sizeof(phdr)); \
97 } \
98} while (0)
99#define ELF_CORE_WRITE_EXTRA_DATA \
100do { \
101 const struct elf32_phdr *const vsyscall_phdrs = \
102 (const struct elf32_phdr *) (VSYSCALL32_BASE \
103 + VSYSCALL32_EHDR->e_phoff); \
104 int i; \
105 for (i = 0; i < VSYSCALL32_EHDR->e_phnum; ++i) { \
106 if (vsyscall_phdrs[i].p_type == PT_LOAD) \
107 DUMP_WRITE((void *) (u64) vsyscall_phdrs[i].p_vaddr, \
108 PAGE_ALIGN(vsyscall_phdrs[i].p_memsz)); \
109 } \
110} while (0)
111
112struct elf_siginfo
113{
114 int si_signo; /* signal number */
115 int si_code; /* extra code */
116 int si_errno; /* errno */
117};
118
119#define jiffies_to_timeval(a,b) do { (b)->tv_usec = 0; (b)->tv_sec = (a)/HZ; }while(0)
120
121struct elf_prstatus
122{
123 struct elf_siginfo pr_info; /* Info associated with signal */
124 short pr_cursig; /* Current signal */
125 unsigned int pr_sigpend; /* Set of pending signals */
126 unsigned int pr_sighold; /* Set of held signals */
127 pid_t pr_pid;
128 pid_t pr_ppid;
129 pid_t pr_pgrp;
130 pid_t pr_sid;
131 struct compat_timeval pr_utime; /* User time */
132 struct compat_timeval pr_stime; /* System time */
133 struct compat_timeval pr_cutime; /* Cumulative user time */
134 struct compat_timeval pr_cstime; /* Cumulative system time */
135 elf_gregset_t pr_reg; /* GP registers */
136 int pr_fpvalid; /* True if math co-processor being used. */
137};
138
139#define ELF_PRARGSZ (80) /* Number of chars for args */
140
141struct elf_prpsinfo
142{
143 char pr_state; /* numeric process state */
144 char pr_sname; /* char for pr_state */
145 char pr_zomb; /* zombie */
146 char pr_nice; /* nice val */
147 unsigned int pr_flag; /* flags */
148 __u16 pr_uid;
149 __u16 pr_gid;
150 pid_t pr_pid, pr_ppid, pr_pgrp, pr_sid;
151 /* Lots missing */
152 char pr_fname[16]; /* filename of executable */
153 char pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */
154};
155
156#define __STR(x) #x
157#define STR(x) __STR(x)
158
159#define _GET_SEG(x) \
160 ({ __u32 seg; asm("movl %%" STR(x) ",%0" : "=r"(seg)); seg; })
161
162/* Assumes current==process to be dumped */
163#define ELF_CORE_COPY_REGS(pr_reg, regs) \
164 pr_reg[0] = regs->rbx; \
165 pr_reg[1] = regs->rcx; \
166 pr_reg[2] = regs->rdx; \
167 pr_reg[3] = regs->rsi; \
168 pr_reg[4] = regs->rdi; \
169 pr_reg[5] = regs->rbp; \
170 pr_reg[6] = regs->rax; \
171 pr_reg[7] = _GET_SEG(ds); \
172 pr_reg[8] = _GET_SEG(es); \
173 pr_reg[9] = _GET_SEG(fs); \
174 pr_reg[10] = _GET_SEG(gs); \
175 pr_reg[11] = regs->orig_rax; \
176 pr_reg[12] = regs->rip; \
177 pr_reg[13] = regs->cs; \
178 pr_reg[14] = regs->eflags; \
179 pr_reg[15] = regs->rsp; \
180 pr_reg[16] = regs->ss;
181
182#define user user32
183
184#define __ASM_X86_64_ELF_H 1
185#define elf_read_implies_exec(ex, have_pt_gnu_stack) (!(have_pt_gnu_stack))
186//#include <asm/ia32.h>
187#include <linux/elf.h>
188
189typedef struct user_i387_ia32_struct elf_fpregset_t;
190typedef struct user32_fxsr_struct elf_fpxregset_t;
191
192
193static inline void elf_core_copy_regs(elf_gregset_t *elfregs, struct pt_regs *regs)
194{
195 ELF_CORE_COPY_REGS((*elfregs), regs)
196}
197
198static inline int elf_core_copy_task_regs(struct task_struct *t, elf_gregset_t* elfregs)
199{
200 struct pt_regs *pp = (struct pt_regs *)(t->thread.rsp0);
201 --pp;
202 ELF_CORE_COPY_REGS((*elfregs), pp);
203 /* fix wrong segments */
204 (*elfregs)[7] = t->thread.ds;
205 (*elfregs)[9] = t->thread.fsindex;
206 (*elfregs)[10] = t->thread.gsindex;
207 (*elfregs)[8] = t->thread.es;
208 return 1;
209}
210
211static inline int
212elf_core_copy_task_fpregs(struct task_struct *tsk, struct pt_regs *regs, elf_fpregset_t *fpu)
213{
214 struct _fpstate_ia32 *fpstate = (void*)fpu;
215 mm_segment_t oldfs = get_fs();
216
217 if (!tsk_used_math(tsk))
218 return 0;
219 if (!regs)
220 regs = (struct pt_regs *)tsk->thread.rsp0;
221 --regs;
222 if (tsk == current)
223 unlazy_fpu(tsk);
224 set_fs(KERNEL_DS);
225 save_i387_ia32(tsk, fpstate, regs, 1);
226 /* Correct for i386 bug. It puts the fop into the upper 16bits of
227 the tag word (like FXSAVE), not into the fcs*/
228 fpstate->cssel |= fpstate->tag & 0xffff0000;
229 set_fs(oldfs);
230 return 1;
231}
232
233#define ELF_CORE_COPY_XFPREGS 1
234static inline int
235elf_core_copy_task_xfpregs(struct task_struct *t, elf_fpxregset_t *xfpu)
236{
237 struct pt_regs *regs = ((struct pt_regs *)(t->thread.rsp0))-1;
238 if (!tsk_used_math(t))
239 return 0;
240 if (t == current)
241 unlazy_fpu(t);
242 memcpy(xfpu, &t->thread.i387.fxsave, sizeof(elf_fpxregset_t));
243 xfpu->fcs = regs->cs;
244 xfpu->fos = t->thread.ds; /* right? */
245 return 1;
246}
247
248#undef elf_check_arch
249#define elf_check_arch(x) \
250 ((x)->e_machine == EM_386)
251
252extern int force_personality32;
253
254#define ELF_EXEC_PAGESIZE PAGE_SIZE
255#define ELF_HWCAP (boot_cpu_data.x86_capability[0])
256#define ELF_PLATFORM ("i686")
257#define SET_PERSONALITY(ex, ibcs2) \
258do { \
259 unsigned long new_flags = 0; \
260 if ((ex).e_ident[EI_CLASS] == ELFCLASS32) \
261 new_flags = _TIF_IA32; \
262 if ((current_thread_info()->flags & _TIF_IA32) \
263 != new_flags) \
264 set_thread_flag(TIF_ABI_PENDING); \
265 else \
266 clear_thread_flag(TIF_ABI_PENDING); \
267 /* XXX This overwrites the user set personality */ \
268 current->personality |= force_personality32; \
269} while (0)
270
271/* Override some function names */
272#define elf_format elf32_format
273
274#define init_elf_binfmt init_elf32_binfmt
275#define exit_elf_binfmt exit_elf32_binfmt
276
277#define load_elf_binary load_elf32_binary
278
279#define ELF_PLAT_INIT(r, load_addr) elf32_init(r)
280#define setup_arg_pages(bprm, stack_top, exec_stack) \
281 ia32_setup_arg_pages(bprm, stack_top, exec_stack)
282int ia32_setup_arg_pages(struct linux_binprm *bprm, unsigned long stack_top, int executable_stack);
283
284#undef start_thread
285#define start_thread(regs,new_rip,new_rsp) do { \
286 asm volatile("movl %0,%%fs" :: "r" (0)); \
287 asm volatile("movl %0,%%es; movl %0,%%ds": :"r" (__USER32_DS)); \
288 load_gs_index(0); \
289 (regs)->rip = (new_rip); \
290 (regs)->rsp = (new_rsp); \
291 (regs)->eflags = 0x200; \
292 (regs)->cs = __USER32_CS; \
293 (regs)->ss = __USER32_DS; \
294 set_fs(USER_DS); \
295} while(0)
296
297
298#define elf_map elf32_map
299
300#include <linux/module.h>
301
302MODULE_DESCRIPTION("Binary format loader for compatibility with IA32 ELF binaries.");
303MODULE_AUTHOR("Eric Youngdale, Andi Kleen");
304
305#undef MODULE_DESCRIPTION
306#undef MODULE_AUTHOR
307
308#define elf_addr_t __u32
309
310#undef TASK_SIZE
311#define TASK_SIZE 0xffffffff
312
313static void elf32_init(struct pt_regs *);
314
315#include "../../../fs/binfmt_elf.c"
316
317static void elf32_init(struct pt_regs *regs)
318{
319 struct task_struct *me = current;
320 regs->rdi = 0;
321 regs->rsi = 0;
322 regs->rdx = 0;
323 regs->rcx = 0;
324 regs->rax = 0;
325 regs->rbx = 0;
326 regs->rbp = 0;
327 regs->r8 = regs->r9 = regs->r10 = regs->r11 = regs->r12 =
328 regs->r13 = regs->r14 = regs->r15 = 0;
329 me->thread.fs = 0;
330 me->thread.gs = 0;
331 me->thread.fsindex = 0;
332 me->thread.gsindex = 0;
333 me->thread.ds = __USER_DS;
334 me->thread.es = __USER_DS;
335}
336
337int setup_arg_pages(struct linux_binprm *bprm, unsigned long stack_top, int executable_stack)
338{
339 unsigned long stack_base;
340 struct vm_area_struct *mpnt;
341 struct mm_struct *mm = current->mm;
342 int i, ret;
343
344 stack_base = IA32_STACK_TOP - MAX_ARG_PAGES * PAGE_SIZE;
345 mm->arg_start = bprm->p + stack_base;
346
347 bprm->p += stack_base;
348 if (bprm->loader)
349 bprm->loader += stack_base;
350 bprm->exec += stack_base;
351
352 mpnt = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
353 if (!mpnt)
354 return -ENOMEM;
355
356 if (security_vm_enough_memory((IA32_STACK_TOP - (PAGE_MASK & (unsigned long) bprm->p))>>PAGE_SHIFT)) {
357 kmem_cache_free(vm_area_cachep, mpnt);
358 return -ENOMEM;
359 }
360
361 memset(mpnt, 0, sizeof(*mpnt));
362
363 down_write(&mm->mmap_sem);
364 {
365 mpnt->vm_mm = mm;
366 mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p;
367 mpnt->vm_end = IA32_STACK_TOP;
368 if (executable_stack == EXSTACK_ENABLE_X)
369 mpnt->vm_flags = VM_STACK_FLAGS | VM_EXEC;
370 else if (executable_stack == EXSTACK_DISABLE_X)
371 mpnt->vm_flags = VM_STACK_FLAGS & ~VM_EXEC;
372 else
373 mpnt->vm_flags = VM_STACK_FLAGS;
374 mpnt->vm_page_prot = (mpnt->vm_flags & VM_EXEC) ?
375 PAGE_COPY_EXEC : PAGE_COPY;
376 if ((ret = insert_vm_struct(mm, mpnt))) {
377 up_write(&mm->mmap_sem);
378 kmem_cache_free(vm_area_cachep, mpnt);
379 return ret;
380 }
381 mm->stack_vm = mm->total_vm = vma_pages(mpnt);
382 }
383
384 for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
385 struct page *page = bprm->page[i];
386 if (page) {
387 bprm->page[i] = NULL;
388 install_arg_page(mpnt, page, stack_base);
389 }
390 stack_base += PAGE_SIZE;
391 }
392 up_write(&mm->mmap_sem);
393
394 return 0;
395}
396
397static unsigned long
398elf32_map (struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int prot, int type)
399{
400 unsigned long map_addr;
401 struct task_struct *me = current;
402
403 down_write(&me->mm->mmap_sem);
404 map_addr = do_mmap(filep, ELF_PAGESTART(addr),
405 eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr), prot,
406 type,
407 eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr));
408 up_write(&me->mm->mmap_sem);
409 return(map_addr);
410}
411
412#ifdef CONFIG_SYSCTL
413/* Register vsyscall32 into the ABI table */
414#include <linux/sysctl.h>
415
416static ctl_table abi_table2[] = {
417 { 99, "vsyscall32", &sysctl_vsyscall32, sizeof(int), 0644, NULL,
418 proc_dointvec },
419 { 0, }
420};
421
422static ctl_table abi_root_table2[] = {
423 { .ctl_name = CTL_ABI, .procname = "abi", .mode = 0555,
424 .child = abi_table2 },
425 { 0 },
426};
427
428static __init int ia32_binfmt_init(void)
429{
430 register_sysctl_table(abi_root_table2, 1);
431 return 0;
432}
433__initcall(ia32_binfmt_init);
434#endif
diff --git a/arch/x86_64/ia32/ia32_ioctl.c b/arch/x86_64/ia32/ia32_ioctl.c
new file mode 100644
index 000000000000..d259f8a6f811
--- /dev/null
+++ b/arch/x86_64/ia32/ia32_ioctl.c
@@ -0,0 +1,201 @@
1/* $Id: ia32_ioctl.c,v 1.25 2002/10/11 07:17:06 ak Exp $
2 * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
3 *
4 * Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com)
5 * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
6 * Copyright (C) 2001,2002 Andi Kleen, SuSE Labs
7 *
8 * These routines maintain argument size conversion between 32bit and 64bit
9 * ioctls.
10 */
11
12#define INCLUDES
13#include <linux/syscalls.h>
14#include "compat_ioctl.c"
15#include <asm/mtrr.h>
16#include <asm/ia32.h>
17
18#define CODE
19#include "compat_ioctl.c"
20
21#ifndef TIOCGDEV
22#define TIOCGDEV _IOR('T',0x32, unsigned int)
23#endif
24static int tiocgdev(unsigned fd, unsigned cmd, unsigned int __user *ptr)
25{
26
27 struct file *file = fget(fd);
28 struct tty_struct *real_tty;
29
30 if (!file)
31 return -EBADF;
32 if (file->f_op->ioctl != tty_ioctl)
33 return -EINVAL;
34 real_tty = (struct tty_struct *)file->private_data;
35 if (!real_tty)
36 return -EINVAL;
37 return put_user(new_encode_dev(tty_devnum(real_tty)), ptr);
38}
39
40#define RTC_IRQP_READ32 _IOR('p', 0x0b, unsigned int) /* Read IRQ rate */
41#define RTC_IRQP_SET32 _IOW('p', 0x0c, unsigned int) /* Set IRQ rate */
42#define RTC_EPOCH_READ32 _IOR('p', 0x0d, unsigned) /* Read epoch */
43#define RTC_EPOCH_SET32 _IOW('p', 0x0e, unsigned) /* Set epoch */
44
45static int rtc32_ioctl(unsigned fd, unsigned cmd, unsigned long arg)
46{
47 unsigned long val;
48 mm_segment_t oldfs = get_fs();
49 int ret;
50
51 switch (cmd) {
52 case RTC_IRQP_READ32:
53 set_fs(KERNEL_DS);
54 ret = sys_ioctl(fd, RTC_IRQP_READ, (unsigned long)&val);
55 set_fs(oldfs);
56 if (!ret)
57 ret = put_user(val, (unsigned int __user *) arg);
58 return ret;
59
60 case RTC_IRQP_SET32:
61 cmd = RTC_IRQP_SET;
62 break;
63
64 case RTC_EPOCH_READ32:
65 set_fs(KERNEL_DS);
66 ret = sys_ioctl(fd, RTC_EPOCH_READ, (unsigned long) &val);
67 set_fs(oldfs);
68 if (!ret)
69 ret = put_user(val, (unsigned int __user *) arg);
70 return ret;
71
72 case RTC_EPOCH_SET32:
73 cmd = RTC_EPOCH_SET;
74 break;
75 }
76 return sys_ioctl(fd,cmd,arg);
77}
78
79/* /proc/mtrr ioctls */
80
81
82struct mtrr_sentry32
83{
84 compat_ulong_t base; /* Base address */
85 compat_uint_t size; /* Size of region */
86 compat_uint_t type; /* Type of region */
87};
88
89struct mtrr_gentry32
90{
91 compat_ulong_t regnum; /* Register number */
92 compat_uint_t base; /* Base address */
93 compat_uint_t size; /* Size of region */
94 compat_uint_t type; /* Type of region */
95};
96
97#define MTRR_IOCTL_BASE 'M'
98
99#define MTRRIOC32_ADD_ENTRY _IOW(MTRR_IOCTL_BASE, 0, struct mtrr_sentry32)
100#define MTRRIOC32_SET_ENTRY _IOW(MTRR_IOCTL_BASE, 1, struct mtrr_sentry32)
101#define MTRRIOC32_DEL_ENTRY _IOW(MTRR_IOCTL_BASE, 2, struct mtrr_sentry32)
102#define MTRRIOC32_GET_ENTRY _IOWR(MTRR_IOCTL_BASE, 3, struct mtrr_gentry32)
103#define MTRRIOC32_KILL_ENTRY _IOW(MTRR_IOCTL_BASE, 4, struct mtrr_sentry32)
104#define MTRRIOC32_ADD_PAGE_ENTRY _IOW(MTRR_IOCTL_BASE, 5, struct mtrr_sentry32)
105#define MTRRIOC32_SET_PAGE_ENTRY _IOW(MTRR_IOCTL_BASE, 6, struct mtrr_sentry32)
106#define MTRRIOC32_DEL_PAGE_ENTRY _IOW(MTRR_IOCTL_BASE, 7, struct mtrr_sentry32)
107#define MTRRIOC32_GET_PAGE_ENTRY _IOWR(MTRR_IOCTL_BASE, 8, struct mtrr_gentry32)
108#define MTRRIOC32_KILL_PAGE_ENTRY _IOW(MTRR_IOCTL_BASE, 9, struct mtrr_sentry32)
109
110
111static int mtrr_ioctl32(unsigned int fd, unsigned int cmd, unsigned long arg)
112{
113 struct mtrr_gentry g;
114 struct mtrr_sentry s;
115 int get = 0, err = 0;
116 struct mtrr_gentry32 __user *g32 = (struct mtrr_gentry32 __user *)arg;
117 mm_segment_t oldfs = get_fs();
118
119 switch (cmd) {
120#define SET(x) case MTRRIOC32_ ## x ## _ENTRY: cmd = MTRRIOC_ ## x ## _ENTRY; break
121#define GET(x) case MTRRIOC32_ ## x ## _ENTRY: cmd = MTRRIOC_ ## x ## _ENTRY; get=1; break
122 SET(ADD);
123 SET(SET);
124 SET(DEL);
125 GET(GET);
126 SET(KILL);
127 SET(ADD_PAGE);
128 SET(SET_PAGE);
129 SET(DEL_PAGE);
130 GET(GET_PAGE);
131 SET(KILL_PAGE);
132 }
133
134 if (get) {
135 err = get_user(g.regnum, &g32->regnum);
136 err |= get_user(g.base, &g32->base);
137 err |= get_user(g.size, &g32->size);
138 err |= get_user(g.type, &g32->type);
139
140 arg = (unsigned long)&g;
141 } else {
142 struct mtrr_sentry32 __user *s32 = (struct mtrr_sentry32 __user *)arg;
143 err = get_user(s.base, &s32->base);
144 err |= get_user(s.size, &s32->size);
145 err |= get_user(s.type, &s32->type);
146
147 arg = (unsigned long)&s;
148 }
149 if (err) return err;
150
151 set_fs(KERNEL_DS);
152 err = sys_ioctl(fd, cmd, arg);
153 set_fs(oldfs);
154
155 if (!err && get) {
156 err = put_user(g.base, &g32->base);
157 err |= put_user(g.size, &g32->size);
158 err |= put_user(g.regnum, &g32->regnum);
159 err |= put_user(g.type, &g32->type);
160 }
161 return err;
162}
163
164#define HANDLE_IOCTL(cmd,handler) { (cmd), (ioctl_trans_handler_t)(handler) },
165#define COMPATIBLE_IOCTL(cmd) HANDLE_IOCTL(cmd,sys_ioctl)
166
167struct ioctl_trans ioctl_start[] = {
168#include <linux/compat_ioctl.h>
169#define DECLARES
170#include "compat_ioctl.c"
171COMPATIBLE_IOCTL(HDIO_SET_KEEPSETTINGS)
172COMPATIBLE_IOCTL(HDIO_SCAN_HWIF)
173COMPATIBLE_IOCTL(BLKRASET)
174COMPATIBLE_IOCTL(0x4B50) /* KDGHWCLK - not in the kernel, but don't complain */
175COMPATIBLE_IOCTL(0x4B51) /* KDSHWCLK - not in the kernel, but don't complain */
176COMPATIBLE_IOCTL(FIOQSIZE)
177
178/* And these ioctls need translation */
179HANDLE_IOCTL(TIOCGDEV, tiocgdev)
180/* realtime device */
181HANDLE_IOCTL(RTC_IRQP_READ, rtc32_ioctl)
182HANDLE_IOCTL(RTC_IRQP_READ32,rtc32_ioctl)
183HANDLE_IOCTL(RTC_IRQP_SET32, rtc32_ioctl)
184HANDLE_IOCTL(RTC_EPOCH_READ32, rtc32_ioctl)
185HANDLE_IOCTL(RTC_EPOCH_SET32, rtc32_ioctl)
186/* take care of sizeof(sizeof()) breakage */
187/* mtrr */
188HANDLE_IOCTL(MTRRIOC32_ADD_ENTRY, mtrr_ioctl32)
189HANDLE_IOCTL(MTRRIOC32_SET_ENTRY, mtrr_ioctl32)
190HANDLE_IOCTL(MTRRIOC32_DEL_ENTRY, mtrr_ioctl32)
191HANDLE_IOCTL(MTRRIOC32_GET_ENTRY, mtrr_ioctl32)
192HANDLE_IOCTL(MTRRIOC32_KILL_ENTRY, mtrr_ioctl32)
193HANDLE_IOCTL(MTRRIOC32_ADD_PAGE_ENTRY, mtrr_ioctl32)
194HANDLE_IOCTL(MTRRIOC32_SET_PAGE_ENTRY, mtrr_ioctl32)
195HANDLE_IOCTL(MTRRIOC32_DEL_PAGE_ENTRY, mtrr_ioctl32)
196HANDLE_IOCTL(MTRRIOC32_GET_PAGE_ENTRY, mtrr_ioctl32)
197HANDLE_IOCTL(MTRRIOC32_KILL_PAGE_ENTRY, mtrr_ioctl32)
198};
199
200int ioctl_table_size = ARRAY_SIZE(ioctl_start);
201
diff --git a/arch/x86_64/ia32/ia32_signal.c b/arch/x86_64/ia32/ia32_signal.c
new file mode 100644
index 000000000000..fbd09b5126ce
--- /dev/null
+++ b/arch/x86_64/ia32/ia32_signal.c
@@ -0,0 +1,621 @@
1/*
2 * linux/arch/x86_64/ia32/ia32_signal.c
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 *
6 * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson
7 * 2000-06-20 Pentium III FXSR, SSE support by Gareth Hughes
8 * 2000-12-* x86-64 compatibility mode signal handling by Andi Kleen
9 *
10 * $Id: ia32_signal.c,v 1.22 2002/07/29 10:34:03 ak Exp $
11 */
12
13#include <linux/sched.h>
14#include <linux/mm.h>
15#include <linux/smp.h>
16#include <linux/smp_lock.h>
17#include <linux/kernel.h>
18#include <linux/signal.h>
19#include <linux/errno.h>
20#include <linux/wait.h>
21#include <linux/ptrace.h>
22#include <linux/unistd.h>
23#include <linux/stddef.h>
24#include <linux/personality.h>
25#include <linux/compat.h>
26#include <asm/ucontext.h>
27#include <asm/uaccess.h>
28#include <asm/i387.h>
29#include <asm/ia32.h>
30#include <asm/ptrace.h>
31#include <asm/ia32_unistd.h>
32#include <asm/user32.h>
33#include <asm/sigcontext32.h>
34#include <asm/fpu32.h>
35#include <asm/proto.h>
36#include <asm/vsyscall32.h>
37
38#define DEBUG_SIG 0
39
40#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
41
42asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset);
43void signal_fault(struct pt_regs *regs, void __user *frame, char *where);
44
45int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
46{
47 int err;
48 if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
49 return -EFAULT;
50
51 /* If you change siginfo_t structure, please make sure that
52 this code is fixed accordingly.
53 It should never copy any pad contained in the structure
54 to avoid security leaks, but must copy the generic
55 3 ints plus the relevant union member. */
56 err = __put_user(from->si_signo, &to->si_signo);
57 err |= __put_user(from->si_errno, &to->si_errno);
58 err |= __put_user((short)from->si_code, &to->si_code);
59
60 if (from->si_code < 0) {
61 err |= __put_user(from->si_pid, &to->si_pid);
62 err |= __put_user(from->si_uid, &to->si_uid);
63 err |= __put_user(ptr_to_compat(from->si_ptr), &to->si_ptr);
64 } else {
65 /* First 32bits of unions are always present:
66 * si_pid === si_band === si_tid === si_addr(LS half) */
67 err |= __put_user(from->_sifields._pad[0], &to->_sifields._pad[0]);
68 switch (from->si_code >> 16) {
69 case __SI_FAULT >> 16:
70 break;
71 case __SI_CHLD >> 16:
72 err |= __put_user(from->si_utime, &to->si_utime);
73 err |= __put_user(from->si_stime, &to->si_stime);
74 err |= __put_user(from->si_status, &to->si_status);
75 /* FALL THROUGH */
76 default:
77 case __SI_KILL >> 16:
78 err |= __put_user(from->si_uid, &to->si_uid);
79 break;
80 case __SI_POLL >> 16:
81 err |= __put_user(from->si_fd, &to->si_fd);
82 break;
83 case __SI_TIMER >> 16:
84 err |= __put_user(from->si_overrun, &to->si_overrun);
85 err |= __put_user(ptr_to_compat(from->si_ptr),
86 &to->si_ptr);
87 break;
88 case __SI_RT >> 16: /* This is not generated by the kernel as of now. */
89 case __SI_MESGQ >> 16:
90 err |= __put_user(from->si_uid, &to->si_uid);
91 err |= __put_user(from->si_int, &to->si_int);
92 break;
93 }
94 }
95 return err;
96}
97
98int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
99{
100 int err;
101 u32 ptr32;
102 if (!access_ok (VERIFY_READ, from, sizeof(compat_siginfo_t)))
103 return -EFAULT;
104
105 err = __get_user(to->si_signo, &from->si_signo);
106 err |= __get_user(to->si_errno, &from->si_errno);
107 err |= __get_user(to->si_code, &from->si_code);
108
109 err |= __get_user(to->si_pid, &from->si_pid);
110 err |= __get_user(to->si_uid, &from->si_uid);
111 err |= __get_user(ptr32, &from->si_ptr);
112 to->si_ptr = compat_ptr(ptr32);
113
114 return err;
115}
116
117asmlinkage long
118sys32_sigsuspend(int history0, int history1, old_sigset_t mask,
119 struct pt_regs *regs)
120{
121 sigset_t saveset;
122
123 mask &= _BLOCKABLE;
124 spin_lock_irq(&current->sighand->siglock);
125 saveset = current->blocked;
126 siginitset(&current->blocked, mask);
127 recalc_sigpending();
128 spin_unlock_irq(&current->sighand->siglock);
129
130 regs->rax = -EINTR;
131 while (1) {
132 current->state = TASK_INTERRUPTIBLE;
133 schedule();
134 if (do_signal(regs, &saveset))
135 return -EINTR;
136 }
137}
138
139asmlinkage long
140sys32_sigaltstack(const stack_ia32_t __user *uss_ptr,
141 stack_ia32_t __user *uoss_ptr,
142 struct pt_regs *regs)
143{
144 stack_t uss,uoss;
145 int ret;
146 mm_segment_t seg;
147 if (uss_ptr) {
148 u32 ptr;
149 memset(&uss,0,sizeof(stack_t));
150 if (!access_ok(VERIFY_READ,uss_ptr,sizeof(stack_ia32_t)) ||
151 __get_user(ptr, &uss_ptr->ss_sp) ||
152 __get_user(uss.ss_flags, &uss_ptr->ss_flags) ||
153 __get_user(uss.ss_size, &uss_ptr->ss_size))
154 return -EFAULT;
155 uss.ss_sp = compat_ptr(ptr);
156 }
157 seg = get_fs();
158 set_fs(KERNEL_DS);
159 ret = do_sigaltstack(uss_ptr ? &uss : NULL, &uoss, regs->rsp);
160 set_fs(seg);
161 if (ret >= 0 && uoss_ptr) {
162 if (!access_ok(VERIFY_WRITE,uoss_ptr,sizeof(stack_ia32_t)) ||
163 __put_user(ptr_to_compat(uoss.ss_sp), &uoss_ptr->ss_sp) ||
164 __put_user(uoss.ss_flags, &uoss_ptr->ss_flags) ||
165 __put_user(uoss.ss_size, &uoss_ptr->ss_size))
166 ret = -EFAULT;
167 }
168 return ret;
169}
170
171/*
172 * Do a signal return; undo the signal stack.
173 */
174
175struct sigframe
176{
177 u32 pretcode;
178 int sig;
179 struct sigcontext_ia32 sc;
180 struct _fpstate_ia32 fpstate;
181 unsigned int extramask[_COMPAT_NSIG_WORDS-1];
182 char retcode[8];
183};
184
185struct rt_sigframe
186{
187 u32 pretcode;
188 int sig;
189 u32 pinfo;
190 u32 puc;
191 compat_siginfo_t info;
192 struct ucontext_ia32 uc;
193 struct _fpstate_ia32 fpstate;
194 char retcode[8];
195};
196
197static int
198ia32_restore_sigcontext(struct pt_regs *regs, struct sigcontext_ia32 __user *sc, unsigned int *peax)
199{
200 unsigned int err = 0;
201
202 /* Always make any pending restarted system calls return -EINTR */
203 current_thread_info()->restart_block.fn = do_no_restart_syscall;
204
205#if DEBUG_SIG
206 printk("SIG restore_sigcontext: sc=%p err(%x) eip(%x) cs(%x) flg(%x)\n",
207 sc, sc->err, sc->eip, sc->cs, sc->eflags);
208#endif
209#define COPY(x) { \
210 unsigned int reg; \
211 err |= __get_user(reg, &sc->e ##x); \
212 regs->r ## x = reg; \
213}
214
215#define RELOAD_SEG(seg,mask) \
216 { unsigned int cur; \
217 unsigned short pre; \
218 err |= __get_user(pre, &sc->seg); \
219 asm volatile("movl %%" #seg ",%0" : "=r" (cur)); \
220 pre |= mask; \
221 if (pre != cur) loadsegment(seg,pre); }
222
223 /* Reload fs and gs if they have changed in the signal handler.
224 This does not handle long fs/gs base changes in the handler, but
225 does not clobber them at least in the normal case. */
226
227 {
228 unsigned gs, oldgs;
229 err |= __get_user(gs, &sc->gs);
230 gs |= 3;
231 asm("movl %%gs,%0" : "=r" (oldgs));
232 if (gs != oldgs)
233 load_gs_index(gs);
234 }
235 RELOAD_SEG(fs,3);
236 RELOAD_SEG(ds,3);
237 RELOAD_SEG(es,3);
238
239 COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
240 COPY(dx); COPY(cx); COPY(ip);
241 /* Don't touch extended registers */
242
243 err |= __get_user(regs->cs, &sc->cs);
244 regs->cs |= 3;
245 err |= __get_user(regs->ss, &sc->ss);
246 regs->ss |= 3;
247
248 {
249 unsigned int tmpflags;
250 err |= __get_user(tmpflags, &sc->eflags);
251 regs->eflags = (regs->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
252 regs->orig_rax = -1; /* disable syscall checks */
253 }
254
255 {
256 u32 tmp;
257 struct _fpstate_ia32 __user * buf;
258 err |= __get_user(tmp, &sc->fpstate);
259 buf = compat_ptr(tmp);
260 if (buf) {
261 if (!access_ok(VERIFY_READ, buf, sizeof(*buf)))
262 goto badframe;
263 err |= restore_i387_ia32(current, buf, 0);
264 } else {
265 struct task_struct *me = current;
266 if (used_math()) {
267 clear_fpu(me);
268 clear_used_math();
269 }
270 }
271 }
272
273 {
274 u32 tmp;
275 err |= __get_user(tmp, &sc->eax);
276 *peax = tmp;
277 }
278 return err;
279
280badframe:
281 return 1;
282}
283
284asmlinkage long sys32_sigreturn(struct pt_regs *regs)
285{
286 struct sigframe __user *frame = (struct sigframe __user *)(regs->rsp-8);
287 sigset_t set;
288 unsigned int eax;
289
290 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
291 goto badframe;
292 if (__get_user(set.sig[0], &frame->sc.oldmask)
293 || (_COMPAT_NSIG_WORDS > 1
294 && __copy_from_user((((char *) &set.sig) + 4), &frame->extramask,
295 sizeof(frame->extramask))))
296 goto badframe;
297
298 sigdelsetmask(&set, ~_BLOCKABLE);
299 spin_lock_irq(&current->sighand->siglock);
300 current->blocked = set;
301 recalc_sigpending();
302 spin_unlock_irq(&current->sighand->siglock);
303
304 if (ia32_restore_sigcontext(regs, &frame->sc, &eax))
305 goto badframe;
306 return eax;
307
308badframe:
309 signal_fault(regs, frame, "32bit sigreturn");
310 return 0;
311}
312
313asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs)
314{
315 struct rt_sigframe __user *frame;
316 sigset_t set;
317 unsigned int eax;
318 struct pt_regs tregs;
319
320 frame = (struct rt_sigframe __user *)(regs->rsp - 4);
321
322 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
323 goto badframe;
324 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
325 goto badframe;
326
327 sigdelsetmask(&set, ~_BLOCKABLE);
328 spin_lock_irq(&current->sighand->siglock);
329 current->blocked = set;
330 recalc_sigpending();
331 spin_unlock_irq(&current->sighand->siglock);
332
333 if (ia32_restore_sigcontext(regs, &frame->uc.uc_mcontext, &eax))
334 goto badframe;
335
336 tregs = *regs;
337 if (sys32_sigaltstack(&frame->uc.uc_stack, NULL, &tregs) == -EFAULT)
338 goto badframe;
339
340 return eax;
341
342badframe:
343 signal_fault(regs,frame,"32bit rt sigreturn");
344 return 0;
345}
346
347/*
348 * Set up a signal frame.
349 */
350
351static int
352ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc, struct _fpstate_ia32 __user *fpstate,
353 struct pt_regs *regs, unsigned int mask)
354{
355 int tmp, err = 0;
356 u32 eflags;
357
358 tmp = 0;
359 __asm__("movl %%gs,%0" : "=r"(tmp): "0"(tmp));
360 err |= __put_user(tmp, (unsigned int __user *)&sc->gs);
361 __asm__("movl %%fs,%0" : "=r"(tmp): "0"(tmp));
362 err |= __put_user(tmp, (unsigned int __user *)&sc->fs);
363 __asm__("movl %%ds,%0" : "=r"(tmp): "0"(tmp));
364 err |= __put_user(tmp, (unsigned int __user *)&sc->ds);
365 __asm__("movl %%es,%0" : "=r"(tmp): "0"(tmp));
366 err |= __put_user(tmp, (unsigned int __user *)&sc->es);
367
368 err |= __put_user((u32)regs->rdi, &sc->edi);
369 err |= __put_user((u32)regs->rsi, &sc->esi);
370 err |= __put_user((u32)regs->rbp, &sc->ebp);
371 err |= __put_user((u32)regs->rsp, &sc->esp);
372 err |= __put_user((u32)regs->rbx, &sc->ebx);
373 err |= __put_user((u32)regs->rdx, &sc->edx);
374 err |= __put_user((u32)regs->rcx, &sc->ecx);
375 err |= __put_user((u32)regs->rax, &sc->eax);
376 err |= __put_user((u32)regs->cs, &sc->cs);
377 err |= __put_user((u32)regs->ss, &sc->ss);
378 err |= __put_user(current->thread.trap_no, &sc->trapno);
379 err |= __put_user(current->thread.error_code, &sc->err);
380 err |= __put_user((u32)regs->rip, &sc->eip);
381 eflags = regs->eflags;
382 if (current->ptrace & PT_PTRACED)
383 eflags &= ~TF_MASK;
384 err |= __put_user((u32)eflags, &sc->eflags);
385 err |= __put_user((u32)regs->rsp, &sc->esp_at_signal);
386
387 tmp = save_i387_ia32(current, fpstate, regs, 0);
388 if (tmp < 0)
389 err = -EFAULT;
390 else {
391 clear_used_math();
392 stts();
393 err |= __put_user(ptr_to_compat(tmp ? fpstate : NULL),
394 &sc->fpstate);
395 }
396
397 /* non-iBCS2 extensions.. */
398 err |= __put_user(mask, &sc->oldmask);
399 err |= __put_user(current->thread.cr2, &sc->cr2);
400
401 return err;
402}
403
404/*
405 * Determine which stack to use..
406 */
407static void __user *
408get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
409{
410 unsigned long rsp;
411
412 /* Default to using normal stack */
413 rsp = regs->rsp;
414
415 /* This is the X/Open sanctioned signal stack switching. */
416 if (ka->sa.sa_flags & SA_ONSTACK) {
417 if (sas_ss_flags(rsp) == 0)
418 rsp = current->sas_ss_sp + current->sas_ss_size;
419 }
420
421 /* This is the legacy signal stack switching. */
422 else if ((regs->ss & 0xffff) != __USER_DS &&
423 !(ka->sa.sa_flags & SA_RESTORER) &&
424 ka->sa.sa_restorer) {
425 rsp = (unsigned long) ka->sa.sa_restorer;
426 }
427
428 return (void __user *)((rsp - frame_size) & -8UL);
429}
430
431void ia32_setup_frame(int sig, struct k_sigaction *ka,
432 compat_sigset_t *set, struct pt_regs * regs)
433{
434 struct sigframe __user *frame;
435 int err = 0;
436
437 frame = get_sigframe(ka, regs, sizeof(*frame));
438
439 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
440 goto give_sigsegv;
441
442 {
443 struct exec_domain *ed = current_thread_info()->exec_domain;
444 err |= __put_user((ed
445 && ed->signal_invmap
446 && sig < 32
447 ? ed->signal_invmap[sig]
448 : sig),
449 &frame->sig);
450 }
451 if (err)
452 goto give_sigsegv;
453
454 err |= ia32_setup_sigcontext(&frame->sc, &frame->fpstate, regs,
455 set->sig[0]);
456 if (err)
457 goto give_sigsegv;
458
459 if (_COMPAT_NSIG_WORDS > 1) {
460 err |= __copy_to_user(frame->extramask, &set->sig[1],
461 sizeof(frame->extramask));
462 }
463 if (err)
464 goto give_sigsegv;
465
466 /* Return stub is in 32bit vsyscall page */
467 {
468 void __user *restorer = VSYSCALL32_SIGRETURN;
469 if (ka->sa.sa_flags & SA_RESTORER)
470 restorer = ka->sa.sa_restorer;
471 err |= __put_user(ptr_to_compat(restorer), &frame->pretcode);
472 }
473 /* These are actually not used anymore, but left because some
474 gdb versions depend on them as a marker. */
475 {
476 /* copy_to_user optimizes that into a single 8 byte store */
477 static const struct {
478 u16 poplmovl;
479 u32 val;
480 u16 int80;
481 u16 pad;
482 } __attribute__((packed)) code = {
483 0xb858, /* popl %eax ; movl $...,%eax */
484 __NR_ia32_sigreturn,
485 0x80cd, /* int $0x80 */
486 0,
487 };
488 err |= __copy_to_user(frame->retcode, &code, 8);
489 }
490 if (err)
491 goto give_sigsegv;
492
493 /* Set up registers for signal handler */
494 regs->rsp = (unsigned long) frame;
495 regs->rip = (unsigned long) ka->sa.sa_handler;
496
497 asm volatile("movl %0,%%ds" :: "r" (__USER32_DS));
498 asm volatile("movl %0,%%es" :: "r" (__USER32_DS));
499
500 regs->cs = __USER32_CS;
501 regs->ss = __USER32_DS;
502
503 set_fs(USER_DS);
504 if (regs->eflags & TF_MASK) {
505 if (current->ptrace & PT_PTRACED) {
506 ptrace_notify(SIGTRAP);
507 } else {
508 regs->eflags &= ~TF_MASK;
509 }
510 }
511
512#if DEBUG_SIG
513 printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
514 current->comm, current->pid, frame, regs->rip, frame->pretcode);
515#endif
516
517 return;
518
519give_sigsegv:
520 force_sigsegv(sig, current);
521}
522
523void ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
524 compat_sigset_t *set, struct pt_regs * regs)
525{
526 struct rt_sigframe __user *frame;
527 int err = 0;
528
529 frame = get_sigframe(ka, regs, sizeof(*frame));
530
531 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
532 goto give_sigsegv;
533
534 {
535 struct exec_domain *ed = current_thread_info()->exec_domain;
536 err |= __put_user((ed
537 && ed->signal_invmap
538 && sig < 32
539 ? ed->signal_invmap[sig]
540 : sig),
541 &frame->sig);
542 }
543 err |= __put_user(ptr_to_compat(&frame->info), &frame->pinfo);
544 err |= __put_user(ptr_to_compat(&frame->uc), &frame->puc);
545 err |= copy_siginfo_to_user32(&frame->info, info);
546 if (err)
547 goto give_sigsegv;
548
549 /* Create the ucontext. */
550 err |= __put_user(0, &frame->uc.uc_flags);
551 err |= __put_user(0, &frame->uc.uc_link);
552 err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
553 err |= __put_user(sas_ss_flags(regs->rsp),
554 &frame->uc.uc_stack.ss_flags);
555 err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
556 err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate,
557 regs, set->sig[0]);
558 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
559 if (err)
560 goto give_sigsegv;
561
562
563 {
564 void __user *restorer = VSYSCALL32_RTSIGRETURN;
565 if (ka->sa.sa_flags & SA_RESTORER)
566 restorer = ka->sa.sa_restorer;
567 err |= __put_user(ptr_to_compat(restorer), &frame->pretcode);
568 }
569
570 /* This is movl $,%eax ; int $0x80 */
571 /* Not actually used anymore, but left because some gdb versions
572 need it. */
573 {
574 /* __copy_to_user optimizes that into a single 8 byte store */
575 static const struct {
576 u8 movl;
577 u32 val;
578 u16 int80;
579 u16 pad;
580 u8 pad2;
581 } __attribute__((packed)) code = {
582 0xb8,
583 __NR_ia32_rt_sigreturn,
584 0x80cd,
585 0,
586 };
587 err |= __copy_to_user(frame->retcode, &code, 8);
588 }
589 if (err)
590 goto give_sigsegv;
591
592 /* Set up registers for signal handler */
593 regs->rsp = (unsigned long) frame;
594 regs->rip = (unsigned long) ka->sa.sa_handler;
595
596 asm volatile("movl %0,%%ds" :: "r" (__USER32_DS));
597 asm volatile("movl %0,%%es" :: "r" (__USER32_DS));
598
599 regs->cs = __USER32_CS;
600 regs->ss = __USER32_DS;
601
602 set_fs(USER_DS);
603 if (regs->eflags & TF_MASK) {
604 if (current->ptrace & PT_PTRACED) {
605 ptrace_notify(SIGTRAP);
606 } else {
607 regs->eflags &= ~TF_MASK;
608 }
609 }
610
611#if DEBUG_SIG
612 printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
613 current->comm, current->pid, frame, regs->rip, frame->pretcode);
614#endif
615
616 return;
617
618give_sigsegv:
619 force_sigsegv(sig, current);
620}
621
diff --git a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S
new file mode 100644
index 000000000000..f3ca0db85b5b
--- /dev/null
+++ b/arch/x86_64/ia32/ia32entry.S
@@ -0,0 +1,602 @@
1/*
2 * Compatibility mode system call entry point for x86-64.
3 *
4 * Copyright 2000-2002 Andi Kleen, SuSE Labs.
5 */
6
7#include <asm/dwarf2.h>
8#include <asm/calling.h>
9#include <asm/offset.h>
10#include <asm/current.h>
11#include <asm/errno.h>
12#include <asm/ia32_unistd.h>
13#include <asm/thread_info.h>
14#include <asm/segment.h>
15#include <asm/vsyscall32.h>
16#include <linux/linkage.h>
17
18 .macro IA32_ARG_FIXUP noebp=0
19 movl %edi,%r8d
20 .if \noebp
21 .else
22 movl %ebp,%r9d
23 .endif
24 xchg %ecx,%esi
25 movl %ebx,%edi
26 movl %edx,%edx /* zero extension */
27 .endm
28
29 /* clobbers %eax */
30 .macro CLEAR_RREGS
31 xorl %eax,%eax
32 movq %rax,R11(%rsp)
33 movq %rax,R10(%rsp)
34 movq %rax,R9(%rsp)
35 movq %rax,R8(%rsp)
36 .endm
37
38/*
39 * 32bit SYSENTER instruction entry.
40 *
41 * Arguments:
42 * %eax System call number.
43 * %ebx Arg1
44 * %ecx Arg2
45 * %edx Arg3
46 * %esi Arg4
47 * %edi Arg5
48 * %ebp user stack
49 * 0(%ebp) Arg6
50 *
51 * Interrupts off.
52 *
53 * This is purely a fast path. For anything complicated we use the int 0x80
54 * path below. Set up a complete hardware stack frame to share code
55 * with the int 0x80 path.
56 */
57ENTRY(ia32_sysenter_target)
58 CFI_STARTPROC
59 swapgs
60 movq %gs:pda_kernelstack, %rsp
61 addq $(PDA_STACKOFFSET),%rsp
62 sti
63 movl %ebp,%ebp /* zero extension */
64 pushq $__USER32_DS
65 pushq %rbp
66 pushfq
67 movl $VSYSCALL32_SYSEXIT, %r10d
68 pushq $__USER32_CS
69 movl %eax, %eax
70 pushq %r10
71 pushq %rax
72 cld
73 SAVE_ARGS 0,0,1
74 /* no need to do an access_ok check here because rbp has been
75 32bit zero extended */
761: movl (%rbp),%r9d
77 .section __ex_table,"a"
78 .quad 1b,ia32_badarg
79 .previous
80 GET_THREAD_INFO(%r10)
81 testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%r10)
82 jnz sysenter_tracesys
83sysenter_do_call:
84 cmpl $(IA32_NR_syscalls),%eax
85 jae ia32_badsys
86 IA32_ARG_FIXUP 1
87 call *ia32_sys_call_table(,%rax,8)
88 movq %rax,RAX-ARGOFFSET(%rsp)
89 GET_THREAD_INFO(%r10)
90 cli
91 testl $_TIF_ALLWORK_MASK,threadinfo_flags(%r10)
92 jnz int_ret_from_sys_call
93 /* clear IF, that popfq doesn't enable interrupts early */
94 andl $~0x200,EFLAGS-R11(%rsp)
95 RESTORE_ARGS 1,24,1,1,1,1
96 popfq
97 popq %rcx /* User %esp */
98 movl $VSYSCALL32_SYSEXIT,%edx /* User %eip */
99 swapgs
100 sti /* sti only takes effect after the next instruction */
101 /* sysexit */
102 .byte 0xf, 0x35
103
104sysenter_tracesys:
105 SAVE_REST
106 CLEAR_RREGS
107 movq $-ENOSYS,RAX(%rsp) /* really needed? */
108 movq %rsp,%rdi /* &pt_regs -> arg1 */
109 call syscall_trace_enter
110 LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */
111 RESTORE_REST
112 movl %ebp, %ebp
113 /* no need to do an access_ok check here because rbp has been
114 32bit zero extended */
1151: movl (%rbp),%r9d
116 .section __ex_table,"a"
117 .quad 1b,ia32_badarg
118 .previous
119 jmp sysenter_do_call
120 CFI_ENDPROC
121
122/*
123 * 32bit SYSCALL instruction entry.
124 *
125 * Arguments:
126 * %eax System call number.
127 * %ebx Arg1
128 * %ecx return EIP
129 * %edx Arg3
130 * %esi Arg4
131 * %edi Arg5
132 * %ebp Arg2 [note: not saved in the stack frame, should not be touched]
133 * %esp user stack
134 * 0(%esp) Arg6
135 *
136 * Interrupts off.
137 *
138 * This is purely a fast path. For anything complicated we use the int 0x80
139 * path below. Set up a complete hardware stack frame to share code
140 * with the int 0x80 path.
141 */
142ENTRY(ia32_cstar_target)
143 CFI_STARTPROC
144 swapgs
145 movl %esp,%r8d
146 movq %gs:pda_kernelstack,%rsp
147 sti
148 SAVE_ARGS 8,1,1
149 movl %eax,%eax /* zero extension */
150 movq %rax,ORIG_RAX-ARGOFFSET(%rsp)
151 movq %rcx,RIP-ARGOFFSET(%rsp)
152 movq %rbp,RCX-ARGOFFSET(%rsp) /* this lies slightly to ptrace */
153 movl %ebp,%ecx
154 movq $__USER32_CS,CS-ARGOFFSET(%rsp)
155 movq $__USER32_DS,SS-ARGOFFSET(%rsp)
156 movq %r11,EFLAGS-ARGOFFSET(%rsp)
157 movq %r8,RSP-ARGOFFSET(%rsp)
158 /* no need to do an access_ok check here because r8 has been
159 32bit zero extended */
160 /* hardware stack frame is complete now */
1611: movl (%r8),%r9d
162 .section __ex_table,"a"
163 .quad 1b,ia32_badarg
164 .previous
165 GET_THREAD_INFO(%r10)
166 testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%r10)
167 jnz cstar_tracesys
168cstar_do_call:
169 cmpl $IA32_NR_syscalls,%eax
170 jae ia32_badsys
171 IA32_ARG_FIXUP 1
172 call *ia32_sys_call_table(,%rax,8)
173 movq %rax,RAX-ARGOFFSET(%rsp)
174 GET_THREAD_INFO(%r10)
175 cli
176 testl $_TIF_ALLWORK_MASK,threadinfo_flags(%r10)
177 jnz int_ret_from_sys_call
178 RESTORE_ARGS 1,-ARG_SKIP,1,1,1
179 movl RIP-ARGOFFSET(%rsp),%ecx
180 movl EFLAGS-ARGOFFSET(%rsp),%r11d
181 movl RSP-ARGOFFSET(%rsp),%esp
182 swapgs
183 sysretl
184
185cstar_tracesys:
186 SAVE_REST
187 CLEAR_RREGS
188 movq $-ENOSYS,RAX(%rsp) /* really needed? */
189 movq %rsp,%rdi /* &pt_regs -> arg1 */
190 call syscall_trace_enter
191 LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */
192 RESTORE_REST
193 movl RSP-ARGOFFSET(%rsp), %r8d
194 /* no need to do an access_ok check here because r8 has been
195 32bit zero extended */
1961: movl (%r8),%r9d
197 .section __ex_table,"a"
198 .quad 1b,ia32_badarg
199 .previous
200 jmp cstar_do_call
201
202ia32_badarg:
203 movq $-EFAULT,%rax
204 jmp ia32_sysret
205 CFI_ENDPROC
206
207/*
208 * Emulated IA32 system calls via int 0x80.
209 *
210 * Arguments:
211 * %eax System call number.
212 * %ebx Arg1
213 * %ecx Arg2
214 * %edx Arg3
215 * %esi Arg4
216 * %edi Arg5
217 * %ebp Arg6 [note: not saved in the stack frame, should not be touched]
218 *
219 * Notes:
220 * Uses the same stack frame as the x86-64 version.
221 * All registers except %eax must be saved (but ptrace may violate that)
222 * Arguments are zero extended. For system calls that want sign extension and
223 * take long arguments a wrapper is needed. Most calls can just be called
224 * directly.
225 * Assumes it is only called from user space and entered with interrupts off.
226 */
227
228ENTRY(ia32_syscall)
229 CFI_STARTPROC
230 swapgs
231 sti
232 movl %eax,%eax
233 pushq %rax
234 cld
235 /* note the registers are not zero extended to the sf.
236 this could be a problem. */
237 SAVE_ARGS 0,0,1
238 GET_THREAD_INFO(%r10)
239 testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%r10)
240 jnz ia32_tracesys
241ia32_do_syscall:
242 cmpl $(IA32_NR_syscalls),%eax
243 jae ia32_badsys
244 IA32_ARG_FIXUP
245 call *ia32_sys_call_table(,%rax,8) # xxx: rip relative
246ia32_sysret:
247 movq %rax,RAX-ARGOFFSET(%rsp)
248 jmp int_ret_from_sys_call
249
250ia32_tracesys:
251 SAVE_REST
252 movq $-ENOSYS,RAX(%rsp) /* really needed? */
253 movq %rsp,%rdi /* &pt_regs -> arg1 */
254 call syscall_trace_enter
255 LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */
256 RESTORE_REST
257 jmp ia32_do_syscall
258
259ia32_badsys:
260 movq $0,ORIG_RAX-ARGOFFSET(%rsp)
261 movq $-ENOSYS,RAX-ARGOFFSET(%rsp)
262 jmp int_ret_from_sys_call
263
264ni_syscall:
265 movq %rax,%rdi
266 jmp sys32_ni_syscall
267
268quiet_ni_syscall:
269 movq $-ENOSYS,%rax
270 ret
271 CFI_ENDPROC
272
273 .macro PTREGSCALL label, func, arg
274 .globl \label
275\label:
276 leaq \func(%rip),%rax
277 leaq -ARGOFFSET+8(%rsp),\arg /* 8 for return address */
278 jmp ia32_ptregs_common
279 .endm
280
281 PTREGSCALL stub32_rt_sigreturn, sys32_rt_sigreturn, %rdi
282 PTREGSCALL stub32_sigreturn, sys32_sigreturn, %rdi
283 PTREGSCALL stub32_sigaltstack, sys32_sigaltstack, %rdx
284 PTREGSCALL stub32_sigsuspend, sys32_sigsuspend, %rcx
285 PTREGSCALL stub32_execve, sys32_execve, %rcx
286 PTREGSCALL stub32_fork, sys_fork, %rdi
287 PTREGSCALL stub32_clone, sys32_clone, %rdx
288 PTREGSCALL stub32_vfork, sys_vfork, %rdi
289 PTREGSCALL stub32_iopl, sys_iopl, %rsi
290 PTREGSCALL stub32_rt_sigsuspend, sys_rt_sigsuspend, %rdx
291
292ENTRY(ia32_ptregs_common)
293 CFI_STARTPROC
294 popq %r11
295 SAVE_REST
296 call *%rax
297 RESTORE_REST
298 jmp ia32_sysret /* misbalances the return cache */
299 CFI_ENDPROC
300
301 .data
302 .align 8
303 .globl ia32_sys_call_table
304ia32_sys_call_table:
305 .quad sys_restart_syscall
306 .quad sys_exit
307 .quad stub32_fork
308 .quad sys_read
309 .quad sys_write
310 .quad sys32_open /* 5 */
311 .quad sys_close
312 .quad sys32_waitpid
313 .quad sys_creat
314 .quad sys_link
315 .quad sys_unlink /* 10 */
316 .quad stub32_execve
317 .quad sys_chdir
318 .quad compat_sys_time
319 .quad sys_mknod
320 .quad sys_chmod /* 15 */
321 .quad sys_lchown16
322 .quad quiet_ni_syscall /* old break syscall holder */
323 .quad sys_stat
324 .quad sys32_lseek
325 .quad sys_getpid /* 20 */
326 .quad compat_sys_mount /* mount */
327 .quad sys_oldumount /* old_umount */
328 .quad sys_setuid16
329 .quad sys_getuid16
330 .quad compat_sys_stime /* stime */ /* 25 */
331 .quad sys32_ptrace /* ptrace */
332 .quad sys_alarm
333 .quad sys_fstat /* (old)fstat */
334 .quad sys_pause
335 .quad compat_sys_utime /* 30 */
336 .quad quiet_ni_syscall /* old stty syscall holder */
337 .quad quiet_ni_syscall /* old gtty syscall holder */
338 .quad sys_access
339 .quad sys_nice
340 .quad quiet_ni_syscall /* 35 */ /* old ftime syscall holder */
341 .quad sys_sync
342 .quad sys32_kill
343 .quad sys_rename
344 .quad sys_mkdir
345 .quad sys_rmdir /* 40 */
346 .quad sys_dup
347 .quad sys32_pipe
348 .quad compat_sys_times
349 .quad quiet_ni_syscall /* old prof syscall holder */
350 .quad sys_brk /* 45 */
351 .quad sys_setgid16
352 .quad sys_getgid16
353 .quad sys_signal
354 .quad sys_geteuid16
355 .quad sys_getegid16 /* 50 */
356 .quad sys_acct
357 .quad sys_umount /* new_umount */
358 .quad quiet_ni_syscall /* old lock syscall holder */
359 .quad compat_sys_ioctl
360 .quad compat_sys_fcntl64 /* 55 */
361 .quad quiet_ni_syscall /* old mpx syscall holder */
362 .quad sys_setpgid
363 .quad quiet_ni_syscall /* old ulimit syscall holder */
364 .quad sys32_olduname
365 .quad sys_umask /* 60 */
366 .quad sys_chroot
367 .quad sys32_ustat
368 .quad sys_dup2
369 .quad sys_getppid
370 .quad sys_getpgrp /* 65 */
371 .quad sys_setsid
372 .quad sys32_sigaction
373 .quad sys_sgetmask
374 .quad sys_ssetmask
375 .quad sys_setreuid16 /* 70 */
376 .quad sys_setregid16
377 .quad stub32_sigsuspend
378 .quad compat_sys_sigpending
379 .quad sys_sethostname
380 .quad compat_sys_setrlimit /* 75 */
381 .quad compat_sys_old_getrlimit /* old_getrlimit */
382 .quad compat_sys_getrusage
383 .quad sys32_gettimeofday
384 .quad sys32_settimeofday
385 .quad sys_getgroups16 /* 80 */
386 .quad sys_setgroups16
387 .quad sys32_old_select
388 .quad sys_symlink
389 .quad sys_lstat
390 .quad sys_readlink /* 85 */
391#ifdef CONFIG_IA32_AOUT
392 .quad sys_uselib
393#else
394 .quad quiet_ni_syscall
395#endif
396 .quad sys_swapon
397 .quad sys_reboot
398 .quad compat_sys_old_readdir
399 .quad sys32_mmap /* 90 */
400 .quad sys_munmap
401 .quad sys_truncate
402 .quad sys_ftruncate
403 .quad sys_fchmod
404 .quad sys_fchown16 /* 95 */
405 .quad sys_getpriority
406 .quad sys_setpriority
407 .quad quiet_ni_syscall /* old profil syscall holder */
408 .quad compat_sys_statfs
409 .quad compat_sys_fstatfs /* 100 */
410 .quad sys_ioperm
411 .quad compat_sys_socketcall
412 .quad sys_syslog
413 .quad compat_sys_setitimer
414 .quad compat_sys_getitimer /* 105 */
415 .quad compat_sys_newstat
416 .quad compat_sys_newlstat
417 .quad compat_sys_newfstat
418 .quad sys32_uname
419 .quad stub32_iopl /* 110 */
420 .quad sys_vhangup
421 .quad quiet_ni_syscall /* old "idle" system call */
422 .quad sys32_vm86_warning /* vm86old */
423 .quad compat_sys_wait4
424 .quad sys_swapoff /* 115 */
425 .quad sys32_sysinfo
426 .quad sys32_ipc
427 .quad sys_fsync
428 .quad stub32_sigreturn
429 .quad stub32_clone /* 120 */
430 .quad sys_setdomainname
431 .quad sys_uname
432 .quad sys_modify_ldt
433 .quad sys32_adjtimex
434 .quad sys32_mprotect /* 125 */
435 .quad compat_sys_sigprocmask
436 .quad quiet_ni_syscall /* create_module */
437 .quad sys_init_module
438 .quad sys_delete_module
439 .quad quiet_ni_syscall /* 130 get_kernel_syms */
440 .quad sys_quotactl
441 .quad sys_getpgid
442 .quad sys_fchdir
443 .quad quiet_ni_syscall /* bdflush */
444 .quad sys_sysfs /* 135 */
445 .quad sys_personality
446 .quad quiet_ni_syscall /* for afs_syscall */
447 .quad sys_setfsuid16
448 .quad sys_setfsgid16
449 .quad sys_llseek /* 140 */
450 .quad compat_sys_getdents
451 .quad compat_sys_select
452 .quad sys_flock
453 .quad sys_msync
454 .quad compat_sys_readv /* 145 */
455 .quad compat_sys_writev
456 .quad sys_getsid
457 .quad sys_fdatasync
458 .quad sys32_sysctl /* sysctl */
459 .quad sys_mlock /* 150 */
460 .quad sys_munlock
461 .quad sys_mlockall
462 .quad sys_munlockall
463 .quad sys_sched_setparam
464 .quad sys_sched_getparam /* 155 */
465 .quad sys_sched_setscheduler
466 .quad sys_sched_getscheduler
467 .quad sys_sched_yield
468 .quad sys_sched_get_priority_max
469 .quad sys_sched_get_priority_min /* 160 */
470 .quad sys_sched_rr_get_interval
471 .quad compat_sys_nanosleep
472 .quad sys_mremap
473 .quad sys_setresuid16
474 .quad sys_getresuid16 /* 165 */
475 .quad sys32_vm86_warning /* vm86 */
476 .quad quiet_ni_syscall /* query_module */
477 .quad sys_poll
478 .quad compat_sys_nfsservctl
479 .quad sys_setresgid16 /* 170 */
480 .quad sys_getresgid16
481 .quad sys_prctl
482 .quad stub32_rt_sigreturn
483 .quad sys32_rt_sigaction
484 .quad sys32_rt_sigprocmask /* 175 */
485 .quad sys32_rt_sigpending
486 .quad compat_sys_rt_sigtimedwait
487 .quad sys32_rt_sigqueueinfo
488 .quad stub32_rt_sigsuspend
489 .quad sys32_pread /* 180 */
490 .quad sys32_pwrite
491 .quad sys_chown16
492 .quad sys_getcwd
493 .quad sys_capget
494 .quad sys_capset
495 .quad stub32_sigaltstack
496 .quad sys32_sendfile
497 .quad quiet_ni_syscall /* streams1 */
498 .quad quiet_ni_syscall /* streams2 */
499 .quad stub32_vfork /* 190 */
500 .quad compat_sys_getrlimit
501 .quad sys32_mmap2
502 .quad sys32_truncate64
503 .quad sys32_ftruncate64
504 .quad sys32_stat64 /* 195 */
505 .quad sys32_lstat64
506 .quad sys32_fstat64
507 .quad sys_lchown
508 .quad sys_getuid
509 .quad sys_getgid /* 200 */
510 .quad sys_geteuid
511 .quad sys_getegid
512 .quad sys_setreuid
513 .quad sys_setregid
514 .quad sys_getgroups /* 205 */
515 .quad sys_setgroups
516 .quad sys_fchown
517 .quad sys_setresuid
518 .quad sys_getresuid
519 .quad sys_setresgid /* 210 */
520 .quad sys_getresgid
521 .quad sys_chown
522 .quad sys_setuid
523 .quad sys_setgid
524 .quad sys_setfsuid /* 215 */
525 .quad sys_setfsgid
526 .quad sys_pivot_root
527 .quad sys_mincore
528 .quad sys_madvise
529 .quad compat_sys_getdents64 /* 220 getdents64 */
530 .quad compat_sys_fcntl64
531 .quad quiet_ni_syscall /* tux */
532 .quad quiet_ni_syscall /* security */
533 .quad sys_gettid
534 .quad sys_readahead /* 225 */
535 .quad sys_setxattr
536 .quad sys_lsetxattr
537 .quad sys_fsetxattr
538 .quad sys_getxattr
539 .quad sys_lgetxattr /* 230 */
540 .quad sys_fgetxattr
541 .quad sys_listxattr
542 .quad sys_llistxattr
543 .quad sys_flistxattr
544 .quad sys_removexattr /* 235 */
545 .quad sys_lremovexattr
546 .quad sys_fremovexattr
547 .quad sys_tkill
548 .quad sys_sendfile64
549 .quad compat_sys_futex /* 240 */
550 .quad compat_sys_sched_setaffinity
551 .quad compat_sys_sched_getaffinity
552 .quad sys32_set_thread_area
553 .quad sys32_get_thread_area
554 .quad compat_sys_io_setup /* 245 */
555 .quad sys_io_destroy
556 .quad compat_sys_io_getevents
557 .quad compat_sys_io_submit
558 .quad sys_io_cancel
559 .quad sys_fadvise64 /* 250 */
560 .quad quiet_ni_syscall /* free_huge_pages */
561 .quad sys_exit_group
562 .quad sys32_lookup_dcookie
563 .quad sys_epoll_create
564 .quad sys_epoll_ctl /* 255 */
565 .quad sys_epoll_wait
566 .quad sys_remap_file_pages
567 .quad sys_set_tid_address
568 .quad sys32_timer_create
569 .quad compat_sys_timer_settime /* 260 */
570 .quad compat_sys_timer_gettime
571 .quad sys_timer_getoverrun
572 .quad sys_timer_delete
573 .quad compat_sys_clock_settime
574 .quad compat_sys_clock_gettime /* 265 */
575 .quad compat_sys_clock_getres
576 .quad compat_sys_clock_nanosleep
577 .quad compat_sys_statfs64
578 .quad compat_sys_fstatfs64
579 .quad sys_tgkill /* 270 */
580 .quad compat_sys_utimes
581 .quad sys32_fadvise64_64
582 .quad quiet_ni_syscall /* sys_vserver */
583 .quad sys_mbind
584 .quad compat_sys_get_mempolicy /* 275 */
585 .quad sys_set_mempolicy
586 .quad compat_sys_mq_open
587 .quad sys_mq_unlink
588 .quad compat_sys_mq_timedsend
589 .quad compat_sys_mq_timedreceive /* 280 */
590 .quad compat_sys_mq_notify
591 .quad compat_sys_mq_getsetattr
592 .quad quiet_ni_syscall /* reserved for kexec */
593 .quad compat_sys_waitid
594 .quad quiet_ni_syscall /* sys_altroot */
595 .quad sys_add_key
596 .quad sys_request_key
597 .quad sys_keyctl
598 /* don't forget to change IA32_NR_syscalls */
599ia32_syscall_end:
600 .rept IA32_NR_syscalls-(ia32_syscall_end-ia32_sys_call_table)/8
601 .quad ni_syscall
602 .endr
diff --git a/arch/x86_64/ia32/ipc32.c b/arch/x86_64/ia32/ipc32.c
new file mode 100644
index 000000000000..369151dc3213
--- /dev/null
+++ b/arch/x86_64/ia32/ipc32.c
@@ -0,0 +1,57 @@
1#include <linux/kernel.h>
2#include <linux/spinlock.h>
3#include <linux/list.h>
4#include <linux/syscalls.h>
5#include <linux/time.h>
6#include <linux/sem.h>
7#include <linux/msg.h>
8#include <linux/shm.h>
9#include <linux/ipc.h>
10#include <linux/compat.h>
11
12#include <asm-i386/ipc.h>
13
14asmlinkage long
15sys32_ipc(u32 call, int first, int second, int third,
16 compat_uptr_t ptr, u32 fifth)
17{
18 int version;
19
20 version = call >> 16; /* hack for backward compatibility */
21 call &= 0xffff;
22
23 switch (call) {
24 case SEMOP:
25 /* struct sembuf is the same on 32 and 64bit :)) */
26 return sys_semtimedop(first, compat_ptr(ptr), second, NULL);
27 case SEMTIMEDOP:
28 return compat_sys_semtimedop(first, compat_ptr(ptr), second,
29 compat_ptr(fifth));
30 case SEMGET:
31 return sys_semget(first, second, third);
32 case SEMCTL:
33 return compat_sys_semctl(first, second, third, compat_ptr(ptr));
34
35 case MSGSND:
36 return compat_sys_msgsnd(first, second, third, compat_ptr(ptr));
37 case MSGRCV:
38 return compat_sys_msgrcv(first, second, fifth, third,
39 version, compat_ptr(ptr));
40 case MSGGET:
41 return sys_msgget((key_t) first, second);
42 case MSGCTL:
43 return compat_sys_msgctl(first, second, compat_ptr(ptr));
44
45 case SHMAT:
46 return compat_sys_shmat(first, second, third, version,
47 compat_ptr(ptr));
48 break;
49 case SHMDT:
50 return sys_shmdt(compat_ptr(ptr));
51 case SHMGET:
52 return sys_shmget(first, (unsigned)second, third);
53 case SHMCTL:
54 return compat_sys_shmctl(first, second, compat_ptr(ptr));
55 }
56 return -ENOSYS;
57}
diff --git a/arch/x86_64/ia32/ptrace32.c b/arch/x86_64/ia32/ptrace32.c
new file mode 100644
index 000000000000..b98b6d2462f6
--- /dev/null
+++ b/arch/x86_64/ia32/ptrace32.c
@@ -0,0 +1,379 @@
1/*
2 * 32bit ptrace for x86-64.
3 *
4 * Copyright 2001,2002 Andi Kleen, SuSE Labs.
5 * Some parts copied from arch/i386/kernel/ptrace.c. See that file for earlier
6 * copyright.
7 *
8 * This allows to access 64bit processes too; but there is no way to see the extended
9 * register contents.
10 *
11 * $Id: ptrace32.c,v 1.16 2003/03/14 16:06:35 ak Exp $
12 */
13
14#include <linux/kernel.h>
15#include <linux/stddef.h>
16#include <linux/sched.h>
17#include <linux/syscalls.h>
18#include <linux/unistd.h>
19#include <linux/mm.h>
20#include <linux/ptrace.h>
21#include <asm/ptrace.h>
22#include <asm/compat.h>
23#include <asm/uaccess.h>
24#include <asm/user32.h>
25#include <asm/user.h>
26#include <asm/errno.h>
27#include <asm/debugreg.h>
28#include <asm/i387.h>
29#include <asm/fpu32.h>
30
31/* determines which flags the user has access to. */
32/* 1 = access 0 = no access */
33#define FLAG_MASK 0x44dd5UL
34
35#define R32(l,q) \
36 case offsetof(struct user32, regs.l): stack[offsetof(struct pt_regs, q)/8] = val; break
37
38static int putreg32(struct task_struct *child, unsigned regno, u32 val)
39{
40 int i;
41 __u64 *stack = (__u64 *)(child->thread.rsp0 - sizeof(struct pt_regs));
42
43 switch (regno) {
44 case offsetof(struct user32, regs.fs):
45 if (val && (val & 3) != 3) return -EIO;
46 child->thread.fs = val & 0xffff;
47 break;
48 case offsetof(struct user32, regs.gs):
49 if (val && (val & 3) != 3) return -EIO;
50 child->thread.gs = val & 0xffff;
51 break;
52 case offsetof(struct user32, regs.ds):
53 if (val && (val & 3) != 3) return -EIO;
54 child->thread.ds = val & 0xffff;
55 break;
56 case offsetof(struct user32, regs.es):
57 child->thread.es = val & 0xffff;
58 break;
59 case offsetof(struct user32, regs.ss):
60 if ((val & 3) != 3) return -EIO;
61 stack[offsetof(struct pt_regs, ss)/8] = val & 0xffff;
62 break;
63 case offsetof(struct user32, regs.cs):
64 if ((val & 3) != 3) return -EIO;
65 stack[offsetof(struct pt_regs, cs)/8] = val & 0xffff;
66 break;
67
68 R32(ebx, rbx);
69 R32(ecx, rcx);
70 R32(edx, rdx);
71 R32(edi, rdi);
72 R32(esi, rsi);
73 R32(ebp, rbp);
74 R32(eax, rax);
75 R32(orig_eax, orig_rax);
76 R32(eip, rip);
77 R32(esp, rsp);
78
79 case offsetof(struct user32, regs.eflags): {
80 __u64 *flags = &stack[offsetof(struct pt_regs, eflags)/8];
81 val &= FLAG_MASK;
82 *flags = val | (*flags & ~FLAG_MASK);
83 break;
84 }
85
86 case offsetof(struct user32, u_debugreg[4]):
87 case offsetof(struct user32, u_debugreg[5]):
88 return -EIO;
89
90 case offsetof(struct user32, u_debugreg[0]):
91 child->thread.debugreg0 = val;
92 break;
93
94 case offsetof(struct user32, u_debugreg[1]):
95 child->thread.debugreg1 = val;
96 break;
97
98 case offsetof(struct user32, u_debugreg[2]):
99 child->thread.debugreg2 = val;
100 break;
101
102 case offsetof(struct user32, u_debugreg[3]):
103 child->thread.debugreg3 = val;
104 break;
105
106 case offsetof(struct user32, u_debugreg[6]):
107 child->thread.debugreg6 = val;
108 break;
109
110 case offsetof(struct user32, u_debugreg[7]):
111 val &= ~DR_CONTROL_RESERVED;
112 /* See arch/i386/kernel/ptrace.c for an explanation of
113 * this awkward check.*/
114 for(i=0; i<4; i++)
115 if ((0x5454 >> ((val >> (16 + 4*i)) & 0xf)) & 1)
116 return -EIO;
117 child->thread.debugreg7 = val;
118 break;
119
120 default:
121 if (regno > sizeof(struct user32) || (regno & 3))
122 return -EIO;
123
124 /* Other dummy fields in the virtual user structure are ignored */
125 break;
126 }
127 return 0;
128}
129
130#undef R32
131
132#define R32(l,q) \
133 case offsetof(struct user32, regs.l): *val = stack[offsetof(struct pt_regs, q)/8]; break
134
135static int getreg32(struct task_struct *child, unsigned regno, u32 *val)
136{
137 __u64 *stack = (__u64 *)(child->thread.rsp0 - sizeof(struct pt_regs));
138
139 switch (regno) {
140 case offsetof(struct user32, regs.fs):
141 *val = child->thread.fs;
142 break;
143 case offsetof(struct user32, regs.gs):
144 *val = child->thread.gs;
145 break;
146 case offsetof(struct user32, regs.ds):
147 *val = child->thread.ds;
148 break;
149 case offsetof(struct user32, regs.es):
150 *val = child->thread.es;
151 break;
152
153 R32(cs, cs);
154 R32(ss, ss);
155 R32(ebx, rbx);
156 R32(ecx, rcx);
157 R32(edx, rdx);
158 R32(edi, rdi);
159 R32(esi, rsi);
160 R32(ebp, rbp);
161 R32(eax, rax);
162 R32(orig_eax, orig_rax);
163 R32(eip, rip);
164 R32(eflags, eflags);
165 R32(esp, rsp);
166
167 case offsetof(struct user32, u_debugreg[0]):
168 *val = child->thread.debugreg0;
169 break;
170 case offsetof(struct user32, u_debugreg[1]):
171 *val = child->thread.debugreg1;
172 break;
173 case offsetof(struct user32, u_debugreg[2]):
174 *val = child->thread.debugreg2;
175 break;
176 case offsetof(struct user32, u_debugreg[3]):
177 *val = child->thread.debugreg3;
178 break;
179 case offsetof(struct user32, u_debugreg[6]):
180 *val = child->thread.debugreg6;
181 break;
182 case offsetof(struct user32, u_debugreg[7]):
183 *val = child->thread.debugreg7;
184 break;
185
186 default:
187 if (regno > sizeof(struct user32) || (regno & 3))
188 return -EIO;
189
190 /* Other dummy fields in the virtual user structure are ignored */
191 *val = 0;
192 break;
193 }
194 return 0;
195}
196
197#undef R32
198
199static struct task_struct *find_target(int request, int pid, int *err)
200{
201 struct task_struct *child;
202
203 *err = -EPERM;
204 if (pid == 1)
205 return NULL;
206
207 *err = -ESRCH;
208 read_lock(&tasklist_lock);
209 child = find_task_by_pid(pid);
210 if (child)
211 get_task_struct(child);
212 read_unlock(&tasklist_lock);
213 if (child) {
214 *err = -EPERM;
215 if (child->pid == 1)
216 goto out;
217 *err = ptrace_check_attach(child, request == PTRACE_KILL);
218 if (*err < 0)
219 goto out;
220 return child;
221 }
222 out:
223 if (child)
224 put_task_struct(child);
225 return NULL;
226
227}
228
229asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data)
230{
231 struct task_struct *child;
232 struct pt_regs *childregs;
233 void __user *datap = compat_ptr(data);
234 int ret;
235 __u32 val;
236
237 switch (request) {
238 default:
239 return sys_ptrace(request, pid, addr, data);
240
241 case PTRACE_PEEKTEXT:
242 case PTRACE_PEEKDATA:
243 case PTRACE_POKEDATA:
244 case PTRACE_POKETEXT:
245 case PTRACE_POKEUSR:
246 case PTRACE_PEEKUSR:
247 case PTRACE_GETREGS:
248 case PTRACE_SETREGS:
249 case PTRACE_SETFPREGS:
250 case PTRACE_GETFPREGS:
251 case PTRACE_SETFPXREGS:
252 case PTRACE_GETFPXREGS:
253 case PTRACE_GETEVENTMSG:
254 break;
255 }
256
257 child = find_target(request, pid, &ret);
258 if (!child)
259 return ret;
260
261 childregs = (struct pt_regs *)(child->thread.rsp0 - sizeof(struct pt_regs));
262
263 switch (request) {
264 case PTRACE_PEEKDATA:
265 case PTRACE_PEEKTEXT:
266 ret = 0;
267 if (access_process_vm(child, addr, &val, sizeof(u32), 0)!=sizeof(u32))
268 ret = -EIO;
269 else
270 ret = put_user(val, (unsigned int __user *)datap);
271 break;
272
273 case PTRACE_POKEDATA:
274 case PTRACE_POKETEXT:
275 ret = 0;
276 if (access_process_vm(child, addr, &data, sizeof(u32), 1)!=sizeof(u32))
277 ret = -EIO;
278 break;
279
280 case PTRACE_PEEKUSR:
281 ret = getreg32(child, addr, &val);
282 if (ret == 0)
283 ret = put_user(val, (__u32 __user *)datap);
284 break;
285
286 case PTRACE_POKEUSR:
287 ret = putreg32(child, addr, data);
288 break;
289
290 case PTRACE_GETREGS: { /* Get all gp regs from the child. */
291 int i;
292 if (!access_ok(VERIFY_WRITE, datap, 16*4)) {
293 ret = -EIO;
294 break;
295 }
296 ret = 0;
297 for ( i = 0; i <= 16*4 ; i += sizeof(__u32) ) {
298 getreg32(child, i, &val);
299 ret |= __put_user(val,(u32 __user *)datap);
300 datap += sizeof(u32);
301 }
302 break;
303 }
304
305 case PTRACE_SETREGS: { /* Set all gp regs in the child. */
306 unsigned long tmp;
307 int i;
308 if (!access_ok(VERIFY_READ, datap, 16*4)) {
309 ret = -EIO;
310 break;
311 }
312 ret = 0;
313 for ( i = 0; i <= 16*4; i += sizeof(u32) ) {
314 ret |= __get_user(tmp, (u32 __user *)datap);
315 putreg32(child, i, tmp);
316 datap += sizeof(u32);
317 }
318 break;
319 }
320
321 case PTRACE_GETFPREGS:
322 ret = -EIO;
323 if (!access_ok(VERIFY_READ, compat_ptr(data),
324 sizeof(struct user_i387_struct)))
325 break;
326 save_i387_ia32(child, datap, childregs, 1);
327 ret = 0;
328 break;
329
330 case PTRACE_SETFPREGS:
331 ret = -EIO;
332 if (!access_ok(VERIFY_WRITE, datap,
333 sizeof(struct user_i387_struct)))
334 break;
335 ret = 0;
336 /* don't check EFAULT to be bug-to-bug compatible to i386 */
337 restore_i387_ia32(child, datap, 1);
338 break;
339
340 case PTRACE_GETFPXREGS: {
341 struct user32_fxsr_struct __user *u = datap;
342 init_fpu(child);
343 ret = -EIO;
344 if (!access_ok(VERIFY_WRITE, u, sizeof(*u)))
345 break;
346 ret = -EFAULT;
347 if (__copy_to_user(u, &child->thread.i387.fxsave, sizeof(*u)))
348 break;
349 ret = __put_user(childregs->cs, &u->fcs);
350 ret |= __put_user(child->thread.ds, &u->fos);
351 break;
352 }
353 case PTRACE_SETFPXREGS: {
354 struct user32_fxsr_struct __user *u = datap;
355 unlazy_fpu(child);
356 ret = -EIO;
357 if (!access_ok(VERIFY_READ, u, sizeof(*u)))
358 break;
359 /* no checking to be bug-to-bug compatible with i386 */
360 __copy_from_user(&child->thread.i387.fxsave, u, sizeof(*u));
361 set_stopped_child_used_math(child);
362 child->thread.i387.fxsave.mxcsr &= mxcsr_feature_mask;
363 ret = 0;
364 break;
365 }
366
367 case PTRACE_GETEVENTMSG:
368 ret = put_user(child->ptrace_message,(unsigned int __user *)compat_ptr(data));
369 break;
370
371 default:
372 ret = -EINVAL;
373 break;
374 }
375
376 put_task_struct(child);
377 return ret;
378}
379
diff --git a/arch/x86_64/ia32/sys_ia32.c b/arch/x86_64/ia32/sys_ia32.c
new file mode 100644
index 000000000000..68a9ab06ee7c
--- /dev/null
+++ b/arch/x86_64/ia32/sys_ia32.c
@@ -0,0 +1,1050 @@
1/*
2 * sys_ia32.c: Conversion between 32bit and 64bit native syscalls. Based on
3 * sys_sparc32
4 *
5 * Copyright (C) 2000 VA Linux Co
6 * Copyright (C) 2000 Don Dugger <n0ano@valinux.com>
7 * Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com>
8 * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
9 * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
10 * Copyright (C) 2000 Hewlett-Packard Co.
11 * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com>
12 * Copyright (C) 2000,2001,2002 Andi Kleen, SuSE Labs (x86-64 port)
13 *
14 * These routines maintain argument size conversion between 32bit and 64bit
15 * environment. In 2.5 most of this should be moved to a generic directory.
16 *
17 * This file assumes that there is a hole at the end of user address space.
18 *
19 * Some of the functions are LE specific currently. These are hopefully all marked.
20 * This should be fixed.
21 */
22
23#include <linux/config.h>
24#include <linux/kernel.h>
25#include <linux/sched.h>
26#include <linux/fs.h>
27#include <linux/file.h>
28#include <linux/signal.h>
29#include <linux/syscalls.h>
30#include <linux/resource.h>
31#include <linux/times.h>
32#include <linux/utsname.h>
33#include <linux/timex.h>
34#include <linux/smp.h>
35#include <linux/smp_lock.h>
36#include <linux/sem.h>
37#include <linux/msg.h>
38#include <linux/mm.h>
39#include <linux/shm.h>
40#include <linux/slab.h>
41#include <linux/uio.h>
42#include <linux/nfs_fs.h>
43#include <linux/quota.h>
44#include <linux/module.h>
45#include <linux/sunrpc/svc.h>
46#include <linux/nfsd/nfsd.h>
47#include <linux/nfsd/cache.h>
48#include <linux/nfsd/xdr.h>
49#include <linux/nfsd/syscall.h>
50#include <linux/poll.h>
51#include <linux/personality.h>
52#include <linux/stat.h>
53#include <linux/ipc.h>
54#include <linux/rwsem.h>
55#include <linux/binfmts.h>
56#include <linux/init.h>
57#include <linux/aio_abi.h>
58#include <linux/aio.h>
59#include <linux/compat.h>
60#include <linux/vfs.h>
61#include <linux/ptrace.h>
62#include <linux/highuid.h>
63#include <linux/vmalloc.h>
64#include <asm/mman.h>
65#include <asm/types.h>
66#include <asm/uaccess.h>
67#include <asm/semaphore.h>
68#include <asm/atomic.h>
69#include <asm/ldt.h>
70
71#include <net/scm.h>
72#include <net/sock.h>
73#include <asm/ia32.h>
74
75#define AA(__x) ((unsigned long)(__x))
76
77int cp_compat_stat(struct kstat *kbuf, struct compat_stat __user *ubuf)
78{
79 typeof(ubuf->st_uid) uid = 0;
80 typeof(ubuf->st_gid) gid = 0;
81 SET_UID(uid, kbuf->uid);
82 SET_GID(gid, kbuf->gid);
83 if (!old_valid_dev(kbuf->dev) || !old_valid_dev(kbuf->rdev))
84 return -EOVERFLOW;
85 if (kbuf->size >= 0x7fffffff)
86 return -EOVERFLOW;
87 if (!access_ok(VERIFY_WRITE, ubuf, sizeof(struct compat_stat)) ||
88 __put_user (old_encode_dev(kbuf->dev), &ubuf->st_dev) ||
89 __put_user (kbuf->ino, &ubuf->st_ino) ||
90 __put_user (kbuf->mode, &ubuf->st_mode) ||
91 __put_user (kbuf->nlink, &ubuf->st_nlink) ||
92 __put_user (uid, &ubuf->st_uid) ||
93 __put_user (gid, &ubuf->st_gid) ||
94 __put_user (old_encode_dev(kbuf->rdev), &ubuf->st_rdev) ||
95 __put_user (kbuf->size, &ubuf->st_size) ||
96 __put_user (kbuf->atime.tv_sec, &ubuf->st_atime) ||
97 __put_user (kbuf->atime.tv_nsec, &ubuf->st_atime_nsec) ||
98 __put_user (kbuf->mtime.tv_sec, &ubuf->st_mtime) ||
99 __put_user (kbuf->mtime.tv_nsec, &ubuf->st_mtime_nsec) ||
100 __put_user (kbuf->ctime.tv_sec, &ubuf->st_ctime) ||
101 __put_user (kbuf->ctime.tv_nsec, &ubuf->st_ctime_nsec) ||
102 __put_user (kbuf->blksize, &ubuf->st_blksize) ||
103 __put_user (kbuf->blocks, &ubuf->st_blocks))
104 return -EFAULT;
105 return 0;
106}
107
108asmlinkage long
109sys32_truncate64(char __user * filename, unsigned long offset_low, unsigned long offset_high)
110{
111 return sys_truncate(filename, ((loff_t) offset_high << 32) | offset_low);
112}
113
114asmlinkage long
115sys32_ftruncate64(unsigned int fd, unsigned long offset_low, unsigned long offset_high)
116{
117 return sys_ftruncate(fd, ((loff_t) offset_high << 32) | offset_low);
118}
119
120/* Another set for IA32/LFS -- x86_64 struct stat is different due to
121 support for 64bit inode numbers. */
122
123static int
124cp_stat64(struct stat64 __user *ubuf, struct kstat *stat)
125{
126 typeof(ubuf->st_uid) uid = 0;
127 typeof(ubuf->st_gid) gid = 0;
128 SET_UID(uid, stat->uid);
129 SET_GID(gid, stat->gid);
130 if (!access_ok(VERIFY_WRITE, ubuf, sizeof(struct stat64)) ||
131 __put_user(huge_encode_dev(stat->dev), &ubuf->st_dev) ||
132 __put_user (stat->ino, &ubuf->__st_ino) ||
133 __put_user (stat->ino, &ubuf->st_ino) ||
134 __put_user (stat->mode, &ubuf->st_mode) ||
135 __put_user (stat->nlink, &ubuf->st_nlink) ||
136 __put_user (uid, &ubuf->st_uid) ||
137 __put_user (gid, &ubuf->st_gid) ||
138 __put_user (huge_encode_dev(stat->rdev), &ubuf->st_rdev) ||
139 __put_user (stat->size, &ubuf->st_size) ||
140 __put_user (stat->atime.tv_sec, &ubuf->st_atime) ||
141 __put_user (stat->atime.tv_nsec, &ubuf->st_atime_nsec) ||
142 __put_user (stat->mtime.tv_sec, &ubuf->st_mtime) ||
143 __put_user (stat->mtime.tv_nsec, &ubuf->st_mtime_nsec) ||
144 __put_user (stat->ctime.tv_sec, &ubuf->st_ctime) ||
145 __put_user (stat->ctime.tv_nsec, &ubuf->st_ctime_nsec) ||
146 __put_user (stat->blksize, &ubuf->st_blksize) ||
147 __put_user (stat->blocks, &ubuf->st_blocks))
148 return -EFAULT;
149 return 0;
150}
151
152asmlinkage long
153sys32_stat64(char __user * filename, struct stat64 __user *statbuf)
154{
155 struct kstat stat;
156 int ret = vfs_stat(filename, &stat);
157 if (!ret)
158 ret = cp_stat64(statbuf, &stat);
159 return ret;
160}
161
162asmlinkage long
163sys32_lstat64(char __user * filename, struct stat64 __user *statbuf)
164{
165 struct kstat stat;
166 int ret = vfs_lstat(filename, &stat);
167 if (!ret)
168 ret = cp_stat64(statbuf, &stat);
169 return ret;
170}
171
172asmlinkage long
173sys32_fstat64(unsigned int fd, struct stat64 __user *statbuf)
174{
175 struct kstat stat;
176 int ret = vfs_fstat(fd, &stat);
177 if (!ret)
178 ret = cp_stat64(statbuf, &stat);
179 return ret;
180}
181
182/*
183 * Linux/i386 didn't use to be able to handle more than
184 * 4 system call parameters, so these system calls used a memory
185 * block for parameter passing..
186 */
187
188struct mmap_arg_struct {
189 unsigned int addr;
190 unsigned int len;
191 unsigned int prot;
192 unsigned int flags;
193 unsigned int fd;
194 unsigned int offset;
195};
196
197asmlinkage long
198sys32_mmap(struct mmap_arg_struct __user *arg)
199{
200 struct mmap_arg_struct a;
201 struct file *file = NULL;
202 unsigned long retval;
203 struct mm_struct *mm ;
204
205 if (copy_from_user(&a, arg, sizeof(a)))
206 return -EFAULT;
207
208 if (a.offset & ~PAGE_MASK)
209 return -EINVAL;
210
211 if (!(a.flags & MAP_ANONYMOUS)) {
212 file = fget(a.fd);
213 if (!file)
214 return -EBADF;
215 }
216
217 mm = current->mm;
218 down_write(&mm->mmap_sem);
219 retval = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags, a.offset>>PAGE_SHIFT);
220 if (file)
221 fput(file);
222
223 up_write(&mm->mmap_sem);
224
225 return retval;
226}
227
228asmlinkage long
229sys32_mprotect(unsigned long start, size_t len, unsigned long prot)
230{
231 return sys_mprotect(start,len,prot);
232}
233
234asmlinkage long
235sys32_pipe(int __user *fd)
236{
237 int retval;
238 int fds[2];
239
240 retval = do_pipe(fds);
241 if (retval)
242 goto out;
243 if (copy_to_user(fd, fds, sizeof(fds)))
244 retval = -EFAULT;
245 out:
246 return retval;
247}
248
249asmlinkage long
250sys32_rt_sigaction(int sig, struct sigaction32 __user *act,
251 struct sigaction32 __user *oact, unsigned int sigsetsize)
252{
253 struct k_sigaction new_ka, old_ka;
254 int ret;
255 compat_sigset_t set32;
256
257 /* XXX: Don't preclude handling different sized sigset_t's. */
258 if (sigsetsize != sizeof(compat_sigset_t))
259 return -EINVAL;
260
261 if (act) {
262 compat_uptr_t handler, restorer;
263
264 if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
265 __get_user(handler, &act->sa_handler) ||
266 __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
267 __get_user(restorer, &act->sa_restorer)||
268 __copy_from_user(&set32, &act->sa_mask, sizeof(compat_sigset_t)))
269 return -EFAULT;
270 new_ka.sa.sa_handler = compat_ptr(handler);
271 new_ka.sa.sa_restorer = compat_ptr(restorer);
272 /* FIXME: here we rely on _COMPAT_NSIG_WORS to be >= than _NSIG_WORDS << 1 */
273 switch (_NSIG_WORDS) {
274 case 4: new_ka.sa.sa_mask.sig[3] = set32.sig[6]
275 | (((long)set32.sig[7]) << 32);
276 case 3: new_ka.sa.sa_mask.sig[2] = set32.sig[4]
277 | (((long)set32.sig[5]) << 32);
278 case 2: new_ka.sa.sa_mask.sig[1] = set32.sig[2]
279 | (((long)set32.sig[3]) << 32);
280 case 1: new_ka.sa.sa_mask.sig[0] = set32.sig[0]
281 | (((long)set32.sig[1]) << 32);
282 }
283 }
284
285 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
286
287 if (!ret && oact) {
288 /* FIXME: here we rely on _COMPAT_NSIG_WORS to be >= than _NSIG_WORDS << 1 */
289 switch (_NSIG_WORDS) {
290 case 4:
291 set32.sig[7] = (old_ka.sa.sa_mask.sig[3] >> 32);
292 set32.sig[6] = old_ka.sa.sa_mask.sig[3];
293 case 3:
294 set32.sig[5] = (old_ka.sa.sa_mask.sig[2] >> 32);
295 set32.sig[4] = old_ka.sa.sa_mask.sig[2];
296 case 2:
297 set32.sig[3] = (old_ka.sa.sa_mask.sig[1] >> 32);
298 set32.sig[2] = old_ka.sa.sa_mask.sig[1];
299 case 1:
300 set32.sig[1] = (old_ka.sa.sa_mask.sig[0] >> 32);
301 set32.sig[0] = old_ka.sa.sa_mask.sig[0];
302 }
303 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
304 __put_user(ptr_to_compat(old_ka.sa.sa_handler), &oact->sa_handler) ||
305 __put_user(ptr_to_compat(old_ka.sa.sa_restorer), &oact->sa_restorer) ||
306 __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
307 __copy_to_user(&oact->sa_mask, &set32, sizeof(compat_sigset_t)))
308 return -EFAULT;
309 }
310
311 return ret;
312}
313
314asmlinkage long
315sys32_sigaction (int sig, struct old_sigaction32 __user *act, struct old_sigaction32 __user *oact)
316{
317 struct k_sigaction new_ka, old_ka;
318 int ret;
319
320 if (act) {
321 compat_old_sigset_t mask;
322 compat_uptr_t handler, restorer;
323
324 if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
325 __get_user(handler, &act->sa_handler) ||
326 __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
327 __get_user(restorer, &act->sa_restorer) ||
328 __get_user(mask, &act->sa_mask))
329 return -EFAULT;
330
331 new_ka.sa.sa_handler = compat_ptr(handler);
332 new_ka.sa.sa_restorer = compat_ptr(restorer);
333
334 siginitset(&new_ka.sa.sa_mask, mask);
335 }
336
337 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
338
339 if (!ret && oact) {
340 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
341 __put_user(ptr_to_compat(old_ka.sa.sa_handler), &oact->sa_handler) ||
342 __put_user(ptr_to_compat(old_ka.sa.sa_restorer), &oact->sa_restorer) ||
343 __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
344 __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
345 return -EFAULT;
346 }
347
348 return ret;
349}
350
351asmlinkage long
352sys32_rt_sigprocmask(int how, compat_sigset_t __user *set,
353 compat_sigset_t __user *oset, unsigned int sigsetsize)
354{
355 sigset_t s;
356 compat_sigset_t s32;
357 int ret;
358 mm_segment_t old_fs = get_fs();
359
360 if (set) {
361 if (copy_from_user (&s32, set, sizeof(compat_sigset_t)))
362 return -EFAULT;
363 switch (_NSIG_WORDS) {
364 case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32);
365 case 3: s.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32);
366 case 2: s.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32);
367 case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32);
368 }
369 }
370 set_fs (KERNEL_DS);
371 ret = sys_rt_sigprocmask(how, set ? &s : NULL, oset ? &s : NULL,
372 sigsetsize);
373 set_fs (old_fs);
374 if (ret) return ret;
375 if (oset) {
376 switch (_NSIG_WORDS) {
377 case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3];
378 case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2];
379 case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1];
380 case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0];
381 }
382 if (copy_to_user (oset, &s32, sizeof(compat_sigset_t)))
383 return -EFAULT;
384 }
385 return 0;
386}
387
388static inline long
389get_tv32(struct timeval *o, struct compat_timeval __user *i)
390{
391 int err = -EFAULT;
392 if (access_ok(VERIFY_READ, i, sizeof(*i))) {
393 err = __get_user(o->tv_sec, &i->tv_sec);
394 err |= __get_user(o->tv_usec, &i->tv_usec);
395 }
396 return err;
397}
398
399static inline long
400put_tv32(struct compat_timeval __user *o, struct timeval *i)
401{
402 int err = -EFAULT;
403 if (access_ok(VERIFY_WRITE, o, sizeof(*o))) {
404 err = __put_user(i->tv_sec, &o->tv_sec);
405 err |= __put_user(i->tv_usec, &o->tv_usec);
406 }
407 return err;
408}
409
410extern int do_setitimer(int which, struct itimerval *, struct itimerval *);
411
412asmlinkage long
413sys32_alarm(unsigned int seconds)
414{
415 struct itimerval it_new, it_old;
416 unsigned int oldalarm;
417
418 it_new.it_interval.tv_sec = it_new.it_interval.tv_usec = 0;
419 it_new.it_value.tv_sec = seconds;
420 it_new.it_value.tv_usec = 0;
421 do_setitimer(ITIMER_REAL, &it_new, &it_old);
422 oldalarm = it_old.it_value.tv_sec;
423 /* ehhh.. We can't return 0 if we have an alarm pending.. */
424 /* And we'd better return too much than too little anyway */
425 if (it_old.it_value.tv_usec)
426 oldalarm++;
427 return oldalarm;
428}
429
430/* Translations due to time_t size differences. Which affects all
431 sorts of things, like timeval and itimerval. */
432
433extern struct timezone sys_tz;
434
435asmlinkage long
436sys32_gettimeofday(struct compat_timeval __user *tv, struct timezone __user *tz)
437{
438 if (tv) {
439 struct timeval ktv;
440 do_gettimeofday(&ktv);
441 if (put_tv32(tv, &ktv))
442 return -EFAULT;
443 }
444 if (tz) {
445 if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
446 return -EFAULT;
447 }
448 return 0;
449}
450
451asmlinkage long
452sys32_settimeofday(struct compat_timeval __user *tv, struct timezone __user *tz)
453{
454 struct timeval ktv;
455 struct timespec kts;
456 struct timezone ktz;
457
458 if (tv) {
459 if (get_tv32(&ktv, tv))
460 return -EFAULT;
461 kts.tv_sec = ktv.tv_sec;
462 kts.tv_nsec = ktv.tv_usec * NSEC_PER_USEC;
463 }
464 if (tz) {
465 if (copy_from_user(&ktz, tz, sizeof(ktz)))
466 return -EFAULT;
467 }
468
469 return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
470}
471
472struct sel_arg_struct {
473 unsigned int n;
474 unsigned int inp;
475 unsigned int outp;
476 unsigned int exp;
477 unsigned int tvp;
478};
479
480asmlinkage long
481sys32_old_select(struct sel_arg_struct __user *arg)
482{
483 struct sel_arg_struct a;
484
485 if (copy_from_user(&a, arg, sizeof(a)))
486 return -EFAULT;
487 return compat_sys_select(a.n, compat_ptr(a.inp), compat_ptr(a.outp),
488 compat_ptr(a.exp), compat_ptr(a.tvp));
489}
490
491extern asmlinkage long
492compat_sys_wait4(compat_pid_t pid, compat_uint_t * stat_addr, int options,
493 struct compat_rusage *ru);
494
495asmlinkage long
496sys32_waitpid(compat_pid_t pid, unsigned int *stat_addr, int options)
497{
498 return compat_sys_wait4(pid, stat_addr, options, NULL);
499}
500
501int sys32_ni_syscall(int call)
502{
503 struct task_struct *me = current;
504 static char lastcomm[sizeof(me->comm)];
505
506 if (strncmp(lastcomm, me->comm, sizeof(lastcomm))) {
507 printk(KERN_INFO "IA32 syscall %d from %s not implemented\n",
508 call, me->comm);
509 strncpy(lastcomm, me->comm, sizeof(lastcomm));
510 }
511 return -ENOSYS;
512}
513
514/* 32-bit timeval and related flotsam. */
515
516asmlinkage long
517sys32_sysfs(int option, u32 arg1, u32 arg2)
518{
519 return sys_sysfs(option, arg1, arg2);
520}
521
522struct sysinfo32 {
523 s32 uptime;
524 u32 loads[3];
525 u32 totalram;
526 u32 freeram;
527 u32 sharedram;
528 u32 bufferram;
529 u32 totalswap;
530 u32 freeswap;
531 unsigned short procs;
532 unsigned short pad;
533 u32 totalhigh;
534 u32 freehigh;
535 u32 mem_unit;
536 char _f[20-2*sizeof(u32)-sizeof(int)];
537};
538
539asmlinkage long
540sys32_sysinfo(struct sysinfo32 __user *info)
541{
542 struct sysinfo s;
543 int ret;
544 mm_segment_t old_fs = get_fs ();
545 int bitcount = 0;
546
547 set_fs (KERNEL_DS);
548 ret = sys_sysinfo(&s);
549 set_fs (old_fs);
550
551 /* Check to see if any memory value is too large for 32-bit and scale
552 * down if needed
553 */
554 if ((s.totalram >> 32) || (s.totalswap >> 32)) {
555 while (s.mem_unit < PAGE_SIZE) {
556 s.mem_unit <<= 1;
557 bitcount++;
558 }
559 s.totalram >>= bitcount;
560 s.freeram >>= bitcount;
561 s.sharedram >>= bitcount;
562 s.bufferram >>= bitcount;
563 s.totalswap >>= bitcount;
564 s.freeswap >>= bitcount;
565 s.totalhigh >>= bitcount;
566 s.freehigh >>= bitcount;
567 }
568
569 if (!access_ok(VERIFY_WRITE, info, sizeof(struct sysinfo32)) ||
570 __put_user (s.uptime, &info->uptime) ||
571 __put_user (s.loads[0], &info->loads[0]) ||
572 __put_user (s.loads[1], &info->loads[1]) ||
573 __put_user (s.loads[2], &info->loads[2]) ||
574 __put_user (s.totalram, &info->totalram) ||
575 __put_user (s.freeram, &info->freeram) ||
576 __put_user (s.sharedram, &info->sharedram) ||
577 __put_user (s.bufferram, &info->bufferram) ||
578 __put_user (s.totalswap, &info->totalswap) ||
579 __put_user (s.freeswap, &info->freeswap) ||
580 __put_user (s.procs, &info->procs) ||
581 __put_user (s.totalhigh, &info->totalhigh) ||
582 __put_user (s.freehigh, &info->freehigh) ||
583 __put_user (s.mem_unit, &info->mem_unit))
584 return -EFAULT;
585 return 0;
586}
587
588asmlinkage long
589sys32_sched_rr_get_interval(compat_pid_t pid, struct compat_timespec __user *interval)
590{
591 struct timespec t;
592 int ret;
593 mm_segment_t old_fs = get_fs ();
594
595 set_fs (KERNEL_DS);
596 ret = sys_sched_rr_get_interval(pid, &t);
597 set_fs (old_fs);
598 if (put_compat_timespec(&t, interval))
599 return -EFAULT;
600 return ret;
601}
602
603asmlinkage long
604sys32_rt_sigpending(compat_sigset_t __user *set, compat_size_t sigsetsize)
605{
606 sigset_t s;
607 compat_sigset_t s32;
608 int ret;
609 mm_segment_t old_fs = get_fs();
610
611 set_fs (KERNEL_DS);
612 ret = sys_rt_sigpending(&s, sigsetsize);
613 set_fs (old_fs);
614 if (!ret) {
615 switch (_NSIG_WORDS) {
616 case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3];
617 case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2];
618 case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1];
619 case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0];
620 }
621 if (copy_to_user (set, &s32, sizeof(compat_sigset_t)))
622 return -EFAULT;
623 }
624 return ret;
625}
626
627asmlinkage long
628sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo)
629{
630 siginfo_t info;
631 int ret;
632 mm_segment_t old_fs = get_fs();
633
634 if (copy_siginfo_from_user32(&info, uinfo))
635 return -EFAULT;
636 set_fs (KERNEL_DS);
637 ret = sys_rt_sigqueueinfo(pid, sig, &info);
638 set_fs (old_fs);
639 return ret;
640}
641
642/* These are here just in case some old ia32 binary calls it. */
643asmlinkage long
644sys32_pause(void)
645{
646 current->state = TASK_INTERRUPTIBLE;
647 schedule();
648 return -ERESTARTNOHAND;
649}
650
651
652#ifdef CONFIG_SYSCTL
653struct sysctl_ia32 {
654 unsigned int name;
655 int nlen;
656 unsigned int oldval;
657 unsigned int oldlenp;
658 unsigned int newval;
659 unsigned int newlen;
660 unsigned int __unused[4];
661};
662
663
664asmlinkage long
665sys32_sysctl(struct sysctl_ia32 __user *args32)
666{
667 struct sysctl_ia32 a32;
668 mm_segment_t old_fs = get_fs ();
669 void __user *oldvalp, *newvalp;
670 size_t oldlen;
671 int __user *namep;
672 long ret;
673 extern int do_sysctl(int *name, int nlen, void *oldval, size_t *oldlenp,
674 void *newval, size_t newlen);
675
676
677 if (copy_from_user(&a32, args32, sizeof (a32)))
678 return -EFAULT;
679
680 /*
681 * We need to pre-validate these because we have to disable address checking
682 * before calling do_sysctl() because of OLDLEN but we can't run the risk of the
683 * user specifying bad addresses here. Well, since we're dealing with 32 bit
684 * addresses, we KNOW that access_ok() will always succeed, so this is an
685 * expensive NOP, but so what...
686 */
687 namep = compat_ptr(a32.name);
688 oldvalp = compat_ptr(a32.oldval);
689 newvalp = compat_ptr(a32.newval);
690
691 if ((oldvalp && get_user(oldlen, (int __user *)compat_ptr(a32.oldlenp)))
692 || !access_ok(VERIFY_WRITE, namep, 0)
693 || !access_ok(VERIFY_WRITE, oldvalp, 0)
694 || !access_ok(VERIFY_WRITE, newvalp, 0))
695 return -EFAULT;
696
697 set_fs(KERNEL_DS);
698 lock_kernel();
699 ret = do_sysctl(namep, a32.nlen, oldvalp, &oldlen, newvalp, (size_t) a32.newlen);
700 unlock_kernel();
701 set_fs(old_fs);
702
703 if (oldvalp && put_user (oldlen, (int __user *)compat_ptr(a32.oldlenp)))
704 return -EFAULT;
705
706 return ret;
707}
708#endif
709
710/* warning: next two assume little endian */
711asmlinkage long
712sys32_pread(unsigned int fd, char __user *ubuf, u32 count, u32 poslo, u32 poshi)
713{
714 return sys_pread64(fd, ubuf, count,
715 ((loff_t)AA(poshi) << 32) | AA(poslo));
716}
717
718asmlinkage long
719sys32_pwrite(unsigned int fd, char __user *ubuf, u32 count, u32 poslo, u32 poshi)
720{
721 return sys_pwrite64(fd, ubuf, count,
722 ((loff_t)AA(poshi) << 32) | AA(poslo));
723}
724
725
726asmlinkage long
727sys32_personality(unsigned long personality)
728{
729 int ret;
730 if (personality(current->personality) == PER_LINUX32 &&
731 personality == PER_LINUX)
732 personality = PER_LINUX32;
733 ret = sys_personality(personality);
734 if (ret == PER_LINUX32)
735 ret = PER_LINUX;
736 return ret;
737}
738
739asmlinkage long
740sys32_sendfile(int out_fd, int in_fd, compat_off_t __user *offset, s32 count)
741{
742 mm_segment_t old_fs = get_fs();
743 int ret;
744 off_t of;
745
746 if (offset && get_user(of, offset))
747 return -EFAULT;
748
749 set_fs(KERNEL_DS);
750 ret = sys_sendfile(out_fd, in_fd, offset ? &of : NULL, count);
751 set_fs(old_fs);
752
753 if (!ret && offset && put_user(of, offset))
754 return -EFAULT;
755
756 return ret;
757}
758
759/* Handle adjtimex compatibility. */
760
761struct timex32 {
762 u32 modes;
763 s32 offset, freq, maxerror, esterror;
764 s32 status, constant, precision, tolerance;
765 struct compat_timeval time;
766 s32 tick;
767 s32 ppsfreq, jitter, shift, stabil;
768 s32 jitcnt, calcnt, errcnt, stbcnt;
769 s32 :32; s32 :32; s32 :32; s32 :32;
770 s32 :32; s32 :32; s32 :32; s32 :32;
771 s32 :32; s32 :32; s32 :32; s32 :32;
772};
773
774extern int do_adjtimex(struct timex *);
775
776asmlinkage long
777sys32_adjtimex(struct timex32 __user *utp)
778{
779 struct timex txc;
780 int ret;
781
782 memset(&txc, 0, sizeof(struct timex));
783
784 if (!access_ok(VERIFY_READ, utp, sizeof(struct timex32)) ||
785 __get_user(txc.modes, &utp->modes) ||
786 __get_user(txc.offset, &utp->offset) ||
787 __get_user(txc.freq, &utp->freq) ||
788 __get_user(txc.maxerror, &utp->maxerror) ||
789 __get_user(txc.esterror, &utp->esterror) ||
790 __get_user(txc.status, &utp->status) ||
791 __get_user(txc.constant, &utp->constant) ||
792 __get_user(txc.precision, &utp->precision) ||
793 __get_user(txc.tolerance, &utp->tolerance) ||
794 __get_user(txc.time.tv_sec, &utp->time.tv_sec) ||
795 __get_user(txc.time.tv_usec, &utp->time.tv_usec) ||
796 __get_user(txc.tick, &utp->tick) ||
797 __get_user(txc.ppsfreq, &utp->ppsfreq) ||
798 __get_user(txc.jitter, &utp->jitter) ||
799 __get_user(txc.shift, &utp->shift) ||
800 __get_user(txc.stabil, &utp->stabil) ||
801 __get_user(txc.jitcnt, &utp->jitcnt) ||
802 __get_user(txc.calcnt, &utp->calcnt) ||
803 __get_user(txc.errcnt, &utp->errcnt) ||
804 __get_user(txc.stbcnt, &utp->stbcnt))
805 return -EFAULT;
806
807 ret = do_adjtimex(&txc);
808
809 if (!access_ok(VERIFY_WRITE, utp, sizeof(struct timex32)) ||
810 __put_user(txc.modes, &utp->modes) ||
811 __put_user(txc.offset, &utp->offset) ||
812 __put_user(txc.freq, &utp->freq) ||
813 __put_user(txc.maxerror, &utp->maxerror) ||
814 __put_user(txc.esterror, &utp->esterror) ||
815 __put_user(txc.status, &utp->status) ||
816 __put_user(txc.constant, &utp->constant) ||
817 __put_user(txc.precision, &utp->precision) ||
818 __put_user(txc.tolerance, &utp->tolerance) ||
819 __put_user(txc.time.tv_sec, &utp->time.tv_sec) ||
820 __put_user(txc.time.tv_usec, &utp->time.tv_usec) ||
821 __put_user(txc.tick, &utp->tick) ||
822 __put_user(txc.ppsfreq, &utp->ppsfreq) ||
823 __put_user(txc.jitter, &utp->jitter) ||
824 __put_user(txc.shift, &utp->shift) ||
825 __put_user(txc.stabil, &utp->stabil) ||
826 __put_user(txc.jitcnt, &utp->jitcnt) ||
827 __put_user(txc.calcnt, &utp->calcnt) ||
828 __put_user(txc.errcnt, &utp->errcnt) ||
829 __put_user(txc.stbcnt, &utp->stbcnt))
830 ret = -EFAULT;
831
832 return ret;
833}
834
835asmlinkage long sys32_mmap2(unsigned long addr, unsigned long len,
836 unsigned long prot, unsigned long flags,
837 unsigned long fd, unsigned long pgoff)
838{
839 struct mm_struct *mm = current->mm;
840 unsigned long error;
841 struct file * file = NULL;
842
843 flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
844 if (!(flags & MAP_ANONYMOUS)) {
845 file = fget(fd);
846 if (!file)
847 return -EBADF;
848 }
849
850 down_write(&mm->mmap_sem);
851 error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
852 up_write(&mm->mmap_sem);
853
854 if (file)
855 fput(file);
856 return error;
857}
858
859asmlinkage long sys32_olduname(struct oldold_utsname __user * name)
860{
861 int error;
862
863 if (!name)
864 return -EFAULT;
865 if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
866 return -EFAULT;
867
868 down_read(&uts_sem);
869
870 error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
871 __put_user(0,name->sysname+__OLD_UTS_LEN);
872 __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
873 __put_user(0,name->nodename+__OLD_UTS_LEN);
874 __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN);
875 __put_user(0,name->release+__OLD_UTS_LEN);
876 __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN);
877 __put_user(0,name->version+__OLD_UTS_LEN);
878 {
879 char *arch = "x86_64";
880 if (personality(current->personality) == PER_LINUX32)
881 arch = "i686";
882
883 __copy_to_user(&name->machine,arch,strlen(arch)+1);
884 }
885
886 up_read(&uts_sem);
887
888 error = error ? -EFAULT : 0;
889
890 return error;
891}
892
893long sys32_uname(struct old_utsname __user * name)
894{
895 int err;
896 if (!name)
897 return -EFAULT;
898 down_read(&uts_sem);
899 err=copy_to_user(name, &system_utsname, sizeof (*name));
900 up_read(&uts_sem);
901 if (personality(current->personality) == PER_LINUX32)
902 err |= copy_to_user(&name->machine, "i686", 5);
903 return err?-EFAULT:0;
904}
905
906long sys32_ustat(unsigned dev, struct ustat32 __user *u32p)
907{
908 struct ustat u;
909 mm_segment_t seg;
910 int ret;
911
912 seg = get_fs();
913 set_fs(KERNEL_DS);
914 ret = sys_ustat(dev,&u);
915 set_fs(seg);
916 if (ret >= 0) {
917 if (!access_ok(VERIFY_WRITE,u32p,sizeof(struct ustat32)) ||
918 __put_user((__u32) u.f_tfree, &u32p->f_tfree) ||
919 __put_user((__u32) u.f_tinode, &u32p->f_tfree) ||
920 __copy_to_user(&u32p->f_fname, u.f_fname, sizeof(u.f_fname)) ||
921 __copy_to_user(&u32p->f_fpack, u.f_fpack, sizeof(u.f_fpack)))
922 ret = -EFAULT;
923 }
924 return ret;
925}
926
927asmlinkage long sys32_execve(char __user *name, compat_uptr_t __user *argv,
928 compat_uptr_t __user *envp, struct pt_regs *regs)
929{
930 long error;
931 char * filename;
932
933 filename = getname(name);
934 error = PTR_ERR(filename);
935 if (IS_ERR(filename))
936 return error;
937 error = compat_do_execve(filename, argv, envp, regs);
938 if (error == 0) {
939 task_lock(current);
940 current->ptrace &= ~PT_DTRACE;
941 task_unlock(current);
942 }
943 putname(filename);
944 return error;
945}
946
947asmlinkage long sys32_clone(unsigned int clone_flags, unsigned int newsp,
948 struct pt_regs *regs)
949{
950 void __user *parent_tid = (void __user *)regs->rdx;
951 void __user *child_tid = (void __user *)regs->rdi;
952 if (!newsp)
953 newsp = regs->rsp;
954 return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid);
955}
956
957/*
958 * Some system calls that need sign extended arguments. This could be done by a generic wrapper.
959 */
960
961long sys32_lseek (unsigned int fd, int offset, unsigned int whence)
962{
963 return sys_lseek(fd, offset, whence);
964}
965
966long sys32_kill(int pid, int sig)
967{
968 return sys_kill(pid, sig);
969}
970
971asmlinkage long sys32_open(const char __user * filename, int flags, int mode)
972{
973 char * tmp;
974 int fd, error;
975
976 /* don't force O_LARGEFILE */
977 tmp = getname(filename);
978 fd = PTR_ERR(tmp);
979 if (!IS_ERR(tmp)) {
980 fd = get_unused_fd();
981 if (fd >= 0) {
982 struct file *f = filp_open(tmp, flags, mode);
983 error = PTR_ERR(f);
984 if (IS_ERR(f)) {
985 put_unused_fd(fd);
986 fd = error;
987 } else
988 fd_install(fd, f);
989 }
990 putname(tmp);
991 }
992 return fd;
993}
994
995extern asmlinkage long
996sys_timer_create(clockid_t which_clock,
997 struct sigevent __user *timer_event_spec,
998 timer_t __user * created_timer_id);
999
1000long
1001sys32_timer_create(u32 clock, struct compat_sigevent __user *se32, timer_t __user *timer_id)
1002{
1003 struct sigevent __user *p = NULL;
1004 if (se32) {
1005 struct sigevent se;
1006 p = compat_alloc_user_space(sizeof(struct sigevent));
1007 if (get_compat_sigevent(&se, se32) ||
1008 copy_to_user(p, &se, sizeof(se)))
1009 return -EFAULT;
1010 }
1011 return sys_timer_create(clock, p, timer_id);
1012}
1013
1014long sys32_fadvise64_64(int fd, __u32 offset_low, __u32 offset_high,
1015 __u32 len_low, __u32 len_high, int advice)
1016{
1017 return sys_fadvise64_64(fd,
1018 (((u64)offset_high)<<32) | offset_low,
1019 (((u64)len_high)<<32) | len_low,
1020 advice);
1021}
1022
1023long sys32_vm86_warning(void)
1024{
1025 struct task_struct *me = current;
1026 static char lastcomm[sizeof(me->comm)];
1027 if (strncmp(lastcomm, me->comm, sizeof(lastcomm))) {
1028 printk(KERN_INFO "%s: vm86 mode not supported on 64 bit kernel\n",
1029 me->comm);
1030 strncpy(lastcomm, me->comm, sizeof(lastcomm));
1031 }
1032 return -ENOSYS;
1033}
1034
1035long sys32_lookup_dcookie(u32 addr_low, u32 addr_high,
1036 char __user * buf, size_t len)
1037{
1038 return sys_lookup_dcookie(((u64)addr_high << 32) | addr_low, buf, len);
1039}
1040
1041static int __init ia32_init (void)
1042{
1043 printk("IA32 emulation $Id: sys_ia32.c,v 1.32 2002/03/24 13:02:28 ak Exp $\n");
1044 return 0;
1045}
1046
1047__initcall(ia32_init);
1048
1049extern unsigned long ia32_sys_call_table[];
1050EXPORT_SYMBOL(ia32_sys_call_table);
diff --git a/arch/x86_64/ia32/syscall32.c b/arch/x86_64/ia32/syscall32.c
new file mode 100644
index 000000000000..399ff4985099
--- /dev/null
+++ b/arch/x86_64/ia32/syscall32.c
@@ -0,0 +1,111 @@
1/* Copyright 2002,2003 Andi Kleen, SuSE Labs */
2
3/* vsyscall handling for 32bit processes. Map a stub page into it
4 on demand because 32bit cannot reach the kernel's fixmaps */
5
6#include <linux/mm.h>
7#include <linux/string.h>
8#include <linux/kernel.h>
9#include <linux/gfp.h>
10#include <linux/init.h>
11#include <linux/stringify.h>
12#include <asm/proto.h>
13#include <asm/tlbflush.h>
14#include <asm/ia32_unistd.h>
15
16/* 32bit VDSOs mapped into user space. */
17asm(".section \".init.data\",\"aw\"\n"
18 "syscall32_syscall:\n"
19 ".incbin \"arch/x86_64/ia32/vsyscall-syscall.so\"\n"
20 "syscall32_syscall_end:\n"
21 "syscall32_sysenter:\n"
22 ".incbin \"arch/x86_64/ia32/vsyscall-sysenter.so\"\n"
23 "syscall32_sysenter_end:\n"
24 ".previous");
25
26extern unsigned char syscall32_syscall[], syscall32_syscall_end[];
27extern unsigned char syscall32_sysenter[], syscall32_sysenter_end[];
28extern int sysctl_vsyscall32;
29
30char *syscall32_page;
31static int use_sysenter = -1;
32
33/*
34 * Map the 32bit vsyscall page on demand.
35 *
36 * RED-PEN: This knows too much about high level VM.
37 *
38 * Alternative would be to generate a vma with appropriate backing options
39 * and let it be handled by generic VM.
40 */
41int __map_syscall32(struct mm_struct *mm, unsigned long address)
42{
43 pgd_t *pgd;
44 pud_t *pud;
45 pte_t *pte;
46 pmd_t *pmd;
47 int err = -ENOMEM;
48
49 spin_lock(&mm->page_table_lock);
50 pgd = pgd_offset(mm, address);
51 pud = pud_alloc(mm, pgd, address);
52 if (pud) {
53 pmd = pmd_alloc(mm, pud, address);
54 if (pmd && (pte = pte_alloc_map(mm, pmd, address)) != NULL) {
55 if (pte_none(*pte)) {
56 set_pte(pte,
57 mk_pte(virt_to_page(syscall32_page),
58 PAGE_KERNEL_VSYSCALL32));
59 }
60 /* Flush only the local CPU. Other CPUs taking a fault
61 will just end up here again
62 This probably not needed and just paranoia. */
63 __flush_tlb_one(address);
64 err = 0;
65 }
66 }
67 spin_unlock(&mm->page_table_lock);
68 return err;
69}
70
71int map_syscall32(struct mm_struct *mm, unsigned long address)
72{
73 int err;
74 down_read(&mm->mmap_sem);
75 err = __map_syscall32(mm, address);
76 up_read(&mm->mmap_sem);
77 return err;
78}
79
80static int __init init_syscall32(void)
81{
82 syscall32_page = (void *)get_zeroed_page(GFP_KERNEL);
83 if (!syscall32_page)
84 panic("Cannot allocate syscall32 page");
85 SetPageReserved(virt_to_page(syscall32_page));
86 if (use_sysenter > 0) {
87 memcpy(syscall32_page, syscall32_sysenter,
88 syscall32_sysenter_end - syscall32_sysenter);
89 } else {
90 memcpy(syscall32_page, syscall32_syscall,
91 syscall32_syscall_end - syscall32_syscall);
92 }
93 return 0;
94}
95
96__initcall(init_syscall32);
97
98/* May not be __init: called during resume */
99void syscall32_cpu_init(void)
100{
101 if (use_sysenter < 0)
102 use_sysenter = (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL);
103
104 /* Load these always in case some future AMD CPU supports
105 SYSENTER from compat mode too. */
106 checking_wrmsrl(MSR_IA32_SYSENTER_CS, (u64)__KERNEL_CS);
107 checking_wrmsrl(MSR_IA32_SYSENTER_ESP, 0ULL);
108 checking_wrmsrl(MSR_IA32_SYSENTER_EIP, (u64)ia32_sysenter_target);
109
110 wrmsrl(MSR_CSTAR, ia32_cstar_target);
111}
diff --git a/arch/x86_64/ia32/tls32.c b/arch/x86_64/ia32/tls32.c
new file mode 100644
index 000000000000..1cc4340de3ca
--- /dev/null
+++ b/arch/x86_64/ia32/tls32.c
@@ -0,0 +1,163 @@
1#include <linux/kernel.h>
2#include <linux/errno.h>
3#include <linux/sched.h>
4#include <linux/user.h>
5
6#include <asm/uaccess.h>
7#include <asm/desc.h>
8#include <asm/system.h>
9#include <asm/ldt.h>
10#include <asm/processor.h>
11#include <asm/proto.h>
12
13/*
14 * sys_alloc_thread_area: get a yet unused TLS descriptor index.
15 */
16static int get_free_idx(void)
17{
18 struct thread_struct *t = &current->thread;
19 int idx;
20
21 for (idx = 0; idx < GDT_ENTRY_TLS_ENTRIES; idx++)
22 if (desc_empty((struct n_desc_struct *)(t->tls_array) + idx))
23 return idx + GDT_ENTRY_TLS_MIN;
24 return -ESRCH;
25}
26
27/*
28 * Set a given TLS descriptor:
29 * When you want addresses > 32bit use arch_prctl()
30 */
31int do_set_thread_area(struct thread_struct *t, struct user_desc __user *u_info)
32{
33 struct user_desc info;
34 struct n_desc_struct *desc;
35 int cpu, idx;
36
37 if (copy_from_user(&info, u_info, sizeof(info)))
38 return -EFAULT;
39
40 idx = info.entry_number;
41
42 /*
43 * index -1 means the kernel should try to find and
44 * allocate an empty descriptor:
45 */
46 if (idx == -1) {
47 idx = get_free_idx();
48 if (idx < 0)
49 return idx;
50 if (put_user(idx, &u_info->entry_number))
51 return -EFAULT;
52 }
53
54 if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)
55 return -EINVAL;
56
57 desc = ((struct n_desc_struct *)t->tls_array) + idx - GDT_ENTRY_TLS_MIN;
58
59 /*
60 * We must not get preempted while modifying the TLS.
61 */
62 cpu = get_cpu();
63
64 if (LDT_empty(&info)) {
65 desc->a = 0;
66 desc->b = 0;
67 } else {
68 desc->a = LDT_entry_a(&info);
69 desc->b = LDT_entry_b(&info);
70 }
71 if (t == &current->thread)
72 load_TLS(t, cpu);
73
74 put_cpu();
75 return 0;
76}
77
78asmlinkage long sys32_set_thread_area(struct user_desc __user *u_info)
79{
80 return do_set_thread_area(&current->thread, u_info);
81}
82
83
84/*
85 * Get the current Thread-Local Storage area:
86 */
87
88#define GET_BASE(desc) ( \
89 (((desc)->a >> 16) & 0x0000ffff) | \
90 (((desc)->b << 16) & 0x00ff0000) | \
91 ( (desc)->b & 0xff000000) )
92
93#define GET_LIMIT(desc) ( \
94 ((desc)->a & 0x0ffff) | \
95 ((desc)->b & 0xf0000) )
96
97#define GET_32BIT(desc) (((desc)->b >> 22) & 1)
98#define GET_CONTENTS(desc) (((desc)->b >> 10) & 3)
99#define GET_WRITABLE(desc) (((desc)->b >> 9) & 1)
100#define GET_LIMIT_PAGES(desc) (((desc)->b >> 23) & 1)
101#define GET_PRESENT(desc) (((desc)->b >> 15) & 1)
102#define GET_USEABLE(desc) (((desc)->b >> 20) & 1)
103#define GET_LONGMODE(desc) (((desc)->b >> 21) & 1)
104
105int do_get_thread_area(struct thread_struct *t, struct user_desc __user *u_info)
106{
107 struct user_desc info;
108 struct n_desc_struct *desc;
109 int idx;
110
111 if (get_user(idx, &u_info->entry_number))
112 return -EFAULT;
113 if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)
114 return -EINVAL;
115
116 desc = ((struct n_desc_struct *)t->tls_array) + idx - GDT_ENTRY_TLS_MIN;
117
118 memset(&info, 0, sizeof(struct user_desc));
119 info.entry_number = idx;
120 info.base_addr = GET_BASE(desc);
121 info.limit = GET_LIMIT(desc);
122 info.seg_32bit = GET_32BIT(desc);
123 info.contents = GET_CONTENTS(desc);
124 info.read_exec_only = !GET_WRITABLE(desc);
125 info.limit_in_pages = GET_LIMIT_PAGES(desc);
126 info.seg_not_present = !GET_PRESENT(desc);
127 info.useable = GET_USEABLE(desc);
128 info.lm = GET_LONGMODE(desc);
129
130 if (copy_to_user(u_info, &info, sizeof(info)))
131 return -EFAULT;
132 return 0;
133}
134
135asmlinkage long sys32_get_thread_area(struct user_desc __user *u_info)
136{
137 return do_get_thread_area(&current->thread, u_info);
138}
139
140
141int ia32_child_tls(struct task_struct *p, struct pt_regs *childregs)
142{
143 struct n_desc_struct *desc;
144 struct user_desc info;
145 struct user_desc __user *cp;
146 int idx;
147
148 cp = (void __user *)childregs->rsi;
149 if (copy_from_user(&info, cp, sizeof(info)))
150 return -EFAULT;
151 if (LDT_empty(&info))
152 return -EINVAL;
153
154 idx = info.entry_number;
155 if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)
156 return -EINVAL;
157
158 desc = (struct n_desc_struct *)(p->thread.tls_array) + idx - GDT_ENTRY_TLS_MIN;
159 desc->a = LDT_entry_a(&info);
160 desc->b = LDT_entry_b(&info);
161
162 return 0;
163}
diff --git a/arch/x86_64/ia32/vsyscall-sigreturn.S b/arch/x86_64/ia32/vsyscall-sigreturn.S
new file mode 100644
index 000000000000..ba4067d350e4
--- /dev/null
+++ b/arch/x86_64/ia32/vsyscall-sigreturn.S
@@ -0,0 +1,120 @@
1/*
2 * Common code for the sigreturn entry points on the vsyscall page.
3 * This code uses SYSCALL_ENTER_KERNEL (either syscall or int $0x80)
4 * to enter the kernel.
5 * This file is #include'd by vsyscall-*.S to define them after the
6 * vsyscall entry point. The addresses we get for these entry points
7 * by doing ".balign 32" must match in both versions of the page.
8 */
9
10 .section .text.sigreturn,"ax"
11 .balign 32
12 .globl __kernel_sigreturn
13 .type __kernel_sigreturn,@function
14__kernel_sigreturn:
15.LSTART_sigreturn:
16 popl %eax
17 movl $__NR_ia32_sigreturn, %eax
18 SYSCALL_ENTER_KERNEL
19.LEND_sigreturn:
20 .size __kernel_sigreturn,.-.LSTART_sigreturn
21
22 .section .text.rtsigreturn,"ax"
23 .balign 32
24 .globl __kernel_rt_sigreturn
25 .type __kernel_rt_sigreturn,@function
26__kernel_rt_sigreturn:
27.LSTART_rt_sigreturn:
28 movl $__NR_ia32_rt_sigreturn, %eax
29 SYSCALL_ENTER_KERNEL
30.LEND_rt_sigreturn:
31 .size __kernel_rt_sigreturn,.-.LSTART_rt_sigreturn
32
33 .section .eh_frame,"a",@progbits
34 .long .LENDFDE2-.LSTARTFDE2 /* Length FDE */
35.LSTARTFDE2:
36 .long .LSTARTFDE2-.LSTARTFRAME /* CIE pointer */
37 /* HACK: The dwarf2 unwind routines will subtract 1 from the
38 return address to get an address in the middle of the
39 presumed call instruction. Since we didn't get here via
40 a call, we need to include the nop before the real start
41 to make up for it. */
42 .long .LSTART_sigreturn-1-. /* PC-relative start address */
43 .long .LEND_sigreturn-.LSTART_sigreturn+1
44 .uleb128 0 /* Augmentation length */
45 /* What follows are the instructions for the table generation.
46 We record the locations of each register saved. This is
47 complicated by the fact that the "CFA" is always assumed to
48 be the value of the stack pointer in the caller. This means
49 that we must define the CFA of this body of code to be the
50 saved value of the stack pointer in the sigcontext. Which
51 also means that there is no fixed relation to the other
52 saved registers, which means that we must use DW_CFA_expression
53 to compute their addresses. It also means that when we
54 adjust the stack with the popl, we have to do it all over again. */
55
56#define do_cfa_expr(offset) \
57 .byte 0x0f; /* DW_CFA_def_cfa_expression */ \
58 .uleb128 1f-0f; /* length */ \
590: .byte 0x74; /* DW_OP_breg4 */ \
60 .sleb128 offset; /* offset */ \
61 .byte 0x06; /* DW_OP_deref */ \
621:
63
64#define do_expr(regno, offset) \
65 .byte 0x10; /* DW_CFA_expression */ \
66 .uleb128 regno; /* regno */ \
67 .uleb128 1f-0f; /* length */ \
680: .byte 0x74; /* DW_OP_breg4 */ \
69 .sleb128 offset; /* offset */ \
701:
71
72 do_cfa_expr(IA32_SIGCONTEXT_esp+4)
73 do_expr(0, IA32_SIGCONTEXT_eax+4)
74 do_expr(1, IA32_SIGCONTEXT_ecx+4)
75 do_expr(2, IA32_SIGCONTEXT_edx+4)
76 do_expr(3, IA32_SIGCONTEXT_ebx+4)
77 do_expr(5, IA32_SIGCONTEXT_ebp+4)
78 do_expr(6, IA32_SIGCONTEXT_esi+4)
79 do_expr(7, IA32_SIGCONTEXT_edi+4)
80 do_expr(8, IA32_SIGCONTEXT_eip+4)
81
82 .byte 0x42 /* DW_CFA_advance_loc 2 -- nop; popl eax. */
83
84 do_cfa_expr(IA32_SIGCONTEXT_esp)
85 do_expr(0, IA32_SIGCONTEXT_eax)
86 do_expr(1, IA32_SIGCONTEXT_ecx)
87 do_expr(2, IA32_SIGCONTEXT_edx)
88 do_expr(3, IA32_SIGCONTEXT_ebx)
89 do_expr(5, IA32_SIGCONTEXT_ebp)
90 do_expr(6, IA32_SIGCONTEXT_esi)
91 do_expr(7, IA32_SIGCONTEXT_edi)
92 do_expr(8, IA32_SIGCONTEXT_eip)
93
94 .align 4
95.LENDFDE2:
96
97 .long .LENDFDE3-.LSTARTFDE3 /* Length FDE */
98.LSTARTFDE3:
99 .long .LSTARTFDE3-.LSTARTFRAME /* CIE pointer */
100 /* HACK: See above wrt unwind library assumptions. */
101 .long .LSTART_rt_sigreturn-1-. /* PC-relative start address */
102 .long .LEND_rt_sigreturn-.LSTART_rt_sigreturn+1
103 .uleb128 0 /* Augmentation */
104 /* What follows are the instructions for the table generation.
105 We record the locations of each register saved. This is
106 slightly less complicated than the above, since we don't
107 modify the stack pointer in the process. */
108
109 do_cfa_expr(IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_esp)
110 do_expr(0, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_eax)
111 do_expr(1, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_ecx)
112 do_expr(2, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_edx)
113 do_expr(3, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_ebx)
114 do_expr(5, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_ebp)
115 do_expr(6, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_esi)
116 do_expr(7, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_edi)
117 do_expr(8, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_eip)
118
119 .align 4
120.LENDFDE3:
diff --git a/arch/x86_64/ia32/vsyscall-syscall.S b/arch/x86_64/ia32/vsyscall-syscall.S
new file mode 100644
index 000000000000..e2aaf3de8a42
--- /dev/null
+++ b/arch/x86_64/ia32/vsyscall-syscall.S
@@ -0,0 +1,68 @@
1/*
2 * Code for the vsyscall page. This version uses the syscall instruction.
3 */
4
5#include <asm/ia32_unistd.h>
6#include <asm/offset.h>
7#include <asm/segment.h>
8
9 .text
10 .section .text.vsyscall,"ax"
11 .globl __kernel_vsyscall
12 .type __kernel_vsyscall,@function
13__kernel_vsyscall:
14.LSTART_vsyscall:
15 push %ebp
16.Lpush_ebp:
17 movl %ecx, %ebp
18 syscall
19 movl $__USER32_DS, %ecx
20 movl %ecx, %ss
21 movl %ebp, %ecx
22 popl %ebp
23.Lpop_ebp:
24 ret
25.LEND_vsyscall:
26 .size __kernel_vsyscall,.-.LSTART_vsyscall
27
28 .section .eh_frame,"a",@progbits
29.LSTARTFRAME:
30 .long .LENDCIE-.LSTARTCIE
31.LSTARTCIE:
32 .long 0 /* CIE ID */
33 .byte 1 /* Version number */
34 .string "zR" /* NUL-terminated augmentation string */
35 .uleb128 1 /* Code alignment factor */
36 .sleb128 -4 /* Data alignment factor */
37 .byte 8 /* Return address register column */
38 .uleb128 1 /* Augmentation value length */
39 .byte 0x1b /* DW_EH_PE_pcrel|DW_EH_PE_sdata4. */
40 .byte 0x0c /* DW_CFA_def_cfa */
41 .uleb128 4
42 .uleb128 4
43 .byte 0x88 /* DW_CFA_offset, column 0x8 */
44 .uleb128 1
45 .align 4
46.LENDCIE:
47
48 .long .LENDFDE1-.LSTARTFDE1 /* Length FDE */
49.LSTARTFDE1:
50 .long .LSTARTFDE1-.LSTARTFRAME /* CIE pointer */
51 .long .LSTART_vsyscall-. /* PC-relative start address */
52 .long .LEND_vsyscall-.LSTART_vsyscall
53 .uleb128 0 /* Augmentation length */
54 /* What follows are the instructions for the table generation.
55 We have to record all changes of the stack pointer. */
56 .byte 0x40 + .Lpush_ebp-.LSTART_vsyscall /* DW_CFA_advance_loc */
57 .byte 0x0e /* DW_CFA_def_cfa_offset */
58 .uleb128 8
59 .byte 0x85, 0x02 /* DW_CFA_offset %ebp -8 */
60 .byte 0x40 + .Lpop_ebp-.Lpush_ebp /* DW_CFA_advance_loc */
61 .byte 0xc5 /* DW_CFA_restore %ebp */
62 .byte 0x0e /* DW_CFA_def_cfa_offset */
63 .uleb128 4
64 .align 4
65.LENDFDE1:
66
67#define SYSCALL_ENTER_KERNEL syscall
68#include "vsyscall-sigreturn.S"
diff --git a/arch/x86_64/ia32/vsyscall-sysenter.S b/arch/x86_64/ia32/vsyscall-sysenter.S
new file mode 100644
index 000000000000..8fb8e0ff3afa
--- /dev/null
+++ b/arch/x86_64/ia32/vsyscall-sysenter.S
@@ -0,0 +1,94 @@
1/*
2 * Code for the vsyscall page. This version uses the sysenter instruction.
3 */
4
5#include <asm/ia32_unistd.h>
6#include <asm/offset.h>
7
8 .text
9 .section .text.vsyscall,"ax"
10 .globl __kernel_vsyscall
11 .type __kernel_vsyscall,@function
12__kernel_vsyscall:
13.LSTART_vsyscall:
14 push %ecx
15.Lpush_ecx:
16 push %edx
17.Lpush_edx:
18 push %ebp
19.Lenter_kernel:
20 movl %esp,%ebp
21 sysenter
22 .space 7,0x90
23 jmp .Lenter_kernel
24 /* 16: System call normal return point is here! */
25 pop %ebp
26.Lpop_ebp:
27 pop %edx
28.Lpop_edx:
29 pop %ecx
30.Lpop_ecx:
31 ret
32.LEND_vsyscall:
33 .size __kernel_vsyscall,.-.LSTART_vsyscall
34
35 .section .eh_frame,"a",@progbits
36.LSTARTFRAME:
37 .long .LENDCIE-.LSTARTCIE
38.LSTARTCIE:
39 .long 0 /* CIE ID */
40 .byte 1 /* Version number */
41 .string "zR" /* NUL-terminated augmentation string */
42 .uleb128 1 /* Code alignment factor */
43 .sleb128 -4 /* Data alignment factor */
44 .byte 8 /* Return address register column */
45 .uleb128 1 /* Augmentation value length */
46 .byte 0x1b /* DW_EH_PE_pcrel|DW_EH_PE_sdata4. */
47 .byte 0x0c /* DW_CFA_def_cfa */
48 .uleb128 4
49 .uleb128 4
50 .byte 0x88 /* DW_CFA_offset, column 0x8 */
51 .uleb128 1
52 .align 4
53.LENDCIE:
54
55 .long .LENDFDE1-.LSTARTFDE1 /* Length FDE */
56.LSTARTFDE1:
57 .long .LSTARTFDE1-.LSTARTFRAME /* CIE pointer */
58 .long .LSTART_vsyscall-. /* PC-relative start address */
59 .long .LEND_vsyscall-.LSTART_vsyscall
60 .uleb128 0 /* Augmentation length */
61 /* What follows are the instructions for the table generation.
62 We have to record all changes of the stack pointer. */
63 .byte 0x04 /* DW_CFA_advance_loc4 */
64 .long .Lpush_ecx-.LSTART_vsyscall
65 .byte 0x0e /* DW_CFA_def_cfa_offset */
66 .byte 0x08 /* RA at offset 8 now */
67 .byte 0x04 /* DW_CFA_advance_loc4 */
68 .long .Lpush_edx-.Lpush_ecx
69 .byte 0x0e /* DW_CFA_def_cfa_offset */
70 .byte 0x0c /* RA at offset 12 now */
71 .byte 0x04 /* DW_CFA_advance_loc4 */
72 .long .Lenter_kernel-.Lpush_edx
73 .byte 0x0e /* DW_CFA_def_cfa_offset */
74 .byte 0x10 /* RA at offset 16 now */
75 .byte 0x85, 0x04 /* DW_CFA_offset %ebp -16 */
76 /* Finally the epilogue. */
77 .byte 0x04 /* DW_CFA_advance_loc4 */
78 .long .Lpop_ebp-.Lenter_kernel
79 .byte 0x0e /* DW_CFA_def_cfa_offset */
80 .byte 0x12 /* RA at offset 12 now */
81 .byte 0xc5 /* DW_CFA_restore %ebp */
82 .byte 0x04 /* DW_CFA_advance_loc4 */
83 .long .Lpop_edx-.Lpop_ebp
84 .byte 0x0e /* DW_CFA_def_cfa_offset */
85 .byte 0x08 /* RA at offset 8 now */
86 .byte 0x04 /* DW_CFA_advance_loc4 */
87 .long .Lpop_ecx-.Lpop_edx
88 .byte 0x0e /* DW_CFA_def_cfa_offset */
89 .byte 0x04 /* RA at offset 4 now */
90 .align 4
91.LENDFDE1:
92
93#define SYSCALL_ENTER_KERNEL int $0x80
94#include "vsyscall-sigreturn.S"
diff --git a/arch/x86_64/ia32/vsyscall.lds b/arch/x86_64/ia32/vsyscall.lds
new file mode 100644
index 000000000000..fa4b4dd4a9ff
--- /dev/null
+++ b/arch/x86_64/ia32/vsyscall.lds
@@ -0,0 +1,77 @@
1/*
2 * Linker script for vsyscall DSO. The vsyscall page is an ELF shared
3 * object prelinked to its virtual address. This script controls its layout.
4 */
5
6/* This must match <asm/fixmap.h>. */
7VSYSCALL_BASE = 0xffffe000;
8
9SECTIONS
10{
11 . = VSYSCALL_BASE + SIZEOF_HEADERS;
12
13 .hash : { *(.hash) } :text
14 .dynsym : { *(.dynsym) }
15 .dynstr : { *(.dynstr) }
16 .gnu.version : { *(.gnu.version) }
17 .gnu.version_d : { *(.gnu.version_d) }
18 .gnu.version_r : { *(.gnu.version_r) }
19
20 /* This linker script is used both with -r and with -shared.
21 For the layouts to match, we need to skip more than enough
22 space for the dynamic symbol table et al. If this amount
23 is insufficient, ld -shared will barf. Just increase it here. */
24 . = VSYSCALL_BASE + 0x400;
25
26 .text.vsyscall : { *(.text.vsyscall) } :text =0x90909090
27
28 /* This is an 32bit object and we cannot easily get the offsets
29 into the 64bit kernel. Just hardcode them here. This assumes
30 that all the stubs don't need more than 0x100 bytes. */
31 . = VSYSCALL_BASE + 0x500;
32
33 .text.sigreturn : { *(.text.sigreturn) } :text =0x90909090
34
35 . = VSYSCALL_BASE + 0x600;
36
37 .text.rtsigreturn : { *(.text.rtsigreturn) } :text =0x90909090
38
39 .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr
40 .eh_frame : { KEEP (*(.eh_frame)) } :text
41 .dynamic : { *(.dynamic) } :text :dynamic
42 .useless : {
43 *(.got.plt) *(.got)
44 *(.data .data.* .gnu.linkonce.d.*)
45 *(.dynbss)
46 *(.bss .bss.* .gnu.linkonce.b.*)
47 } :text
48}
49
50/*
51 * We must supply the ELF program headers explicitly to get just one
52 * PT_LOAD segment, and set the flags explicitly to make segments read-only.
53 */
54PHDRS
55{
56 text PT_LOAD FILEHDR PHDRS FLAGS(5); /* PF_R|PF_X */
57 dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
58 eh_frame_hdr 0x6474e550; /* PT_GNU_EH_FRAME, but ld doesn't match the name */
59}
60
61/*
62 * This controls what symbols we export from the DSO.
63 */
64VERSION
65{
66 LINUX_2.5 {
67 global:
68 __kernel_vsyscall;
69 __kernel_sigreturn;
70 __kernel_rt_sigreturn;
71
72 local: *;
73 };
74}
75
76/* The ELF entry point can be used to set the AT_SYSINFO value. */
77ENTRY(__kernel_vsyscall);