[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>

+101 -186
+80 -65
arch/sparc64/kernel/sys32.S
··· 158 jmpl %g2 + %o0, %g0 159 nop 160 161 - /* Each entry is exactly 32 bytes. */ 162 .align 32 163 __socketcall_table_begin: 164 do_sys_socket: /* sys_socket(int, int, int) */ 165 - ldswa [%o1 + 0x0] %asi, %o0 166 sethi %hi(sys_socket), %g1 167 - ldswa [%o1 + 0x8] %asi, %o2 168 jmpl %g1 + %lo(sys_socket), %g0 169 - ldswa [%o1 + 0x4] %asi, %o1 170 nop 171 nop 172 nop 173 do_sys_bind: /* sys_bind(int fd, struct sockaddr *, int) */ 174 - ldswa [%o1 + 0x0] %asi, %o0 175 sethi %hi(sys_bind), %g1 176 - ldswa [%o1 + 0x8] %asi, %o2 177 jmpl %g1 + %lo(sys_bind), %g0 178 - lduwa [%o1 + 0x4] %asi, %o1 179 nop 180 nop 181 nop 182 do_sys_connect: /* sys_connect(int, struct sockaddr *, int) */ 183 - ldswa [%o1 + 0x0] %asi, %o0 184 sethi %hi(sys_connect), %g1 185 - ldswa [%o1 + 0x8] %asi, %o2 186 jmpl %g1 + %lo(sys_connect), %g0 187 - lduwa [%o1 + 0x4] %asi, %o1 188 nop 189 nop 190 nop 191 do_sys_listen: /* sys_listen(int, int) */ 192 - ldswa [%o1 + 0x0] %asi, %o0 193 sethi %hi(sys_listen), %g1 194 jmpl %g1 + %lo(sys_listen), %g0 195 - ldswa [%o1 + 0x4] %asi, %o1 196 nop 197 nop 198 nop 199 nop 200 do_sys_accept: /* sys_accept(int, struct sockaddr *, int *) */ 201 - ldswa [%o1 + 0x0] %asi, %o0 202 sethi %hi(sys_accept), %g1 203 - lduwa [%o1 + 0x8] %asi, %o2 204 jmpl %g1 + %lo(sys_accept), %g0 205 - lduwa [%o1 + 0x4] %asi, %o1 206 nop 207 nop 208 nop 209 do_sys_getsockname: /* sys_getsockname(int, struct sockaddr *, int *) */ 210 - ldswa [%o1 + 0x0] %asi, %o0 211 sethi %hi(sys_getsockname), %g1 212 - lduwa [%o1 + 0x8] %asi, %o2 213 jmpl %g1 + %lo(sys_getsockname), %g0 214 - lduwa [%o1 + 0x4] %asi, %o1 215 nop 216 nop 217 nop 218 do_sys_getpeername: /* sys_getpeername(int, struct sockaddr *, int *) */ 219 - ldswa [%o1 + 0x0] %asi, %o0 220 sethi %hi(sys_getpeername), %g1 221 - lduwa [%o1 + 0x8] %asi, %o2 222 jmpl %g1 + %lo(sys_getpeername), %g0 223 - lduwa [%o1 + 0x4] %asi, %o1 224 nop 225 nop 226 nop 227 do_sys_socketpair: /* sys_socketpair(int, int, int, int *) */ 228 - ldswa [%o1 + 0x0] %asi, %o0 229 sethi %hi(sys_socketpair), %g1 230 - ldswa [%o1 + 0x8] %asi, %o2 231 - lduwa [%o1 + 0xc] %asi, %o3 232 jmpl %g1 + %lo(sys_socketpair), %g0 233 - ldswa [%o1 + 0x4] %asi, %o1 234 nop 235 nop 236 do_sys_send: /* sys_send(int, void *, size_t, unsigned int) */ 237 - ldswa [%o1 + 0x0] %asi, %o0 238 sethi %hi(sys_send), %g1 239 - lduwa [%o1 + 0x8] %asi, %o2 240 - lduwa [%o1 + 0xc] %asi, %o3 241 jmpl %g1 + %lo(sys_send), %g0 242 - lduwa [%o1 + 0x4] %asi, %o1 243 nop 244 nop 245 do_sys_recv: /* sys_recv(int, void *, size_t, unsigned int) */ 246 - ldswa [%o1 + 0x0] %asi, %o0 247 sethi %hi(sys_recv), %g1 248 - lduwa [%o1 + 0x8] %asi, %o2 249 - lduwa [%o1 + 0xc] %asi, %o3 250 jmpl %g1 + %lo(sys_recv), %g0 251 - lduwa [%o1 + 0x4] %asi, %o1 252 nop 253 nop 254 do_sys_sendto: /* sys_sendto(int, u32, compat_size_t, unsigned int, u32, int) */ 255 - ldswa [%o1 + 0x0] %asi, %o0 256 sethi %hi(sys_sendto), %g1 257 - lduwa [%o1 + 0x8] %asi, %o2 258 - lduwa [%o1 + 0xc] %asi, %o3 259 - lduwa [%o1 + 0x10] %asi, %o4 260 - ldswa [%o1 + 0x14] %asi, %o5 261 jmpl %g1 + %lo(sys_sendto), %g0 262 - lduwa [%o1 + 0x4] %asi, %o1 263 do_sys_recvfrom: /* sys_recvfrom(int, u32, compat_size_t, unsigned int, u32, u32) */ 264 - ldswa [%o1 + 0x0] %asi, %o0 265 sethi %hi(sys_recvfrom), %g1 266 - lduwa [%o1 + 0x8] %asi, %o2 267 - lduwa [%o1 + 0xc] %asi, %o3 268 - lduwa [%o1 + 0x10] %asi, %o4 269 - lduwa [%o1 + 0x14] %asi, %o5 270 jmpl %g1 + %lo(sys_recvfrom), %g0 271 - lduwa [%o1 + 0x4] %asi, %o1 272 do_sys_shutdown: /* sys_shutdown(int, int) */ 273 - ldswa [%o1 + 0x0] %asi, %o0 274 sethi %hi(sys_shutdown), %g1 275 jmpl %g1 + %lo(sys_shutdown), %g0 276 - ldswa [%o1 + 0x4] %asi, %o1 277 nop 278 nop 279 nop 280 nop 281 do_sys_setsockopt: /* compat_sys_setsockopt(int, int, int, char *, int) */ 282 - ldswa [%o1 + 0x0] %asi, %o0 283 sethi %hi(compat_sys_setsockopt), %g1 284 - ldswa [%o1 + 0x8] %asi, %o2 285 - lduwa [%o1 + 0xc] %asi, %o3 286 - ldswa [%o1 + 0x10] %asi, %o4 287 jmpl %g1 + %lo(compat_sys_setsockopt), %g0 288 - ldswa [%o1 + 0x4] %asi, %o1 289 nop 290 do_sys_getsockopt: /* compat_sys_getsockopt(int, int, int, u32, u32) */ 291 - ldswa [%o1 + 0x0] %asi, %o0 292 sethi %hi(compat_sys_getsockopt), %g1 293 - ldswa [%o1 + 0x8] %asi, %o2 294 - lduwa [%o1 + 0xc] %asi, %o3 295 - lduwa [%o1 + 0x10] %asi, %o4 296 jmpl %g1 + %lo(compat_sys_getsockopt), %g0 297 - ldswa [%o1 + 0x4] %asi, %o1 298 nop 299 do_sys_sendmsg: /* compat_sys_sendmsg(int, struct compat_msghdr *, unsigned int) */ 300 - ldswa [%o1 + 0x0] %asi, %o0 301 sethi %hi(compat_sys_sendmsg), %g1 302 - lduwa [%o1 + 0x8] %asi, %o2 303 jmpl %g1 + %lo(compat_sys_sendmsg), %g0 304 - lduwa [%o1 + 0x4] %asi, %o1 305 nop 306 nop 307 nop 308 do_sys_recvmsg: /* compat_sys_recvmsg(int, struct compat_msghdr *, unsigned int) */ 309 - ldswa [%o1 + 0x0] %asi, %o0 310 sethi %hi(compat_sys_recvmsg), %g1 311 - lduwa [%o1 + 0x8] %asi, %o2 312 jmpl %g1 + %lo(compat_sys_recvmsg), %g0 313 - lduwa [%o1 + 0x4] %asi, %o1 314 nop 315 nop 316 nop 317 - __socketcall_table_end: 318 319 do_einval: 320 retl ··· 325 326 .section __ex_table 327 .align 4 328 - .word __socketcall_table_begin, 0, __socketcall_table_end, do_efault 329 .previous
··· 158 jmpl %g2 + %o0, %g0 159 nop 160 161 .align 32 162 __socketcall_table_begin: 163 + 164 + /* Each entry is exactly 32 bytes. */ 165 do_sys_socket: /* sys_socket(int, int, int) */ 166 + 1: ldswa [%o1 + 0x0] %asi, %o0 167 sethi %hi(sys_socket), %g1 168 + 2: ldswa [%o1 + 0x8] %asi, %o2 169 jmpl %g1 + %lo(sys_socket), %g0 170 + 3: ldswa [%o1 + 0x4] %asi, %o1 171 nop 172 nop 173 nop 174 do_sys_bind: /* sys_bind(int fd, struct sockaddr *, int) */ 175 + 4: ldswa [%o1 + 0x0] %asi, %o0 176 sethi %hi(sys_bind), %g1 177 + 5: ldswa [%o1 + 0x8] %asi, %o2 178 jmpl %g1 + %lo(sys_bind), %g0 179 + 6: lduwa [%o1 + 0x4] %asi, %o1 180 nop 181 nop 182 nop 183 do_sys_connect: /* sys_connect(int, struct sockaddr *, int) */ 184 + 7: ldswa [%o1 + 0x0] %asi, %o0 185 sethi %hi(sys_connect), %g1 186 + 8: ldswa [%o1 + 0x8] %asi, %o2 187 jmpl %g1 + %lo(sys_connect), %g0 188 + 9: lduwa [%o1 + 0x4] %asi, %o1 189 nop 190 nop 191 nop 192 do_sys_listen: /* sys_listen(int, int) */ 193 + 10: ldswa [%o1 + 0x0] %asi, %o0 194 sethi %hi(sys_listen), %g1 195 jmpl %g1 + %lo(sys_listen), %g0 196 + 11: ldswa [%o1 + 0x4] %asi, %o1 197 nop 198 nop 199 nop 200 nop 201 do_sys_accept: /* sys_accept(int, struct sockaddr *, int *) */ 202 + 12: ldswa [%o1 + 0x0] %asi, %o0 203 sethi %hi(sys_accept), %g1 204 + 13: lduwa [%o1 + 0x8] %asi, %o2 205 jmpl %g1 + %lo(sys_accept), %g0 206 + 14: lduwa [%o1 + 0x4] %asi, %o1 207 nop 208 nop 209 nop 210 do_sys_getsockname: /* sys_getsockname(int, struct sockaddr *, int *) */ 211 + 15: ldswa [%o1 + 0x0] %asi, %o0 212 sethi %hi(sys_getsockname), %g1 213 + 16: lduwa [%o1 + 0x8] %asi, %o2 214 jmpl %g1 + %lo(sys_getsockname), %g0 215 + 17: lduwa [%o1 + 0x4] %asi, %o1 216 nop 217 nop 218 nop 219 do_sys_getpeername: /* sys_getpeername(int, struct sockaddr *, int *) */ 220 + 18: ldswa [%o1 + 0x0] %asi, %o0 221 sethi %hi(sys_getpeername), %g1 222 + 19: lduwa [%o1 + 0x8] %asi, %o2 223 jmpl %g1 + %lo(sys_getpeername), %g0 224 + 20: lduwa [%o1 + 0x4] %asi, %o1 225 nop 226 nop 227 nop 228 do_sys_socketpair: /* sys_socketpair(int, int, int, int *) */ 229 + 21: ldswa [%o1 + 0x0] %asi, %o0 230 sethi %hi(sys_socketpair), %g1 231 + 22: ldswa [%o1 + 0x8] %asi, %o2 232 + 23: lduwa [%o1 + 0xc] %asi, %o3 233 jmpl %g1 + %lo(sys_socketpair), %g0 234 + 24: ldswa [%o1 + 0x4] %asi, %o1 235 nop 236 nop 237 do_sys_send: /* sys_send(int, void *, size_t, unsigned int) */ 238 + 25: ldswa [%o1 + 0x0] %asi, %o0 239 sethi %hi(sys_send), %g1 240 + 26: lduwa [%o1 + 0x8] %asi, %o2 241 + 27: lduwa [%o1 + 0xc] %asi, %o3 242 jmpl %g1 + %lo(sys_send), %g0 243 + 28: lduwa [%o1 + 0x4] %asi, %o1 244 nop 245 nop 246 do_sys_recv: /* sys_recv(int, void *, size_t, unsigned int) */ 247 + 29: ldswa [%o1 + 0x0] %asi, %o0 248 sethi %hi(sys_recv), %g1 249 + 30: lduwa [%o1 + 0x8] %asi, %o2 250 + 31: lduwa [%o1 + 0xc] %asi, %o3 251 jmpl %g1 + %lo(sys_recv), %g0 252 + 32: lduwa [%o1 + 0x4] %asi, %o1 253 nop 254 nop 255 do_sys_sendto: /* sys_sendto(int, u32, compat_size_t, unsigned int, u32, int) */ 256 + 33: ldswa [%o1 + 0x0] %asi, %o0 257 sethi %hi(sys_sendto), %g1 258 + 34: lduwa [%o1 + 0x8] %asi, %o2 259 + 35: lduwa [%o1 + 0xc] %asi, %o3 260 + 36: lduwa [%o1 + 0x10] %asi, %o4 261 + 37: ldswa [%o1 + 0x14] %asi, %o5 262 jmpl %g1 + %lo(sys_sendto), %g0 263 + 38: lduwa [%o1 + 0x4] %asi, %o1 264 do_sys_recvfrom: /* sys_recvfrom(int, u32, compat_size_t, unsigned int, u32, u32) */ 265 + 39: ldswa [%o1 + 0x0] %asi, %o0 266 sethi %hi(sys_recvfrom), %g1 267 + 40: lduwa [%o1 + 0x8] %asi, %o2 268 + 41: lduwa [%o1 + 0xc] %asi, %o3 269 + 42: lduwa [%o1 + 0x10] %asi, %o4 270 + 43: lduwa [%o1 + 0x14] %asi, %o5 271 jmpl %g1 + %lo(sys_recvfrom), %g0 272 + 44: lduwa [%o1 + 0x4] %asi, %o1 273 do_sys_shutdown: /* sys_shutdown(int, int) */ 274 + 45: ldswa [%o1 + 0x0] %asi, %o0 275 sethi %hi(sys_shutdown), %g1 276 jmpl %g1 + %lo(sys_shutdown), %g0 277 + 46: ldswa [%o1 + 0x4] %asi, %o1 278 nop 279 nop 280 nop 281 nop 282 do_sys_setsockopt: /* compat_sys_setsockopt(int, int, int, char *, int) */ 283 + 47: ldswa [%o1 + 0x0] %asi, %o0 284 sethi %hi(compat_sys_setsockopt), %g1 285 + 48: ldswa [%o1 + 0x8] %asi, %o2 286 + 49: lduwa [%o1 + 0xc] %asi, %o3 287 + 50: ldswa [%o1 + 0x10] %asi, %o4 288 jmpl %g1 + %lo(compat_sys_setsockopt), %g0 289 + 51: ldswa [%o1 + 0x4] %asi, %o1 290 nop 291 do_sys_getsockopt: /* compat_sys_getsockopt(int, int, int, u32, u32) */ 292 + 52: ldswa [%o1 + 0x0] %asi, %o0 293 sethi %hi(compat_sys_getsockopt), %g1 294 + 53: ldswa [%o1 + 0x8] %asi, %o2 295 + 54: lduwa [%o1 + 0xc] %asi, %o3 296 + 55: lduwa [%o1 + 0x10] %asi, %o4 297 jmpl %g1 + %lo(compat_sys_getsockopt), %g0 298 + 56: ldswa [%o1 + 0x4] %asi, %o1 299 nop 300 do_sys_sendmsg: /* compat_sys_sendmsg(int, struct compat_msghdr *, unsigned int) */ 301 + 57: ldswa [%o1 + 0x0] %asi, %o0 302 sethi %hi(compat_sys_sendmsg), %g1 303 + 58: lduwa [%o1 + 0x8] %asi, %o2 304 jmpl %g1 + %lo(compat_sys_sendmsg), %g0 305 + 59: lduwa [%o1 + 0x4] %asi, %o1 306 nop 307 nop 308 nop 309 do_sys_recvmsg: /* compat_sys_recvmsg(int, struct compat_msghdr *, unsigned int) */ 310 + 60: ldswa [%o1 + 0x0] %asi, %o0 311 sethi %hi(compat_sys_recvmsg), %g1 312 + 61: lduwa [%o1 + 0x8] %asi, %o2 313 jmpl %g1 + %lo(compat_sys_recvmsg), %g0 314 + 62: lduwa [%o1 + 0x4] %asi, %o1 315 nop 316 nop 317 nop 318 319 do_einval: 320 retl ··· 325 326 .section __ex_table 327 .align 4 328 + .word 1b, do_efault, 2b, do_efault, 3b, do_efault, 4b, do_efault 329 + .word 5b, do_efault, 6b, do_efault, 7b, do_efault, 8b, do_efault 330 + .word 9b, do_efault, 10b, do_efault, 11b, do_efault, 12b, do_efault 331 + .word 13b, do_efault, 14b, do_efault, 15b, do_efault, 16b, do_efault 332 + .word 17b, do_efault, 18b, do_efault, 19b, do_efault, 20b, do_efault 333 + .word 21b, do_efault, 22b, do_efault, 23b, do_efault, 24b, do_efault 334 + .word 25b, do_efault, 26b, do_efault, 27b, do_efault, 28b, do_efault 335 + .word 29b, do_efault, 30b, do_efault, 31b, do_efault, 32b, do_efault 336 + .word 33b, do_efault, 34b, do_efault, 35b, do_efault, 36b, do_efault 337 + .word 37b, do_efault, 38b, do_efault, 39b, do_efault, 40b, do_efault 338 + .word 41b, do_efault, 42b, do_efault, 43b, do_efault, 44b, do_efault 339 + .word 45b, do_efault, 46b, do_efault, 47b, do_efault, 48b, do_efault 340 + .word 49b, do_efault, 50b, do_efault, 51b, do_efault, 52b, do_efault 341 + .word 53b, do_efault, 54b, do_efault, 55b, do_efault, 56b, do_efault 342 + .word 57b, do_efault, 58b, do_efault, 59b, do_efault, 60b, do_efault 343 + .word 61b, do_efault, 62b, do_efault 344 .previous
+11 -13
arch/sparc64/kernel/traps.c
··· 189 190 if (regs->tstate & TSTATE_PRIV) { 191 /* Test if this comes from uaccess places. */ 192 - unsigned long fixup; 193 - unsigned long g2 = regs->u_regs[UREG_G2]; 194 195 - if ((fixup = search_extables_range(regs->tpc, &g2))) { 196 - /* Ouch, somebody is trying ugly VM hole tricks on us... */ 197 #ifdef DEBUG_EXCEPTIONS 198 printk("Exception: PC<%016lx> faddr<UNKNOWN>\n", regs->tpc); 199 - printk("EX_TABLE: insn<%016lx> fixup<%016lx> " 200 - "g2<%016lx>\n", regs->tpc, fixup, g2); 201 #endif 202 - regs->tpc = fixup; 203 regs->tnpc = regs->tpc + 4; 204 - regs->u_regs[UREG_G2] = g2; 205 return; 206 } 207 /* Shit... */ ··· 1609 /* OK, usermode access. */ 1610 recoverable = 1; 1611 } else { 1612 - unsigned long g2 = regs->u_regs[UREG_G2]; 1613 - unsigned long fixup = search_extables_range(regs->tpc, &g2); 1614 1615 - if (fixup != 0UL) { 1616 /* OK, kernel access to userspace. */ 1617 recoverable = 1; 1618 ··· 1631 * recoverable condition. 1632 */ 1633 if (recoverable) { 1634 - regs->tpc = fixup; 1635 regs->tnpc = regs->tpc + 4; 1636 - regs->u_regs[UREG_G2] = g2; 1637 } 1638 } 1639 }
··· 189 190 if (regs->tstate & TSTATE_PRIV) { 191 /* Test if this comes from uaccess places. */ 192 + const struct exception_table_entry *entry; 193 194 + entry = search_exception_tables(regs->tpc); 195 + if (entry) { 196 + /* Ouch, somebody is trying VM hole tricks on us... */ 197 #ifdef DEBUG_EXCEPTIONS 198 printk("Exception: PC<%016lx> faddr<UNKNOWN>\n", regs->tpc); 199 + printk("EX_TABLE: insn<%016lx> fixup<%016lx>\n", 200 + regs->tpc, entry->fixup); 201 #endif 202 + regs->tpc = entry->fixup; 203 regs->tnpc = regs->tpc + 4; 204 return; 205 } 206 /* Shit... */ ··· 1610 /* OK, usermode access. */ 1611 recoverable = 1; 1612 } else { 1613 + const struct exception_table_entry *entry; 1614 1615 + entry = search_exception_tables(regs->tpc); 1616 + if (entry) { 1617 /* OK, kernel access to userspace. */ 1618 recoverable = 1; 1619 ··· 1632 * recoverable condition. 1633 */ 1634 if (recoverable) { 1635 + regs->tpc = entry->fixup; 1636 regs->tnpc = regs->tpc + 4; 1637 } 1638 } 1639 }
+4 -5
arch/sparc64/kernel/unaligned.c
··· 246 { 247 struct pt_regs *regs = current_thread_info()->kern_una_regs; 248 unsigned int insn = current_thread_info()->kern_una_insn; 249 - unsigned long g2 = regs->u_regs[UREG_G2]; 250 - unsigned long fixup = search_extables_range(regs->tpc, &g2); 251 252 - if (!fixup) { 253 unsigned long address; 254 255 address = compute_effective_address(regs, insn, ··· 270 die_if_kernel("Oops", regs); 271 /* Not reached */ 272 } 273 - regs->tpc = fixup; 274 regs->tnpc = regs->tpc + 4; 275 - regs->u_regs [UREG_G2] = g2; 276 277 regs->tstate &= ~TSTATE_ASI; 278 regs->tstate |= (ASI_AIUS << 24UL);
··· 246 { 247 struct pt_regs *regs = current_thread_info()->kern_una_regs; 248 unsigned int insn = current_thread_info()->kern_una_insn; 249 + const struct exception_table_entry *entry; 250 251 + entry = search_exception_tables(regs->tpc); 252 + if (!entry) { 253 unsigned long address; 254 255 address = compute_effective_address(regs, insn, ··· 270 die_if_kernel("Oops", regs); 271 /* Not reached */ 272 } 273 + regs->tpc = entry->fixup; 274 regs->tnpc = regs->tpc + 4; 275 276 regs->tstate &= ~TSTATE_ASI; 277 regs->tstate |= (ASI_AIUS << 24UL);
+1 -1
arch/sparc64/mm/Makefile
··· 5 EXTRA_AFLAGS := -ansi 6 EXTRA_CFLAGS := -Werror 7 8 - obj-y := ultra.o tlb.o fault.o init.o generic.o extable.o 9 10 obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
··· 5 EXTRA_AFLAGS := -ansi 6 EXTRA_CFLAGS := -Werror 7 8 + obj-y := ultra.o tlb.o fault.o init.o generic.o 9 10 obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
-80
arch/sparc64/mm/extable.c
··· 1 - /* 2 - * linux/arch/sparc64/mm/extable.c 3 - */ 4 - 5 - #include <linux/config.h> 6 - #include <linux/module.h> 7 - #include <asm/uaccess.h> 8 - 9 - extern const struct exception_table_entry __start___ex_table[]; 10 - extern const struct exception_table_entry __stop___ex_table[]; 11 - 12 - void sort_extable(struct exception_table_entry *start, 13 - struct exception_table_entry *finish) 14 - { 15 - } 16 - 17 - /* Caller knows they are in a range if ret->fixup == 0 */ 18 - const struct exception_table_entry * 19 - search_extable(const struct exception_table_entry *start, 20 - const struct exception_table_entry *last, 21 - unsigned long value) 22 - { 23 - const struct exception_table_entry *walk; 24 - 25 - /* Single insn entries are encoded as: 26 - * word 1: insn address 27 - * word 2: fixup code address 28 - * 29 - * Range entries are encoded as: 30 - * word 1: first insn address 31 - * word 2: 0 32 - * word 3: last insn address + 4 bytes 33 - * word 4: fixup code address 34 - * 35 - * See asm/uaccess.h for more details. 36 - */ 37 - 38 - /* 1. Try to find an exact match. */ 39 - for (walk = start; walk <= last; walk++) { 40 - if (walk->fixup == 0) { 41 - /* A range entry, skip both parts. */ 42 - walk++; 43 - continue; 44 - } 45 - 46 - if (walk->insn == value) 47 - return walk; 48 - } 49 - 50 - /* 2. Try to find a range match. */ 51 - for (walk = start; walk <= (last - 1); walk++) { 52 - if (walk->fixup) 53 - continue; 54 - 55 - if (walk[0].insn <= value && walk[1].insn > value) 56 - return walk; 57 - 58 - walk++; 59 - } 60 - 61 - return NULL; 62 - } 63 - 64 - /* Special extable search, which handles ranges. Returns fixup */ 65 - unsigned long search_extables_range(unsigned long addr, unsigned long *g2) 66 - { 67 - const struct exception_table_entry *entry; 68 - 69 - entry = search_exception_tables(addr); 70 - if (!entry) 71 - return 0; 72 - 73 - /* Inside range? Fix g2 and return correct fixup */ 74 - if (!entry->fixup) { 75 - *g2 = (addr - entry->insn) / 4; 76 - return (entry + 1)->fixup; 77 - } 78 - 79 - return entry->fixup; 80 - }
···
+3 -7
arch/sparc64/mm/fault.c
··· 242 static void do_kernel_fault(struct pt_regs *regs, int si_code, int fault_code, 243 unsigned int insn, unsigned long address) 244 { 245 - unsigned long g2; 246 unsigned char asi = ASI_P; 247 248 if ((!insn) && (regs->tstate & TSTATE_PRIV)) ··· 272 } 273 } 274 275 - g2 = regs->u_regs[UREG_G2]; 276 - 277 /* Is this in ex_table? */ 278 if (regs->tstate & TSTATE_PRIV) { 279 - unsigned long fixup; 280 281 if (asi == ASI_P && (insn & 0xc0800000) == 0xc0800000) { 282 if (insn & 0x2000) ··· 285 286 /* Look in asi.h: All _S asis have LS bit set */ 287 if ((asi & 0x1) && 288 - (fixup = search_extables_range(regs->tpc, &g2))) { 289 - regs->tpc = fixup; 290 regs->tnpc = regs->tpc + 4; 291 - regs->u_regs[UREG_G2] = g2; 292 return; 293 } 294 } else {
··· 242 static void do_kernel_fault(struct pt_regs *regs, int si_code, int fault_code, 243 unsigned int insn, unsigned long address) 244 { 245 unsigned char asi = ASI_P; 246 247 if ((!insn) && (regs->tstate & TSTATE_PRIV)) ··· 273 } 274 } 275 276 /* Is this in ex_table? */ 277 if (regs->tstate & TSTATE_PRIV) { 278 + const struct exception_table_entry *entry; 279 280 if (asi == ASI_P && (insn & 0xc0800000) == 0xc0800000) { 281 if (insn & 0x2000) ··· 288 289 /* Look in asi.h: All _S asis have LS bit set */ 290 if ((asi & 0x1) && 291 + (entry = search_exception_tables(regs->tpc))) { 292 + regs->tpc = entry->fixup; 293 regs->tnpc = regs->tpc + 4; 294 return; 295 } 296 } else {
+2 -15
include/asm-sparc64/uaccess.h
··· 70 * with the main instruction path. This means when everything is well, 71 * we don't even have to jump over them. Further, they do not intrude 72 * on our cache or tlb entries. 73 - * 74 - * There is a special way how to put a range of potentially faulting 75 - * insns (like twenty ldd/std's with now intervening other instructions) 76 - * You specify address of first in insn and 0 in fixup and in the next 77 - * exception_table_entry you specify last potentially faulting insn + 1 78 - * and in fixup the routine which should handle the fault. 79 - * That fixup code will get 80 - * (faulting_insn_address - first_insn_in_the_range_address)/4 81 - * in %g2 (ie. index of the faulting instruction in the range). 82 */ 83 84 - struct exception_table_entry 85 - { 86 - unsigned insn, fixup; 87 }; 88 - 89 - /* Special exable search, which handles ranges. Returns fixup */ 90 - unsigned long search_extables_range(unsigned long addr, unsigned long *g2); 91 92 extern void __ret_efault(void); 93
··· 70 * with the main instruction path. This means when everything is well, 71 * we don't even have to jump over them. Further, they do not intrude 72 * on our cache or tlb entries. 73 */ 74 75 + struct exception_table_entry { 76 + unsigned int insn, fixup; 77 }; 78 79 extern void __ret_efault(void); 80