diff options
author | Anshuman Khandual <khandual@linux.vnet.ibm.com> | 2016-07-27 22:57:40 -0400 |
---|---|---|
committer | Michael Ellerman <mpe@ellerman.id.au> | 2016-07-31 21:15:21 -0400 |
commit | 08e1c01d6aedf00af04d9571a0a5d5867298b719 (patch) | |
tree | b04d0692fc5d812b1ebafad9c832df42a3731e3b | |
parent | 9d3918f7c0e516bb8782915cdb2f8cbdbf6c4f9b (diff) |
powerpc/ptrace: Enable support for TM SPR state
This patch enables support for TM SPR state related ELF core
note NT_PPC_TM_SPR based ptrace requests through PTRACE_GETREGSET,
PTRACE_SETREGSET calls. This is achieved through adding a register
set REGSET_TM_SPR in powerpc corresponding to the ELF core note
section added. It implements the get, set and active functions for
this new register set added.
Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
Signed-off-by: Simon Guo <wei.guo.simon@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
-rw-r--r-- | arch/powerpc/include/uapi/asm/elf.h | 1 | ||||
-rw-r--r-- | arch/powerpc/kernel/ptrace.c | 143 |
2 files changed, 143 insertions, 1 deletions
diff --git a/arch/powerpc/include/uapi/asm/elf.h b/arch/powerpc/include/uapi/asm/elf.h index 1549172aa258..e703c646163b 100644 --- a/arch/powerpc/include/uapi/asm/elf.h +++ b/arch/powerpc/include/uapi/asm/elf.h | |||
@@ -93,6 +93,7 @@ | |||
93 | #define ELF_NFPREG 33 /* includes fpscr */ | 93 | #define ELF_NFPREG 33 /* includes fpscr */ |
94 | #define ELF_NVMX 34 /* includes all vector registers */ | 94 | #define ELF_NVMX 34 /* includes all vector registers */ |
95 | #define ELF_NVSX 32 /* includes all VSX registers */ | 95 | #define ELF_NVSX 32 /* includes all VSX registers */ |
96 | #define ELF_NTMSPRREG 3 /* include tfhar, tfiar, texasr */ | ||
96 | 97 | ||
97 | typedef unsigned long elf_greg_t64; | 98 | typedef unsigned long elf_greg_t64; |
98 | typedef elf_greg_t64 elf_gregset_t64[ELF_NGREG]; | 99 | typedef elf_greg_t64 elf_gregset_t64[ELF_NGREG]; |
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index df6afe7da4da..f654224d2653 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c | |||
@@ -66,6 +66,7 @@ struct pt_regs_offset { | |||
66 | 66 | ||
67 | #define TVSO(f) (offsetof(struct thread_vr_state, f)) | 67 | #define TVSO(f) (offsetof(struct thread_vr_state, f)) |
68 | #define TFSO(f) (offsetof(struct thread_fp_state, f)) | 68 | #define TFSO(f) (offsetof(struct thread_fp_state, f)) |
69 | #define TSO(f) (offsetof(struct thread_struct, f)) | ||
69 | 70 | ||
70 | static const struct pt_regs_offset regoffset_table[] = { | 71 | static const struct pt_regs_offset regoffset_table[] = { |
71 | GPR_OFFSET_NAME(0), | 72 | GPR_OFFSET_NAME(0), |
@@ -1412,7 +1413,136 @@ static int tm_cvsx_set(struct task_struct *target, | |||
1412 | 1413 | ||
1413 | return ret; | 1414 | return ret; |
1414 | } | 1415 | } |
1415 | #endif | 1416 | |
1417 | /** | ||
1418 | * tm_spr_active - get active number of registers in TM SPR | ||
1419 | * @target: The target task. | ||
1420 | * @regset: The user regset structure. | ||
1421 | * | ||
1422 | * This function checks the active number of available | ||
1423 | * regisers in the transactional memory SPR category. | ||
1424 | */ | ||
1425 | static int tm_spr_active(struct task_struct *target, | ||
1426 | const struct user_regset *regset) | ||
1427 | { | ||
1428 | if (!cpu_has_feature(CPU_FTR_TM)) | ||
1429 | return -ENODEV; | ||
1430 | |||
1431 | return regset->n; | ||
1432 | } | ||
1433 | |||
1434 | /** | ||
1435 | * tm_spr_get - get the TM related SPR registers | ||
1436 | * @target: The target task. | ||
1437 | * @regset: The user regset structure. | ||
1438 | * @pos: The buffer position. | ||
1439 | * @count: Number of bytes to copy. | ||
1440 | * @kbuf: Kernel buffer to copy from. | ||
1441 | * @ubuf: User buffer to copy into. | ||
1442 | * | ||
1443 | * This function gets transactional memory related SPR registers. | ||
1444 | * The userspace interface buffer layout is as follows. | ||
1445 | * | ||
1446 | * struct { | ||
1447 | * u64 tm_tfhar; | ||
1448 | * u64 tm_texasr; | ||
1449 | * u64 tm_tfiar; | ||
1450 | * }; | ||
1451 | */ | ||
1452 | static int tm_spr_get(struct task_struct *target, | ||
1453 | const struct user_regset *regset, | ||
1454 | unsigned int pos, unsigned int count, | ||
1455 | void *kbuf, void __user *ubuf) | ||
1456 | { | ||
1457 | int ret; | ||
1458 | |||
1459 | /* Build tests */ | ||
1460 | BUILD_BUG_ON(TSO(tm_tfhar) + sizeof(u64) != TSO(tm_texasr)); | ||
1461 | BUILD_BUG_ON(TSO(tm_texasr) + sizeof(u64) != TSO(tm_tfiar)); | ||
1462 | BUILD_BUG_ON(TSO(tm_tfiar) + sizeof(u64) != TSO(ckpt_regs)); | ||
1463 | |||
1464 | if (!cpu_has_feature(CPU_FTR_TM)) | ||
1465 | return -ENODEV; | ||
1466 | |||
1467 | /* Flush the states */ | ||
1468 | flush_fp_to_thread(target); | ||
1469 | flush_altivec_to_thread(target); | ||
1470 | flush_tmregs_to_thread(target); | ||
1471 | |||
1472 | /* TFHAR register */ | ||
1473 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, | ||
1474 | &target->thread.tm_tfhar, 0, sizeof(u64)); | ||
1475 | |||
1476 | /* TEXASR register */ | ||
1477 | if (!ret) | ||
1478 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, | ||
1479 | &target->thread.tm_texasr, sizeof(u64), | ||
1480 | 2 * sizeof(u64)); | ||
1481 | |||
1482 | /* TFIAR register */ | ||
1483 | if (!ret) | ||
1484 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, | ||
1485 | &target->thread.tm_tfiar, | ||
1486 | 2 * sizeof(u64), 3 * sizeof(u64)); | ||
1487 | return ret; | ||
1488 | } | ||
1489 | |||
1490 | /** | ||
1491 | * tm_spr_set - set the TM related SPR registers | ||
1492 | * @target: The target task. | ||
1493 | * @regset: The user regset structure. | ||
1494 | * @pos: The buffer position. | ||
1495 | * @count: Number of bytes to copy. | ||
1496 | * @kbuf: Kernel buffer to copy into. | ||
1497 | * @ubuf: User buffer to copy from. | ||
1498 | * | ||
1499 | * This function sets transactional memory related SPR registers. | ||
1500 | * The userspace interface buffer layout is as follows. | ||
1501 | * | ||
1502 | * struct { | ||
1503 | * u64 tm_tfhar; | ||
1504 | * u64 tm_texasr; | ||
1505 | * u64 tm_tfiar; | ||
1506 | * }; | ||
1507 | */ | ||
1508 | static int tm_spr_set(struct task_struct *target, | ||
1509 | const struct user_regset *regset, | ||
1510 | unsigned int pos, unsigned int count, | ||
1511 | const void *kbuf, const void __user *ubuf) | ||
1512 | { | ||
1513 | int ret; | ||
1514 | |||
1515 | /* Build tests */ | ||
1516 | BUILD_BUG_ON(TSO(tm_tfhar) + sizeof(u64) != TSO(tm_texasr)); | ||
1517 | BUILD_BUG_ON(TSO(tm_texasr) + sizeof(u64) != TSO(tm_tfiar)); | ||
1518 | BUILD_BUG_ON(TSO(tm_tfiar) + sizeof(u64) != TSO(ckpt_regs)); | ||
1519 | |||
1520 | if (!cpu_has_feature(CPU_FTR_TM)) | ||
1521 | return -ENODEV; | ||
1522 | |||
1523 | /* Flush the states */ | ||
1524 | flush_fp_to_thread(target); | ||
1525 | flush_altivec_to_thread(target); | ||
1526 | flush_tmregs_to_thread(target); | ||
1527 | |||
1528 | /* TFHAR register */ | ||
1529 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
1530 | &target->thread.tm_tfhar, 0, sizeof(u64)); | ||
1531 | |||
1532 | /* TEXASR register */ | ||
1533 | if (!ret) | ||
1534 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
1535 | &target->thread.tm_texasr, sizeof(u64), | ||
1536 | 2 * sizeof(u64)); | ||
1537 | |||
1538 | /* TFIAR register */ | ||
1539 | if (!ret) | ||
1540 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
1541 | &target->thread.tm_tfiar, | ||
1542 | 2 * sizeof(u64), 3 * sizeof(u64)); | ||
1543 | return ret; | ||
1544 | } | ||
1545 | #endif /* CONFIG_PPC_TRANSACTIONAL_MEM */ | ||
1416 | 1546 | ||
1417 | /* | 1547 | /* |
1418 | * These are our native regset flavors. | 1548 | * These are our native regset flavors. |
@@ -1434,6 +1564,7 @@ enum powerpc_regset { | |||
1434 | REGSET_TM_CFPR, /* TM checkpointed FPR registers */ | 1564 | REGSET_TM_CFPR, /* TM checkpointed FPR registers */ |
1435 | REGSET_TM_CVMX, /* TM checkpointed VMX registers */ | 1565 | REGSET_TM_CVMX, /* TM checkpointed VMX registers */ |
1436 | REGSET_TM_CVSX, /* TM checkpointed VSX registers */ | 1566 | REGSET_TM_CVSX, /* TM checkpointed VSX registers */ |
1567 | REGSET_TM_SPR, /* TM specific SPR registers */ | ||
1437 | #endif | 1568 | #endif |
1438 | }; | 1569 | }; |
1439 | 1570 | ||
@@ -1490,6 +1621,11 @@ static const struct user_regset native_regsets[] = { | |||
1490 | .size = sizeof(double), .align = sizeof(double), | 1621 | .size = sizeof(double), .align = sizeof(double), |
1491 | .active = tm_cvsx_active, .get = tm_cvsx_get, .set = tm_cvsx_set | 1622 | .active = tm_cvsx_active, .get = tm_cvsx_get, .set = tm_cvsx_set |
1492 | }, | 1623 | }, |
1624 | [REGSET_TM_SPR] = { | ||
1625 | .core_note_type = NT_PPC_TM_SPR, .n = ELF_NTMSPRREG, | ||
1626 | .size = sizeof(u64), .align = sizeof(u64), | ||
1627 | .active = tm_spr_active, .get = tm_spr_get, .set = tm_spr_set | ||
1628 | }, | ||
1493 | #endif | 1629 | #endif |
1494 | }; | 1630 | }; |
1495 | 1631 | ||
@@ -1737,6 +1873,11 @@ static const struct user_regset compat_regsets[] = { | |||
1737 | .size = sizeof(double), .align = sizeof(double), | 1873 | .size = sizeof(double), .align = sizeof(double), |
1738 | .active = tm_cvsx_active, .get = tm_cvsx_get, .set = tm_cvsx_set | 1874 | .active = tm_cvsx_active, .get = tm_cvsx_get, .set = tm_cvsx_set |
1739 | }, | 1875 | }, |
1876 | [REGSET_TM_SPR] = { | ||
1877 | .core_note_type = NT_PPC_TM_SPR, .n = ELF_NTMSPRREG, | ||
1878 | .size = sizeof(u64), .align = sizeof(u64), | ||
1879 | .active = tm_spr_active, .get = tm_spr_get, .set = tm_spr_set | ||
1880 | }, | ||
1740 | #endif | 1881 | #endif |
1741 | }; | 1882 | }; |
1742 | 1883 | ||