[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 158 jmpl %g2 + %o0, %g0 159 159 nop 160 160 161 - /* Each entry is exactly 32 bytes. */ 162 161 .align 32 163 162 __socketcall_table_begin: 163 + 164 + /* Each entry is exactly 32 bytes. */ 164 165 do_sys_socket: /* sys_socket(int, int, int) */ 165 - ldswa [%o1 + 0x0] %asi, %o0 166 + 1: ldswa [%o1 + 0x0] %asi, %o0 166 167 sethi %hi(sys_socket), %g1 167 - ldswa [%o1 + 0x8] %asi, %o2 168 + 2: ldswa [%o1 + 0x8] %asi, %o2 168 169 jmpl %g1 + %lo(sys_socket), %g0 169 - ldswa [%o1 + 0x4] %asi, %o1 170 + 3: ldswa [%o1 + 0x4] %asi, %o1 170 171 nop 171 172 nop 172 173 nop 173 174 do_sys_bind: /* sys_bind(int fd, struct sockaddr *, int) */ 174 - ldswa [%o1 + 0x0] %asi, %o0 175 + 4: ldswa [%o1 + 0x0] %asi, %o0 175 176 sethi %hi(sys_bind), %g1 176 - ldswa [%o1 + 0x8] %asi, %o2 177 + 5: ldswa [%o1 + 0x8] %asi, %o2 177 178 jmpl %g1 + %lo(sys_bind), %g0 178 - lduwa [%o1 + 0x4] %asi, %o1 179 + 6: lduwa [%o1 + 0x4] %asi, %o1 179 180 nop 180 181 nop 181 182 nop 182 183 do_sys_connect: /* sys_connect(int, struct sockaddr *, int) */ 183 - ldswa [%o1 + 0x0] %asi, %o0 184 + 7: ldswa [%o1 + 0x0] %asi, %o0 184 185 sethi %hi(sys_connect), %g1 185 - ldswa [%o1 + 0x8] %asi, %o2 186 + 8: ldswa [%o1 + 0x8] %asi, %o2 186 187 jmpl %g1 + %lo(sys_connect), %g0 187 - lduwa [%o1 + 0x4] %asi, %o1 188 + 9: lduwa [%o1 + 0x4] %asi, %o1 188 189 nop 189 190 nop 190 191 nop 191 192 do_sys_listen: /* sys_listen(int, int) */ 192 - ldswa [%o1 + 0x0] %asi, %o0 193 + 10: ldswa [%o1 + 0x0] %asi, %o0 193 194 sethi %hi(sys_listen), %g1 194 195 jmpl %g1 + %lo(sys_listen), %g0 195 - ldswa [%o1 + 0x4] %asi, %o1 196 + 11: ldswa [%o1 + 0x4] %asi, %o1 196 197 nop 197 198 nop 198 199 nop 199 200 nop 200 201 do_sys_accept: /* sys_accept(int, struct sockaddr *, int *) */ 201 - ldswa [%o1 + 0x0] %asi, %o0 202 + 12: ldswa [%o1 + 0x0] %asi, %o0 202 203 sethi %hi(sys_accept), %g1 203 - lduwa [%o1 + 0x8] %asi, %o2 204 + 13: lduwa [%o1 + 0x8] %asi, %o2 204 205 jmpl %g1 + %lo(sys_accept), %g0 205 - lduwa [%o1 + 0x4] %asi, %o1 206 + 14: lduwa [%o1 + 0x4] %asi, %o1 206 207 nop 207 208 nop 208 209 nop 209 210 do_sys_getsockname: /* sys_getsockname(int, struct sockaddr *, int *) */ 210 - ldswa [%o1 + 0x0] %asi, %o0 211 + 15: ldswa [%o1 + 0x0] %asi, %o0 211 212 sethi %hi(sys_getsockname), %g1 212 - lduwa [%o1 + 0x8] %asi, %o2 213 + 16: lduwa [%o1 + 0x8] %asi, %o2 213 214 jmpl %g1 + %lo(sys_getsockname), %g0 214 - lduwa [%o1 + 0x4] %asi, %o1 215 + 17: lduwa [%o1 + 0x4] %asi, %o1 215 216 nop 216 217 nop 217 218 nop 218 219 do_sys_getpeername: /* sys_getpeername(int, struct sockaddr *, int *) */ 219 - ldswa [%o1 + 0x0] %asi, %o0 220 + 18: ldswa [%o1 + 0x0] %asi, %o0 220 221 sethi %hi(sys_getpeername), %g1 221 - lduwa [%o1 + 0x8] %asi, %o2 222 + 19: lduwa [%o1 + 0x8] %asi, %o2 222 223 jmpl %g1 + %lo(sys_getpeername), %g0 223 - lduwa [%o1 + 0x4] %asi, %o1 224 + 20: lduwa [%o1 + 0x4] %asi, %o1 224 225 nop 225 226 nop 226 227 nop 227 228 do_sys_socketpair: /* sys_socketpair(int, int, int, int *) */ 228 - ldswa [%o1 + 0x0] %asi, %o0 229 + 21: ldswa [%o1 + 0x0] %asi, %o0 229 230 sethi %hi(sys_socketpair), %g1 230 - ldswa [%o1 + 0x8] %asi, %o2 231 - lduwa [%o1 + 0xc] %asi, %o3 231 + 22: ldswa [%o1 + 0x8] %asi, %o2 232 + 23: lduwa [%o1 + 0xc] %asi, %o3 232 233 jmpl %g1 + %lo(sys_socketpair), %g0 233 - ldswa [%o1 + 0x4] %asi, %o1 234 + 24: ldswa [%o1 + 0x4] %asi, %o1 234 235 nop 235 236 nop 236 237 do_sys_send: /* sys_send(int, void *, size_t, unsigned int) */ 237 - ldswa [%o1 + 0x0] %asi, %o0 238 + 25: ldswa [%o1 + 0x0] %asi, %o0 238 239 sethi %hi(sys_send), %g1 239 - lduwa [%o1 + 0x8] %asi, %o2 240 - lduwa [%o1 + 0xc] %asi, %o3 240 + 26: lduwa [%o1 + 0x8] %asi, %o2 241 + 27: lduwa [%o1 + 0xc] %asi, %o3 241 242 jmpl %g1 + %lo(sys_send), %g0 242 - lduwa [%o1 + 0x4] %asi, %o1 243 + 28: lduwa [%o1 + 0x4] %asi, %o1 243 244 nop 244 245 nop 245 246 do_sys_recv: /* sys_recv(int, void *, size_t, unsigned int) */ 246 - ldswa [%o1 + 0x0] %asi, %o0 247 + 29: ldswa [%o1 + 0x0] %asi, %o0 247 248 sethi %hi(sys_recv), %g1 248 - lduwa [%o1 + 0x8] %asi, %o2 249 - lduwa [%o1 + 0xc] %asi, %o3 249 + 30: lduwa [%o1 + 0x8] %asi, %o2 250 + 31: lduwa [%o1 + 0xc] %asi, %o3 250 251 jmpl %g1 + %lo(sys_recv), %g0 251 - lduwa [%o1 + 0x4] %asi, %o1 252 + 32: lduwa [%o1 + 0x4] %asi, %o1 252 253 nop 253 254 nop 254 255 do_sys_sendto: /* sys_sendto(int, u32, compat_size_t, unsigned int, u32, int) */ 255 - ldswa [%o1 + 0x0] %asi, %o0 256 + 33: ldswa [%o1 + 0x0] %asi, %o0 256 257 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 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 261 262 jmpl %g1 + %lo(sys_sendto), %g0 262 - lduwa [%o1 + 0x4] %asi, %o1 263 + 38: lduwa [%o1 + 0x4] %asi, %o1 263 264 do_sys_recvfrom: /* sys_recvfrom(int, u32, compat_size_t, unsigned int, u32, u32) */ 264 - ldswa [%o1 + 0x0] %asi, %o0 265 + 39: ldswa [%o1 + 0x0] %asi, %o0 265 266 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 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 270 271 jmpl %g1 + %lo(sys_recvfrom), %g0 271 - lduwa [%o1 + 0x4] %asi, %o1 272 + 44: lduwa [%o1 + 0x4] %asi, %o1 272 273 do_sys_shutdown: /* sys_shutdown(int, int) */ 273 - ldswa [%o1 + 0x0] %asi, %o0 274 + 45: ldswa [%o1 + 0x0] %asi, %o0 274 275 sethi %hi(sys_shutdown), %g1 275 276 jmpl %g1 + %lo(sys_shutdown), %g0 276 - ldswa [%o1 + 0x4] %asi, %o1 277 + 46: ldswa [%o1 + 0x4] %asi, %o1 277 278 nop 278 279 nop 279 280 nop 280 281 nop 281 282 do_sys_setsockopt: /* compat_sys_setsockopt(int, int, int, char *, int) */ 282 - ldswa [%o1 + 0x0] %asi, %o0 283 + 47: ldswa [%o1 + 0x0] %asi, %o0 283 284 sethi %hi(compat_sys_setsockopt), %g1 284 - ldswa [%o1 + 0x8] %asi, %o2 285 - lduwa [%o1 + 0xc] %asi, %o3 286 - ldswa [%o1 + 0x10] %asi, %o4 285 + 48: ldswa [%o1 + 0x8] %asi, %o2 286 + 49: lduwa [%o1 + 0xc] %asi, %o3 287 + 50: ldswa [%o1 + 0x10] %asi, %o4 287 288 jmpl %g1 + %lo(compat_sys_setsockopt), %g0 288 - ldswa [%o1 + 0x4] %asi, %o1 289 + 51: ldswa [%o1 + 0x4] %asi, %o1 289 290 nop 290 291 do_sys_getsockopt: /* compat_sys_getsockopt(int, int, int, u32, u32) */ 291 - ldswa [%o1 + 0x0] %asi, %o0 292 + 52: ldswa [%o1 + 0x0] %asi, %o0 292 293 sethi %hi(compat_sys_getsockopt), %g1 293 - ldswa [%o1 + 0x8] %asi, %o2 294 - lduwa [%o1 + 0xc] %asi, %o3 295 - lduwa [%o1 + 0x10] %asi, %o4 294 + 53: ldswa [%o1 + 0x8] %asi, %o2 295 + 54: lduwa [%o1 + 0xc] %asi, %o3 296 + 55: lduwa [%o1 + 0x10] %asi, %o4 296 297 jmpl %g1 + %lo(compat_sys_getsockopt), %g0 297 - ldswa [%o1 + 0x4] %asi, %o1 298 + 56: ldswa [%o1 + 0x4] %asi, %o1 298 299 nop 299 300 do_sys_sendmsg: /* compat_sys_sendmsg(int, struct compat_msghdr *, unsigned int) */ 300 - ldswa [%o1 + 0x0] %asi, %o0 301 + 57: ldswa [%o1 + 0x0] %asi, %o0 301 302 sethi %hi(compat_sys_sendmsg), %g1 302 - lduwa [%o1 + 0x8] %asi, %o2 303 + 58: lduwa [%o1 + 0x8] %asi, %o2 303 304 jmpl %g1 + %lo(compat_sys_sendmsg), %g0 304 - lduwa [%o1 + 0x4] %asi, %o1 305 + 59: lduwa [%o1 + 0x4] %asi, %o1 305 306 nop 306 307 nop 307 308 nop 308 309 do_sys_recvmsg: /* compat_sys_recvmsg(int, struct compat_msghdr *, unsigned int) */ 309 - ldswa [%o1 + 0x0] %asi, %o0 310 + 60: ldswa [%o1 + 0x0] %asi, %o0 310 311 sethi %hi(compat_sys_recvmsg), %g1 311 - lduwa [%o1 + 0x8] %asi, %o2 312 + 61: lduwa [%o1 + 0x8] %asi, %o2 312 313 jmpl %g1 + %lo(compat_sys_recvmsg), %g0 313 - lduwa [%o1 + 0x4] %asi, %o1 314 + 62: lduwa [%o1 + 0x4] %asi, %o1 314 315 nop 315 316 nop 316 317 nop 317 - __socketcall_table_end: 318 318 319 319 do_einval: 320 320 retl ··· 325 325 326 326 .section __ex_table 327 327 .align 4 328 - .word __socketcall_table_begin, 0, __socketcall_table_end, do_efault 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 329 344 .previous
+11 -13
arch/sparc64/kernel/traps.c
··· 189 189 190 190 if (regs->tstate & TSTATE_PRIV) { 191 191 /* Test if this comes from uaccess places. */ 192 - unsigned long fixup; 193 - unsigned long g2 = regs->u_regs[UREG_G2]; 192 + const struct exception_table_entry *entry; 194 193 195 - if ((fixup = search_extables_range(regs->tpc, &g2))) { 196 - /* Ouch, somebody is trying ugly VM hole tricks on us... */ 194 + entry = search_exception_tables(regs->tpc); 195 + if (entry) { 196 + /* Ouch, somebody is trying VM hole tricks on us... */ 197 197 #ifdef DEBUG_EXCEPTIONS 198 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); 199 + printk("EX_TABLE: insn<%016lx> fixup<%016lx>\n", 200 + regs->tpc, entry->fixup); 201 201 #endif 202 - regs->tpc = fixup; 202 + regs->tpc = entry->fixup; 203 203 regs->tnpc = regs->tpc + 4; 204 - regs->u_regs[UREG_G2] = g2; 205 204 return; 206 205 } 207 206 /* Shit... */ ··· 1609 1610 /* OK, usermode access. */ 1610 1611 recoverable = 1; 1611 1612 } else { 1612 - unsigned long g2 = regs->u_regs[UREG_G2]; 1613 - unsigned long fixup = search_extables_range(regs->tpc, &g2); 1613 + const struct exception_table_entry *entry; 1614 1614 1615 - if (fixup != 0UL) { 1615 + entry = search_exception_tables(regs->tpc); 1616 + if (entry) { 1616 1617 /* OK, kernel access to userspace. */ 1617 1618 recoverable = 1; 1618 1619 ··· 1631 1632 * recoverable condition. 1632 1633 */ 1633 1634 if (recoverable) { 1634 - regs->tpc = fixup; 1635 + regs->tpc = entry->fixup; 1635 1636 regs->tnpc = regs->tpc + 4; 1636 - regs->u_regs[UREG_G2] = g2; 1637 1637 } 1638 1638 } 1639 1639 }
+4 -5
arch/sparc64/kernel/unaligned.c
··· 246 246 { 247 247 struct pt_regs *regs = current_thread_info()->kern_una_regs; 248 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); 249 + const struct exception_table_entry *entry; 251 250 252 - if (!fixup) { 251 + entry = search_exception_tables(regs->tpc); 252 + if (!entry) { 253 253 unsigned long address; 254 254 255 255 address = compute_effective_address(regs, insn, ··· 270 270 die_if_kernel("Oops", regs); 271 271 /* Not reached */ 272 272 } 273 - regs->tpc = fixup; 273 + regs->tpc = entry->fixup; 274 274 regs->tnpc = regs->tpc + 4; 275 - regs->u_regs [UREG_G2] = g2; 276 275 277 276 regs->tstate &= ~TSTATE_ASI; 278 277 regs->tstate |= (ASI_AIUS << 24UL);
+1 -1
arch/sparc64/mm/Makefile
··· 5 5 EXTRA_AFLAGS := -ansi 6 6 EXTRA_CFLAGS := -Werror 7 7 8 - obj-y := ultra.o tlb.o fault.o init.o generic.o extable.o 8 + obj-y := ultra.o tlb.o fault.o init.o generic.o 9 9 10 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 242 static void do_kernel_fault(struct pt_regs *regs, int si_code, int fault_code, 243 243 unsigned int insn, unsigned long address) 244 244 { 245 - unsigned long g2; 246 245 unsigned char asi = ASI_P; 247 246 248 247 if ((!insn) && (regs->tstate & TSTATE_PRIV)) ··· 272 273 } 273 274 } 274 275 275 - g2 = regs->u_regs[UREG_G2]; 276 - 277 276 /* Is this in ex_table? */ 278 277 if (regs->tstate & TSTATE_PRIV) { 279 - unsigned long fixup; 278 + const struct exception_table_entry *entry; 280 279 281 280 if (asi == ASI_P && (insn & 0xc0800000) == 0xc0800000) { 282 281 if (insn & 0x2000) ··· 285 288 286 289 /* Look in asi.h: All _S asis have LS bit set */ 287 290 if ((asi & 0x1) && 288 - (fixup = search_extables_range(regs->tpc, &g2))) { 289 - regs->tpc = fixup; 291 + (entry = search_exception_tables(regs->tpc))) { 292 + regs->tpc = entry->fixup; 290 293 regs->tnpc = regs->tpc + 4; 291 - regs->u_regs[UREG_G2] = g2; 292 294 return; 293 295 } 294 296 } else {
+2 -15
include/asm-sparc64/uaccess.h
··· 70 70 * with the main instruction path. This means when everything is well, 71 71 * we don't even have to jump over them. Further, they do not intrude 72 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 73 */ 83 74 84 - struct exception_table_entry 85 - { 86 - unsigned insn, fixup; 75 + struct exception_table_entry { 76 + unsigned int insn, fixup; 87 77 }; 88 - 89 - /* Special exable search, which handles ranges. Returns fixup */ 90 - unsigned long search_extables_range(unsigned long addr, unsigned long *g2); 91 78 92 79 extern void __ret_efault(void); 93 80