diff options
author | Anshuman Khandual <khandual@linux.vnet.ibm.com> | 2016-07-27 22:57:39 -0400 |
---|---|---|
committer | Michael Ellerman <mpe@ellerman.id.au> | 2016-07-31 21:15:20 -0400 |
commit | 9d3918f7c0e516bb8782915cdb2f8cbdbf6c4f9b (patch) | |
tree | c90e9e05fc25c8ffb45583ae95be956b767e94be | |
parent | 8c13f5999997d36fc5fb296809efedc13c801704 (diff) |
powerpc/ptrace: Enable support for NT_PPC_CVSX
This patch enables support for TM checkpointed VSX register
set ELF core note NT_PPC_CVSX based ptrace requests through
PTRACE_GETREGSET, PTRACE_SETREGSET calls. This is achieved
through adding a register set REGSET_CVSX 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 | 129 |
2 files changed, 130 insertions, 0 deletions
diff --git a/arch/powerpc/include/uapi/asm/elf.h b/arch/powerpc/include/uapi/asm/elf.h index ecb4e84cb22c..1549172aa258 100644 --- a/arch/powerpc/include/uapi/asm/elf.h +++ b/arch/powerpc/include/uapi/asm/elf.h | |||
@@ -92,6 +92,7 @@ | |||
92 | #define ELF_NGREG 48 /* includes nip, msr, lr, etc. */ | 92 | #define ELF_NGREG 48 /* includes nip, msr, lr, etc. */ |
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 | 96 | ||
96 | typedef unsigned long elf_greg_t64; | 97 | typedef unsigned long elf_greg_t64; |
97 | typedef elf_greg_t64 elf_gregset_t64[ELF_NGREG]; | 98 | typedef elf_greg_t64 elf_gregset_t64[ELF_NGREG]; |
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 6e42137c0175..df6afe7da4da 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c | |||
@@ -65,6 +65,7 @@ struct pt_regs_offset { | |||
65 | #define REG_OFFSET_END {.name = NULL, .offset = 0} | 65 | #define REG_OFFSET_END {.name = NULL, .offset = 0} |
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 | 69 | ||
69 | static const struct pt_regs_offset regoffset_table[] = { | 70 | static const struct pt_regs_offset regoffset_table[] = { |
70 | GPR_OFFSET_NAME(0), | 71 | GPR_OFFSET_NAME(0), |
@@ -1294,6 +1295,123 @@ static int tm_cvmx_set(struct task_struct *target, | |||
1294 | 1295 | ||
1295 | return ret; | 1296 | return ret; |
1296 | } | 1297 | } |
1298 | |||
1299 | /** | ||
1300 | * tm_cvsx_active - get active number of registers in CVSX | ||
1301 | * @target: The target task. | ||
1302 | * @regset: The user regset structure. | ||
1303 | * | ||
1304 | * This function checks for the active number of available | ||
1305 | * regisers in transaction checkpointed VSX category. | ||
1306 | */ | ||
1307 | static int tm_cvsx_active(struct task_struct *target, | ||
1308 | const struct user_regset *regset) | ||
1309 | { | ||
1310 | if (!cpu_has_feature(CPU_FTR_TM)) | ||
1311 | return -ENODEV; | ||
1312 | |||
1313 | if (!MSR_TM_ACTIVE(target->thread.regs->msr)) | ||
1314 | return 0; | ||
1315 | |||
1316 | flush_vsx_to_thread(target); | ||
1317 | return target->thread.used_vsr ? regset->n : 0; | ||
1318 | } | ||
1319 | |||
1320 | /** | ||
1321 | * tm_cvsx_get - get CVSX registers | ||
1322 | * @target: The target task. | ||
1323 | * @regset: The user regset structure. | ||
1324 | * @pos: The buffer position. | ||
1325 | * @count: Number of bytes to copy. | ||
1326 | * @kbuf: Kernel buffer to copy from. | ||
1327 | * @ubuf: User buffer to copy into. | ||
1328 | * | ||
1329 | * This function gets in transaction checkpointed VSX registers. | ||
1330 | * | ||
1331 | * When the transaction is active 'fp_state' holds the checkpointed | ||
1332 | * values for the current transaction to fall back on if it aborts | ||
1333 | * in between. This function gets those checkpointed VSX registers. | ||
1334 | * The userspace interface buffer layout is as follows. | ||
1335 | * | ||
1336 | * struct data { | ||
1337 | * u64 vsx[32]; | ||
1338 | *}; | ||
1339 | */ | ||
1340 | static int tm_cvsx_get(struct task_struct *target, | ||
1341 | const struct user_regset *regset, | ||
1342 | unsigned int pos, unsigned int count, | ||
1343 | void *kbuf, void __user *ubuf) | ||
1344 | { | ||
1345 | u64 buf[32]; | ||
1346 | int ret, i; | ||
1347 | |||
1348 | if (!cpu_has_feature(CPU_FTR_TM)) | ||
1349 | return -ENODEV; | ||
1350 | |||
1351 | if (!MSR_TM_ACTIVE(target->thread.regs->msr)) | ||
1352 | return -ENODATA; | ||
1353 | |||
1354 | /* Flush the state */ | ||
1355 | flush_fp_to_thread(target); | ||
1356 | flush_altivec_to_thread(target); | ||
1357 | flush_tmregs_to_thread(target); | ||
1358 | flush_vsx_to_thread(target); | ||
1359 | |||
1360 | for (i = 0; i < 32 ; i++) | ||
1361 | buf[i] = target->thread.fp_state.fpr[i][TS_VSRLOWOFFSET]; | ||
1362 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, | ||
1363 | buf, 0, 32 * sizeof(double)); | ||
1364 | |||
1365 | return ret; | ||
1366 | } | ||
1367 | |||
1368 | /** | ||
1369 | * tm_cvsx_set - set CFPR registers | ||
1370 | * @target: The target task. | ||
1371 | * @regset: The user regset structure. | ||
1372 | * @pos: The buffer position. | ||
1373 | * @count: Number of bytes to copy. | ||
1374 | * @kbuf: Kernel buffer to copy into. | ||
1375 | * @ubuf: User buffer to copy from. | ||
1376 | * | ||
1377 | * This function sets in transaction checkpointed VSX registers. | ||
1378 | * | ||
1379 | * When the transaction is active 'fp_state' holds the checkpointed | ||
1380 | * VSX register values for the current transaction to fall back on | ||
1381 | * if it aborts in between. This function sets these checkpointed | ||
1382 | * FPR registers. The userspace interface buffer layout is as follows. | ||
1383 | * | ||
1384 | * struct data { | ||
1385 | * u64 vsx[32]; | ||
1386 | *}; | ||
1387 | */ | ||
1388 | static int tm_cvsx_set(struct task_struct *target, | ||
1389 | const struct user_regset *regset, | ||
1390 | unsigned int pos, unsigned int count, | ||
1391 | const void *kbuf, const void __user *ubuf) | ||
1392 | { | ||
1393 | u64 buf[32]; | ||
1394 | int ret, i; | ||
1395 | |||
1396 | if (!cpu_has_feature(CPU_FTR_TM)) | ||
1397 | return -ENODEV; | ||
1398 | |||
1399 | if (!MSR_TM_ACTIVE(target->thread.regs->msr)) | ||
1400 | return -ENODATA; | ||
1401 | |||
1402 | /* Flush the state */ | ||
1403 | flush_fp_to_thread(target); | ||
1404 | flush_altivec_to_thread(target); | ||
1405 | flush_tmregs_to_thread(target); | ||
1406 | flush_vsx_to_thread(target); | ||
1407 | |||
1408 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
1409 | buf, 0, 32 * sizeof(double)); | ||
1410 | for (i = 0; i < 32 ; i++) | ||
1411 | target->thread.fp_state.fpr[i][TS_VSRLOWOFFSET] = buf[i]; | ||
1412 | |||
1413 | return ret; | ||
1414 | } | ||
1297 | #endif | 1415 | #endif |
1298 | 1416 | ||
1299 | /* | 1417 | /* |
@@ -1315,6 +1433,7 @@ enum powerpc_regset { | |||
1315 | REGSET_TM_CGPR, /* TM checkpointed GPR registers */ | 1433 | REGSET_TM_CGPR, /* TM checkpointed GPR registers */ |
1316 | REGSET_TM_CFPR, /* TM checkpointed FPR registers */ | 1434 | REGSET_TM_CFPR, /* TM checkpointed FPR registers */ |
1317 | REGSET_TM_CVMX, /* TM checkpointed VMX registers */ | 1435 | REGSET_TM_CVMX, /* TM checkpointed VMX registers */ |
1436 | REGSET_TM_CVSX, /* TM checkpointed VSX registers */ | ||
1318 | #endif | 1437 | #endif |
1319 | }; | 1438 | }; |
1320 | 1439 | ||
@@ -1366,6 +1485,11 @@ static const struct user_regset native_regsets[] = { | |||
1366 | .size = sizeof(vector128), .align = sizeof(vector128), | 1485 | .size = sizeof(vector128), .align = sizeof(vector128), |
1367 | .active = tm_cvmx_active, .get = tm_cvmx_get, .set = tm_cvmx_set | 1486 | .active = tm_cvmx_active, .get = tm_cvmx_get, .set = tm_cvmx_set |
1368 | }, | 1487 | }, |
1488 | [REGSET_TM_CVSX] = { | ||
1489 | .core_note_type = NT_PPC_TM_CVSX, .n = ELF_NVSX, | ||
1490 | .size = sizeof(double), .align = sizeof(double), | ||
1491 | .active = tm_cvsx_active, .get = tm_cvsx_get, .set = tm_cvsx_set | ||
1492 | }, | ||
1369 | #endif | 1493 | #endif |
1370 | }; | 1494 | }; |
1371 | 1495 | ||
@@ -1608,6 +1732,11 @@ static const struct user_regset compat_regsets[] = { | |||
1608 | .size = sizeof(vector128), .align = sizeof(vector128), | 1732 | .size = sizeof(vector128), .align = sizeof(vector128), |
1609 | .active = tm_cvmx_active, .get = tm_cvmx_get, .set = tm_cvmx_set | 1733 | .active = tm_cvmx_active, .get = tm_cvmx_get, .set = tm_cvmx_set |
1610 | }, | 1734 | }, |
1735 | [REGSET_TM_CVSX] = { | ||
1736 | .core_note_type = NT_PPC_TM_CVSX, .n = ELF_NVSX, | ||
1737 | .size = sizeof(double), .align = sizeof(double), | ||
1738 | .active = tm_cvsx_active, .get = tm_cvsx_get, .set = tm_cvsx_set | ||
1739 | }, | ||
1611 | #endif | 1740 | #endif |
1612 | }; | 1741 | }; |
1613 | 1742 | ||