diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /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/Makefile | 29 | ||||
-rw-r--r-- | arch/um/sys-i386/bugs.c | 222 | ||||
-rw-r--r-- | arch/um/sys-i386/checksum.S | 460 | ||||
-rw-r--r-- | arch/um/sys-i386/delay.c | 14 | ||||
-rw-r--r-- | arch/um/sys-i386/fault.c | 42 | ||||
-rw-r--r-- | arch/um/sys-i386/ksyms.c | 17 | ||||
-rw-r--r-- | arch/um/sys-i386/ldt.c | 98 | ||||
-rw-r--r-- | arch/um/sys-i386/ptrace.c | 369 | ||||
-rw-r--r-- | arch/um/sys-i386/ptrace_user.c | 131 | ||||
-rw-r--r-- | arch/um/sys-i386/sigcontext.c | 71 | ||||
-rw-r--r-- | arch/um/sys-i386/signal.c | 382 | ||||
-rw-r--r-- | arch/um/sys-i386/syscalls.c | 210 | ||||
-rw-r--r-- | arch/um/sys-i386/sysrq.c | 35 | ||||
-rw-r--r-- | arch/um/sys-i386/util/Makefile | 8 | ||||
-rw-r--r-- | arch/um/sys-i386/util/mk_sc.c | 52 | ||||
-rw-r--r-- | arch/um/sys-i386/util/mk_thread_kern.c | 22 | ||||
-rw-r--r-- | arch/um/sys-i386/util/mk_thread_user.c | 30 |
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 @@ | |||
1 | obj-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 | |||
4 | obj-$(CONFIG_HIGHMEM) += highmem.o | ||
5 | obj-$(CONFIG_MODULES) += module.o | ||
6 | |||
7 | USER_OBJS := bugs.o ptrace_user.o sigcontext.o fault.o | ||
8 | |||
9 | include arch/um/scripts/Makefile.rules | ||
10 | |||
11 | SYMLINKS = 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. | ||
15 | clean-files := $(SYMLINKS) | ||
16 | |||
17 | targets += $(SYMLINKS) | ||
18 | |||
19 | SYMLINKS := $(foreach f,$(SYMLINKS),$(obj)/$f) | ||
20 | |||
21 | bitops.c-dir = lib | ||
22 | semaphore.c-dir = kernel | ||
23 | highmem.c-dir = mm | ||
24 | module.c-dir = kernel | ||
25 | |||
26 | $(SYMLINKS): FORCE | ||
27 | $(call if_changed,make_link) | ||
28 | |||
29 | subdir- := 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 */ | ||
20 | int host_has_cmov = 1; | ||
21 | int host_has_xmm = 0; | ||
22 | |||
23 | static 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 | |||
51 | static 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 | |||
81 | int 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 | |||
104 | static 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 | */ | ||
147 | static 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 | |||
162 | void arch_init_thread(void) | ||
163 | { | ||
164 | #if 0 | ||
165 | disable_lcall(); | ||
166 | #endif | ||
167 | } | ||
168 | |||
169 | void 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 | |||
184 | int 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 | /* | ||
36 | unsigned 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 | */ | ||
52 | arch_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 | ||
64 | 1: movw (%esi), %bx | ||
65 | addl $2, %esi | ||
66 | addw %bx, %ax | ||
67 | adcl $0, %eax | ||
68 | 2: | ||
69 | movl %ecx, %edx | ||
70 | shrl $5, %ecx | ||
71 | jz 2f | ||
72 | testl %esi, %esi | ||
73 | 1: 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 | ||
93 | 2: movl %edx, %ecx | ||
94 | andl $0x1c, %edx | ||
95 | je 4f | ||
96 | shrl $2, %edx # This clears CF | ||
97 | 3: adcl (%esi), %eax | ||
98 | lea 4(%esi), %esi | ||
99 | dec %edx | ||
100 | jne 3b | ||
101 | adcl $0, %eax | ||
102 | 4: 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 | ||
110 | 5: movb (%esi),%cl | ||
111 | 6: addl %ecx,%eax | ||
112 | adcl $0, %eax | ||
113 | 7: | ||
114 | popl %ebx | ||
115 | popl %esi | ||
116 | ret | ||
117 | |||
118 | #else | ||
119 | |||
120 | /* Version for PentiumII/PPro */ | ||
121 | |||
122 | arch_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 | ||
131 | 10: | ||
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 | ||
144 | 20: addw (%esi), %ax | ||
145 | lea 2(%esi), %esi | ||
146 | adcl $0, %eax | ||
147 | jmp 10b | ||
148 | |||
149 | 30: 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 | ||
156 | 32: | ||
157 | addw (%esi), %ax # csumming 2 bytes, 2-aligned | ||
158 | adcl $0, %eax | ||
159 | jmp 80f | ||
160 | |||
161 | 40: | ||
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 | ||
194 | 45: | ||
195 | lea 128(%esi), %esi | ||
196 | adcl $0, %eax | ||
197 | dec %ecx | ||
198 | jge 40b | ||
199 | movl %edx, %ecx | ||
200 | 50: 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 | ||
211 | 80: | ||
212 | popl %ebx | ||
213 | popl %esi | ||
214 | ret | ||
215 | |||
216 | #endif | ||
217 | |||
218 | /* | ||
219 | unsigned 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 | |||
254 | csum_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 | ||
270 | SRC(1: movw (%esi), %bx ) | ||
271 | addl $2, %esi | ||
272 | DST( movw %bx, (%edi) ) | ||
273 | addl $2, %edi | ||
274 | addw %bx, %ax | ||
275 | adcl $0, %eax | ||
276 | 2: | ||
277 | movl %ecx, FP(%esp) | ||
278 | shrl $5, %ecx | ||
279 | jz 2f | ||
280 | testl %esi, %esi | ||
281 | SRC(1: movl (%esi), %ebx ) | ||
282 | SRC( movl 4(%esi), %edx ) | ||
283 | adcl %ebx, %eax | ||
284 | DST( movl %ebx, (%edi) ) | ||
285 | adcl %edx, %eax | ||
286 | DST( movl %edx, 4(%edi) ) | ||
287 | |||
288 | SRC( movl 8(%esi), %ebx ) | ||
289 | SRC( movl 12(%esi), %edx ) | ||
290 | adcl %ebx, %eax | ||
291 | DST( movl %ebx, 8(%edi) ) | ||
292 | adcl %edx, %eax | ||
293 | DST( movl %edx, 12(%edi) ) | ||
294 | |||
295 | SRC( movl 16(%esi), %ebx ) | ||
296 | SRC( movl 20(%esi), %edx ) | ||
297 | adcl %ebx, %eax | ||
298 | DST( movl %ebx, 16(%edi) ) | ||
299 | adcl %edx, %eax | ||
300 | DST( movl %edx, 20(%edi) ) | ||
301 | |||
302 | SRC( movl 24(%esi), %ebx ) | ||
303 | SRC( movl 28(%esi), %edx ) | ||
304 | adcl %ebx, %eax | ||
305 | DST( movl %ebx, 24(%edi) ) | ||
306 | adcl %edx, %eax | ||
307 | DST( 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 | ||
314 | 2: movl FP(%esp), %edx | ||
315 | movl %edx, %ecx | ||
316 | andl $0x1c, %edx | ||
317 | je 4f | ||
318 | shrl $2, %edx # This clears CF | ||
319 | SRC(3: movl (%esi), %ebx ) | ||
320 | adcl %ebx, %eax | ||
321 | DST( movl %ebx, (%edi) ) | ||
322 | lea 4(%esi), %esi | ||
323 | lea 4(%edi), %edi | ||
324 | dec %edx | ||
325 | jne 3b | ||
326 | adcl $0, %eax | ||
327 | 4: andl $3, %ecx | ||
328 | jz 7f | ||
329 | cmpl $2, %ecx | ||
330 | jb 5f | ||
331 | SRC( movw (%esi), %cx ) | ||
332 | leal 2(%esi), %esi | ||
333 | DST( movw %cx, (%edi) ) | ||
334 | leal 2(%edi), %edi | ||
335 | je 6f | ||
336 | shll $16,%ecx | ||
337 | SRC(5: movb (%esi), %cl ) | ||
338 | DST( movb %cl, (%edi) ) | ||
339 | 6: addl %ecx, %eax | ||
340 | adcl $0, %eax | ||
341 | 7: | ||
342 | 5000: | ||
343 | |||
344 | # Exception handler: | ||
345 | .section .fixup, "ax" | ||
346 | |||
347 | 6001: | ||
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 | |||
360 | 6002: | ||
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 | |||
389 | csum_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 | ||
410 | 1: 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) | ||
417 | 3: adcl $0,%eax | ||
418 | addl $64, %edx | ||
419 | dec %ecx | ||
420 | jge 1b | ||
421 | 4: movl ARGBASE+12(%esp),%edx #len | ||
422 | andl $3, %edx | ||
423 | jz 7f | ||
424 | cmpl $2, %edx | ||
425 | jb 5f | ||
426 | SRC( movw (%esi), %dx ) | ||
427 | leal 2(%esi), %esi | ||
428 | DST( movw %dx, (%edi) ) | ||
429 | leal 2(%edi), %edi | ||
430 | je 6f | ||
431 | shll $16,%edx | ||
432 | 5: | ||
433 | SRC( movb (%esi), %dl ) | ||
434 | DST( movb %dl, (%edi) ) | ||
435 | 6: addl %edx, %eax | ||
436 | adcl $0, %eax | ||
437 | 7: | ||
438 | .section .fixup, "ax" | ||
439 | 6001: 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 | ||
447 | 6002: 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 @@ | |||
1 | void __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. */ | ||
11 | struct exception_table_entry | ||
12 | { | ||
13 | unsigned long insn; | ||
14 | unsigned long fixup; | ||
15 | }; | ||
16 | |||
17 | const struct exception_table_entry *search_exception_tables(unsigned long add); | ||
18 | |||
19 | /* Compare this to arch/i386/mm/extable.c:fixup_exception() */ | ||
20 | int 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 | |||
10 | EXPORT_SYMBOL(__down_failed); | ||
11 | EXPORT_SYMBOL(__down_failed_interruptible); | ||
12 | EXPORT_SYMBOL(__down_failed_trylock); | ||
13 | EXPORT_SYMBOL(__up_wakeup); | ||
14 | |||
15 | /* Networking helper routines. */ | ||
16 | EXPORT_SYMBOL(csum_partial_copy_from); | ||
17 | EXPORT_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 | ||
14 | extern int modify_ldt(int func, void *ptr, unsigned long bytecount); | ||
15 | |||
16 | /* XXX this needs copy_to_user and copy_from_user */ | ||
17 | |||
18 | int 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 | ||
28 | extern int userspace_pid; | ||
29 | |||
30 | #include "skas_ptrace.h" | ||
31 | |||
32 | int 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 | |||
81 | int 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 | |||
17 | void arch_switch(void) | ||
18 | { | ||
19 | update_debugregs(current->thread.arch.debugregs_seq); | ||
20 | } | ||
21 | |||
22 | int 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 | |||
41 | int 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 | |||
76 | unsigned 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 | |||
96 | struct 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 | |||
116 | static 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 | |||
130 | static 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 | ||
180 | static 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 | |||
210 | static 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 | ||
217 | static 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 | |||
248 | static 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 | |||
254 | int 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 | |||
264 | int 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 | ||
275 | int 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 | |||
288 | int 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 | ||
294 | int 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 | |||
307 | int 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 | ||
313 | int 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 | ||
330 | static 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 | |||
348 | static 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 | |||
354 | int 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 | |||
18 | int 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 | |||
25 | int 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 | |||
32 | int 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 | |||
39 | int 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 | |||
46 | static 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 | |||
63 | static 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 */ | ||
77 | static unsigned long kernel_debugregs[8] = { [ 0 ... 7 ] = 0 }; | ||
78 | static int debugregs_seq = 0; | ||
79 | |||
80 | void arch_enter_kernel(void *task, int pid) | ||
81 | { | ||
82 | read_debugregs(pid, TASK_DEBUGREGS(task)); | ||
83 | write_debugregs(pid, kernel_debugregs); | ||
84 | } | ||
85 | |||
86 | void arch_leave_kernel(void *task, int pid) | ||
87 | { | ||
88 | read_debugregs(pid, kernel_debugregs); | ||
89 | write_debugregs(pid, TASK_DEBUGREGS(task)); | ||
90 | } | ||
91 | |||
92 | void 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 | |||
105 | static void update_debugregs_cb(void *arg) | ||
106 | { | ||
107 | int pid = *((int *) arg); | ||
108 | |||
109 | write_debugregs(pid, kernel_debugregs); | ||
110 | } | ||
111 | |||
112 | void 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 | |||
13 | void 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 | |||
22 | unsigned long *sc_sigmask(void *sc_ptr) | ||
23 | { | ||
24 | struct sigcontext *sc = sc_ptr; | ||
25 | return &sc->oldmask; | ||
26 | } | ||
27 | |||
28 | int 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 | |||
22 | static 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 | |||
64 | int 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 | */ | ||
120 | int 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 | |||
138 | int 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 | |||
155 | static 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 | |||
165 | static 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 | |||
175 | static 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, ¤t->thread.regs); | ||
184 | err |= copy_to_user(&uc->uc_sigmask, set, sizeof(*set)); | ||
185 | return(err); | ||
186 | } | ||
187 | |||
188 | struct 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 | |||
198 | struct 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 | |||
210 | int 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 | |||
260 | int 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 | |||
310 | long sys_sigreturn(struct pt_regs regs) | ||
311 | { | ||
312 | unsigned long sp = PT_REGS_SP(¤t->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(¤t->sighand->siglock); | ||
327 | current->blocked = set; | ||
328 | recalc_sigpending(); | ||
329 | spin_unlock_irq(¤t->sighand->siglock); | ||
330 | |||
331 | if(copy_sc_from_user(¤t->thread.regs, sc)) | ||
332 | goto segfault; | ||
333 | |||
334 | /* Avoid ERESTART handling */ | ||
335 | PT_REGS_SYSCALL_NR(¤t->thread.regs) = -1; | ||
336 | return(PT_REGS_SYSCALL_RET(¤t->thread.regs)); | ||
337 | |||
338 | segfault: | ||
339 | force_sig(SIGSEGV, current); | ||
340 | return 0; | ||
341 | } | ||
342 | |||
343 | long sys_rt_sigreturn(struct pt_regs regs) | ||
344 | { | ||
345 | unsigned long __user sp = PT_REGS_SP(¤t->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(¤t->sighand->siglock); | ||
357 | current->blocked = set; | ||
358 | recalc_sigpending(); | ||
359 | spin_unlock_irq(¤t->sighand->siglock); | ||
360 | |||
361 | if(copy_sc_from_user(¤t->thread.regs, &uc->uc_mcontext)) | ||
362 | goto segfault; | ||
363 | |||
364 | /* Avoid ERESTART handling */ | ||
365 | PT_REGS_SYSCALL_NR(¤t->thread.regs) = -1; | ||
366 | return(PT_REGS_SYSCALL_RET(¤t->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 | |||
20 | struct 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 | |||
29 | extern int old_mmap(unsigned long addr, unsigned long len, | ||
30 | unsigned long prot, unsigned long flags, | ||
31 | unsigned long fd, unsigned long offset); | ||
32 | |||
33 | long 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 | |||
46 | struct 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 | |||
54 | long 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 | */ | ||
67 | long 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 | */ | ||
90 | long 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 | |||
170 | long 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 | |||
12 | void 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 *) ®s); | ||
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 | |||
2 | hostprogs-y := mk_sc mk_thread | ||
3 | always := $(hostprogs-y) | ||
4 | |||
5 | mk_thread-objs := mk_thread_kern.o mk_thread_user.o | ||
6 | |||
7 | HOSTCFLAGS_mk_thread_kern.o := $(CFLAGS) $(CPPFLAGS) | ||
8 | HOSTCFLAGS_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 | |||
19 | int 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 | |||
5 | extern void print_head(void); | ||
6 | extern void print_constant_ptr(char *name, int value); | ||
7 | extern void print_constant(char *name, char *type, int value); | ||
8 | extern void print_tail(void); | ||
9 | |||
10 | #define THREAD_OFFSET(field) offsetof(struct task_struct, thread.field) | ||
11 | |||
12 | int 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 | |||
3 | void 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 | |||
14 | void print_constant_ptr(char *name, int value) | ||
15 | { | ||
16 | printf("#define %s(task) ((unsigned long *) " | ||
17 | "&(((char *) (task))[%d]))\n", name, value); | ||
18 | } | ||
19 | |||
20 | void 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 | |||
26 | void print_tail(void) | ||
27 | { | ||
28 | printf("\n"); | ||
29 | printf("#endif\n"); | ||
30 | } | ||