aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/sys-i386
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/um/sys-i386
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/um/sys-i386')
-rw-r--r--arch/um/sys-i386/Makefile29
-rw-r--r--arch/um/sys-i386/bugs.c222
-rw-r--r--arch/um/sys-i386/checksum.S460
-rw-r--r--arch/um/sys-i386/delay.c14
-rw-r--r--arch/um/sys-i386/fault.c42
-rw-r--r--arch/um/sys-i386/ksyms.c17
-rw-r--r--arch/um/sys-i386/ldt.c98
-rw-r--r--arch/um/sys-i386/ptrace.c369
-rw-r--r--arch/um/sys-i386/ptrace_user.c131
-rw-r--r--arch/um/sys-i386/sigcontext.c71
-rw-r--r--arch/um/sys-i386/signal.c382
-rw-r--r--arch/um/sys-i386/syscalls.c210
-rw-r--r--arch/um/sys-i386/sysrq.c35
-rw-r--r--arch/um/sys-i386/util/Makefile8
-rw-r--r--arch/um/sys-i386/util/mk_sc.c52
-rw-r--r--arch/um/sys-i386/util/mk_thread_kern.c22
-rw-r--r--arch/um/sys-i386/util/mk_thread_user.c30
17 files changed, 2192 insertions, 0 deletions
diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile
new file mode 100644
index 000000000000..71b47e618605
--- /dev/null
+++ b/arch/um/sys-i386/Makefile
@@ -0,0 +1,29 @@
1obj-y = bitops.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \
2 ptrace_user.o semaphore.o signal.o sigcontext.o syscalls.o sysrq.o
3
4obj-$(CONFIG_HIGHMEM) += highmem.o
5obj-$(CONFIG_MODULES) += module.o
6
7USER_OBJS := bugs.o ptrace_user.o sigcontext.o fault.o
8
9include arch/um/scripts/Makefile.rules
10
11SYMLINKS = bitops.c semaphore.c highmem.c module.c
12
13# this needs to be before the foreach, because clean-files does not accept
14# complete paths like $(src)/$f.
15clean-files := $(SYMLINKS)
16
17targets += $(SYMLINKS)
18
19SYMLINKS := $(foreach f,$(SYMLINKS),$(obj)/$f)
20
21bitops.c-dir = lib
22semaphore.c-dir = kernel
23highmem.c-dir = mm
24module.c-dir = kernel
25
26$(SYMLINKS): FORCE
27 $(call if_changed,make_link)
28
29subdir- := util
diff --git a/arch/um/sys-i386/bugs.c b/arch/um/sys-i386/bugs.c
new file mode 100644
index 000000000000..41b0ab2fe830
--- /dev/null
+++ b/arch/um/sys-i386/bugs.c
@@ -0,0 +1,222 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <unistd.h>
7#include <errno.h>
8#include <string.h>
9#include <sys/signal.h>
10#include <asm/ldt.h>
11#include "kern_util.h"
12#include "user.h"
13#include "sysdep/ptrace.h"
14#include "task.h"
15#include "os.h"
16
17#define MAXTOKEN 64
18
19/* Set during early boot */
20int host_has_cmov = 1;
21int host_has_xmm = 0;
22
23static char token(int fd, char *buf, int len, char stop)
24{
25 int n;
26 char *ptr, *end, c;
27
28 ptr = buf;
29 end = &buf[len];
30 do {
31 n = os_read_file(fd, ptr, sizeof(*ptr));
32 c = *ptr++;
33 if(n != sizeof(*ptr)){
34 if(n == 0) return(0);
35 printk("Reading /proc/cpuinfo failed, err = %d\n", -n);
36 if(n < 0)
37 return(n);
38 else
39 return(-EIO);
40 }
41 } while((c != '\n') && (c != stop) && (ptr < end));
42
43 if(ptr == end){
44 printk("Failed to find '%c' in /proc/cpuinfo\n", stop);
45 return(-1);
46 }
47 *(ptr - 1) = '\0';
48 return(c);
49}
50
51static int find_cpuinfo_line(int fd, char *key, char *scratch, int len)
52{
53 int n;
54 char c;
55
56 scratch[len - 1] = '\0';
57 while(1){
58 c = token(fd, scratch, len - 1, ':');
59 if(c <= 0)
60 return(0);
61 else if(c != ':'){
62 printk("Failed to find ':' in /proc/cpuinfo\n");
63 return(0);
64 }
65
66 if(!strncmp(scratch, key, strlen(key)))
67 return(1);
68
69 do {
70 n = os_read_file(fd, &c, sizeof(c));
71 if(n != sizeof(c)){
72 printk("Failed to find newline in "
73 "/proc/cpuinfo, err = %d\n", -n);
74 return(0);
75 }
76 } while(c != '\n');
77 }
78 return(0);
79}
80
81int cpu_feature(char *what, char *buf, int len)
82{
83 int fd, ret = 0;
84
85 fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0);
86 if(fd < 0){
87 printk("Couldn't open /proc/cpuinfo, err = %d\n", -fd);
88 return(0);
89 }
90
91 if(!find_cpuinfo_line(fd, what, buf, len)){
92 printk("Couldn't find '%s' line in /proc/cpuinfo\n", what);
93 goto out_close;
94 }
95
96 token(fd, buf, len, '\n');
97 ret = 1;
98
99 out_close:
100 os_close_file(fd);
101 return(ret);
102}
103
104static int check_cpu_flag(char *feature, int *have_it)
105{
106 char buf[MAXTOKEN], c;
107 int fd, len = sizeof(buf)/sizeof(buf[0]);
108
109 printk("Checking for host processor %s support...", feature);
110 fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0);
111 if(fd < 0){
112 printk("Couldn't open /proc/cpuinfo, err = %d\n", -fd);
113 return(0);
114 }
115
116 *have_it = 0;
117 if(!find_cpuinfo_line(fd, "flags", buf, sizeof(buf) / sizeof(buf[0])))
118 goto out;
119
120 c = token(fd, buf, len - 1, ' ');
121 if(c < 0) goto out;
122 else if(c != ' '){
123 printk("Failed to find ' ' in /proc/cpuinfo\n");
124 goto out;
125 }
126
127 while(1){
128 c = token(fd, buf, len - 1, ' ');
129 if(c < 0) goto out;
130 else if(c == '\n') break;
131
132 if(!strcmp(buf, feature)){
133 *have_it = 1;
134 goto out;
135 }
136 }
137 out:
138 if(*have_it == 0) printk("No\n");
139 else if(*have_it == 1) printk("Yes\n");
140 os_close_file(fd);
141 return(1);
142}
143
144#if 0 /* This doesn't work in tt mode, plus it's causing compilation problems
145 * for some people.
146 */
147static void disable_lcall(void)
148{
149 struct modify_ldt_ldt_s ldt;
150 int err;
151
152 bzero(&ldt, sizeof(ldt));
153 ldt.entry_number = 7;
154 ldt.base_addr = 0;
155 ldt.limit = 0;
156 err = modify_ldt(1, &ldt, sizeof(ldt));
157 if(err)
158 printk("Failed to disable lcall7 - errno = %d\n", errno);
159}
160#endif
161
162void arch_init_thread(void)
163{
164#if 0
165 disable_lcall();
166#endif
167}
168
169void arch_check_bugs(void)
170{
171 int have_it;
172
173 if(os_access("/proc/cpuinfo", OS_ACC_R_OK) < 0){
174 printk("/proc/cpuinfo not available - skipping CPU capability "
175 "checks\n");
176 return;
177 }
178 if(check_cpu_flag("cmov", &have_it))
179 host_has_cmov = have_it;
180 if(check_cpu_flag("xmm", &have_it))
181 host_has_xmm = have_it;
182}
183
184int arch_handle_signal(int sig, union uml_pt_regs *regs)
185{
186 unsigned char tmp[2];
187
188 /* This is testing for a cmov (0x0f 0x4x) instruction causing a
189 * SIGILL in init.
190 */
191 if((sig != SIGILL) || (TASK_PID(get_current()) != 1)) return(0);
192
193 if (copy_from_user_proc(tmp, (void *) UPT_IP(regs), 2))
194 panic("SIGILL in init, could not read instructions!\n");
195 if((tmp[0] != 0x0f) || ((tmp[1] & 0xf0) != 0x40))
196 return(0);
197
198 if(host_has_cmov == 0)
199 panic("SIGILL caused by cmov, which this processor doesn't "
200 "implement, boot a filesystem compiled for older "
201 "processors");
202 else if(host_has_cmov == 1)
203 panic("SIGILL caused by cmov, which this processor claims to "
204 "implement");
205 else if(host_has_cmov == -1)
206 panic("SIGILL caused by cmov, couldn't tell if this processor "
207 "implements it, boot a filesystem compiled for older "
208 "processors");
209 else panic("Bad value for host_has_cmov (%d)", host_has_cmov);
210 return(0);
211}
212
213/*
214 * Overrides for Emacs so that we follow Linus's tabbing style.
215 * Emacs will notice this stuff at the end of the file and automatically
216 * adjust the settings for this buffer only. This must remain at the end
217 * of the file.
218 * ---------------------------------------------------------------------------
219 * Local variables:
220 * c-file-style: "linux"
221 * End:
222 */
diff --git a/arch/um/sys-i386/checksum.S b/arch/um/sys-i386/checksum.S
new file mode 100644
index 000000000000..a11171fb6223
--- /dev/null
+++ b/arch/um/sys-i386/checksum.S
@@ -0,0 +1,460 @@
1/*
2 * INET An implementation of the TCP/IP protocol suite for the LINUX
3 * operating system. INET is implemented using the BSD Socket
4 * interface as the means of communication with the user level.
5 *
6 * IP/TCP/UDP checksumming routines
7 *
8 * Authors: Jorge Cwik, <jorge@laser.satlink.net>
9 * Arnt Gulbrandsen, <agulbra@nvg.unit.no>
10 * Tom May, <ftom@netcom.com>
11 * Pentium Pro/II routines:
12 * Alexander Kjeldaas <astor@guardian.no>
13 * Finn Arne Gangstad <finnag@guardian.no>
14 * Lots of code moved from tcp.c and ip.c; see those files
15 * for more names.
16 *
17 * Changes: Ingo Molnar, converted csum_partial_copy() to 2.1 exception
18 * handling.
19 * Andi Kleen, add zeroing on error
20 * converted to pure assembler
21 *
22 * This program is free software; you can redistribute it and/or
23 * modify it under the terms of the GNU General Public License
24 * as published by the Free Software Foundation; either version
25 * 2 of the License, or (at your option) any later version.
26 */
27
28#include <linux/config.h>
29#include <asm/errno.h>
30
31/*
32 * computes a partial checksum, e.g. for TCP/UDP fragments
33 */
34
35/*
36unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
37 */
38
39.text
40.align 4
41.globl arch_csum_partial
42
43#ifndef CONFIG_X86_USE_PPRO_CHECKSUM
44
45 /*
46 * Experiments with Ethernet and SLIP connections show that buff
47 * is aligned on either a 2-byte or 4-byte boundary. We get at
48 * least a twofold speedup on 486 and Pentium if it is 4-byte aligned.
49 * Fortunately, it is easy to convert 2-byte alignment to 4-byte
50 * alignment for the unrolled loop.
51 */
52arch_csum_partial:
53 pushl %esi
54 pushl %ebx
55 movl 20(%esp),%eax # Function arg: unsigned int sum
56 movl 16(%esp),%ecx # Function arg: int len
57 movl 12(%esp),%esi # Function arg: unsigned char *buff
58 testl $2, %esi # Check alignment.
59 jz 2f # Jump if alignment is ok.
60 subl $2, %ecx # Alignment uses up two bytes.
61 jae 1f # Jump if we had at least two bytes.
62 addl $2, %ecx # ecx was < 2. Deal with it.
63 jmp 4f
641: movw (%esi), %bx
65 addl $2, %esi
66 addw %bx, %ax
67 adcl $0, %eax
682:
69 movl %ecx, %edx
70 shrl $5, %ecx
71 jz 2f
72 testl %esi, %esi
731: movl (%esi), %ebx
74 adcl %ebx, %eax
75 movl 4(%esi), %ebx
76 adcl %ebx, %eax
77 movl 8(%esi), %ebx
78 adcl %ebx, %eax
79 movl 12(%esi), %ebx
80 adcl %ebx, %eax
81 movl 16(%esi), %ebx
82 adcl %ebx, %eax
83 movl 20(%esi), %ebx
84 adcl %ebx, %eax
85 movl 24(%esi), %ebx
86 adcl %ebx, %eax
87 movl 28(%esi), %ebx
88 adcl %ebx, %eax
89 lea 32(%esi), %esi
90 dec %ecx
91 jne 1b
92 adcl $0, %eax
932: movl %edx, %ecx
94 andl $0x1c, %edx
95 je 4f
96 shrl $2, %edx # This clears CF
973: adcl (%esi), %eax
98 lea 4(%esi), %esi
99 dec %edx
100 jne 3b
101 adcl $0, %eax
1024: andl $3, %ecx
103 jz 7f
104 cmpl $2, %ecx
105 jb 5f
106 movw (%esi),%cx
107 leal 2(%esi),%esi
108 je 6f
109 shll $16,%ecx
1105: movb (%esi),%cl
1116: addl %ecx,%eax
112 adcl $0, %eax
1137:
114 popl %ebx
115 popl %esi
116 ret
117
118#else
119
120/* Version for PentiumII/PPro */
121
122arch_csum_partial:
123 pushl %esi
124 pushl %ebx
125 movl 20(%esp),%eax # Function arg: unsigned int sum
126 movl 16(%esp),%ecx # Function arg: int len
127 movl 12(%esp),%esi # Function arg: const unsigned char *buf
128
129 testl $2, %esi
130 jnz 30f
13110:
132 movl %ecx, %edx
133 movl %ecx, %ebx
134 andl $0x7c, %ebx
135 shrl $7, %ecx
136 addl %ebx,%esi
137 shrl $2, %ebx
138 negl %ebx
139 lea 45f(%ebx,%ebx,2), %ebx
140 testl %esi, %esi
141 jmp *%ebx
142
143 # Handle 2-byte-aligned regions
14420: addw (%esi), %ax
145 lea 2(%esi), %esi
146 adcl $0, %eax
147 jmp 10b
148
14930: subl $2, %ecx
150 ja 20b
151 je 32f
152 movzbl (%esi),%ebx # csumming 1 byte, 2-aligned
153 addl %ebx, %eax
154 adcl $0, %eax
155 jmp 80f
15632:
157 addw (%esi), %ax # csumming 2 bytes, 2-aligned
158 adcl $0, %eax
159 jmp 80f
160
16140:
162 addl -128(%esi), %eax
163 adcl -124(%esi), %eax
164 adcl -120(%esi), %eax
165 adcl -116(%esi), %eax
166 adcl -112(%esi), %eax
167 adcl -108(%esi), %eax
168 adcl -104(%esi), %eax
169 adcl -100(%esi), %eax
170 adcl -96(%esi), %eax
171 adcl -92(%esi), %eax
172 adcl -88(%esi), %eax
173 adcl -84(%esi), %eax
174 adcl -80(%esi), %eax
175 adcl -76(%esi), %eax
176 adcl -72(%esi), %eax
177 adcl -68(%esi), %eax
178 adcl -64(%esi), %eax
179 adcl -60(%esi), %eax
180 adcl -56(%esi), %eax
181 adcl -52(%esi), %eax
182 adcl -48(%esi), %eax
183 adcl -44(%esi), %eax
184 adcl -40(%esi), %eax
185 adcl -36(%esi), %eax
186 adcl -32(%esi), %eax
187 adcl -28(%esi), %eax
188 adcl -24(%esi), %eax
189 adcl -20(%esi), %eax
190 adcl -16(%esi), %eax
191 adcl -12(%esi), %eax
192 adcl -8(%esi), %eax
193 adcl -4(%esi), %eax
19445:
195 lea 128(%esi), %esi
196 adcl $0, %eax
197 dec %ecx
198 jge 40b
199 movl %edx, %ecx
20050: andl $3, %ecx
201 jz 80f
202
203 # Handle the last 1-3 bytes without jumping
204 notl %ecx # 1->2, 2->1, 3->0, higher bits are masked
205 movl $0xffffff,%ebx # by the shll and shrl instructions
206 shll $3,%ecx
207 shrl %cl,%ebx
208 andl -128(%esi),%ebx # esi is 4-aligned so should be ok
209 addl %ebx,%eax
210 adcl $0,%eax
21180:
212 popl %ebx
213 popl %esi
214 ret
215
216#endif
217
218/*
219unsigned int csum_partial_copy_generic (const char *src, char *dst,
220 int len, int sum, int *src_err_ptr, int *dst_err_ptr)
221 */
222
223/*
224 * Copy from ds while checksumming, otherwise like csum_partial
225 *
226 * The macros SRC and DST specify the type of access for the instruction.
227 * thus we can call a custom exception handler for all access types.
228 *
229 * FIXME: could someone double-check whether I haven't mixed up some SRC and
230 * DST definitions? It's damn hard to trigger all cases. I hope I got
231 * them all but there's no guarantee.
232 */
233
234#define SRC(y...) \
235 9999: y; \
236 .section __ex_table, "a"; \
237 .long 9999b, 6001f ; \
238 .previous
239
240#define DST(y...) \
241 9999: y; \
242 .section __ex_table, "a"; \
243 .long 9999b, 6002f ; \
244 .previous
245
246.align 4
247.globl csum_partial_copy_generic_i386
248
249#ifndef CONFIG_X86_USE_PPRO_CHECKSUM
250
251#define ARGBASE 16
252#define FP 12
253
254csum_partial_copy_generic_i386:
255 subl $4,%esp
256 pushl %edi
257 pushl %esi
258 pushl %ebx
259 movl ARGBASE+16(%esp),%eax # sum
260 movl ARGBASE+12(%esp),%ecx # len
261 movl ARGBASE+4(%esp),%esi # src
262 movl ARGBASE+8(%esp),%edi # dst
263
264 testl $2, %edi # Check alignment.
265 jz 2f # Jump if alignment is ok.
266 subl $2, %ecx # Alignment uses up two bytes.
267 jae 1f # Jump if we had at least two bytes.
268 addl $2, %ecx # ecx was < 2. Deal with it.
269 jmp 4f
270SRC(1: movw (%esi), %bx )
271 addl $2, %esi
272DST( movw %bx, (%edi) )
273 addl $2, %edi
274 addw %bx, %ax
275 adcl $0, %eax
2762:
277 movl %ecx, FP(%esp)
278 shrl $5, %ecx
279 jz 2f
280 testl %esi, %esi
281SRC(1: movl (%esi), %ebx )
282SRC( movl 4(%esi), %edx )
283 adcl %ebx, %eax
284DST( movl %ebx, (%edi) )
285 adcl %edx, %eax
286DST( movl %edx, 4(%edi) )
287
288SRC( movl 8(%esi), %ebx )
289SRC( movl 12(%esi), %edx )
290 adcl %ebx, %eax
291DST( movl %ebx, 8(%edi) )
292 adcl %edx, %eax
293DST( movl %edx, 12(%edi) )
294
295SRC( movl 16(%esi), %ebx )
296SRC( movl 20(%esi), %edx )
297 adcl %ebx, %eax
298DST( movl %ebx, 16(%edi) )
299 adcl %edx, %eax
300DST( movl %edx, 20(%edi) )
301
302SRC( movl 24(%esi), %ebx )
303SRC( movl 28(%esi), %edx )
304 adcl %ebx, %eax
305DST( movl %ebx, 24(%edi) )
306 adcl %edx, %eax
307DST( movl %edx, 28(%edi) )
308
309 lea 32(%esi), %esi
310 lea 32(%edi), %edi
311 dec %ecx
312 jne 1b
313 adcl $0, %eax
3142: movl FP(%esp), %edx
315 movl %edx, %ecx
316 andl $0x1c, %edx
317 je 4f
318 shrl $2, %edx # This clears CF
319SRC(3: movl (%esi), %ebx )
320 adcl %ebx, %eax
321DST( movl %ebx, (%edi) )
322 lea 4(%esi), %esi
323 lea 4(%edi), %edi
324 dec %edx
325 jne 3b
326 adcl $0, %eax
3274: andl $3, %ecx
328 jz 7f
329 cmpl $2, %ecx
330 jb 5f
331SRC( movw (%esi), %cx )
332 leal 2(%esi), %esi
333DST( movw %cx, (%edi) )
334 leal 2(%edi), %edi
335 je 6f
336 shll $16,%ecx
337SRC(5: movb (%esi), %cl )
338DST( movb %cl, (%edi) )
3396: addl %ecx, %eax
340 adcl $0, %eax
3417:
3425000:
343
344# Exception handler:
345.section .fixup, "ax"
346
3476001:
348 movl ARGBASE+20(%esp), %ebx # src_err_ptr
349 movl $-EFAULT, (%ebx)
350
351 # zero the complete destination - computing the rest
352 # is too much work
353 movl ARGBASE+8(%esp), %edi # dst
354 movl ARGBASE+12(%esp), %ecx # len
355 xorl %eax,%eax
356 rep ; stosb
357
358 jmp 5000b
359
3606002:
361 movl ARGBASE+24(%esp), %ebx # dst_err_ptr
362 movl $-EFAULT,(%ebx)
363 jmp 5000b
364
365.previous
366
367 popl %ebx
368 popl %esi
369 popl %edi
370 popl %ecx # equivalent to addl $4,%esp
371 ret
372
373#else
374
375/* Version for PentiumII/PPro */
376
377#define ROUND1(x) \
378 SRC(movl x(%esi), %ebx ) ; \
379 addl %ebx, %eax ; \
380 DST(movl %ebx, x(%edi) ) ;
381
382#define ROUND(x) \
383 SRC(movl x(%esi), %ebx ) ; \
384 adcl %ebx, %eax ; \
385 DST(movl %ebx, x(%edi) ) ;
386
387#define ARGBASE 12
388
389csum_partial_copy_generic_i386:
390 pushl %ebx
391 pushl %edi
392 pushl %esi
393 movl ARGBASE+4(%esp),%esi #src
394 movl ARGBASE+8(%esp),%edi #dst
395 movl ARGBASE+12(%esp),%ecx #len
396 movl ARGBASE+16(%esp),%eax #sum
397# movl %ecx, %edx
398 movl %ecx, %ebx
399 movl %esi, %edx
400 shrl $6, %ecx
401 andl $0x3c, %ebx
402 negl %ebx
403 subl %ebx, %esi
404 subl %ebx, %edi
405 lea -1(%esi),%edx
406 andl $-32,%edx
407 lea 3f(%ebx,%ebx), %ebx
408 testl %esi, %esi
409 jmp *%ebx
4101: addl $64,%esi
411 addl $64,%edi
412 SRC(movb -32(%edx),%bl) ; SRC(movb (%edx),%bl)
413 ROUND1(-64) ROUND(-60) ROUND(-56) ROUND(-52)
414 ROUND (-48) ROUND(-44) ROUND(-40) ROUND(-36)
415 ROUND (-32) ROUND(-28) ROUND(-24) ROUND(-20)
416 ROUND (-16) ROUND(-12) ROUND(-8) ROUND(-4)
4173: adcl $0,%eax
418 addl $64, %edx
419 dec %ecx
420 jge 1b
4214: movl ARGBASE+12(%esp),%edx #len
422 andl $3, %edx
423 jz 7f
424 cmpl $2, %edx
425 jb 5f
426SRC( movw (%esi), %dx )
427 leal 2(%esi), %esi
428DST( movw %dx, (%edi) )
429 leal 2(%edi), %edi
430 je 6f
431 shll $16,%edx
4325:
433SRC( movb (%esi), %dl )
434DST( movb %dl, (%edi) )
4356: addl %edx, %eax
436 adcl $0, %eax
4377:
438.section .fixup, "ax"
4396001: movl ARGBASE+20(%esp), %ebx # src_err_ptr
440 movl $-EFAULT, (%ebx)
441 # zero the complete destination (computing the rest is too much work)
442 movl ARGBASE+8(%esp),%edi # dst
443 movl ARGBASE+12(%esp),%ecx # len
444 xorl %eax,%eax
445 rep; stosb
446 jmp 7b
4476002: movl ARGBASE+24(%esp), %ebx # dst_err_ptr
448 movl $-EFAULT, (%ebx)
449 jmp 7b
450.previous
451
452 popl %esi
453 popl %edi
454 popl %ebx
455 ret
456
457#undef ROUND
458#undef ROUND1
459
460#endif
diff --git a/arch/um/sys-i386/delay.c b/arch/um/sys-i386/delay.c
new file mode 100644
index 000000000000..20d37dbbaf08
--- /dev/null
+++ b/arch/um/sys-i386/delay.c
@@ -0,0 +1,14 @@
1void __delay(unsigned long time)
2{
3 /* Stolen from the i386 __loop_delay */
4 int d0;
5 __asm__ __volatile__(
6 "\tjmp 1f\n"
7 ".align 16\n"
8 "1:\tjmp 2f\n"
9 ".align 16\n"
10 "2:\tdecl %0\n\tjns 2b"
11 :"=&a" (d0)
12 :"0" (time));
13}
14
diff --git a/arch/um/sys-i386/fault.c b/arch/um/sys-i386/fault.c
new file mode 100644
index 000000000000..d0bbcdfdb53f
--- /dev/null
+++ b/arch/um/sys-i386/fault.c
@@ -0,0 +1,42 @@
1/*
2 * Copyright (C) 2002 - 2004 Jeff Dike (jdike@addtoit.com)
3 * Licensed under the GPL
4 */
5
6#include <signal.h>
7#include "sysdep/ptrace.h"
8#include "sysdep/sigcontext.h"
9
10/* These two are from asm-um/uaccess.h and linux/module.h, check them. */
11struct exception_table_entry
12{
13 unsigned long insn;
14 unsigned long fixup;
15};
16
17const struct exception_table_entry *search_exception_tables(unsigned long add);
18
19/* Compare this to arch/i386/mm/extable.c:fixup_exception() */
20int arch_fixup(unsigned long address, void *sc_ptr)
21{
22 struct sigcontext *sc = sc_ptr;
23 const struct exception_table_entry *fixup;
24
25 fixup = search_exception_tables(address);
26 if(fixup != 0){
27 sc->eip = fixup->fixup;
28 return(1);
29 }
30 return(0);
31}
32
33/*
34 * Overrides for Emacs so that we follow Linus's tabbing style.
35 * Emacs will notice this stuff at the end of the file and automatically
36 * adjust the settings for this buffer only. This must remain at the end
37 * of the file.
38 * ---------------------------------------------------------------------------
39 * Local variables:
40 * c-file-style: "linux"
41 * End:
42 */
diff --git a/arch/um/sys-i386/ksyms.c b/arch/um/sys-i386/ksyms.c
new file mode 100644
index 000000000000..74f70a120458
--- /dev/null
+++ b/arch/um/sys-i386/ksyms.c
@@ -0,0 +1,17 @@
1#include "linux/module.h"
2#include "linux/in6.h"
3#include "linux/rwsem.h"
4#include "asm/byteorder.h"
5#include "asm/semaphore.h"
6#include "asm/uaccess.h"
7#include "asm/checksum.h"
8#include "asm/errno.h"
9
10EXPORT_SYMBOL(__down_failed);
11EXPORT_SYMBOL(__down_failed_interruptible);
12EXPORT_SYMBOL(__down_failed_trylock);
13EXPORT_SYMBOL(__up_wakeup);
14
15/* Networking helper routines. */
16EXPORT_SYMBOL(csum_partial_copy_from);
17EXPORT_SYMBOL(csum_partial_copy_to);
diff --git a/arch/um/sys-i386/ldt.c b/arch/um/sys-i386/ldt.c
new file mode 100644
index 000000000000..31bcb2f997d4
--- /dev/null
+++ b/arch/um/sys-i386/ldt.c
@@ -0,0 +1,98 @@
1/*
2 * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/config.h"
7#include "linux/slab.h"
8#include "asm/uaccess.h"
9#include "asm/ptrace.h"
10#include "choose-mode.h"
11#include "kern.h"
12
13#ifdef CONFIG_MODE_TT
14extern int modify_ldt(int func, void *ptr, unsigned long bytecount);
15
16/* XXX this needs copy_to_user and copy_from_user */
17
18int sys_modify_ldt_tt(int func, void __user *ptr, unsigned long bytecount)
19{
20 if (!access_ok(VERIFY_READ, ptr, bytecount))
21 return -EFAULT;
22
23 return modify_ldt(func, ptr, bytecount);
24}
25#endif
26
27#ifdef CONFIG_MODE_SKAS
28extern int userspace_pid;
29
30#include "skas_ptrace.h"
31
32int sys_modify_ldt_skas(int func, void __user *ptr, unsigned long bytecount)
33{
34 struct ptrace_ldt ldt;
35 void *buf;
36 int res, n;
37
38 buf = kmalloc(bytecount, GFP_KERNEL);
39 if(buf == NULL)
40 return(-ENOMEM);
41
42 res = 0;
43
44 switch(func){
45 case 1:
46 case 0x11:
47 res = copy_from_user(buf, ptr, bytecount);
48 break;
49 }
50
51 if(res != 0){
52 res = -EFAULT;
53 goto out;
54 }
55
56 ldt = ((struct ptrace_ldt) { .func = func,
57 .ptr = buf,
58 .bytecount = bytecount });
59 res = ptrace(PTRACE_LDT, userspace_pid, 0, (unsigned long) &ldt);
60 if(res < 0)
61 goto out;
62
63 switch(func){
64 case 0:
65 case 2:
66 n = res;
67 res = copy_to_user(ptr, buf, n);
68 if(res != 0)
69 res = -EFAULT;
70 else
71 res = n;
72 break;
73 }
74
75 out:
76 kfree(buf);
77 return(res);
78}
79#endif
80
81int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
82{
83 return(CHOOSE_MODE_PROC(sys_modify_ldt_tt, sys_modify_ldt_skas, func,
84 ptr, bytecount));
85}
86
87
88
89/*
90 * Overrides for Emacs so that we follow Linus's tabbing style.
91 * Emacs will notice this stuff at the end of the file and automatically
92 * adjust the settings for this buffer only. This must remain at the end
93 * of the file.
94 * ---------------------------------------------------------------------------
95 * Local variables:
96 * c-file-style: "linux"
97 * End:
98 */
diff --git a/arch/um/sys-i386/ptrace.c b/arch/um/sys-i386/ptrace.c
new file mode 100644
index 000000000000..e470d28cdf84
--- /dev/null
+++ b/arch/um/sys-i386/ptrace.c
@@ -0,0 +1,369 @@
1/*
2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <linux/config.h>
7#include <linux/compiler.h>
8#include "linux/sched.h"
9#include "asm/elf.h"
10#include "asm/ptrace.h"
11#include "asm/uaccess.h"
12#include "asm/unistd.h"
13#include "sysdep/ptrace.h"
14#include "sysdep/sigcontext.h"
15#include "sysdep/sc.h"
16
17void arch_switch(void)
18{
19 update_debugregs(current->thread.arch.debugregs_seq);
20}
21
22int is_syscall(unsigned long addr)
23{
24 unsigned short instr;
25 int n;
26
27 n = copy_from_user(&instr, (void __user *) addr, sizeof(instr));
28 if(n){
29 printk("is_syscall : failed to read instruction from 0x%lx\n",
30 addr);
31 return(0);
32 }
33 /* int 0x80 or sysenter */
34 return((instr == 0x80cd) || (instr == 0x340f));
35}
36
37/* determines which flags the user has access to. */
38/* 1 = access 0 = no access */
39#define FLAG_MASK 0x00044dd5
40
41int putreg(struct task_struct *child, int regno, unsigned long value)
42{
43 regno >>= 2;
44 switch (regno) {
45 case FS:
46 if (value && (value & 3) != 3)
47 return -EIO;
48 PT_REGS_FS(&child->thread.regs) = value;
49 return 0;
50 case GS:
51 if (value && (value & 3) != 3)
52 return -EIO;
53 PT_REGS_GS(&child->thread.regs) = value;
54 return 0;
55 case DS:
56 case ES:
57 if (value && (value & 3) != 3)
58 return -EIO;
59 value &= 0xffff;
60 break;
61 case SS:
62 case CS:
63 if ((value & 3) != 3)
64 return -EIO;
65 value &= 0xffff;
66 break;
67 case EFL:
68 value &= FLAG_MASK;
69 value |= PT_REGS_EFLAGS(&child->thread.regs);
70 break;
71 }
72 PT_REGS_SET(&child->thread.regs, regno, value);
73 return 0;
74}
75
76unsigned long getreg(struct task_struct *child, int regno)
77{
78 unsigned long retval = ~0UL;
79
80 regno >>= 2;
81 switch (regno) {
82 case FS:
83 case GS:
84 case DS:
85 case ES:
86 case SS:
87 case CS:
88 retval = 0xffff;
89 /* fall through */
90 default:
91 retval &= PT_REG(&child->thread.regs, regno);
92 }
93 return retval;
94}
95
96struct i387_fxsave_struct {
97 unsigned short cwd;
98 unsigned short swd;
99 unsigned short twd;
100 unsigned short fop;
101 long fip;
102 long fcs;
103 long foo;
104 long fos;
105 long mxcsr;
106 long reserved;
107 long st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */
108 long xmm_space[32]; /* 8*16 bytes for each XMM-reg = 128 bytes */
109 long padding[56];
110};
111
112/*
113 * FPU tag word conversions.
114 */
115
116static inline unsigned short twd_i387_to_fxsr( unsigned short twd )
117{
118 unsigned int tmp; /* to avoid 16 bit prefixes in the code */
119
120 /* Transform each pair of bits into 01 (valid) or 00 (empty) */
121 tmp = ~twd;
122 tmp = (tmp | (tmp>>1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */
123 /* and move the valid bits to the lower byte. */
124 tmp = (tmp | (tmp >> 1)) & 0x3333; /* 00VV00VV00VV00VV */
125 tmp = (tmp | (tmp >> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */
126 tmp = (tmp | (tmp >> 4)) & 0x00ff; /* 00000000VVVVVVVV */
127 return tmp;
128}
129
130static inline unsigned long twd_fxsr_to_i387( struct i387_fxsave_struct *fxsave )
131{
132 struct _fpxreg *st = NULL;
133 unsigned long twd = (unsigned long) fxsave->twd;
134 unsigned long tag;
135 unsigned long ret = 0xffff0000;
136 int i;
137
138#define FPREG_ADDR(f, n) ((char *)&(f)->st_space + (n) * 16);
139
140 for ( i = 0 ; i < 8 ; i++ ) {
141 if ( twd & 0x1 ) {
142 st = (struct _fpxreg *) FPREG_ADDR( fxsave, i );
143
144 switch ( st->exponent & 0x7fff ) {
145 case 0x7fff:
146 tag = 2; /* Special */
147 break;
148 case 0x0000:
149 if ( !st->significand[0] &&
150 !st->significand[1] &&
151 !st->significand[2] &&
152 !st->significand[3] ) {
153 tag = 1; /* Zero */
154 } else {
155 tag = 2; /* Special */
156 }
157 break;
158 default:
159 if ( st->significand[3] & 0x8000 ) {
160 tag = 0; /* Valid */
161 } else {
162 tag = 2; /* Special */
163 }
164 break;
165 }
166 } else {
167 tag = 3; /* Empty */
168 }
169 ret |= (tag << (2 * i));
170 twd = twd >> 1;
171 }
172 return ret;
173}
174
175/*
176 * FXSR floating point environment conversions.
177 */
178
179#ifdef CONFIG_MODE_TT
180static inline int convert_fxsr_to_user_tt(struct _fpstate __user *buf,
181 struct pt_regs *regs)
182{
183 struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs));
184 unsigned long env[7];
185 struct _fpreg __user *to;
186 struct _fpxreg *from;
187 int i;
188
189 env[0] = (unsigned long)fxsave->cwd | 0xffff0000;
190 env[1] = (unsigned long)fxsave->swd | 0xffff0000;
191 env[2] = twd_fxsr_to_i387(fxsave);
192 env[3] = fxsave->fip;
193 env[4] = fxsave->fcs | ((unsigned long)fxsave->fop << 16);
194 env[5] = fxsave->foo;
195 env[6] = fxsave->fos;
196
197 if ( __copy_to_user( buf, env, 7 * sizeof(unsigned long) ) )
198 return 1;
199
200 to = &buf->_st[0];
201 from = (struct _fpxreg *) &fxsave->st_space[0];
202 for ( i = 0 ; i < 8 ; i++, to++, from++ ) {
203 if ( __copy_to_user( to, from, sizeof(*to) ) )
204 return 1;
205 }
206 return 0;
207}
208#endif
209
210static inline int convert_fxsr_to_user(struct _fpstate __user *buf,
211 struct pt_regs *regs)
212{
213 return(CHOOSE_MODE(convert_fxsr_to_user_tt(buf, regs), 0));
214}
215
216#ifdef CONFIG_MODE_TT
217static inline int convert_fxsr_from_user_tt(struct pt_regs *regs,
218 struct _fpstate __user *buf)
219{
220 struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs));
221 unsigned long env[7];
222 struct _fpxreg *to;
223 struct _fpreg __user *from;
224 int i;
225
226 if ( __copy_from_user( env, buf, 7 * sizeof(long) ) )
227 return 1;
228
229 fxsave->cwd = (unsigned short)(env[0] & 0xffff);
230 fxsave->swd = (unsigned short)(env[1] & 0xffff);
231 fxsave->twd = twd_i387_to_fxsr((unsigned short)(env[2] & 0xffff));
232 fxsave->fip = env[3];
233 fxsave->fop = (unsigned short)((env[4] & 0xffff0000) >> 16);
234 fxsave->fcs = (env[4] & 0xffff);
235 fxsave->foo = env[5];
236 fxsave->fos = env[6];
237
238 to = (struct _fpxreg *) &fxsave->st_space[0];
239 from = &buf->_st[0];
240 for ( i = 0 ; i < 8 ; i++, to++, from++ ) {
241 if ( __copy_from_user( to, from, sizeof(*from) ) )
242 return 1;
243 }
244 return 0;
245}
246#endif
247
248static inline int convert_fxsr_from_user(struct pt_regs *regs,
249 struct _fpstate __user *buf)
250{
251 return(CHOOSE_MODE(convert_fxsr_from_user_tt(regs, buf), 0));
252}
253
254int get_fpregs(unsigned long buf, struct task_struct *child)
255{
256 int err;
257
258 err = convert_fxsr_to_user((struct _fpstate __user *) buf,
259 &child->thread.regs);
260 if(err) return(-EFAULT);
261 else return(0);
262}
263
264int set_fpregs(unsigned long buf, struct task_struct *child)
265{
266 int err;
267
268 err = convert_fxsr_from_user(&child->thread.regs,
269 (struct _fpstate __user *) buf);
270 if(err) return(-EFAULT);
271 else return(0);
272}
273
274#ifdef CONFIG_MODE_TT
275int get_fpxregs_tt(unsigned long buf, struct task_struct *tsk)
276{
277 struct pt_regs *regs = &tsk->thread.regs;
278 struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs));
279 int err;
280
281 err = __copy_to_user((void __user *) buf, fxsave,
282 sizeof(struct user_fxsr_struct));
283 if(err) return -EFAULT;
284 else return 0;
285}
286#endif
287
288int get_fpxregs(unsigned long buf, struct task_struct *tsk)
289{
290 return(CHOOSE_MODE(get_fpxregs_tt(buf, tsk), 0));
291}
292
293#ifdef CONFIG_MODE_TT
294int set_fpxregs_tt(unsigned long buf, struct task_struct *tsk)
295{
296 struct pt_regs *regs = &tsk->thread.regs;
297 struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs));
298 int err;
299
300 err = __copy_from_user(fxsave, (void __user *) buf,
301 sizeof(struct user_fxsr_struct) );
302 if(err) return -EFAULT;
303 else return 0;
304}
305#endif
306
307int set_fpxregs(unsigned long buf, struct task_struct *tsk)
308{
309 return(CHOOSE_MODE(set_fpxregs_tt(buf, tsk), 0));
310}
311
312#ifdef notdef
313int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
314{
315 fpu->cwd = (((SC_FP_CW(PT_REGS_SC(regs)) & 0xffff) << 16) |
316 (SC_FP_SW(PT_REGS_SC(regs)) & 0xffff));
317 fpu->swd = SC_FP_CSSEL(PT_REGS_SC(regs)) & 0xffff;
318 fpu->twd = SC_FP_IPOFF(PT_REGS_SC(regs));
319 fpu->fip = SC_FP_CSSEL(PT_REGS_SC(regs)) & 0xffff;
320 fpu->fcs = SC_FP_DATAOFF(PT_REGS_SC(regs));
321 fpu->foo = SC_FP_DATASEL(PT_REGS_SC(regs));
322 fpu->fos = 0;
323 memcpy(fpu->st_space, (void *) SC_FP_ST(PT_REGS_SC(regs)),
324 sizeof(fpu->st_space));
325 return(1);
326}
327#endif
328
329#ifdef CONFIG_MODE_TT
330static inline void copy_fpu_fxsave_tt(struct pt_regs *regs,
331 struct user_i387_struct *buf)
332{
333 struct i387_fxsave_struct *fpu = SC_FXSR_ENV(PT_REGS_SC(regs));
334 unsigned short *to;
335 unsigned short *from;
336 int i;
337
338 memcpy( buf, fpu, 7 * sizeof(long) );
339
340 to = (unsigned short *) &buf->st_space[0];
341 from = (unsigned short *) &fpu->st_space[0];
342 for ( i = 0 ; i < 8 ; i++, to += 5, from += 8 ) {
343 memcpy( to, from, 5 * sizeof(unsigned short) );
344 }
345}
346#endif
347
348static inline void copy_fpu_fxsave(struct pt_regs *regs,
349 struct user_i387_struct *buf)
350{
351 (void) CHOOSE_MODE(copy_fpu_fxsave_tt(regs, buf), 0);
352}
353
354int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu )
355{
356 copy_fpu_fxsave(regs, (struct user_i387_struct *) fpu);
357 return(1);
358}
359
360/*
361 * Overrides for Emacs so that we follow Linus's tabbing style.
362 * Emacs will notice this stuff at the end of the file and automatically
363 * adjust the settings for this buffer only. This must remain at the end
364 * of the file.
365 * ---------------------------------------------------------------------------
366 * Local variables:
367 * c-file-style: "linux"
368 * End:
369 */
diff --git a/arch/um/sys-i386/ptrace_user.c b/arch/um/sys-i386/ptrace_user.c
new file mode 100644
index 000000000000..7c376c95de50
--- /dev/null
+++ b/arch/um/sys-i386/ptrace_user.c
@@ -0,0 +1,131 @@
1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stdio.h>
7#include <errno.h>
8#include <unistd.h>
9#include <linux/stddef.h>
10#include "ptrace_user.h"
11/* Grr, asm/user.h includes asm/ptrace.h, so has to follow ptrace_user.h */
12#include <asm/user.h>
13#include "kern_util.h"
14#include "sysdep/thread.h"
15#include "user.h"
16#include "os.h"
17
18int ptrace_getregs(long pid, unsigned long *regs_out)
19{
20 if (ptrace(PTRACE_GETREGS, pid, 0, regs_out) < 0)
21 return -errno;
22 return 0;
23}
24
25int ptrace_setregs(long pid, unsigned long *regs)
26{
27 if (ptrace(PTRACE_SETREGS, pid, 0, regs) < 0)
28 return -errno;
29 return 0;
30}
31
32int ptrace_getfpregs(long pid, unsigned long *regs)
33{
34 if (ptrace(PTRACE_GETFPREGS, pid, 0, regs) < 0)
35 return -errno;
36 return 0;
37}
38
39int ptrace_setfpregs(long pid, unsigned long *regs)
40{
41 if (ptrace(PTRACE_SETFPREGS, pid, 0, regs) < 0)
42 return -errno;
43 return 0;
44}
45
46static void write_debugregs(int pid, unsigned long *regs)
47{
48 struct user *dummy;
49 int nregs, i;
50
51 dummy = NULL;
52 nregs = sizeof(dummy->u_debugreg)/sizeof(dummy->u_debugreg[0]);
53 for(i = 0; i < nregs; i++){
54 if((i == 4) || (i == 5)) continue;
55 if(ptrace(PTRACE_POKEUSR, pid, &dummy->u_debugreg[i],
56 regs[i]) < 0)
57 printk("write_debugregs - ptrace failed on "
58 "register %d, value = 0x%x, errno = %d\n", i,
59 regs[i], errno);
60 }
61}
62
63static void read_debugregs(int pid, unsigned long *regs)
64{
65 struct user *dummy;
66 int nregs, i;
67
68 dummy = NULL;
69 nregs = sizeof(dummy->u_debugreg)/sizeof(dummy->u_debugreg[0]);
70 for(i = 0; i < nregs; i++){
71 regs[i] = ptrace(PTRACE_PEEKUSR, pid,
72 &dummy->u_debugreg[i], 0);
73 }
74}
75
76/* Accessed only by the tracing thread */
77static unsigned long kernel_debugregs[8] = { [ 0 ... 7 ] = 0 };
78static int debugregs_seq = 0;
79
80void arch_enter_kernel(void *task, int pid)
81{
82 read_debugregs(pid, TASK_DEBUGREGS(task));
83 write_debugregs(pid, kernel_debugregs);
84}
85
86void arch_leave_kernel(void *task, int pid)
87{
88 read_debugregs(pid, kernel_debugregs);
89 write_debugregs(pid, TASK_DEBUGREGS(task));
90}
91
92void ptrace_pokeuser(unsigned long addr, unsigned long data)
93{
94 if((addr < offsetof(struct user, u_debugreg[0])) ||
95 (addr > offsetof(struct user, u_debugreg[7])))
96 return;
97 addr -= offsetof(struct user, u_debugreg[0]);
98 addr = addr >> 2;
99 if(kernel_debugregs[addr] == data) return;
100
101 kernel_debugregs[addr] = data;
102 debugregs_seq++;
103}
104
105static void update_debugregs_cb(void *arg)
106{
107 int pid = *((int *) arg);
108
109 write_debugregs(pid, kernel_debugregs);
110}
111
112void update_debugregs(int seq)
113{
114 int me;
115
116 if(seq == debugregs_seq) return;
117
118 me = os_getpid();
119 initial_thread_cb(update_debugregs_cb, &me);
120}
121
122/*
123 * Overrides for Emacs so that we follow Linus's tabbing style.
124 * Emacs will notice this stuff at the end of the file and automatically
125 * adjust the settings for this buffer only. This must remain at the end
126 * of the file.
127 * ---------------------------------------------------------------------------
128 * Local variables:
129 * c-file-style: "linux"
130 * End:
131 */
diff --git a/arch/um/sys-i386/sigcontext.c b/arch/um/sys-i386/sigcontext.c
new file mode 100644
index 000000000000..467d489c31cd
--- /dev/null
+++ b/arch/um/sys-i386/sigcontext.c
@@ -0,0 +1,71 @@
1/*
2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <stddef.h>
7#include <string.h>
8#include <asm/ptrace.h>
9#include <asm/sigcontext.h>
10#include "sysdep/ptrace.h"
11#include "kern_util.h"
12
13void sc_to_sc(void *to_ptr, void *from_ptr)
14{
15 struct sigcontext *to = to_ptr, *from = from_ptr;
16
17 memcpy(to, from, sizeof(*to) + sizeof(struct _fpstate));
18 if(from->fpstate != NULL)
19 to->fpstate = (struct _fpstate *) (to + 1);
20}
21
22unsigned long *sc_sigmask(void *sc_ptr)
23{
24 struct sigcontext *sc = sc_ptr;
25 return &sc->oldmask;
26}
27
28int sc_get_fpregs(unsigned long buf, void *sc_ptr)
29{
30 struct sigcontext *sc = sc_ptr;
31 struct _fpstate *from = sc->fpstate, *to = (struct _fpstate *) buf;
32 int err = 0;
33
34 if(from == NULL){
35 err |= clear_user_proc(&to->cw, sizeof(to->cw));
36 err |= clear_user_proc(&to->sw, sizeof(to->sw));
37 err |= clear_user_proc(&to->tag, sizeof(to->tag));
38 err |= clear_user_proc(&to->ipoff, sizeof(to->ipoff));
39 err |= clear_user_proc(&to->cssel, sizeof(to->cssel));
40 err |= clear_user_proc(&to->dataoff, sizeof(to->dataoff));
41 err |= clear_user_proc(&to->datasel, sizeof(to->datasel));
42 err |= clear_user_proc(&to->_st, sizeof(to->_st));
43 }
44 else {
45 err |= copy_to_user_proc(&to->cw, &from->cw, sizeof(to->cw));
46 err |= copy_to_user_proc(&to->sw, &from->sw, sizeof(to->sw));
47 err |= copy_to_user_proc(&to->tag, &from->tag,
48 sizeof(to->tag));
49 err |= copy_to_user_proc(&to->ipoff, &from->ipoff,
50 sizeof(to->ipoff));
51 err |= copy_to_user_proc(&to->cssel,& from->cssel,
52 sizeof(to->cssel));
53 err |= copy_to_user_proc(&to->dataoff, &from->dataoff,
54 sizeof(to->dataoff));
55 err |= copy_to_user_proc(&to->datasel, &from->datasel,
56 sizeof(to->datasel));
57 err |= copy_to_user_proc(to->_st, from->_st, sizeof(to->_st));
58 }
59 return(err);
60}
61
62/*
63 * Overrides for Emacs so that we follow Linus's tabbing style.
64 * Emacs will notice this stuff at the end of the file and automatically
65 * adjust the settings for this buffer only. This must remain at the end
66 * of the file.
67 * ---------------------------------------------------------------------------
68 * Local variables:
69 * c-file-style: "linux"
70 * End:
71 */
diff --git a/arch/um/sys-i386/signal.c b/arch/um/sys-i386/signal.c
new file mode 100644
index 000000000000..76ba87254b25
--- /dev/null
+++ b/arch/um/sys-i386/signal.c
@@ -0,0 +1,382 @@
1/*
2 * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/signal.h"
7#include "linux/ptrace.h"
8#include "asm/current.h"
9#include "asm/ucontext.h"
10#include "asm/uaccess.h"
11#include "asm/unistd.h"
12#include "frame_kern.h"
13#include "signal_user.h"
14#include "sigcontext.h"
15#include "registers.h"
16#include "mode.h"
17
18#ifdef CONFIG_MODE_SKAS
19
20#include "skas.h"
21
22static int copy_sc_from_user_skas(struct pt_regs *regs,
23 struct sigcontext *from)
24{
25 struct sigcontext sc;
26 unsigned long fpregs[HOST_FP_SIZE];
27 int err;
28
29 err = copy_from_user(&sc, from, sizeof(sc));
30 err |= copy_from_user(fpregs, sc.fpstate, sizeof(fpregs));
31 if(err)
32 return(err);
33
34 REGS_GS(regs->regs.skas.regs) = sc.gs;
35 REGS_FS(regs->regs.skas.regs) = sc.fs;
36 REGS_ES(regs->regs.skas.regs) = sc.es;
37 REGS_DS(regs->regs.skas.regs) = sc.ds;
38 REGS_EDI(regs->regs.skas.regs) = sc.edi;
39 REGS_ESI(regs->regs.skas.regs) = sc.esi;
40 REGS_EBP(regs->regs.skas.regs) = sc.ebp;
41 REGS_SP(regs->regs.skas.regs) = sc.esp;
42 REGS_EBX(regs->regs.skas.regs) = sc.ebx;
43 REGS_EDX(regs->regs.skas.regs) = sc.edx;
44 REGS_ECX(regs->regs.skas.regs) = sc.ecx;
45 REGS_EAX(regs->regs.skas.regs) = sc.eax;
46 REGS_IP(regs->regs.skas.regs) = sc.eip;
47 REGS_CS(regs->regs.skas.regs) = sc.cs;
48 REGS_EFLAGS(regs->regs.skas.regs) = sc.eflags;
49 REGS_SS(regs->regs.skas.regs) = sc.ss;
50 regs->regs.skas.fault_addr = sc.cr2;
51 regs->regs.skas.fault_type = FAULT_WRITE(sc.err);
52 regs->regs.skas.trap_type = sc.trapno;
53
54 err = restore_fp_registers(userspace_pid[0], fpregs);
55 if(err < 0){
56 printk("copy_sc_from_user_skas - PTRACE_SETFPREGS failed, "
57 "errno = %d\n", err);
58 return(1);
59 }
60
61 return(0);
62}
63
64int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp,
65 struct pt_regs *regs, unsigned long fault_addr,
66 int fault_type)
67{
68 struct sigcontext sc;
69 unsigned long fpregs[HOST_FP_SIZE];
70 int err;
71
72 sc.gs = REGS_GS(regs->regs.skas.regs);
73 sc.fs = REGS_FS(regs->regs.skas.regs);
74 sc.es = REGS_ES(regs->regs.skas.regs);
75 sc.ds = REGS_DS(regs->regs.skas.regs);
76 sc.edi = REGS_EDI(regs->regs.skas.regs);
77 sc.esi = REGS_ESI(regs->regs.skas.regs);
78 sc.ebp = REGS_EBP(regs->regs.skas.regs);
79 sc.esp = REGS_SP(regs->regs.skas.regs);
80 sc.ebx = REGS_EBX(regs->regs.skas.regs);
81 sc.edx = REGS_EDX(regs->regs.skas.regs);
82 sc.ecx = REGS_ECX(regs->regs.skas.regs);
83 sc.eax = REGS_EAX(regs->regs.skas.regs);
84 sc.eip = REGS_IP(regs->regs.skas.regs);
85 sc.cs = REGS_CS(regs->regs.skas.regs);
86 sc.eflags = REGS_EFLAGS(regs->regs.skas.regs);
87 sc.esp_at_signal = regs->regs.skas.regs[UESP];
88 sc.ss = regs->regs.skas.regs[SS];
89 sc.cr2 = fault_addr;
90 sc.err = TO_SC_ERR(fault_type);
91 sc.trapno = regs->regs.skas.trap_type;
92
93 err = save_fp_registers(userspace_pid[0], fpregs);
94 if(err < 0){
95 printk("copy_sc_to_user_skas - PTRACE_GETFPREGS failed, "
96 "errno = %d\n", err);
97 return(1);
98 }
99 to_fp = (to_fp ? to_fp : (struct _fpstate *) (to + 1));
100 sc.fpstate = to_fp;
101
102 if(err)
103 return(err);
104
105 return(copy_to_user(to, &sc, sizeof(sc)) ||
106 copy_to_user(to_fp, fpregs, sizeof(fpregs)));
107}
108#endif
109
110#ifdef CONFIG_MODE_TT
111
112/* These copy a sigcontext to/from userspace. They copy the fpstate pointer,
113 * blowing away the old, good one. So, that value is saved, and then restored
114 * after the sigcontext copy. In copy_from, the variable holding the saved
115 * fpstate pointer, and the sigcontext that it should be restored to are both
116 * in the kernel, so we can just restore using an assignment. In copy_to, the
117 * saved pointer is in the kernel, but the sigcontext is in userspace, so we
118 * copy_to_user it.
119 */
120int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from,
121 int fpsize)
122{
123 struct _fpstate *to_fp, *from_fp;
124 unsigned long sigs;
125 int err;
126
127 to_fp = to->fpstate;
128 from_fp = from->fpstate;
129 sigs = to->oldmask;
130 err = copy_from_user(to, from, sizeof(*to));
131 to->oldmask = sigs;
132 to->fpstate = to_fp;
133 if(to_fp != NULL)
134 err |= copy_from_user(to_fp, from_fp, fpsize);
135 return(err);
136}
137
138int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp,
139 struct sigcontext *from, int fpsize)
140{
141 struct _fpstate *to_fp, *from_fp;
142 int err;
143
144 to_fp = (fp ? fp : (struct _fpstate *) (to + 1));
145 from_fp = from->fpstate;
146 err = copy_to_user(to, from, sizeof(*to));
147 if(from_fp != NULL){
148 err |= copy_to_user(&to->fpstate, &to_fp, sizeof(to->fpstate));
149 err |= copy_to_user(to_fp, from_fp, fpsize);
150 }
151 return(err);
152}
153#endif
154
155static int copy_sc_from_user(struct pt_regs *to, void __user *from)
156{
157 int ret;
158
159 ret = CHOOSE_MODE(copy_sc_from_user_tt(UPT_SC(&to->regs), from,
160 sizeof(struct _fpstate)),
161 copy_sc_from_user_skas(to, from));
162 return(ret);
163}
164
165static int copy_sc_to_user(struct sigcontext *to, struct _fpstate *fp,
166 struct pt_regs *from)
167{
168 return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs),
169 sizeof(*fp)),
170 copy_sc_to_user_skas(to, fp, from,
171 current->thread.cr2,
172 current->thread.err)));
173}
174
175static int copy_ucontext_to_user(struct ucontext *uc, struct _fpstate *fp,
176 sigset_t *set, unsigned long sp)
177{
178 int err = 0;
179
180 err |= put_user(current->sas_ss_sp, &uc->uc_stack.ss_sp);
181 err |= put_user(sas_ss_flags(sp), &uc->uc_stack.ss_flags);
182 err |= put_user(current->sas_ss_size, &uc->uc_stack.ss_size);
183 err |= copy_sc_to_user(&uc->uc_mcontext, fp, &current->thread.regs);
184 err |= copy_to_user(&uc->uc_sigmask, set, sizeof(*set));
185 return(err);
186}
187
188struct sigframe
189{
190 char *pretcode;
191 int sig;
192 struct sigcontext sc;
193 struct _fpstate fpstate;
194 unsigned long extramask[_NSIG_WORDS-1];
195 char retcode[8];
196};
197
198struct rt_sigframe
199{
200 char *pretcode;
201 int sig;
202 struct siginfo *pinfo;
203 void *puc;
204 struct siginfo info;
205 struct ucontext uc;
206 struct _fpstate fpstate;
207 char retcode[8];
208};
209
210int setup_signal_stack_sc(unsigned long stack_top, int sig,
211 struct k_sigaction *ka, struct pt_regs *regs,
212 sigset_t *mask)
213{
214 struct sigframe __user *frame;
215 void *restorer;
216 int err = 0;
217
218 stack_top &= -8UL;
219 frame = (struct sigframe *) stack_top - 1;
220 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
221 return 1;
222
223 restorer = (void *) frame->retcode;
224 if(ka->sa.sa_flags & SA_RESTORER)
225 restorer = ka->sa.sa_restorer;
226
227 err |= __put_user(restorer, &frame->pretcode);
228 err |= __put_user(sig, &frame->sig);
229 err |= copy_sc_to_user(&frame->sc, NULL, regs);
230 err |= __put_user(mask->sig[0], &frame->sc.oldmask);
231 if (_NSIG_WORDS > 1)
232 err |= __copy_to_user(&frame->extramask, &mask->sig[1],
233 sizeof(frame->extramask));
234
235 /*
236 * This is popl %eax ; movl $,%eax ; int $0x80
237 *
238 * WE DO NOT USE IT ANY MORE! It's only left here for historical
239 * reasons and because gdb uses it as a signature to notice
240 * signal handler stack frames.
241 */
242 err |= __put_user(0xb858, (short __user *)(frame->retcode+0));
243 err |= __put_user(__NR_sigreturn, (int __user *)(frame->retcode+2));
244 err |= __put_user(0x80cd, (short __user *)(frame->retcode+6));
245
246 if(err)
247 return(err);
248
249 PT_REGS_SP(regs) = (unsigned long) frame;
250 PT_REGS_IP(regs) = (unsigned long) ka->sa.sa_handler;
251 PT_REGS_EAX(regs) = (unsigned long) sig;
252 PT_REGS_EDX(regs) = (unsigned long) 0;
253 PT_REGS_ECX(regs) = (unsigned long) 0;
254
255 if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED))
256 ptrace_notify(SIGTRAP);
257 return(0);
258}
259
260int setup_signal_stack_si(unsigned long stack_top, int sig,
261 struct k_sigaction *ka, struct pt_regs *regs,
262 siginfo_t *info, sigset_t *mask)
263{
264 struct rt_sigframe __user *frame;
265 void *restorer;
266 int err = 0;
267
268 stack_top &= -8UL;
269 frame = (struct rt_sigframe *) stack_top - 1;
270 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
271 return 1;
272
273 restorer = (void *) frame->retcode;
274 if(ka->sa.sa_flags & SA_RESTORER)
275 restorer = ka->sa.sa_restorer;
276
277 err |= __put_user(restorer, &frame->pretcode);
278 err |= __put_user(sig, &frame->sig);
279 err |= __put_user(&frame->info, &frame->pinfo);
280 err |= __put_user(&frame->uc, &frame->puc);
281 err |= copy_siginfo_to_user(&frame->info, info);
282 err |= copy_ucontext_to_user(&frame->uc, &frame->fpstate, mask,
283 PT_REGS_SP(regs));
284
285 /*
286 * This is movl $,%eax ; int $0x80
287 *
288 * WE DO NOT USE IT ANY MORE! It's only left here for historical
289 * reasons and because gdb uses it as a signature to notice
290 * signal handler stack frames.
291 */
292 err |= __put_user(0xb8, (char __user *)(frame->retcode+0));
293 err |= __put_user(__NR_rt_sigreturn, (int __user *)(frame->retcode+1));
294 err |= __put_user(0x80cd, (short __user *)(frame->retcode+5));
295
296 if(err)
297 return(err);
298
299 PT_REGS_SP(regs) = (unsigned long) frame;
300 PT_REGS_IP(regs) = (unsigned long) ka->sa.sa_handler;
301 PT_REGS_EAX(regs) = (unsigned long) sig;
302 PT_REGS_EDX(regs) = (unsigned long) &frame->info;
303 PT_REGS_ECX(regs) = (unsigned long) &frame->uc;
304
305 if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED))
306 ptrace_notify(SIGTRAP);
307 return(0);
308}
309
310long sys_sigreturn(struct pt_regs regs)
311{
312 unsigned long sp = PT_REGS_SP(&current->thread.regs);
313 struct sigframe __user *frame = (struct sigframe *)(sp - 8);
314 sigset_t set;
315 struct sigcontext __user *sc = &frame->sc;
316 unsigned long __user *oldmask = &sc->oldmask;
317 unsigned long __user *extramask = frame->extramask;
318 int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long);
319
320 if(copy_from_user(&set.sig[0], oldmask, sizeof(&set.sig[0])) ||
321 copy_from_user(&set.sig[1], extramask, sig_size))
322 goto segfault;
323
324 sigdelsetmask(&set, ~_BLOCKABLE);
325
326 spin_lock_irq(&current->sighand->siglock);
327 current->blocked = set;
328 recalc_sigpending();
329 spin_unlock_irq(&current->sighand->siglock);
330
331 if(copy_sc_from_user(&current->thread.regs, sc))
332 goto segfault;
333
334 /* Avoid ERESTART handling */
335 PT_REGS_SYSCALL_NR(&current->thread.regs) = -1;
336 return(PT_REGS_SYSCALL_RET(&current->thread.regs));
337
338 segfault:
339 force_sig(SIGSEGV, current);
340 return 0;
341}
342
343long sys_rt_sigreturn(struct pt_regs regs)
344{
345 unsigned long __user sp = PT_REGS_SP(&current->thread.regs);
346 struct rt_sigframe __user *frame = (struct rt_sigframe *) (sp - 4);
347 sigset_t set;
348 struct ucontext __user *uc = &frame->uc;
349 int sig_size = _NSIG_WORDS * sizeof(unsigned long);
350
351 if(copy_from_user(&set, &uc->uc_sigmask, sig_size))
352 goto segfault;
353
354 sigdelsetmask(&set, ~_BLOCKABLE);
355
356 spin_lock_irq(&current->sighand->siglock);
357 current->blocked = set;
358 recalc_sigpending();
359 spin_unlock_irq(&current->sighand->siglock);
360
361 if(copy_sc_from_user(&current->thread.regs, &uc->uc_mcontext))
362 goto segfault;
363
364 /* Avoid ERESTART handling */
365 PT_REGS_SYSCALL_NR(&current->thread.regs) = -1;
366 return(PT_REGS_SYSCALL_RET(&current->thread.regs));
367
368 segfault:
369 force_sig(SIGSEGV, current);
370 return 0;
371}
372
373/*
374 * Overrides for Emacs so that we follow Linus's tabbing style.
375 * Emacs will notice this stuff at the end of the file and automatically
376 * adjust the settings for this buffer only. This must remain at the end
377 * of the file.
378 * ---------------------------------------------------------------------------
379 * Local variables:
380 * c-file-style: "linux"
381 * End:
382 */
diff --git a/arch/um/sys-i386/syscalls.c b/arch/um/sys-i386/syscalls.c
new file mode 100644
index 000000000000..335e2d89504d
--- /dev/null
+++ b/arch/um/sys-i386/syscalls.c
@@ -0,0 +1,210 @@
1/*
2 * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/sched.h"
7#include "linux/shm.h"
8#include "asm/ipc.h"
9#include "asm/mman.h"
10#include "asm/uaccess.h"
11#include "asm/unistd.h"
12
13/*
14 * Perform the select(nd, in, out, ex, tv) and mmap() system
15 * calls. Linux/i386 didn't use to be able to handle more than
16 * 4 system call parameters, so these system calls used a memory
17 * block for parameter passing..
18 */
19
20struct mmap_arg_struct {
21 unsigned long addr;
22 unsigned long len;
23 unsigned long prot;
24 unsigned long flags;
25 unsigned long fd;
26 unsigned long offset;
27};
28
29extern int old_mmap(unsigned long addr, unsigned long len,
30 unsigned long prot, unsigned long flags,
31 unsigned long fd, unsigned long offset);
32
33long old_mmap_i386(struct mmap_arg_struct __user *arg)
34{
35 struct mmap_arg_struct a;
36 int err = -EFAULT;
37
38 if (copy_from_user(&a, arg, sizeof(a)))
39 goto out;
40
41 err = old_mmap(a.addr, a.len, a.prot, a.flags, a.fd, a.offset);
42 out:
43 return err;
44}
45
46struct sel_arg_struct {
47 unsigned long n;
48 fd_set __user *inp;
49 fd_set __user *outp;
50 fd_set __user *exp;
51 struct timeval __user *tvp;
52};
53
54long old_select(struct sel_arg_struct __user *arg)
55{
56 struct sel_arg_struct a;
57
58 if (copy_from_user(&a, arg, sizeof(a)))
59 return -EFAULT;
60 /* sys_select() does the appropriate kernel locking */
61 return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
62}
63
64/* The i386 version skips reading from %esi, the fourth argument. So we must do
65 * this, too.
66 */
67long sys_clone(unsigned long clone_flags, unsigned long newsp,
68 int __user *parent_tid, int unused, int __user *child_tid)
69{
70 long ret;
71
72 /* XXX: normal arch do here this pass, and also pass the regs to
73 * do_fork, instead of NULL. Currently the arch-independent code
74 * ignores these values, while the UML code (actually it's
75 * copy_thread) does the right thing. But this should change,
76 probably. */
77 /*if (!newsp)
78 newsp = UPT_SP(current->thread.regs);*/
79 current->thread.forking = 1;
80 ret = do_fork(clone_flags, newsp, NULL, 0, parent_tid, child_tid);
81 current->thread.forking = 0;
82 return(ret);
83}
84
85/*
86 * sys_ipc() is the de-multiplexer for the SysV IPC calls..
87 *
88 * This is really horribly ugly.
89 */
90long sys_ipc (uint call, int first, int second,
91 int third, void __user *ptr, long fifth)
92{
93 int version, ret;
94
95 version = call >> 16; /* hack for backward compatibility */
96 call &= 0xffff;
97
98 switch (call) {
99 case SEMOP:
100 return sys_semtimedop(first, (struct sembuf *) ptr, second,
101 NULL);
102 case SEMTIMEDOP:
103 return sys_semtimedop(first, (struct sembuf *) ptr, second,
104 (const struct timespec *) fifth);
105 case SEMGET:
106 return sys_semget (first, second, third);
107 case SEMCTL: {
108 union semun fourth;
109 if (!ptr)
110 return -EINVAL;
111 if (get_user(fourth.__pad, (void **) ptr))
112 return -EFAULT;
113 return sys_semctl (first, second, third, fourth);
114 }
115
116 case MSGSND:
117 return sys_msgsnd (first, (struct msgbuf *) ptr,
118 second, third);
119 case MSGRCV:
120 switch (version) {
121 case 0: {
122 struct ipc_kludge tmp;
123 if (!ptr)
124 return -EINVAL;
125
126 if (copy_from_user(&tmp,
127 (struct ipc_kludge *) ptr,
128 sizeof (tmp)))
129 return -EFAULT;
130 return sys_msgrcv (first, tmp.msgp, second,
131 tmp.msgtyp, third);
132 }
133 default:
134 panic("msgrcv with version != 0");
135 return sys_msgrcv (first,
136 (struct msgbuf *) ptr,
137 second, fifth, third);
138 }
139 case MSGGET:
140 return sys_msgget ((key_t) first, second);
141 case MSGCTL:
142 return sys_msgctl (first, second, (struct msqid_ds *) ptr);
143
144 case SHMAT:
145 switch (version) {
146 default: {
147 ulong raddr;
148 ret = do_shmat (first, (char *) ptr, second, &raddr);
149 if (ret)
150 return ret;
151 return put_user (raddr, (ulong *) third);
152 }
153 case 1: /* iBCS2 emulator entry point */
154 if (!segment_eq(get_fs(), get_ds()))
155 return -EINVAL;
156 return do_shmat (first, (char *) ptr, second, (ulong *) third);
157 }
158 case SHMDT:
159 return sys_shmdt ((char *)ptr);
160 case SHMGET:
161 return sys_shmget (first, second, third);
162 case SHMCTL:
163 return sys_shmctl (first, second,
164 (struct shmid_ds *) ptr);
165 default:
166 return -ENOSYS;
167 }
168}
169
170long sys_sigaction(int sig, const struct old_sigaction __user *act,
171 struct old_sigaction __user *oact)
172{
173 struct k_sigaction new_ka, old_ka;
174 int ret;
175
176 if (act) {
177 old_sigset_t mask;
178 if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
179 __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
180 __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
181 return -EFAULT;
182 __get_user(new_ka.sa.sa_flags, &act->sa_flags);
183 __get_user(mask, &act->sa_mask);
184 siginitset(&new_ka.sa.sa_mask, mask);
185 }
186
187 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
188
189 if (!ret && oact) {
190 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
191 __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
192 __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
193 return -EFAULT;
194 __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
195 __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
196 }
197
198 return ret;
199}
200
201/*
202 * Overrides for Emacs so that we follow Linus's tabbing style.
203 * Emacs will notice this stuff at the end of the file and automatically
204 * adjust the settings for this buffer only. This must remain at the end
205 * of the file.
206 * ---------------------------------------------------------------------------
207 * Local variables:
208 * c-file-style: "linux"
209 * End:
210 */
diff --git a/arch/um/sys-i386/sysrq.c b/arch/um/sys-i386/sysrq.c
new file mode 100644
index 000000000000..281fc7b8ca00
--- /dev/null
+++ b/arch/um/sys-i386/sysrq.c
@@ -0,0 +1,35 @@
1/*
2 * Copyright (C) 2001 - 2003 Jeff Dike (jdike@addtoit.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/kernel.h"
7#include "linux/smp.h"
8#include "linux/sched.h"
9#include "asm/ptrace.h"
10#include "sysrq.h"
11
12void show_regs(struct pt_regs *regs)
13{
14 printk("\n");
15 printk("EIP: %04lx:[<%08lx>] CPU: %d %s",
16 0xffff & PT_REGS_CS(regs), PT_REGS_IP(regs),
17 smp_processor_id(), print_tainted());
18 if (PT_REGS_CS(regs) & 3)
19 printk(" ESP: %04lx:%08lx", 0xffff & PT_REGS_SS(regs),
20 PT_REGS_SP(regs));
21 printk(" EFLAGS: %08lx\n %s\n", PT_REGS_EFLAGS(regs),
22 print_tainted());
23 printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n",
24 PT_REGS_EAX(regs), PT_REGS_EBX(regs),
25 PT_REGS_ECX(regs),
26 PT_REGS_EDX(regs));
27 printk("ESI: %08lx EDI: %08lx EBP: %08lx",
28 PT_REGS_ESI(regs), PT_REGS_EDI(regs),
29 PT_REGS_EBP(regs));
30 printk(" DS: %04lx ES: %04lx\n",
31 0xffff & PT_REGS_DS(regs),
32 0xffff & PT_REGS_ES(regs));
33
34 show_trace((unsigned long *) &regs);
35}
diff --git a/arch/um/sys-i386/util/Makefile b/arch/um/sys-i386/util/Makefile
new file mode 100644
index 000000000000..34860f9ca7b0
--- /dev/null
+++ b/arch/um/sys-i386/util/Makefile
@@ -0,0 +1,8 @@
1
2hostprogs-y := mk_sc mk_thread
3always := $(hostprogs-y)
4
5mk_thread-objs := mk_thread_kern.o mk_thread_user.o
6
7HOSTCFLAGS_mk_thread_kern.o := $(CFLAGS) $(CPPFLAGS)
8HOSTCFLAGS_mk_thread_user.o := $(USER_CFLAGS)
diff --git a/arch/um/sys-i386/util/mk_sc.c b/arch/um/sys-i386/util/mk_sc.c
new file mode 100644
index 000000000000..85cbd30396f7
--- /dev/null
+++ b/arch/um/sys-i386/util/mk_sc.c
@@ -0,0 +1,52 @@
1#include <stdio.h>
2#include <signal.h>
3#include <linux/stddef.h>
4
5#define SC_OFFSET(name, field) \
6 printf("#define " name "(sc) *((unsigned long *) &(((char *) (sc))[%d]))\n",\
7 offsetof(struct sigcontext, field))
8
9#define SC_FP_OFFSET(name, field) \
10 printf("#define " name \
11 "(sc) *((unsigned long *) &(((char *) (SC_FPSTATE(sc)))[%d]))\n",\
12 offsetof(struct _fpstate, field))
13
14#define SC_FP_OFFSET_PTR(name, field, type) \
15 printf("#define " name \
16 "(sc) ((" type " *) &(((char *) (SC_FPSTATE(sc)))[%d]))\n",\
17 offsetof(struct _fpstate, field))
18
19int main(int argc, char **argv)
20{
21 SC_OFFSET("SC_IP", eip);
22 SC_OFFSET("SC_SP", esp);
23 SC_OFFSET("SC_FS", fs);
24 SC_OFFSET("SC_GS", gs);
25 SC_OFFSET("SC_DS", ds);
26 SC_OFFSET("SC_ES", es);
27 SC_OFFSET("SC_SS", ss);
28 SC_OFFSET("SC_CS", cs);
29 SC_OFFSET("SC_EFLAGS", eflags);
30 SC_OFFSET("SC_EAX", eax);
31 SC_OFFSET("SC_EBX", ebx);
32 SC_OFFSET("SC_ECX", ecx);
33 SC_OFFSET("SC_EDX", edx);
34 SC_OFFSET("SC_EDI", edi);
35 SC_OFFSET("SC_ESI", esi);
36 SC_OFFSET("SC_EBP", ebp);
37 SC_OFFSET("SC_TRAPNO", trapno);
38 SC_OFFSET("SC_ERR", err);
39 SC_OFFSET("SC_CR2", cr2);
40 SC_OFFSET("SC_FPSTATE", fpstate);
41 SC_OFFSET("SC_SIGMASK", oldmask);
42 SC_FP_OFFSET("SC_FP_CW", cw);
43 SC_FP_OFFSET("SC_FP_SW", sw);
44 SC_FP_OFFSET("SC_FP_TAG", tag);
45 SC_FP_OFFSET("SC_FP_IPOFF", ipoff);
46 SC_FP_OFFSET("SC_FP_CSSEL", cssel);
47 SC_FP_OFFSET("SC_FP_DATAOFF", dataoff);
48 SC_FP_OFFSET("SC_FP_DATASEL", datasel);
49 SC_FP_OFFSET_PTR("SC_FP_ST", _st, "struct _fpstate");
50 SC_FP_OFFSET_PTR("SC_FXSR_ENV", _fxsr_env, "void");
51 return(0);
52}
diff --git a/arch/um/sys-i386/util/mk_thread_kern.c b/arch/um/sys-i386/util/mk_thread_kern.c
new file mode 100644
index 000000000000..948b1ce85230
--- /dev/null
+++ b/arch/um/sys-i386/util/mk_thread_kern.c
@@ -0,0 +1,22 @@
1#include "linux/config.h"
2#include "linux/stddef.h"
3#include "linux/sched.h"
4
5extern void print_head(void);
6extern void print_constant_ptr(char *name, int value);
7extern void print_constant(char *name, char *type, int value);
8extern void print_tail(void);
9
10#define THREAD_OFFSET(field) offsetof(struct task_struct, thread.field)
11
12int main(int argc, char **argv)
13{
14 print_head();
15 print_constant_ptr("TASK_DEBUGREGS", THREAD_OFFSET(arch.debugregs));
16#ifdef CONFIG_MODE_TT
17 print_constant("TASK_EXTERN_PID", "int", THREAD_OFFSET(mode.tt.extern_pid));
18#endif
19 print_tail();
20 return(0);
21}
22
diff --git a/arch/um/sys-i386/util/mk_thread_user.c b/arch/um/sys-i386/util/mk_thread_user.c
new file mode 100644
index 000000000000..2620cd6aa1f1
--- /dev/null
+++ b/arch/um/sys-i386/util/mk_thread_user.c
@@ -0,0 +1,30 @@
1#include <stdio.h>
2
3void print_head(void)
4{
5 printf("/*\n");
6 printf(" * Generated by mk_thread\n");
7 printf(" */\n");
8 printf("\n");
9 printf("#ifndef __UM_THREAD_H\n");
10 printf("#define __UM_THREAD_H\n");
11 printf("\n");
12}
13
14void print_constant_ptr(char *name, int value)
15{
16 printf("#define %s(task) ((unsigned long *) "
17 "&(((char *) (task))[%d]))\n", name, value);
18}
19
20void print_constant(char *name, char *type, int value)
21{
22 printf("#define %s(task) *((%s *) &(((char *) (task))[%d]))\n", name, type,
23 value);
24}
25
26void print_tail(void)
27{
28 printf("\n");
29 printf("#endif\n");
30}