aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/lib/sstep.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/lib/sstep.c')
-rw-r--r--arch/powerpc/lib/sstep.c97
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}