diff options
author | Bodo Stroesser <bstroesser@fujitsu-siemens.com> | 2005-05-05 19:15:31 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-05-05 19:36:36 -0400 |
commit | c578455a3eccf4dd7bd111e77129c301d6d67914 (patch) | |
tree | b52def020bd10e1b8bffcf90e1e2a3c1b35010c8 | |
parent | ea66e8a3b6c4760e8fbf59b1becb6bd8e3dd5376 (diff) |
[PATCH] uml: S390 preparation, abstract host page fault data
This patch removes the arch-specific fault/trap-infos from thread and
skas-regs.
It adds a new struct faultinfo, that is arch-specific defined in
sysdep/faultinfo.h.
The structure is inserted in thread.arch and thread.regs.skas and
thread.regs.tt
Now, segv and other trap-handlers can copy the contents from regs.X.faultinfo
to thread.arch.faultinfo with one simple assignment.
Also, the number of macros necessary is reduced to
FAULT_ADDRESS(struct faultinfo)
extracts the faulting address from faultinfo
FAULT_WRITE(struct faultinfo)
extracts the "is_write" flag
SEGV_IS_FIXABLE(struct faultinfo)
is true for the fixable segvs, i.e. (TRAP == 14)
on i386
UPT_FAULTINFO(regs)
result is (struct faultinfo *) to the faultinfo
in regs->skas.faultinfo
GET_FAULTINFO_FROM_SC(struct faultinfo, struct sigcontext *)
copies the relevant parts of the sigcontext to
struct faultinfo.
On SIGSEGV, call user_signal() instead of handle_segv(), if the architecture
provides the information needed in PTRACE_FAULTINFO, or if PTRACE_FAULTINFO is
missing, because segv-stub will provide the info.
The benefit of the change is, that in case of a non-fixable SIGSEGV, we can
give user processes a SIGSEGV, instead of possibly looping on pagefault
handling.
Since handle_segv() sikked arch_fixup() implicitly by passing ip==0 to segv(),
I changed segv() to call arch_fixup() only, if !is_user.
Signed-off-by: Bodo Stroesser <bstroesser@fujitsu-siemens.com>
Signed-off-by: Jeff Dike <jdike@addtoit.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
24 files changed, 279 insertions, 115 deletions
diff --git a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h index 15389c886b41..e5fec5570199 100644 --- a/arch/um/include/kern_util.h +++ b/arch/um/include/kern_util.h | |||
@@ -8,6 +8,7 @@ | |||
8 | 8 | ||
9 | #include "linux/threads.h" | 9 | #include "linux/threads.h" |
10 | #include "sysdep/ptrace.h" | 10 | #include "sysdep/ptrace.h" |
11 | #include "sysdep/faultinfo.h" | ||
11 | 12 | ||
12 | extern int ncpus; | 13 | extern int ncpus; |
13 | extern char *linux_prog; | 14 | extern char *linux_prog; |
@@ -31,8 +32,8 @@ extern int current_pid(void); | |||
31 | extern unsigned long alloc_stack(int order, int atomic); | 32 | extern unsigned long alloc_stack(int order, int atomic); |
32 | extern int do_signal(void); | 33 | extern int do_signal(void); |
33 | extern int is_stack_fault(unsigned long sp); | 34 | extern int is_stack_fault(unsigned long sp); |
34 | extern unsigned long segv(unsigned long address, unsigned long ip, | 35 | extern unsigned long segv(struct faultinfo fi, unsigned long ip, |
35 | int is_write, int is_user, void *sc); | 36 | int is_user, void *sc); |
36 | extern int handle_page_fault(unsigned long address, unsigned long ip, | 37 | extern int handle_page_fault(unsigned long address, unsigned long ip, |
37 | int is_write, int is_user, int *code_out); | 38 | int is_write, int is_user, int *code_out); |
38 | extern void syscall_ready(void); | 39 | extern void syscall_ready(void); |
@@ -82,7 +83,7 @@ extern void timer_irq(union uml_pt_regs *regs); | |||
82 | extern void unprotect_stack(unsigned long stack); | 83 | extern void unprotect_stack(unsigned long stack); |
83 | extern void do_uml_exitcalls(void); | 84 | extern void do_uml_exitcalls(void); |
84 | extern int attach_debugger(int idle_pid, int pid, int stop); | 85 | extern int attach_debugger(int idle_pid, int pid, int stop); |
85 | extern void bad_segv(unsigned long address, unsigned long ip, int is_write); | 86 | extern void bad_segv(struct faultinfo fi, unsigned long ip); |
86 | extern int config_gdb(char *str); | 87 | extern int config_gdb(char *str); |
87 | extern int remove_gdb(void); | 88 | extern int remove_gdb(void); |
88 | extern char *uml_strdup(char *string); | 89 | extern char *uml_strdup(char *string); |
diff --git a/arch/um/include/sysdep-i386/faultinfo.h b/arch/um/include/sysdep-i386/faultinfo.h new file mode 100644 index 000000000000..db437cc373bc --- /dev/null +++ b/arch/um/include/sysdep-i386/faultinfo.h | |||
@@ -0,0 +1,29 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2004 Fujitsu Siemens Computers GmbH | ||
3 | * Author: Bodo Stroesser <bstroesser@fujitsu-siemens.com> | ||
4 | * Licensed under the GPL | ||
5 | */ | ||
6 | |||
7 | #ifndef __FAULTINFO_I386_H | ||
8 | #define __FAULTINFO_I386_H | ||
9 | |||
10 | /* this structure contains the full arch-specific faultinfo | ||
11 | * from the traps. | ||
12 | * On i386, ptrace_faultinfo unfortunately doesn't provide | ||
13 | * all the info, since trap_no is missing. | ||
14 | * All common elements are defined at the same position in | ||
15 | * both structures, thus making it easy to copy the | ||
16 | * contents without knowledge about the structure elements. | ||
17 | */ | ||
18 | struct faultinfo { | ||
19 | int error_code; /* in ptrace_faultinfo misleadingly called is_write */ | ||
20 | unsigned long cr2; /* in ptrace_faultinfo called addr */ | ||
21 | int trap_no; /* missing in ptrace_faultinfo */ | ||
22 | }; | ||
23 | |||
24 | #define FAULT_WRITE(fi) ((fi).error_code & 2) | ||
25 | #define FAULT_ADDRESS(fi) ((fi).cr2) | ||
26 | |||
27 | #define PTRACE_FULL_FAULTINFO 0 | ||
28 | |||
29 | #endif | ||
diff --git a/arch/um/include/sysdep-i386/ptrace.h b/arch/um/include/sysdep-i386/ptrace.h index 661d495e2044..84ec7ff5cf8c 100644 --- a/arch/um/include/sysdep-i386/ptrace.h +++ b/arch/um/include/sysdep-i386/ptrace.h | |||
@@ -31,6 +31,7 @@ extern int sysemu_supported; | |||
31 | #ifdef UML_CONFIG_MODE_SKAS | 31 | #ifdef UML_CONFIG_MODE_SKAS |
32 | 32 | ||
33 | #include "skas_ptregs.h" | 33 | #include "skas_ptregs.h" |
34 | #include "sysdep/faultinfo.h" | ||
34 | 35 | ||
35 | #define REGS_IP(r) ((r)[HOST_IP]) | 36 | #define REGS_IP(r) ((r)[HOST_IP]) |
36 | #define REGS_SP(r) ((r)[HOST_SP]) | 37 | #define REGS_SP(r) ((r)[HOST_SP]) |
@@ -53,12 +54,6 @@ extern int sysemu_supported; | |||
53 | 54 | ||
54 | #define REGS_RESTART_SYSCALL(r) IP_RESTART_SYSCALL(REGS_IP(r)) | 55 | #define REGS_RESTART_SYSCALL(r) IP_RESTART_SYSCALL(REGS_IP(r)) |
55 | 56 | ||
56 | #define REGS_SEGV_IS_FIXABLE(r) SEGV_IS_FIXABLE((r)->trap_type) | ||
57 | |||
58 | #define REGS_FAULT_ADDR(r) ((r)->fault_addr) | ||
59 | |||
60 | #define REGS_FAULT_WRITE(r) FAULT_WRITE((r)->fault_type) | ||
61 | |||
62 | #endif | 57 | #endif |
63 | #ifndef PTRACE_SYSEMU_SINGLESTEP | 58 | #ifndef PTRACE_SYSEMU_SINGLESTEP |
64 | #define PTRACE_SYSEMU_SINGLESTEP 32 | 59 | #define PTRACE_SYSEMU_SINGLESTEP 32 |
@@ -71,6 +66,7 @@ union uml_pt_regs { | |||
71 | struct tt_regs { | 66 | struct tt_regs { |
72 | long syscall; | 67 | long syscall; |
73 | void *sc; | 68 | void *sc; |
69 | struct faultinfo faultinfo; | ||
74 | } tt; | 70 | } tt; |
75 | #endif | 71 | #endif |
76 | #ifdef UML_CONFIG_MODE_SKAS | 72 | #ifdef UML_CONFIG_MODE_SKAS |
@@ -78,9 +74,7 @@ union uml_pt_regs { | |||
78 | unsigned long regs[HOST_FRAME_SIZE]; | 74 | unsigned long regs[HOST_FRAME_SIZE]; |
79 | unsigned long fp[HOST_FP_SIZE]; | 75 | unsigned long fp[HOST_FP_SIZE]; |
80 | unsigned long xfp[HOST_XFP_SIZE]; | 76 | unsigned long xfp[HOST_XFP_SIZE]; |
81 | unsigned long fault_addr; | 77 | struct faultinfo faultinfo; |
82 | unsigned long fault_type; | ||
83 | unsigned long trap_type; | ||
84 | long syscall; | 78 | long syscall; |
85 | int is_user; | 79 | int is_user; |
86 | } skas; | 80 | } skas; |
@@ -217,15 +211,8 @@ struct syscall_args { | |||
217 | #define UPT_SYSCALL_NR(r) UPT_ORIG_EAX(r) | 211 | #define UPT_SYSCALL_NR(r) UPT_ORIG_EAX(r) |
218 | #define UPT_SYSCALL_RET(r) UPT_EAX(r) | 212 | #define UPT_SYSCALL_RET(r) UPT_EAX(r) |
219 | 213 | ||
220 | #define UPT_SEGV_IS_FIXABLE(r) \ | 214 | #define UPT_FAULTINFO(r) \ |
221 | CHOOSE_MODE(SC_SEGV_IS_FIXABLE(UPT_SC(r)), \ | 215 | CHOOSE_MODE((&(r)->tt.faultinfo), (&(r)->skas.faultinfo)) |
222 | REGS_SEGV_IS_FIXABLE(&r->skas)) | ||
223 | |||
224 | #define UPT_FAULT_ADDR(r) \ | ||
225 | __CHOOSE_MODE(SC_FAULT_ADDR(UPT_SC(r)), REGS_FAULT_ADDR(&r->skas)) | ||
226 | |||
227 | #define UPT_FAULT_WRITE(r) \ | ||
228 | CHOOSE_MODE(SC_FAULT_WRITE(UPT_SC(r)), REGS_FAULT_WRITE(&r->skas)) | ||
229 | 216 | ||
230 | #endif | 217 | #endif |
231 | 218 | ||
diff --git a/arch/um/include/sysdep-i386/sigcontext.h b/arch/um/include/sysdep-i386/sigcontext.h index dfee589de360..1fe729265167 100644 --- a/arch/um/include/sysdep-i386/sigcontext.h +++ b/arch/um/include/sysdep-i386/sigcontext.h | |||
@@ -13,15 +13,12 @@ | |||
13 | #define SC_RESTART_SYSCALL(sc) IP_RESTART_SYSCALL(SC_IP(sc)) | 13 | #define SC_RESTART_SYSCALL(sc) IP_RESTART_SYSCALL(SC_IP(sc)) |
14 | #define SC_SET_SYSCALL_RETURN(sc, result) SC_EAX(sc) = (result) | 14 | #define SC_SET_SYSCALL_RETURN(sc, result) SC_EAX(sc) = (result) |
15 | 15 | ||
16 | #define SC_FAULT_ADDR(sc) SC_CR2(sc) | 16 | #define GET_FAULTINFO_FROM_SC(fi,sc) \ |
17 | #define SC_FAULT_TYPE(sc) SC_ERR(sc) | 17 | { \ |
18 | 18 | (fi).cr2 = SC_CR2(sc); \ | |
19 | #define FAULT_WRITE(err) (err & 2) | 19 | (fi).error_code = SC_ERR(sc); \ |
20 | #define TO_SC_ERR(is_write) ((is_write) ? 2 : 0) | 20 | (fi).trap_no = SC_TRAPNO(sc); \ |
21 | 21 | } | |
22 | #define SC_FAULT_WRITE(sc) (FAULT_WRITE(SC_ERR(sc))) | ||
23 | |||
24 | #define SC_TRAP_TYPE(sc) SC_TRAPNO(sc) | ||
25 | 22 | ||
26 | /* ptrace expects that, at the start of a system call, %eax contains | 23 | /* ptrace expects that, at the start of a system call, %eax contains |
27 | * -ENOSYS, so this makes it so. | 24 | * -ENOSYS, so this makes it so. |
@@ -29,9 +26,7 @@ | |||
29 | #define SC_START_SYSCALL(sc) do SC_EAX(sc) = -ENOSYS; while(0) | 26 | #define SC_START_SYSCALL(sc) do SC_EAX(sc) = -ENOSYS; while(0) |
30 | 27 | ||
31 | /* This is Page Fault */ | 28 | /* This is Page Fault */ |
32 | #define SEGV_IS_FIXABLE(trap) (trap == 14) | 29 | #define SEGV_IS_FIXABLE(fi) ((fi)->trap_no == 14) |
33 | |||
34 | #define SC_SEGV_IS_FIXABLE(sc) (SEGV_IS_FIXABLE(SC_TRAPNO(sc))) | ||
35 | 30 | ||
36 | extern unsigned long *sc_sigmask(void *sc_ptr); | 31 | extern unsigned long *sc_sigmask(void *sc_ptr); |
37 | extern int sc_get_fpregs(unsigned long buf, void *sc_ptr); | 32 | extern int sc_get_fpregs(unsigned long buf, void *sc_ptr); |
diff --git a/arch/um/include/sysdep-i386/skas_ptrace.h b/arch/um/include/sysdep-i386/skas_ptrace.h new file mode 100644 index 000000000000..e27b8a791773 --- /dev/null +++ b/arch/um/include/sysdep-i386/skas_ptrace.h | |||
@@ -0,0 +1,22 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #ifndef __SYSDEP_I386_SKAS_PTRACE_H | ||
7 | #define __SYSDEP_I386_SKAS_PTRACE_H | ||
8 | |||
9 | struct ptrace_faultinfo { | ||
10 | int is_write; | ||
11 | unsigned long addr; | ||
12 | }; | ||
13 | |||
14 | struct ptrace_ldt { | ||
15 | int func; | ||
16 | void *ptr; | ||
17 | unsigned long bytecount; | ||
18 | }; | ||
19 | |||
20 | #define PTRACE_LDT 54 | ||
21 | |||
22 | #endif | ||
diff --git a/arch/um/include/sysdep-ia64/skas_ptrace.h b/arch/um/include/sysdep-ia64/skas_ptrace.h new file mode 100644 index 000000000000..25a38e715702 --- /dev/null +++ b/arch/um/include/sysdep-ia64/skas_ptrace.h | |||
@@ -0,0 +1,22 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #ifndef __SYSDEP_IA64_SKAS_PTRACE_H | ||
7 | #define __SYSDEP_IA64_SKAS_PTRACE_H | ||
8 | |||
9 | struct ptrace_faultinfo { | ||
10 | int is_write; | ||
11 | unsigned long addr; | ||
12 | }; | ||
13 | |||
14 | struct ptrace_ldt { | ||
15 | int func; | ||
16 | void *ptr; | ||
17 | unsigned long bytecount; | ||
18 | }; | ||
19 | |||
20 | #define PTRACE_LDT 54 | ||
21 | |||
22 | #endif | ||
diff --git a/arch/um/include/sysdep-ppc/skas_ptrace.h b/arch/um/include/sysdep-ppc/skas_ptrace.h new file mode 100644 index 000000000000..d9fbbac10de0 --- /dev/null +++ b/arch/um/include/sysdep-ppc/skas_ptrace.h | |||
@@ -0,0 +1,22 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #ifndef __SYSDEP_PPC_SKAS_PTRACE_H | ||
7 | #define __SYSDEP_PPC_SKAS_PTRACE_H | ||
8 | |||
9 | struct ptrace_faultinfo { | ||
10 | int is_write; | ||
11 | unsigned long addr; | ||
12 | }; | ||
13 | |||
14 | struct ptrace_ldt { | ||
15 | int func; | ||
16 | void *ptr; | ||
17 | unsigned long bytecount; | ||
18 | }; | ||
19 | |||
20 | #define PTRACE_LDT 54 | ||
21 | |||
22 | #endif | ||
diff --git a/arch/um/include/sysdep-x86_64/faultinfo.h b/arch/um/include/sysdep-x86_64/faultinfo.h new file mode 100644 index 000000000000..cb917b0d5660 --- /dev/null +++ b/arch/um/include/sysdep-x86_64/faultinfo.h | |||
@@ -0,0 +1,29 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2004 Fujitsu Siemens Computers GmbH | ||
3 | * Author: Bodo Stroesser <bstroesser@fujitsu-siemens.com> | ||
4 | * Licensed under the GPL | ||
5 | */ | ||
6 | |||
7 | #ifndef __FAULTINFO_X86_64_H | ||
8 | #define __FAULTINFO_X86_64_H | ||
9 | |||
10 | /* this structure contains the full arch-specific faultinfo | ||
11 | * from the traps. | ||
12 | * On i386, ptrace_faultinfo unfortunately doesn't provide | ||
13 | * all the info, since trap_no is missing. | ||
14 | * All common elements are defined at the same position in | ||
15 | * both structures, thus making it easy to copy the | ||
16 | * contents without knowledge about the structure elements. | ||
17 | */ | ||
18 | struct faultinfo { | ||
19 | int error_code; /* in ptrace_faultinfo misleadingly called is_write */ | ||
20 | unsigned long cr2; /* in ptrace_faultinfo called addr */ | ||
21 | int trap_no; /* missing in ptrace_faultinfo */ | ||
22 | }; | ||
23 | |||
24 | #define FAULT_WRITE(fi) ((fi).error_code & 2) | ||
25 | #define FAULT_ADDRESS(fi) ((fi).cr2) | ||
26 | |||
27 | #define PTRACE_FULL_FAULTINFO 1 | ||
28 | |||
29 | #endif | ||
diff --git a/arch/um/include/sysdep-x86_64/ptrace.h b/arch/um/include/sysdep-x86_64/ptrace.h index 915c82daffbd..348e8fcd513f 100644 --- a/arch/um/include/sysdep-x86_64/ptrace.h +++ b/arch/um/include/sysdep-x86_64/ptrace.h | |||
@@ -9,6 +9,7 @@ | |||
9 | 9 | ||
10 | #include "uml-config.h" | 10 | #include "uml-config.h" |
11 | #include "user_constants.h" | 11 | #include "user_constants.h" |
12 | #include "sysdep/faultinfo.h" | ||
12 | 13 | ||
13 | #define MAX_REG_OFFSET (UM_FRAME_SIZE) | 14 | #define MAX_REG_OFFSET (UM_FRAME_SIZE) |
14 | #define MAX_REG_NR ((MAX_REG_OFFSET) / sizeof(unsigned long)) | 15 | #define MAX_REG_NR ((MAX_REG_OFFSET) / sizeof(unsigned long)) |
@@ -83,6 +84,7 @@ union uml_pt_regs { | |||
83 | long syscall; | 84 | long syscall; |
84 | unsigned long orig_rax; | 85 | unsigned long orig_rax; |
85 | void *sc; | 86 | void *sc; |
87 | struct faultinfo faultinfo; | ||
86 | } tt; | 88 | } tt; |
87 | #endif | 89 | #endif |
88 | #ifdef UML_CONFIG_MODE_SKAS | 90 | #ifdef UML_CONFIG_MODE_SKAS |
@@ -90,9 +92,7 @@ union uml_pt_regs { | |||
90 | /* XXX */ | 92 | /* XXX */ |
91 | unsigned long regs[27]; | 93 | unsigned long regs[27]; |
92 | unsigned long fp[65]; | 94 | unsigned long fp[65]; |
93 | unsigned long fault_addr; | 95 | struct faultinfo faultinfo; |
94 | unsigned long fault_type; | ||
95 | unsigned long trap_type; | ||
96 | long syscall; | 96 | long syscall; |
97 | int is_user; | 97 | int is_user; |
98 | } skas; | 98 | } skas; |
@@ -241,14 +241,8 @@ struct syscall_args { | |||
241 | CHOOSE_MODE(SC_SEGV_IS_FIXABLE(UPT_SC(r)), \ | 241 | CHOOSE_MODE(SC_SEGV_IS_FIXABLE(UPT_SC(r)), \ |
242 | REGS_SEGV_IS_FIXABLE(&r->skas)) | 242 | REGS_SEGV_IS_FIXABLE(&r->skas)) |
243 | 243 | ||
244 | #define UPT_FAULT_ADDR(r) \ | 244 | #define UPT_FAULTINFO(r) \ |
245 | __CHOOSE_MODE(SC_FAULT_ADDR(UPT_SC(r)), REGS_FAULT_ADDR(&r->skas)) | 245 | CHOOSE_MODE((&(r)->tt.faultinfo), (&(r)->skas.faultinfo)) |
246 | |||
247 | #define UPT_FAULT_WRITE(r) \ | ||
248 | CHOOSE_MODE(SC_FAULT_WRITE(UPT_SC(r)), REGS_FAULT_WRITE(&r->skas)) | ||
249 | |||
250 | #define UPT_TRAP(r) __CHOOSE_MODE(SC_TRAP_TYPE(UPT_SC(r)), REGS_TRAP(&r->skas)) | ||
251 | #define UPT_ERR(r) __CHOOSE_MODE(SC_FAULT_TYPE(UPT_SC(r)), REGS_ERR(&r->skas)) | ||
252 | 246 | ||
253 | #endif | 247 | #endif |
254 | 248 | ||
diff --git a/arch/um/include/sysdep-x86_64/sigcontext.h b/arch/um/include/sysdep-x86_64/sigcontext.h index 1e38a54ff4cf..2a78260d15a0 100644 --- a/arch/um/include/sysdep-x86_64/sigcontext.h +++ b/arch/um/include/sysdep-x86_64/sigcontext.h | |||
@@ -17,11 +17,12 @@ | |||
17 | #define SC_FAULT_ADDR(sc) SC_CR2(sc) | 17 | #define SC_FAULT_ADDR(sc) SC_CR2(sc) |
18 | #define SC_FAULT_TYPE(sc) SC_ERR(sc) | 18 | #define SC_FAULT_TYPE(sc) SC_ERR(sc) |
19 | 19 | ||
20 | #define FAULT_WRITE(err) ((err) & 2) | 20 | #define GET_FAULTINFO_FROM_SC(fi,sc) \ |
21 | 21 | { \ | |
22 | #define SC_FAULT_WRITE(sc) FAULT_WRITE(SC_FAULT_TYPE(sc)) | 22 | (fi).cr2 = SC_CR2(sc); \ |
23 | 23 | (fi).error_code = SC_ERR(sc); \ | |
24 | #define SC_TRAP_TYPE(sc) SC_TRAPNO(sc) | 24 | (fi).trap_no = SC_TRAPNO(sc); \ |
25 | } | ||
25 | 26 | ||
26 | /* ptrace expects that, at the start of a system call, %eax contains | 27 | /* ptrace expects that, at the start of a system call, %eax contains |
27 | * -ENOSYS, so this makes it so. | 28 | * -ENOSYS, so this makes it so. |
@@ -29,8 +30,8 @@ | |||
29 | 30 | ||
30 | #define SC_START_SYSCALL(sc) do SC_RAX(sc) = -ENOSYS; while(0) | 31 | #define SC_START_SYSCALL(sc) do SC_RAX(sc) = -ENOSYS; while(0) |
31 | 32 | ||
32 | #define SEGV_IS_FIXABLE(trap) ((trap) == 14) | 33 | /* This is Page Fault */ |
33 | #define SC_SEGV_IS_FIXABLE(sc) SEGV_IS_FIXABLE(SC_TRAP_TYPE(sc)) | 34 | #define SEGV_IS_FIXABLE(fi) ((fi)->trap_no == 14) |
34 | 35 | ||
35 | extern unsigned long *sc_sigmask(void *sc_ptr); | 36 | extern unsigned long *sc_sigmask(void *sc_ptr); |
36 | 37 | ||
diff --git a/arch/um/include/sysdep-x86_64/skas_ptrace.h b/arch/um/include/sysdep-x86_64/skas_ptrace.h new file mode 100644 index 000000000000..95db4be786e4 --- /dev/null +++ b/arch/um/include/sysdep-x86_64/skas_ptrace.h | |||
@@ -0,0 +1,22 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #ifndef __SYSDEP_X86_64_SKAS_PTRACE_H | ||
7 | #define __SYSDEP_X86_64_SKAS_PTRACE_H | ||
8 | |||
9 | struct ptrace_faultinfo { | ||
10 | int is_write; | ||
11 | unsigned long addr; | ||
12 | }; | ||
13 | |||
14 | struct ptrace_ldt { | ||
15 | int func; | ||
16 | void *ptr; | ||
17 | unsigned long bytecount; | ||
18 | }; | ||
19 | |||
20 | #define PTRACE_LDT 54 | ||
21 | |||
22 | #endif | ||
diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index ffc599bd85c3..ec19fed7c64b 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c | |||
@@ -252,13 +252,13 @@ long sys_ptrace(long request, long pid, long addr, long data) | |||
252 | break; | 252 | break; |
253 | #endif | 253 | #endif |
254 | case PTRACE_FAULTINFO: { | 254 | case PTRACE_FAULTINFO: { |
255 | struct ptrace_faultinfo fault; | 255 | /* Take the info from thread->arch->faultinfo, |
256 | 256 | * but transfer max. sizeof(struct ptrace_faultinfo). | |
257 | fault = ((struct ptrace_faultinfo) | 257 | * On i386, ptrace_faultinfo is smaller! |
258 | { .is_write = child->thread.err, | 258 | */ |
259 | .addr = child->thread.cr2 }); | 259 | ret = copy_to_user((unsigned long __user *) data, |
260 | ret = copy_to_user((unsigned long __user *) data, &fault, | 260 | &child->thread.arch.faultinfo, |
261 | sizeof(fault)); | 261 | sizeof(struct ptrace_faultinfo)); |
262 | if(ret) | 262 | if(ret) |
263 | break; | 263 | break; |
264 | break; | 264 | break; |
@@ -269,6 +269,7 @@ long sys_ptrace(long request, long pid, long addr, long data) | |||
269 | sizeof(child->pending.signal)); | 269 | sizeof(child->pending.signal)); |
270 | break; | 270 | break; |
271 | 271 | ||
272 | #ifdef PTRACE_LDT | ||
272 | case PTRACE_LDT: { | 273 | case PTRACE_LDT: { |
273 | struct ptrace_ldt ldt; | 274 | struct ptrace_ldt ldt; |
274 | 275 | ||
@@ -284,6 +285,7 @@ long sys_ptrace(long request, long pid, long addr, long data) | |||
284 | ret = -EIO; | 285 | ret = -EIO; |
285 | break; | 286 | break; |
286 | } | 287 | } |
288 | #endif | ||
287 | #ifdef CONFIG_PROC_MM | 289 | #ifdef CONFIG_PROC_MM |
288 | case PTRACE_SWITCH_MM: { | 290 | case PTRACE_SWITCH_MM: { |
289 | struct mm_struct *old = child->mm; | 291 | struct mm_struct *old = child->mm; |
diff --git a/arch/um/kernel/skas/include/skas.h b/arch/um/kernel/skas/include/skas.h index f0702c2c7204..96b51dba3471 100644 --- a/arch/um/kernel/skas/include/skas.h +++ b/arch/um/kernel/skas/include/skas.h | |||
@@ -27,9 +27,10 @@ extern void map(int fd, unsigned long virt, unsigned long len, int r, int w, | |||
27 | extern int unmap(int fd, void *addr, unsigned long len); | 27 | extern int unmap(int fd, void *addr, unsigned long len); |
28 | extern int protect(int fd, unsigned long addr, unsigned long len, | 28 | extern int protect(int fd, unsigned long addr, unsigned long len, |
29 | int r, int w, int x); | 29 | int r, int w, int x); |
30 | extern void user_signal(int sig, union uml_pt_regs *regs); | 30 | extern void user_signal(int sig, union uml_pt_regs *regs, int pid); |
31 | extern int new_mm(int from); | 31 | extern int new_mm(int from); |
32 | extern void start_userspace(int cpu); | 32 | extern void start_userspace(int cpu); |
33 | extern void get_skas_faultinfo(int pid, struct faultinfo * fi); | ||
33 | extern long execute_syscall_skas(void *r); | 34 | extern long execute_syscall_skas(void *r); |
34 | 35 | ||
35 | #endif | 36 | #endif |
diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c index b4ffaaa81241..c0b30515dfb6 100644 --- a/arch/um/kernel/skas/process.c +++ b/arch/um/kernel/skas/process.c | |||
@@ -4,6 +4,7 @@ | |||
4 | */ | 4 | */ |
5 | 5 | ||
6 | #include <stdlib.h> | 6 | #include <stdlib.h> |
7 | #include <string.h> | ||
7 | #include <unistd.h> | 8 | #include <unistd.h> |
8 | #include <errno.h> | 9 | #include <errno.h> |
9 | #include <signal.h> | 10 | #include <signal.h> |
@@ -37,17 +38,26 @@ int is_skas_winch(int pid, int fd, void *data) | |||
37 | return(1); | 38 | return(1); |
38 | } | 39 | } |
39 | 40 | ||
40 | static void handle_segv(int pid) | 41 | void get_skas_faultinfo(int pid, struct faultinfo * fi) |
41 | { | 42 | { |
42 | struct ptrace_faultinfo fault; | ||
43 | int err; | 43 | int err; |
44 | 44 | ||
45 | err = ptrace(PTRACE_FAULTINFO, pid, 0, &fault); | 45 | err = ptrace(PTRACE_FAULTINFO, pid, 0, fi); |
46 | if(err) | 46 | if(err) |
47 | panic("handle_segv - PTRACE_FAULTINFO failed, errno = %d\n", | 47 | panic("get_skas_faultinfo - PTRACE_FAULTINFO failed, " |
48 | errno); | 48 | "errno = %d\n", errno); |
49 | |||
50 | /* Special handling for i386, which has different structs */ | ||
51 | if (sizeof(struct ptrace_faultinfo) < sizeof(struct faultinfo)) | ||
52 | memset((char *)fi + sizeof(struct ptrace_faultinfo), 0, | ||
53 | sizeof(struct faultinfo) - | ||
54 | sizeof(struct ptrace_faultinfo)); | ||
55 | } | ||
49 | 56 | ||
50 | segv(fault.addr, 0, FAULT_WRITE(fault.is_write), 1, NULL); | 57 | static void handle_segv(int pid, union uml_pt_regs * regs) |
58 | { | ||
59 | get_skas_faultinfo(pid, ®s->skas.faultinfo); | ||
60 | segv(regs->skas.faultinfo, 0, 1, NULL); | ||
51 | } | 61 | } |
52 | 62 | ||
53 | /*To use the same value of using_sysemu as the caller, ask it that value (in local_using_sysemu)*/ | 63 | /*To use the same value of using_sysemu as the caller, ask it that value (in local_using_sysemu)*/ |
@@ -163,7 +173,7 @@ void userspace(union uml_pt_regs *regs) | |||
163 | if(WIFSTOPPED(status)){ | 173 | if(WIFSTOPPED(status)){ |
164 | switch(WSTOPSIG(status)){ | 174 | switch(WSTOPSIG(status)){ |
165 | case SIGSEGV: | 175 | case SIGSEGV: |
166 | handle_segv(pid); | 176 | handle_segv(pid, regs); |
167 | break; | 177 | break; |
168 | case SIGTRAP + 0x80: | 178 | case SIGTRAP + 0x80: |
169 | handle_trap(pid, regs, local_using_sysemu); | 179 | handle_trap(pid, regs, local_using_sysemu); |
@@ -177,7 +187,7 @@ void userspace(union uml_pt_regs *regs) | |||
177 | case SIGBUS: | 187 | case SIGBUS: |
178 | case SIGFPE: | 188 | case SIGFPE: |
179 | case SIGWINCH: | 189 | case SIGWINCH: |
180 | user_signal(WSTOPSIG(status), regs); | 190 | user_signal(WSTOPSIG(status), regs, pid); |
181 | break; | 191 | break; |
182 | default: | 192 | default: |
183 | printk("userspace - child stopped with signal " | 193 | printk("userspace - child stopped with signal " |
diff --git a/arch/um/kernel/skas/trap_user.c b/arch/um/kernel/skas/trap_user.c index 8e9b46d4702e..0dee1d95c806 100644 --- a/arch/um/kernel/skas/trap_user.c +++ b/arch/um/kernel/skas/trap_user.c | |||
@@ -5,12 +5,15 @@ | |||
5 | 5 | ||
6 | #include <signal.h> | 6 | #include <signal.h> |
7 | #include <errno.h> | 7 | #include <errno.h> |
8 | #include "sysdep/ptrace.h" | ||
9 | #include "signal_user.h" | 8 | #include "signal_user.h" |
10 | #include "user_util.h" | 9 | #include "user_util.h" |
11 | #include "kern_util.h" | 10 | #include "kern_util.h" |
12 | #include "task.h" | 11 | #include "task.h" |
13 | #include "sigcontext.h" | 12 | #include "sigcontext.h" |
13 | #include "skas.h" | ||
14 | #include "ptrace_user.h" | ||
15 | #include "sysdep/ptrace.h" | ||
16 | #include "sysdep/ptrace_user.h" | ||
14 | 17 | ||
15 | void sig_handler_common_skas(int sig, void *sc_ptr) | 18 | void sig_handler_common_skas(int sig, void *sc_ptr) |
16 | { | 19 | { |
@@ -31,9 +34,11 @@ void sig_handler_common_skas(int sig, void *sc_ptr) | |||
31 | r = &TASK_REGS(get_current())->skas; | 34 | r = &TASK_REGS(get_current())->skas; |
32 | save_user = r->is_user; | 35 | save_user = r->is_user; |
33 | r->is_user = 0; | 36 | r->is_user = 0; |
34 | r->fault_addr = SC_FAULT_ADDR(sc); | 37 | if ( sig == SIGFPE || sig == SIGSEGV || |
35 | r->fault_type = SC_FAULT_TYPE(sc); | 38 | sig == SIGBUS || sig == SIGILL || |
36 | r->trap_type = SC_TRAP_TYPE(sc); | 39 | sig == SIGTRAP ) { |
40 | GET_FAULTINFO_FROM_SC(r->faultinfo, sc); | ||
41 | } | ||
37 | 42 | ||
38 | change_sig(SIGUSR1, 1); | 43 | change_sig(SIGUSR1, 1); |
39 | info = &sig_info[sig]; | 44 | info = &sig_info[sig]; |
@@ -45,14 +50,17 @@ void sig_handler_common_skas(int sig, void *sc_ptr) | |||
45 | r->is_user = save_user; | 50 | r->is_user = save_user; |
46 | } | 51 | } |
47 | 52 | ||
48 | void user_signal(int sig, union uml_pt_regs *regs) | 53 | extern int ptrace_faultinfo; |
54 | |||
55 | void user_signal(int sig, union uml_pt_regs *regs, int pid) | ||
49 | { | 56 | { |
50 | struct signal_info *info; | 57 | struct signal_info *info; |
58 | int segv = ((sig == SIGFPE) || (sig == SIGSEGV) || (sig == SIGBUS) || | ||
59 | (sig == SIGILL) || (sig == SIGTRAP)); | ||
51 | 60 | ||
52 | regs->skas.is_user = 1; | 61 | regs->skas.is_user = 1; |
53 | regs->skas.fault_addr = 0; | 62 | if (segv) |
54 | regs->skas.fault_type = 0; | 63 | get_skas_faultinfo(pid, ®s->skas.faultinfo); |
55 | regs->skas.trap_type = 0; | ||
56 | info = &sig_info[sig]; | 64 | info = &sig_info[sig]; |
57 | (*info->handler)(sig, regs); | 65 | (*info->handler)(sig, regs); |
58 | 66 | ||
diff --git a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c index 47e766e6ba10..54e2ec33a43c 100644 --- a/arch/um/kernel/trap_kern.c +++ b/arch/um/kernel/trap_kern.c | |||
@@ -133,12 +133,19 @@ static int check_remapped_addr(unsigned long address, int is_write) | |||
133 | return(0); | 133 | return(0); |
134 | } | 134 | } |
135 | 135 | ||
136 | unsigned long segv(unsigned long address, unsigned long ip, int is_write, | 136 | /* |
137 | int is_user, void *sc) | 137 | * We give a *copy* of the faultinfo in the regs to segv. |
138 | * This must be done, since nesting SEGVs could overwrite | ||
139 | * the info in the regs. A pointer to the info then would | ||
140 | * give us bad data! | ||
141 | */ | ||
142 | unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc) | ||
138 | { | 143 | { |
139 | struct siginfo si; | 144 | struct siginfo si; |
140 | void *catcher; | 145 | void *catcher; |
141 | int err; | 146 | int err; |
147 | int is_write = FAULT_WRITE(fi); | ||
148 | unsigned long address = FAULT_ADDRESS(fi); | ||
142 | 149 | ||
143 | if(!is_user && (address >= start_vm) && (address < end_vm)){ | 150 | if(!is_user && (address >= start_vm) && (address < end_vm)){ |
144 | flush_tlb_kernel_vm(); | 151 | flush_tlb_kernel_vm(); |
@@ -159,7 +166,7 @@ unsigned long segv(unsigned long address, unsigned long ip, int is_write, | |||
159 | } | 166 | } |
160 | else if(current->thread.fault_addr != NULL) | 167 | else if(current->thread.fault_addr != NULL) |
161 | panic("fault_addr set but no fault catcher"); | 168 | panic("fault_addr set but no fault catcher"); |
162 | else if(arch_fixup(ip, sc)) | 169 | else if(!is_user && arch_fixup(ip, sc)) |
163 | return(0); | 170 | return(0); |
164 | 171 | ||
165 | if(!is_user) | 172 | if(!is_user) |
@@ -171,6 +178,7 @@ unsigned long segv(unsigned long address, unsigned long ip, int is_write, | |||
171 | si.si_errno = 0; | 178 | si.si_errno = 0; |
172 | si.si_code = BUS_ADRERR; | 179 | si.si_code = BUS_ADRERR; |
173 | si.si_addr = (void *)address; | 180 | si.si_addr = (void *)address; |
181 | current->thread.arch.faultinfo = fi; | ||
174 | force_sig_info(SIGBUS, &si, current); | 182 | force_sig_info(SIGBUS, &si, current); |
175 | } | 183 | } |
176 | else if(err == -ENOMEM){ | 184 | else if(err == -ENOMEM){ |
@@ -180,22 +188,20 @@ unsigned long segv(unsigned long address, unsigned long ip, int is_write, | |||
180 | else { | 188 | else { |
181 | si.si_signo = SIGSEGV; | 189 | si.si_signo = SIGSEGV; |
182 | si.si_addr = (void *) address; | 190 | si.si_addr = (void *) address; |
183 | current->thread.cr2 = address; | 191 | current->thread.arch.faultinfo = fi; |
184 | current->thread.err = is_write; | ||
185 | force_sig_info(SIGSEGV, &si, current); | 192 | force_sig_info(SIGSEGV, &si, current); |
186 | } | 193 | } |
187 | return(0); | 194 | return(0); |
188 | } | 195 | } |
189 | 196 | ||
190 | void bad_segv(unsigned long address, unsigned long ip, int is_write) | 197 | void bad_segv(struct faultinfo fi, unsigned long ip) |
191 | { | 198 | { |
192 | struct siginfo si; | 199 | struct siginfo si; |
193 | 200 | ||
194 | si.si_signo = SIGSEGV; | 201 | si.si_signo = SIGSEGV; |
195 | si.si_code = SEGV_ACCERR; | 202 | si.si_code = SEGV_ACCERR; |
196 | si.si_addr = (void *) address; | 203 | si.si_addr = (void *) FAULT_ADDRESS(fi); |
197 | current->thread.cr2 = address; | 204 | current->thread.arch.faultinfo = fi; |
198 | current->thread.err = is_write; | ||
199 | force_sig_info(SIGSEGV, &si, current); | 205 | force_sig_info(SIGSEGV, &si, current); |
200 | } | 206 | } |
201 | 207 | ||
@@ -204,6 +210,7 @@ void relay_signal(int sig, union uml_pt_regs *regs) | |||
204 | if(arch_handle_signal(sig, regs)) return; | 210 | if(arch_handle_signal(sig, regs)) return; |
205 | if(!UPT_IS_USER(regs)) | 211 | if(!UPT_IS_USER(regs)) |
206 | panic("Kernel mode signal %d", sig); | 212 | panic("Kernel mode signal %d", sig); |
213 | current->thread.arch.faultinfo = *UPT_FAULTINFO(regs); | ||
207 | force_sig(sig, current); | 214 | force_sig(sig, current); |
208 | } | 215 | } |
209 | 216 | ||
diff --git a/arch/um/kernel/trap_user.c b/arch/um/kernel/trap_user.c index 50a4042a509f..f825a6eda3f5 100644 --- a/arch/um/kernel/trap_user.c +++ b/arch/um/kernel/trap_user.c | |||
@@ -54,23 +54,22 @@ struct { | |||
54 | void segv_handler(int sig, union uml_pt_regs *regs) | 54 | void segv_handler(int sig, union uml_pt_regs *regs) |
55 | { | 55 | { |
56 | int index, max; | 56 | int index, max; |
57 | struct faultinfo * fi = UPT_FAULTINFO(regs); | ||
57 | 58 | ||
58 | if(UPT_IS_USER(regs) && !UPT_SEGV_IS_FIXABLE(regs)){ | 59 | if(UPT_IS_USER(regs) && !SEGV_IS_FIXABLE(fi)){ |
59 | bad_segv(UPT_FAULT_ADDR(regs), UPT_IP(regs), | 60 | bad_segv(*fi, UPT_IP(regs)); |
60 | UPT_FAULT_WRITE(regs)); | ||
61 | return; | 61 | return; |
62 | } | 62 | } |
63 | max = sizeof(segfault_record)/sizeof(segfault_record[0]); | 63 | max = sizeof(segfault_record)/sizeof(segfault_record[0]); |
64 | index = next_trap_index(max); | 64 | index = next_trap_index(max); |
65 | 65 | ||
66 | nsegfaults++; | 66 | nsegfaults++; |
67 | segfault_record[index].address = UPT_FAULT_ADDR(regs); | 67 | segfault_record[index].address = FAULT_ADDRESS(*fi); |
68 | segfault_record[index].pid = os_getpid(); | 68 | segfault_record[index].pid = os_getpid(); |
69 | segfault_record[index].is_write = UPT_FAULT_WRITE(regs); | 69 | segfault_record[index].is_write = FAULT_WRITE(*fi); |
70 | segfault_record[index].sp = UPT_SP(regs); | 70 | segfault_record[index].sp = UPT_SP(regs); |
71 | segfault_record[index].is_user = UPT_IS_USER(regs); | 71 | segfault_record[index].is_user = UPT_IS_USER(regs); |
72 | segv(UPT_FAULT_ADDR(regs), UPT_IP(regs), UPT_FAULT_WRITE(regs), | 72 | segv(*fi, UPT_IP(regs), UPT_IS_USER(regs), regs); |
73 | UPT_IS_USER(regs), regs); | ||
74 | } | 73 | } |
75 | 74 | ||
76 | void usr2_handler(int sig, union uml_pt_regs *regs) | 75 | void usr2_handler(int sig, union uml_pt_regs *regs) |
diff --git a/arch/um/kernel/tt/tracer.c b/arch/um/kernel/tt/tracer.c index 7b5d937e5955..f7b1753a025c 100644 --- a/arch/um/kernel/tt/tracer.c +++ b/arch/um/kernel/tt/tracer.c | |||
@@ -89,8 +89,10 @@ void tracer_panic(char *format, ...) | |||
89 | 89 | ||
90 | static void tracer_segv(int sig, struct sigcontext sc) | 90 | static void tracer_segv(int sig, struct sigcontext sc) |
91 | { | 91 | { |
92 | struct faultinfo fi; | ||
93 | GET_FAULTINFO_FROM_SC(fi, &sc); | ||
92 | printf("Tracing thread segfault at address 0x%lx, ip 0x%lx\n", | 94 | printf("Tracing thread segfault at address 0x%lx, ip 0x%lx\n", |
93 | SC_FAULT_ADDR(&sc), SC_IP(&sc)); | 95 | FAULT_ADDRESS(fi), SC_IP(&sc)); |
94 | while(1) | 96 | while(1) |
95 | pause(); | 97 | pause(); |
96 | } | 98 | } |
diff --git a/arch/um/kernel/tt/trap_user.c b/arch/um/kernel/tt/trap_user.c index 92a3820ca543..fc108615beaf 100644 --- a/arch/um/kernel/tt/trap_user.c +++ b/arch/um/kernel/tt/trap_user.c | |||
@@ -7,6 +7,7 @@ | |||
7 | #include <errno.h> | 7 | #include <errno.h> |
8 | #include <signal.h> | 8 | #include <signal.h> |
9 | #include "sysdep/ptrace.h" | 9 | #include "sysdep/ptrace.h" |
10 | #include "sysdep/sigcontext.h" | ||
10 | #include "signal_user.h" | 11 | #include "signal_user.h" |
11 | #include "user_util.h" | 12 | #include "user_util.h" |
12 | #include "kern_util.h" | 13 | #include "kern_util.h" |
@@ -28,6 +29,11 @@ void sig_handler_common_tt(int sig, void *sc_ptr) | |||
28 | change_sig(SIGSEGV, 1); | 29 | change_sig(SIGSEGV, 1); |
29 | 30 | ||
30 | r = &TASK_REGS(get_current())->tt; | 31 | r = &TASK_REGS(get_current())->tt; |
32 | if ( sig == SIGFPE || sig == SIGSEGV || | ||
33 | sig == SIGBUS || sig == SIGILL || | ||
34 | sig == SIGTRAP ) { | ||
35 | GET_FAULTINFO_FROM_SC(r->faultinfo, sc); | ||
36 | } | ||
31 | save_regs = *r; | 37 | save_regs = *r; |
32 | is_user = user_context(SC_SP(sc)); | 38 | is_user = user_context(SC_SP(sc)); |
33 | r->sc = sc; | 39 | r->sc = sc; |
diff --git a/arch/um/sys-i386/signal.c b/arch/um/sys-i386/signal.c index 76ba87254b25..03913ca5d256 100644 --- a/arch/um/sys-i386/signal.c +++ b/arch/um/sys-i386/signal.c | |||
@@ -47,9 +47,6 @@ static int copy_sc_from_user_skas(struct pt_regs *regs, | |||
47 | REGS_CS(regs->regs.skas.regs) = sc.cs; | 47 | REGS_CS(regs->regs.skas.regs) = sc.cs; |
48 | REGS_EFLAGS(regs->regs.skas.regs) = sc.eflags; | 48 | REGS_EFLAGS(regs->regs.skas.regs) = sc.eflags; |
49 | REGS_SS(regs->regs.skas.regs) = sc.ss; | 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 | 50 | ||
54 | err = restore_fp_registers(userspace_pid[0], fpregs); | 51 | err = restore_fp_registers(userspace_pid[0], fpregs); |
55 | if(err < 0){ | 52 | if(err < 0){ |
@@ -62,11 +59,11 @@ static int copy_sc_from_user_skas(struct pt_regs *regs, | |||
62 | } | 59 | } |
63 | 60 | ||
64 | int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, | 61 | int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, |
65 | struct pt_regs *regs, unsigned long fault_addr, | 62 | struct pt_regs *regs) |
66 | int fault_type) | ||
67 | { | 63 | { |
68 | struct sigcontext sc; | 64 | struct sigcontext sc; |
69 | unsigned long fpregs[HOST_FP_SIZE]; | 65 | unsigned long fpregs[HOST_FP_SIZE]; |
66 | struct faultinfo * fi = ¤t->thread.arch.faultinfo; | ||
70 | int err; | 67 | int err; |
71 | 68 | ||
72 | sc.gs = REGS_GS(regs->regs.skas.regs); | 69 | sc.gs = REGS_GS(regs->regs.skas.regs); |
@@ -86,9 +83,9 @@ int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, | |||
86 | sc.eflags = REGS_EFLAGS(regs->regs.skas.regs); | 83 | sc.eflags = REGS_EFLAGS(regs->regs.skas.regs); |
87 | sc.esp_at_signal = regs->regs.skas.regs[UESP]; | 84 | sc.esp_at_signal = regs->regs.skas.regs[UESP]; |
88 | sc.ss = regs->regs.skas.regs[SS]; | 85 | sc.ss = regs->regs.skas.regs[SS]; |
89 | sc.cr2 = fault_addr; | 86 | sc.cr2 = fi->cr2; |
90 | sc.err = TO_SC_ERR(fault_type); | 87 | sc.err = fi->error_code; |
91 | sc.trapno = regs->regs.skas.trap_type; | 88 | sc.trapno = fi->trap_no; |
92 | 89 | ||
93 | err = save_fp_registers(userspace_pid[0], fpregs); | 90 | err = save_fp_registers(userspace_pid[0], fpregs); |
94 | if(err < 0){ | 91 | if(err < 0){ |
@@ -167,9 +164,7 @@ static int copy_sc_to_user(struct sigcontext *to, struct _fpstate *fp, | |||
167 | { | 164 | { |
168 | return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs), | 165 | return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs), |
169 | sizeof(*fp)), | 166 | sizeof(*fp)), |
170 | copy_sc_to_user_skas(to, fp, from, | 167 | copy_sc_to_user_skas(to, fp, from))); |
171 | current->thread.cr2, | ||
172 | current->thread.err))); | ||
173 | } | 168 | } |
174 | 169 | ||
175 | static int copy_ucontext_to_user(struct ucontext *uc, struct _fpstate *fp, | 170 | static int copy_ucontext_to_user(struct ucontext *uc, struct _fpstate *fp, |
diff --git a/arch/um/sys-x86_64/signal.c b/arch/um/sys-x86_64/signal.c index 5bc5a0d796e5..b740177066a0 100644 --- a/arch/um/sys-x86_64/signal.c +++ b/arch/um/sys-x86_64/signal.c | |||
@@ -57,7 +57,7 @@ static int copy_sc_from_user_skas(struct pt_regs *regs, | |||
57 | int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, | 57 | int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, |
58 | struct pt_regs *regs, unsigned long mask) | 58 | struct pt_regs *regs, unsigned long mask) |
59 | { | 59 | { |
60 | unsigned long eflags; | 60 | struct faultinfo * fi = ¤t->thread.arch.faultinfo; |
61 | int err = 0; | 61 | int err = 0; |
62 | 62 | ||
63 | err |= __put_user(0, &to->gs); | 63 | err |= __put_user(0, &to->gs); |
@@ -84,14 +84,16 @@ int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, | |||
84 | err |= PUTREG(regs, R14, to, r14); | 84 | err |= PUTREG(regs, R14, to, r14); |
85 | err |= PUTREG(regs, R15, to, r15); | 85 | err |= PUTREG(regs, R15, to, r15); |
86 | err |= PUTREG(regs, CS, to, cs); /* XXX x86_64 doesn't do this */ | 86 | err |= PUTREG(regs, CS, to, cs); /* XXX x86_64 doesn't do this */ |
87 | err |= __put_user(current->thread.err, &to->err); | 87 | |
88 | err |= __put_user(current->thread.trap_no, &to->trapno); | 88 | err |= __put_user(fi->cr2, &to->cr2); |
89 | err |= __put_user(fi->error_code, &to->err); | ||
90 | err |= __put_user(fi->trap_no, &to->trapno); | ||
91 | |||
89 | err |= PUTREG(regs, RIP, to, rip); | 92 | err |= PUTREG(regs, RIP, to, rip); |
90 | err |= PUTREG(regs, EFLAGS, to, eflags); | 93 | err |= PUTREG(regs, EFLAGS, to, eflags); |
91 | #undef PUTREG | 94 | #undef PUTREG |
92 | 95 | ||
93 | err |= __put_user(mask, &to->oldmask); | 96 | err |= __put_user(mask, &to->oldmask); |
94 | err |= __put_user(current->thread.cr2, &to->cr2); | ||
95 | 97 | ||
96 | return(err); | 98 | return(err); |
97 | } | 99 | } |
diff --git a/include/asm-um/processor-generic.h b/include/asm-um/processor-generic.h index b953b1ad3b02..b2fc94fbc2d9 100644 --- a/include/asm-um/processor-generic.h +++ b/include/asm-um/processor-generic.h | |||
@@ -24,9 +24,6 @@ struct thread_struct { | |||
24 | int forking; | 24 | int forking; |
25 | int nsyscalls; | 25 | int nsyscalls; |
26 | struct pt_regs regs; | 26 | struct pt_regs regs; |
27 | unsigned long cr2; | ||
28 | int err; | ||
29 | unsigned long trap_no; | ||
30 | int singlestep_syscall; | 27 | int singlestep_syscall; |
31 | void *fault_addr; | 28 | void *fault_addr; |
32 | void *fault_catcher; | 29 | void *fault_catcher; |
@@ -74,8 +71,6 @@ struct thread_struct { | |||
74 | .forking = 0, \ | 71 | .forking = 0, \ |
75 | .nsyscalls = 0, \ | 72 | .nsyscalls = 0, \ |
76 | .regs = EMPTY_REGS, \ | 73 | .regs = EMPTY_REGS, \ |
77 | .cr2 = 0, \ | ||
78 | .err = 0, \ | ||
79 | .fault_addr = NULL, \ | 74 | .fault_addr = NULL, \ |
80 | .prev_sched = NULL, \ | 75 | .prev_sched = NULL, \ |
81 | .temp_stack = 0, \ | 76 | .temp_stack = 0, \ |
diff --git a/include/asm-um/processor-i386.h b/include/asm-um/processor-i386.h index 2deb8f1adbf1..431bad3ae9d7 100644 --- a/include/asm-um/processor-i386.h +++ b/include/asm-um/processor-i386.h | |||
@@ -9,13 +9,18 @@ | |||
9 | extern int host_has_xmm; | 9 | extern int host_has_xmm; |
10 | extern int host_has_cmov; | 10 | extern int host_has_cmov; |
11 | 11 | ||
12 | /* include faultinfo structure */ | ||
13 | #include "sysdep/faultinfo.h" | ||
14 | |||
12 | struct arch_thread { | 15 | struct arch_thread { |
13 | unsigned long debugregs[8]; | 16 | unsigned long debugregs[8]; |
14 | int debugregs_seq; | 17 | int debugregs_seq; |
18 | struct faultinfo faultinfo; | ||
15 | }; | 19 | }; |
16 | 20 | ||
17 | #define INIT_ARCH_THREAD { .debugregs = { [ 0 ... 7 ] = 0 }, \ | 21 | #define INIT_ARCH_THREAD { .debugregs = { [ 0 ... 7 ] = 0 }, \ |
18 | .debugregs_seq = 0 } | 22 | .debugregs_seq = 0, \ |
23 | .faultinfo = { 0, 0, 0 } } | ||
19 | 24 | ||
20 | #include "asm/arch/user.h" | 25 | #include "asm/arch/user.h" |
21 | 26 | ||
diff --git a/include/asm-um/processor-x86_64.h b/include/asm-um/processor-x86_64.h index a1ae3a4cd938..0beb9a42ae05 100644 --- a/include/asm-um/processor-x86_64.h +++ b/include/asm-um/processor-x86_64.h | |||
@@ -7,9 +7,13 @@ | |||
7 | #ifndef __UM_PROCESSOR_X86_64_H | 7 | #ifndef __UM_PROCESSOR_X86_64_H |
8 | #define __UM_PROCESSOR_X86_64_H | 8 | #define __UM_PROCESSOR_X86_64_H |
9 | 9 | ||
10 | #include "asm/arch/user.h" | 10 | /* include faultinfo structure */ |
11 | #include "sysdep/faultinfo.h" | ||
11 | 12 | ||
12 | struct arch_thread { | 13 | struct arch_thread { |
14 | unsigned long debugregs[8]; | ||
15 | int debugregs_seq; | ||
16 | struct faultinfo faultinfo; | ||
13 | }; | 17 | }; |
14 | 18 | ||
15 | /* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */ | 19 | /* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */ |
@@ -20,7 +24,11 @@ extern inline void rep_nop(void) | |||
20 | 24 | ||
21 | #define cpu_relax() rep_nop() | 25 | #define cpu_relax() rep_nop() |
22 | 26 | ||
23 | #define INIT_ARCH_THREAD { } | 27 | #define INIT_ARCH_THREAD { .debugregs = { [ 0 ... 7 ] = 0 }, \ |
28 | .debugregs_seq = 0, \ | ||
29 | .faultinfo = { 0, 0, 0 } } | ||
30 | |||
31 | #include "asm/arch/user.h" | ||
24 | 32 | ||
25 | #define current_text_addr() \ | 33 | #define current_text_addr() \ |
26 | ({ void *pc; __asm__("movq $1f,%0\n1:":"=g" (pc)); pc; }) | 34 | ({ void *pc; __asm__("movq $1f,%0\n1:":"=g" (pc)); pc; }) |