diff options
Diffstat (limited to 'arch/powerpc/lib/sstep.c')
-rw-r--r-- | arch/powerpc/lib/sstep.c | 97 |
1 files changed, 85 insertions, 12 deletions
diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c index b1faa1593c90..c0511c27a733 100644 --- a/arch/powerpc/lib/sstep.c +++ b/arch/powerpc/lib/sstep.c | |||
@@ -212,11 +212,19 @@ static int __kprobes read_mem_unaligned(unsigned long *dest, unsigned long ea, | |||
212 | { | 212 | { |
213 | int err; | 213 | int err; |
214 | unsigned long x, b, c; | 214 | unsigned long x, b, c; |
215 | #ifdef __LITTLE_ENDIAN__ | ||
216 | int len = nb; /* save a copy of the length for byte reversal */ | ||
217 | #endif | ||
215 | 218 | ||
216 | /* unaligned, do this in pieces */ | 219 | /* unaligned, do this in pieces */ |
217 | x = 0; | 220 | x = 0; |
218 | for (; nb > 0; nb -= c) { | 221 | for (; nb > 0; nb -= c) { |
222 | #ifdef __LITTLE_ENDIAN__ | ||
223 | c = 1; | ||
224 | #endif | ||
225 | #ifdef __BIG_ENDIAN__ | ||
219 | c = max_align(ea); | 226 | c = max_align(ea); |
227 | #endif | ||
220 | if (c > nb) | 228 | if (c > nb) |
221 | c = max_align(nb); | 229 | c = max_align(nb); |
222 | err = read_mem_aligned(&b, ea, c); | 230 | err = read_mem_aligned(&b, ea, c); |
@@ -225,7 +233,24 @@ static int __kprobes read_mem_unaligned(unsigned long *dest, unsigned long ea, | |||
225 | x = (x << (8 * c)) + b; | 233 | x = (x << (8 * c)) + b; |
226 | ea += c; | 234 | ea += c; |
227 | } | 235 | } |
236 | #ifdef __LITTLE_ENDIAN__ | ||
237 | switch (len) { | ||
238 | case 2: | ||
239 | *dest = byterev_2(x); | ||
240 | break; | ||
241 | case 4: | ||
242 | *dest = byterev_4(x); | ||
243 | break; | ||
244 | #ifdef __powerpc64__ | ||
245 | case 8: | ||
246 | *dest = byterev_8(x); | ||
247 | break; | ||
248 | #endif | ||
249 | } | ||
250 | #endif | ||
251 | #ifdef __BIG_ENDIAN__ | ||
228 | *dest = x; | 252 | *dest = x; |
253 | #endif | ||
229 | return 0; | 254 | return 0; |
230 | } | 255 | } |
231 | 256 | ||
@@ -273,9 +298,29 @@ static int __kprobes write_mem_unaligned(unsigned long val, unsigned long ea, | |||
273 | int err; | 298 | int err; |
274 | unsigned long c; | 299 | unsigned long c; |
275 | 300 | ||
301 | #ifdef __LITTLE_ENDIAN__ | ||
302 | switch (nb) { | ||
303 | case 2: | ||
304 | val = byterev_2(val); | ||
305 | break; | ||
306 | case 4: | ||
307 | val = byterev_4(val); | ||
308 | break; | ||
309 | #ifdef __powerpc64__ | ||
310 | case 8: | ||
311 | val = byterev_8(val); | ||
312 | break; | ||
313 | #endif | ||
314 | } | ||
315 | #endif | ||
276 | /* unaligned or little-endian, do this in pieces */ | 316 | /* unaligned or little-endian, do this in pieces */ |
277 | for (; nb > 0; nb -= c) { | 317 | for (; nb > 0; nb -= c) { |
318 | #ifdef __LITTLE_ENDIAN__ | ||
319 | c = 1; | ||
320 | #endif | ||
321 | #ifdef __BIG_ENDIAN__ | ||
278 | c = max_align(ea); | 322 | c = max_align(ea); |
323 | #endif | ||
279 | if (c > nb) | 324 | if (c > nb) |
280 | c = max_align(nb); | 325 | c = max_align(nb); |
281 | err = write_mem_aligned(val >> (nb - c) * 8, ea, c); | 326 | err = write_mem_aligned(val >> (nb - c) * 8, ea, c); |
@@ -310,22 +355,36 @@ static int __kprobes do_fp_load(int rn, int (*func)(int, unsigned long), | |||
310 | struct pt_regs *regs) | 355 | struct pt_regs *regs) |
311 | { | 356 | { |
312 | int err; | 357 | int err; |
313 | unsigned long val[sizeof(double) / sizeof(long)]; | 358 | union { |
359 | double dbl; | ||
360 | unsigned long ul[2]; | ||
361 | struct { | ||
362 | #ifdef __BIG_ENDIAN__ | ||
363 | unsigned _pad_; | ||
364 | unsigned word; | ||
365 | #endif | ||
366 | #ifdef __LITTLE_ENDIAN__ | ||
367 | unsigned word; | ||
368 | unsigned _pad_; | ||
369 | #endif | ||
370 | } single; | ||
371 | } data; | ||
314 | unsigned long ptr; | 372 | unsigned long ptr; |
315 | 373 | ||
316 | if (!address_ok(regs, ea, nb)) | 374 | if (!address_ok(regs, ea, nb)) |
317 | return -EFAULT; | 375 | return -EFAULT; |
318 | if ((ea & 3) == 0) | 376 | if ((ea & 3) == 0) |
319 | return (*func)(rn, ea); | 377 | return (*func)(rn, ea); |
320 | ptr = (unsigned long) &val[0]; | 378 | ptr = (unsigned long) &data.ul; |
321 | if (sizeof(unsigned long) == 8 || nb == 4) { | 379 | if (sizeof(unsigned long) == 8 || nb == 4) { |
322 | err = read_mem_unaligned(&val[0], ea, nb, regs); | 380 | err = read_mem_unaligned(&data.ul[0], ea, nb, regs); |
323 | ptr += sizeof(unsigned long) - nb; | 381 | if (nb == 4) |
382 | ptr = (unsigned long)&(data.single.word); | ||
324 | } else { | 383 | } else { |
325 | /* reading a double on 32-bit */ | 384 | /* reading a double on 32-bit */ |
326 | err = read_mem_unaligned(&val[0], ea, 4, regs); | 385 | err = read_mem_unaligned(&data.ul[0], ea, 4, regs); |
327 | if (!err) | 386 | if (!err) |
328 | err = read_mem_unaligned(&val[1], ea + 4, 4, regs); | 387 | err = read_mem_unaligned(&data.ul[1], ea + 4, 4, regs); |
329 | } | 388 | } |
330 | if (err) | 389 | if (err) |
331 | return err; | 390 | return err; |
@@ -337,28 +396,42 @@ static int __kprobes do_fp_store(int rn, int (*func)(int, unsigned long), | |||
337 | struct pt_regs *regs) | 396 | struct pt_regs *regs) |
338 | { | 397 | { |
339 | int err; | 398 | int err; |
340 | unsigned long val[sizeof(double) / sizeof(long)]; | 399 | union { |
400 | double dbl; | ||
401 | unsigned long ul[2]; | ||
402 | struct { | ||
403 | #ifdef __BIG_ENDIAN__ | ||
404 | unsigned _pad_; | ||
405 | unsigned word; | ||
406 | #endif | ||
407 | #ifdef __LITTLE_ENDIAN__ | ||
408 | unsigned word; | ||
409 | unsigned _pad_; | ||
410 | #endif | ||
411 | } single; | ||
412 | } data; | ||
341 | unsigned long ptr; | 413 | unsigned long ptr; |
342 | 414 | ||
343 | if (!address_ok(regs, ea, nb)) | 415 | if (!address_ok(regs, ea, nb)) |
344 | return -EFAULT; | 416 | return -EFAULT; |
345 | if ((ea & 3) == 0) | 417 | if ((ea & 3) == 0) |
346 | return (*func)(rn, ea); | 418 | return (*func)(rn, ea); |
347 | ptr = (unsigned long) &val[0]; | 419 | ptr = (unsigned long) &data.ul[0]; |
348 | if (sizeof(unsigned long) == 8 || nb == 4) { | 420 | if (sizeof(unsigned long) == 8 || nb == 4) { |
349 | ptr += sizeof(unsigned long) - nb; | 421 | if (nb == 4) |
422 | ptr = (unsigned long)&(data.single.word); | ||
350 | err = (*func)(rn, ptr); | 423 | err = (*func)(rn, ptr); |
351 | if (err) | 424 | if (err) |
352 | return err; | 425 | return err; |
353 | err = write_mem_unaligned(val[0], ea, nb, regs); | 426 | err = write_mem_unaligned(data.ul[0], ea, nb, regs); |
354 | } else { | 427 | } else { |
355 | /* writing a double on 32-bit */ | 428 | /* writing a double on 32-bit */ |
356 | err = (*func)(rn, ptr); | 429 | err = (*func)(rn, ptr); |
357 | if (err) | 430 | if (err) |
358 | return err; | 431 | return err; |
359 | err = write_mem_unaligned(val[0], ea, 4, regs); | 432 | err = write_mem_unaligned(data.ul[0], ea, 4, regs); |
360 | if (!err) | 433 | if (!err) |
361 | err = write_mem_unaligned(val[1], ea + 4, 4, regs); | 434 | err = write_mem_unaligned(data.ul[1], ea + 4, 4, regs); |
362 | } | 435 | } |
363 | return err; | 436 | return err; |
364 | } | 437 | } |