[SPARC64]: Convert to use generic exception table support.
The funny "range" exception table entries we had were only used by the compat layer socketcall assembly, and it wasn't even needed there. For free we now get proper exception table sorting and fast binary searching. Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
705747ab87
commit
8cf14af0a7
|
@ -158,163 +158,163 @@ sys32_socketcall: /* %o0=call, %o1=args */
|
||||||
jmpl %g2 + %o0, %g0
|
jmpl %g2 + %o0, %g0
|
||||||
nop
|
nop
|
||||||
|
|
||||||
/* Each entry is exactly 32 bytes. */
|
|
||||||
.align 32
|
.align 32
|
||||||
__socketcall_table_begin:
|
__socketcall_table_begin:
|
||||||
|
|
||||||
|
/* Each entry is exactly 32 bytes. */
|
||||||
do_sys_socket: /* sys_socket(int, int, int) */
|
do_sys_socket: /* sys_socket(int, int, int) */
|
||||||
ldswa [%o1 + 0x0] %asi, %o0
|
1: ldswa [%o1 + 0x0] %asi, %o0
|
||||||
sethi %hi(sys_socket), %g1
|
sethi %hi(sys_socket), %g1
|
||||||
ldswa [%o1 + 0x8] %asi, %o2
|
2: ldswa [%o1 + 0x8] %asi, %o2
|
||||||
jmpl %g1 + %lo(sys_socket), %g0
|
jmpl %g1 + %lo(sys_socket), %g0
|
||||||
ldswa [%o1 + 0x4] %asi, %o1
|
3: ldswa [%o1 + 0x4] %asi, %o1
|
||||||
nop
|
nop
|
||||||
nop
|
nop
|
||||||
nop
|
nop
|
||||||
do_sys_bind: /* sys_bind(int fd, struct sockaddr *, int) */
|
do_sys_bind: /* sys_bind(int fd, struct sockaddr *, int) */
|
||||||
ldswa [%o1 + 0x0] %asi, %o0
|
4: ldswa [%o1 + 0x0] %asi, %o0
|
||||||
sethi %hi(sys_bind), %g1
|
sethi %hi(sys_bind), %g1
|
||||||
ldswa [%o1 + 0x8] %asi, %o2
|
5: ldswa [%o1 + 0x8] %asi, %o2
|
||||||
jmpl %g1 + %lo(sys_bind), %g0
|
jmpl %g1 + %lo(sys_bind), %g0
|
||||||
lduwa [%o1 + 0x4] %asi, %o1
|
6: lduwa [%o1 + 0x4] %asi, %o1
|
||||||
nop
|
nop
|
||||||
nop
|
nop
|
||||||
nop
|
nop
|
||||||
do_sys_connect: /* sys_connect(int, struct sockaddr *, int) */
|
do_sys_connect: /* sys_connect(int, struct sockaddr *, int) */
|
||||||
ldswa [%o1 + 0x0] %asi, %o0
|
7: ldswa [%o1 + 0x0] %asi, %o0
|
||||||
sethi %hi(sys_connect), %g1
|
sethi %hi(sys_connect), %g1
|
||||||
ldswa [%o1 + 0x8] %asi, %o2
|
8: ldswa [%o1 + 0x8] %asi, %o2
|
||||||
jmpl %g1 + %lo(sys_connect), %g0
|
jmpl %g1 + %lo(sys_connect), %g0
|
||||||
lduwa [%o1 + 0x4] %asi, %o1
|
9: lduwa [%o1 + 0x4] %asi, %o1
|
||||||
nop
|
nop
|
||||||
nop
|
nop
|
||||||
nop
|
nop
|
||||||
do_sys_listen: /* sys_listen(int, int) */
|
do_sys_listen: /* sys_listen(int, int) */
|
||||||
ldswa [%o1 + 0x0] %asi, %o0
|
10: ldswa [%o1 + 0x0] %asi, %o0
|
||||||
sethi %hi(sys_listen), %g1
|
sethi %hi(sys_listen), %g1
|
||||||
jmpl %g1 + %lo(sys_listen), %g0
|
jmpl %g1 + %lo(sys_listen), %g0
|
||||||
ldswa [%o1 + 0x4] %asi, %o1
|
11: ldswa [%o1 + 0x4] %asi, %o1
|
||||||
nop
|
nop
|
||||||
nop
|
nop
|
||||||
nop
|
nop
|
||||||
nop
|
nop
|
||||||
do_sys_accept: /* sys_accept(int, struct sockaddr *, int *) */
|
do_sys_accept: /* sys_accept(int, struct sockaddr *, int *) */
|
||||||
ldswa [%o1 + 0x0] %asi, %o0
|
12: ldswa [%o1 + 0x0] %asi, %o0
|
||||||
sethi %hi(sys_accept), %g1
|
sethi %hi(sys_accept), %g1
|
||||||
lduwa [%o1 + 0x8] %asi, %o2
|
13: lduwa [%o1 + 0x8] %asi, %o2
|
||||||
jmpl %g1 + %lo(sys_accept), %g0
|
jmpl %g1 + %lo(sys_accept), %g0
|
||||||
lduwa [%o1 + 0x4] %asi, %o1
|
14: lduwa [%o1 + 0x4] %asi, %o1
|
||||||
nop
|
nop
|
||||||
nop
|
nop
|
||||||
nop
|
nop
|
||||||
do_sys_getsockname: /* sys_getsockname(int, struct sockaddr *, int *) */
|
do_sys_getsockname: /* sys_getsockname(int, struct sockaddr *, int *) */
|
||||||
ldswa [%o1 + 0x0] %asi, %o0
|
15: ldswa [%o1 + 0x0] %asi, %o0
|
||||||
sethi %hi(sys_getsockname), %g1
|
sethi %hi(sys_getsockname), %g1
|
||||||
lduwa [%o1 + 0x8] %asi, %o2
|
16: lduwa [%o1 + 0x8] %asi, %o2
|
||||||
jmpl %g1 + %lo(sys_getsockname), %g0
|
jmpl %g1 + %lo(sys_getsockname), %g0
|
||||||
lduwa [%o1 + 0x4] %asi, %o1
|
17: lduwa [%o1 + 0x4] %asi, %o1
|
||||||
nop
|
nop
|
||||||
nop
|
nop
|
||||||
nop
|
nop
|
||||||
do_sys_getpeername: /* sys_getpeername(int, struct sockaddr *, int *) */
|
do_sys_getpeername: /* sys_getpeername(int, struct sockaddr *, int *) */
|
||||||
ldswa [%o1 + 0x0] %asi, %o0
|
18: ldswa [%o1 + 0x0] %asi, %o0
|
||||||
sethi %hi(sys_getpeername), %g1
|
sethi %hi(sys_getpeername), %g1
|
||||||
lduwa [%o1 + 0x8] %asi, %o2
|
19: lduwa [%o1 + 0x8] %asi, %o2
|
||||||
jmpl %g1 + %lo(sys_getpeername), %g0
|
jmpl %g1 + %lo(sys_getpeername), %g0
|
||||||
lduwa [%o1 + 0x4] %asi, %o1
|
20: lduwa [%o1 + 0x4] %asi, %o1
|
||||||
nop
|
nop
|
||||||
nop
|
nop
|
||||||
nop
|
nop
|
||||||
do_sys_socketpair: /* sys_socketpair(int, int, int, int *) */
|
do_sys_socketpair: /* sys_socketpair(int, int, int, int *) */
|
||||||
ldswa [%o1 + 0x0] %asi, %o0
|
21: ldswa [%o1 + 0x0] %asi, %o0
|
||||||
sethi %hi(sys_socketpair), %g1
|
sethi %hi(sys_socketpair), %g1
|
||||||
ldswa [%o1 + 0x8] %asi, %o2
|
22: ldswa [%o1 + 0x8] %asi, %o2
|
||||||
lduwa [%o1 + 0xc] %asi, %o3
|
23: lduwa [%o1 + 0xc] %asi, %o3
|
||||||
jmpl %g1 + %lo(sys_socketpair), %g0
|
jmpl %g1 + %lo(sys_socketpair), %g0
|
||||||
ldswa [%o1 + 0x4] %asi, %o1
|
24: ldswa [%o1 + 0x4] %asi, %o1
|
||||||
nop
|
nop
|
||||||
nop
|
nop
|
||||||
do_sys_send: /* sys_send(int, void *, size_t, unsigned int) */
|
do_sys_send: /* sys_send(int, void *, size_t, unsigned int) */
|
||||||
ldswa [%o1 + 0x0] %asi, %o0
|
25: ldswa [%o1 + 0x0] %asi, %o0
|
||||||
sethi %hi(sys_send), %g1
|
sethi %hi(sys_send), %g1
|
||||||
lduwa [%o1 + 0x8] %asi, %o2
|
26: lduwa [%o1 + 0x8] %asi, %o2
|
||||||
lduwa [%o1 + 0xc] %asi, %o3
|
27: lduwa [%o1 + 0xc] %asi, %o3
|
||||||
jmpl %g1 + %lo(sys_send), %g0
|
jmpl %g1 + %lo(sys_send), %g0
|
||||||
lduwa [%o1 + 0x4] %asi, %o1
|
28: lduwa [%o1 + 0x4] %asi, %o1
|
||||||
nop
|
nop
|
||||||
nop
|
nop
|
||||||
do_sys_recv: /* sys_recv(int, void *, size_t, unsigned int) */
|
do_sys_recv: /* sys_recv(int, void *, size_t, unsigned int) */
|
||||||
ldswa [%o1 + 0x0] %asi, %o0
|
29: ldswa [%o1 + 0x0] %asi, %o0
|
||||||
sethi %hi(sys_recv), %g1
|
sethi %hi(sys_recv), %g1
|
||||||
lduwa [%o1 + 0x8] %asi, %o2
|
30: lduwa [%o1 + 0x8] %asi, %o2
|
||||||
lduwa [%o1 + 0xc] %asi, %o3
|
31: lduwa [%o1 + 0xc] %asi, %o3
|
||||||
jmpl %g1 + %lo(sys_recv), %g0
|
jmpl %g1 + %lo(sys_recv), %g0
|
||||||
lduwa [%o1 + 0x4] %asi, %o1
|
32: lduwa [%o1 + 0x4] %asi, %o1
|
||||||
nop
|
nop
|
||||||
nop
|
nop
|
||||||
do_sys_sendto: /* sys_sendto(int, u32, compat_size_t, unsigned int, u32, int) */
|
do_sys_sendto: /* sys_sendto(int, u32, compat_size_t, unsigned int, u32, int) */
|
||||||
ldswa [%o1 + 0x0] %asi, %o0
|
33: ldswa [%o1 + 0x0] %asi, %o0
|
||||||
sethi %hi(sys_sendto), %g1
|
sethi %hi(sys_sendto), %g1
|
||||||
lduwa [%o1 + 0x8] %asi, %o2
|
34: lduwa [%o1 + 0x8] %asi, %o2
|
||||||
lduwa [%o1 + 0xc] %asi, %o3
|
35: lduwa [%o1 + 0xc] %asi, %o3
|
||||||
lduwa [%o1 + 0x10] %asi, %o4
|
36: lduwa [%o1 + 0x10] %asi, %o4
|
||||||
ldswa [%o1 + 0x14] %asi, %o5
|
37: ldswa [%o1 + 0x14] %asi, %o5
|
||||||
jmpl %g1 + %lo(sys_sendto), %g0
|
jmpl %g1 + %lo(sys_sendto), %g0
|
||||||
lduwa [%o1 + 0x4] %asi, %o1
|
38: lduwa [%o1 + 0x4] %asi, %o1
|
||||||
do_sys_recvfrom: /* sys_recvfrom(int, u32, compat_size_t, unsigned int, u32, u32) */
|
do_sys_recvfrom: /* sys_recvfrom(int, u32, compat_size_t, unsigned int, u32, u32) */
|
||||||
ldswa [%o1 + 0x0] %asi, %o0
|
39: ldswa [%o1 + 0x0] %asi, %o0
|
||||||
sethi %hi(sys_recvfrom), %g1
|
sethi %hi(sys_recvfrom), %g1
|
||||||
lduwa [%o1 + 0x8] %asi, %o2
|
40: lduwa [%o1 + 0x8] %asi, %o2
|
||||||
lduwa [%o1 + 0xc] %asi, %o3
|
41: lduwa [%o1 + 0xc] %asi, %o3
|
||||||
lduwa [%o1 + 0x10] %asi, %o4
|
42: lduwa [%o1 + 0x10] %asi, %o4
|
||||||
lduwa [%o1 + 0x14] %asi, %o5
|
43: lduwa [%o1 + 0x14] %asi, %o5
|
||||||
jmpl %g1 + %lo(sys_recvfrom), %g0
|
jmpl %g1 + %lo(sys_recvfrom), %g0
|
||||||
lduwa [%o1 + 0x4] %asi, %o1
|
44: lduwa [%o1 + 0x4] %asi, %o1
|
||||||
do_sys_shutdown: /* sys_shutdown(int, int) */
|
do_sys_shutdown: /* sys_shutdown(int, int) */
|
||||||
ldswa [%o1 + 0x0] %asi, %o0
|
45: ldswa [%o1 + 0x0] %asi, %o0
|
||||||
sethi %hi(sys_shutdown), %g1
|
sethi %hi(sys_shutdown), %g1
|
||||||
jmpl %g1 + %lo(sys_shutdown), %g0
|
jmpl %g1 + %lo(sys_shutdown), %g0
|
||||||
ldswa [%o1 + 0x4] %asi, %o1
|
46: ldswa [%o1 + 0x4] %asi, %o1
|
||||||
nop
|
nop
|
||||||
nop
|
nop
|
||||||
nop
|
nop
|
||||||
nop
|
nop
|
||||||
do_sys_setsockopt: /* compat_sys_setsockopt(int, int, int, char *, int) */
|
do_sys_setsockopt: /* compat_sys_setsockopt(int, int, int, char *, int) */
|
||||||
ldswa [%o1 + 0x0] %asi, %o0
|
47: ldswa [%o1 + 0x0] %asi, %o0
|
||||||
sethi %hi(compat_sys_setsockopt), %g1
|
sethi %hi(compat_sys_setsockopt), %g1
|
||||||
ldswa [%o1 + 0x8] %asi, %o2
|
48: ldswa [%o1 + 0x8] %asi, %o2
|
||||||
lduwa [%o1 + 0xc] %asi, %o3
|
49: lduwa [%o1 + 0xc] %asi, %o3
|
||||||
ldswa [%o1 + 0x10] %asi, %o4
|
50: ldswa [%o1 + 0x10] %asi, %o4
|
||||||
jmpl %g1 + %lo(compat_sys_setsockopt), %g0
|
jmpl %g1 + %lo(compat_sys_setsockopt), %g0
|
||||||
ldswa [%o1 + 0x4] %asi, %o1
|
51: ldswa [%o1 + 0x4] %asi, %o1
|
||||||
nop
|
nop
|
||||||
do_sys_getsockopt: /* compat_sys_getsockopt(int, int, int, u32, u32) */
|
do_sys_getsockopt: /* compat_sys_getsockopt(int, int, int, u32, u32) */
|
||||||
ldswa [%o1 + 0x0] %asi, %o0
|
52: ldswa [%o1 + 0x0] %asi, %o0
|
||||||
sethi %hi(compat_sys_getsockopt), %g1
|
sethi %hi(compat_sys_getsockopt), %g1
|
||||||
ldswa [%o1 + 0x8] %asi, %o2
|
53: ldswa [%o1 + 0x8] %asi, %o2
|
||||||
lduwa [%o1 + 0xc] %asi, %o3
|
54: lduwa [%o1 + 0xc] %asi, %o3
|
||||||
lduwa [%o1 + 0x10] %asi, %o4
|
55: lduwa [%o1 + 0x10] %asi, %o4
|
||||||
jmpl %g1 + %lo(compat_sys_getsockopt), %g0
|
jmpl %g1 + %lo(compat_sys_getsockopt), %g0
|
||||||
ldswa [%o1 + 0x4] %asi, %o1
|
56: ldswa [%o1 + 0x4] %asi, %o1
|
||||||
nop
|
nop
|
||||||
do_sys_sendmsg: /* compat_sys_sendmsg(int, struct compat_msghdr *, unsigned int) */
|
do_sys_sendmsg: /* compat_sys_sendmsg(int, struct compat_msghdr *, unsigned int) */
|
||||||
ldswa [%o1 + 0x0] %asi, %o0
|
57: ldswa [%o1 + 0x0] %asi, %o0
|
||||||
sethi %hi(compat_sys_sendmsg), %g1
|
sethi %hi(compat_sys_sendmsg), %g1
|
||||||
lduwa [%o1 + 0x8] %asi, %o2
|
58: lduwa [%o1 + 0x8] %asi, %o2
|
||||||
jmpl %g1 + %lo(compat_sys_sendmsg), %g0
|
jmpl %g1 + %lo(compat_sys_sendmsg), %g0
|
||||||
lduwa [%o1 + 0x4] %asi, %o1
|
59: lduwa [%o1 + 0x4] %asi, %o1
|
||||||
nop
|
nop
|
||||||
nop
|
nop
|
||||||
nop
|
nop
|
||||||
do_sys_recvmsg: /* compat_sys_recvmsg(int, struct compat_msghdr *, unsigned int) */
|
do_sys_recvmsg: /* compat_sys_recvmsg(int, struct compat_msghdr *, unsigned int) */
|
||||||
ldswa [%o1 + 0x0] %asi, %o0
|
60: ldswa [%o1 + 0x0] %asi, %o0
|
||||||
sethi %hi(compat_sys_recvmsg), %g1
|
sethi %hi(compat_sys_recvmsg), %g1
|
||||||
lduwa [%o1 + 0x8] %asi, %o2
|
61: lduwa [%o1 + 0x8] %asi, %o2
|
||||||
jmpl %g1 + %lo(compat_sys_recvmsg), %g0
|
jmpl %g1 + %lo(compat_sys_recvmsg), %g0
|
||||||
lduwa [%o1 + 0x4] %asi, %o1
|
62: lduwa [%o1 + 0x4] %asi, %o1
|
||||||
nop
|
nop
|
||||||
nop
|
nop
|
||||||
nop
|
nop
|
||||||
__socketcall_table_end:
|
|
||||||
|
|
||||||
do_einval:
|
do_einval:
|
||||||
retl
|
retl
|
||||||
|
@ -325,5 +325,20 @@ do_efault:
|
||||||
|
|
||||||
.section __ex_table
|
.section __ex_table
|
||||||
.align 4
|
.align 4
|
||||||
.word __socketcall_table_begin, 0, __socketcall_table_end, do_efault
|
.word 1b, do_efault, 2b, do_efault, 3b, do_efault, 4b, do_efault
|
||||||
|
.word 5b, do_efault, 6b, do_efault, 7b, do_efault, 8b, do_efault
|
||||||
|
.word 9b, do_efault, 10b, do_efault, 11b, do_efault, 12b, do_efault
|
||||||
|
.word 13b, do_efault, 14b, do_efault, 15b, do_efault, 16b, do_efault
|
||||||
|
.word 17b, do_efault, 18b, do_efault, 19b, do_efault, 20b, do_efault
|
||||||
|
.word 21b, do_efault, 22b, do_efault, 23b, do_efault, 24b, do_efault
|
||||||
|
.word 25b, do_efault, 26b, do_efault, 27b, do_efault, 28b, do_efault
|
||||||
|
.word 29b, do_efault, 30b, do_efault, 31b, do_efault, 32b, do_efault
|
||||||
|
.word 33b, do_efault, 34b, do_efault, 35b, do_efault, 36b, do_efault
|
||||||
|
.word 37b, do_efault, 38b, do_efault, 39b, do_efault, 40b, do_efault
|
||||||
|
.word 41b, do_efault, 42b, do_efault, 43b, do_efault, 44b, do_efault
|
||||||
|
.word 45b, do_efault, 46b, do_efault, 47b, do_efault, 48b, do_efault
|
||||||
|
.word 49b, do_efault, 50b, do_efault, 51b, do_efault, 52b, do_efault
|
||||||
|
.word 53b, do_efault, 54b, do_efault, 55b, do_efault, 56b, do_efault
|
||||||
|
.word 57b, do_efault, 58b, do_efault, 59b, do_efault, 60b, do_efault
|
||||||
|
.word 61b, do_efault, 62b, do_efault
|
||||||
.previous
|
.previous
|
||||||
|
|
|
@ -189,19 +189,18 @@ void spitfire_data_access_exception(struct pt_regs *regs, unsigned long sfsr, un
|
||||||
|
|
||||||
if (regs->tstate & TSTATE_PRIV) {
|
if (regs->tstate & TSTATE_PRIV) {
|
||||||
/* Test if this comes from uaccess places. */
|
/* Test if this comes from uaccess places. */
|
||||||
unsigned long fixup;
|
const struct exception_table_entry *entry;
|
||||||
unsigned long g2 = regs->u_regs[UREG_G2];
|
|
||||||
|
|
||||||
if ((fixup = search_extables_range(regs->tpc, &g2))) {
|
entry = search_exception_tables(regs->tpc);
|
||||||
/* Ouch, somebody is trying ugly VM hole tricks on us... */
|
if (entry) {
|
||||||
|
/* Ouch, somebody is trying VM hole tricks on us... */
|
||||||
#ifdef DEBUG_EXCEPTIONS
|
#ifdef DEBUG_EXCEPTIONS
|
||||||
printk("Exception: PC<%016lx> faddr<UNKNOWN>\n", regs->tpc);
|
printk("Exception: PC<%016lx> faddr<UNKNOWN>\n", regs->tpc);
|
||||||
printk("EX_TABLE: insn<%016lx> fixup<%016lx> "
|
printk("EX_TABLE: insn<%016lx> fixup<%016lx>\n",
|
||||||
"g2<%016lx>\n", regs->tpc, fixup, g2);
|
regs->tpc, entry->fixup);
|
||||||
#endif
|
#endif
|
||||||
regs->tpc = fixup;
|
regs->tpc = entry->fixup;
|
||||||
regs->tnpc = regs->tpc + 4;
|
regs->tnpc = regs->tpc + 4;
|
||||||
regs->u_regs[UREG_G2] = g2;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* Shit... */
|
/* Shit... */
|
||||||
|
@ -1610,10 +1609,10 @@ void cheetah_deferred_handler(struct pt_regs *regs, unsigned long afsr, unsigned
|
||||||
/* OK, usermode access. */
|
/* OK, usermode access. */
|
||||||
recoverable = 1;
|
recoverable = 1;
|
||||||
} else {
|
} else {
|
||||||
unsigned long g2 = regs->u_regs[UREG_G2];
|
const struct exception_table_entry *entry;
|
||||||
unsigned long fixup = search_extables_range(regs->tpc, &g2);
|
|
||||||
|
|
||||||
if (fixup != 0UL) {
|
entry = search_exception_tables(regs->tpc);
|
||||||
|
if (entry) {
|
||||||
/* OK, kernel access to userspace. */
|
/* OK, kernel access to userspace. */
|
||||||
recoverable = 1;
|
recoverable = 1;
|
||||||
|
|
||||||
|
@ -1632,9 +1631,8 @@ void cheetah_deferred_handler(struct pt_regs *regs, unsigned long afsr, unsigned
|
||||||
* recoverable condition.
|
* recoverable condition.
|
||||||
*/
|
*/
|
||||||
if (recoverable) {
|
if (recoverable) {
|
||||||
regs->tpc = fixup;
|
regs->tpc = entry->fixup;
|
||||||
regs->tnpc = regs->tpc + 4;
|
regs->tnpc = regs->tpc + 4;
|
||||||
regs->u_regs[UREG_G2] = g2;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -246,10 +246,10 @@ void kernel_mna_trap_fault(void)
|
||||||
{
|
{
|
||||||
struct pt_regs *regs = current_thread_info()->kern_una_regs;
|
struct pt_regs *regs = current_thread_info()->kern_una_regs;
|
||||||
unsigned int insn = current_thread_info()->kern_una_insn;
|
unsigned int insn = current_thread_info()->kern_una_insn;
|
||||||
unsigned long g2 = regs->u_regs[UREG_G2];
|
const struct exception_table_entry *entry;
|
||||||
unsigned long fixup = search_extables_range(regs->tpc, &g2);
|
|
||||||
|
|
||||||
if (!fixup) {
|
entry = search_exception_tables(regs->tpc);
|
||||||
|
if (!entry) {
|
||||||
unsigned long address;
|
unsigned long address;
|
||||||
|
|
||||||
address = compute_effective_address(regs, insn,
|
address = compute_effective_address(regs, insn,
|
||||||
|
@ -270,9 +270,8 @@ void kernel_mna_trap_fault(void)
|
||||||
die_if_kernel("Oops", regs);
|
die_if_kernel("Oops", regs);
|
||||||
/* Not reached */
|
/* Not reached */
|
||||||
}
|
}
|
||||||
regs->tpc = fixup;
|
regs->tpc = entry->fixup;
|
||||||
regs->tnpc = regs->tpc + 4;
|
regs->tnpc = regs->tpc + 4;
|
||||||
regs->u_regs [UREG_G2] = g2;
|
|
||||||
|
|
||||||
regs->tstate &= ~TSTATE_ASI;
|
regs->tstate &= ~TSTATE_ASI;
|
||||||
regs->tstate |= (ASI_AIUS << 24UL);
|
regs->tstate |= (ASI_AIUS << 24UL);
|
||||||
|
|
|
@ -5,6 +5,6 @@
|
||||||
EXTRA_AFLAGS := -ansi
|
EXTRA_AFLAGS := -ansi
|
||||||
EXTRA_CFLAGS := -Werror
|
EXTRA_CFLAGS := -Werror
|
||||||
|
|
||||||
obj-y := ultra.o tlb.o fault.o init.o generic.o extable.o
|
obj-y := ultra.o tlb.o fault.o init.o generic.o
|
||||||
|
|
||||||
obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
|
obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
|
||||||
|
|
|
@ -1,80 +0,0 @@
|
||||||
/*
|
|
||||||
* linux/arch/sparc64/mm/extable.c
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/config.h>
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <asm/uaccess.h>
|
|
||||||
|
|
||||||
extern const struct exception_table_entry __start___ex_table[];
|
|
||||||
extern const struct exception_table_entry __stop___ex_table[];
|
|
||||||
|
|
||||||
void sort_extable(struct exception_table_entry *start,
|
|
||||||
struct exception_table_entry *finish)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Caller knows they are in a range if ret->fixup == 0 */
|
|
||||||
const struct exception_table_entry *
|
|
||||||
search_extable(const struct exception_table_entry *start,
|
|
||||||
const struct exception_table_entry *last,
|
|
||||||
unsigned long value)
|
|
||||||
{
|
|
||||||
const struct exception_table_entry *walk;
|
|
||||||
|
|
||||||
/* Single insn entries are encoded as:
|
|
||||||
* word 1: insn address
|
|
||||||
* word 2: fixup code address
|
|
||||||
*
|
|
||||||
* Range entries are encoded as:
|
|
||||||
* word 1: first insn address
|
|
||||||
* word 2: 0
|
|
||||||
* word 3: last insn address + 4 bytes
|
|
||||||
* word 4: fixup code address
|
|
||||||
*
|
|
||||||
* See asm/uaccess.h for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* 1. Try to find an exact match. */
|
|
||||||
for (walk = start; walk <= last; walk++) {
|
|
||||||
if (walk->fixup == 0) {
|
|
||||||
/* A range entry, skip both parts. */
|
|
||||||
walk++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (walk->insn == value)
|
|
||||||
return walk;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 2. Try to find a range match. */
|
|
||||||
for (walk = start; walk <= (last - 1); walk++) {
|
|
||||||
if (walk->fixup)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (walk[0].insn <= value && walk[1].insn > value)
|
|
||||||
return walk;
|
|
||||||
|
|
||||||
walk++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Special extable search, which handles ranges. Returns fixup */
|
|
||||||
unsigned long search_extables_range(unsigned long addr, unsigned long *g2)
|
|
||||||
{
|
|
||||||
const struct exception_table_entry *entry;
|
|
||||||
|
|
||||||
entry = search_exception_tables(addr);
|
|
||||||
if (!entry)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Inside range? Fix g2 and return correct fixup */
|
|
||||||
if (!entry->fixup) {
|
|
||||||
*g2 = (addr - entry->insn) / 4;
|
|
||||||
return (entry + 1)->fixup;
|
|
||||||
}
|
|
||||||
|
|
||||||
return entry->fixup;
|
|
||||||
}
|
|
|
@ -242,7 +242,6 @@ static unsigned int get_fault_insn(struct pt_regs *regs, unsigned int insn)
|
||||||
static void do_kernel_fault(struct pt_regs *regs, int si_code, int fault_code,
|
static void do_kernel_fault(struct pt_regs *regs, int si_code, int fault_code,
|
||||||
unsigned int insn, unsigned long address)
|
unsigned int insn, unsigned long address)
|
||||||
{
|
{
|
||||||
unsigned long g2;
|
|
||||||
unsigned char asi = ASI_P;
|
unsigned char asi = ASI_P;
|
||||||
|
|
||||||
if ((!insn) && (regs->tstate & TSTATE_PRIV))
|
if ((!insn) && (regs->tstate & TSTATE_PRIV))
|
||||||
|
@ -273,11 +272,9 @@ static void do_kernel_fault(struct pt_regs *regs, int si_code, int fault_code,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
g2 = regs->u_regs[UREG_G2];
|
|
||||||
|
|
||||||
/* Is this in ex_table? */
|
/* Is this in ex_table? */
|
||||||
if (regs->tstate & TSTATE_PRIV) {
|
if (regs->tstate & TSTATE_PRIV) {
|
||||||
unsigned long fixup;
|
const struct exception_table_entry *entry;
|
||||||
|
|
||||||
if (asi == ASI_P && (insn & 0xc0800000) == 0xc0800000) {
|
if (asi == ASI_P && (insn & 0xc0800000) == 0xc0800000) {
|
||||||
if (insn & 0x2000)
|
if (insn & 0x2000)
|
||||||
|
@ -288,10 +285,9 @@ static void do_kernel_fault(struct pt_regs *regs, int si_code, int fault_code,
|
||||||
|
|
||||||
/* Look in asi.h: All _S asis have LS bit set */
|
/* Look in asi.h: All _S asis have LS bit set */
|
||||||
if ((asi & 0x1) &&
|
if ((asi & 0x1) &&
|
||||||
(fixup = search_extables_range(regs->tpc, &g2))) {
|
(entry = search_exception_tables(regs->tpc))) {
|
||||||
regs->tpc = fixup;
|
regs->tpc = entry->fixup;
|
||||||
regs->tnpc = regs->tpc + 4;
|
regs->tnpc = regs->tpc + 4;
|
||||||
regs->u_regs[UREG_G2] = g2;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -70,25 +70,12 @@ static inline int access_ok(int type, const void __user * addr, unsigned long si
|
||||||
* with the main instruction path. This means when everything is well,
|
* with the main instruction path. This means when everything is well,
|
||||||
* we don't even have to jump over them. Further, they do not intrude
|
* we don't even have to jump over them. Further, they do not intrude
|
||||||
* on our cache or tlb entries.
|
* on our cache or tlb entries.
|
||||||
*
|
|
||||||
* There is a special way how to put a range of potentially faulting
|
|
||||||
* insns (like twenty ldd/std's with now intervening other instructions)
|
|
||||||
* You specify address of first in insn and 0 in fixup and in the next
|
|
||||||
* exception_table_entry you specify last potentially faulting insn + 1
|
|
||||||
* and in fixup the routine which should handle the fault.
|
|
||||||
* That fixup code will get
|
|
||||||
* (faulting_insn_address - first_insn_in_the_range_address)/4
|
|
||||||
* in %g2 (ie. index of the faulting instruction in the range).
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct exception_table_entry
|
struct exception_table_entry {
|
||||||
{
|
unsigned int insn, fixup;
|
||||||
unsigned insn, fixup;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Special exable search, which handles ranges. Returns fixup */
|
|
||||||
unsigned long search_extables_range(unsigned long addr, unsigned long *g2);
|
|
||||||
|
|
||||||
extern void __ret_efault(void);
|
extern void __ret_efault(void);
|
||||||
|
|
||||||
/* Uh, these should become the main single-value transfer routines..
|
/* Uh, these should become the main single-value transfer routines..
|
||||||
|
|
Loading…
Reference in New Issue