diff options
author | Anshuman Khandual <khandual@linux.vnet.ibm.com> | 2016-07-27 22:57:38 -0400 |
---|---|---|
committer | Michael Ellerman <mpe@ellerman.id.au> | 2016-07-31 21:15:19 -0400 |
commit | 8c13f5999997d36fc5fb296809efedc13c801704 (patch) | |
tree | 574c9849aea49f9c819061899845b4e763831b76 | |
parent | 19cbcbf75a0c1b6b07b9b07de36f30c73e58d230 (diff) |
powerpc/ptrace: Enable support for NT_PPC_CVMX
This patch enables support for TM checkpointed VMX register
set ELF core note NT_PPC_CVMX based ptrace requests through
PTRACE_GETREGSET, PTRACE_SETREGSET calls. This is achieved
through adding a register set REGSET_CVMX 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 | 158 |
2 files changed, 159 insertions, 0 deletions
diff --git a/arch/powerpc/include/uapi/asm/elf.h b/arch/powerpc/include/uapi/asm/elf.h index c2d21d11c2d2..ecb4e84cb22c 100644 --- a/arch/powerpc/include/uapi/asm/elf.h +++ b/arch/powerpc/include/uapi/asm/elf.h | |||
@@ -91,6 +91,7 @@ | |||
91 | 91 | ||
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 | 95 | ||
95 | typedef unsigned long elf_greg_t64; | 96 | typedef unsigned long elf_greg_t64; |
96 | typedef elf_greg_t64 elf_gregset_t64[ELF_NGREG]; | 97 | typedef elf_greg_t64 elf_gregset_t64[ELF_NGREG]; |
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index b216c397b84f..6e42137c0175 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c | |||
@@ -64,6 +64,8 @@ struct pt_regs_offset { | |||
64 | {.name = STR(gpr##num), .offset = offsetof(struct pt_regs, gpr[num])} | 64 | {.name = STR(gpr##num), .offset = offsetof(struct pt_regs, gpr[num])} |
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)) | ||
68 | |||
67 | static const struct pt_regs_offset regoffset_table[] = { | 69 | static const struct pt_regs_offset regoffset_table[] = { |
68 | GPR_OFFSET_NAME(0), | 70 | GPR_OFFSET_NAME(0), |
69 | GPR_OFFSET_NAME(1), | 71 | GPR_OFFSET_NAME(1), |
@@ -1147,6 +1149,151 @@ static int tm_cfpr_set(struct task_struct *target, | |||
1147 | target->thread.fp_state.fpscr = buf[32]; | 1149 | target->thread.fp_state.fpscr = buf[32]; |
1148 | return 0; | 1150 | return 0; |
1149 | } | 1151 | } |
1152 | |||
1153 | /** | ||
1154 | * tm_cvmx_active - get active number of registers in CVMX | ||
1155 | * @target: The target task. | ||
1156 | * @regset: The user regset structure. | ||
1157 | * | ||
1158 | * This function checks for the active number of available | ||
1159 | * regisers in checkpointed VMX category. | ||
1160 | */ | ||
1161 | static int tm_cvmx_active(struct task_struct *target, | ||
1162 | const struct user_regset *regset) | ||
1163 | { | ||
1164 | if (!cpu_has_feature(CPU_FTR_TM)) | ||
1165 | return -ENODEV; | ||
1166 | |||
1167 | if (!MSR_TM_ACTIVE(target->thread.regs->msr)) | ||
1168 | return 0; | ||
1169 | |||
1170 | return regset->n; | ||
1171 | } | ||
1172 | |||
1173 | /** | ||
1174 | * tm_cvmx_get - get CMVX registers | ||
1175 | * @target: The target task. | ||
1176 | * @regset: The user regset structure. | ||
1177 | * @pos: The buffer position. | ||
1178 | * @count: Number of bytes to copy. | ||
1179 | * @kbuf: Kernel buffer to copy from. | ||
1180 | * @ubuf: User buffer to copy into. | ||
1181 | * | ||
1182 | * This function gets in transaction checkpointed VMX registers. | ||
1183 | * | ||
1184 | * When the transaction is active 'vr_state' and 'vr_save' hold | ||
1185 | * the checkpointed values for the current transaction to fall | ||
1186 | * back on if it aborts in between. The userspace interface buffer | ||
1187 | * layout is as follows. | ||
1188 | * | ||
1189 | * struct data { | ||
1190 | * vector128 vr[32]; | ||
1191 | * vector128 vscr; | ||
1192 | * vector128 vrsave; | ||
1193 | *}; | ||
1194 | */ | ||
1195 | static int tm_cvmx_get(struct task_struct *target, | ||
1196 | const struct user_regset *regset, | ||
1197 | unsigned int pos, unsigned int count, | ||
1198 | void *kbuf, void __user *ubuf) | ||
1199 | { | ||
1200 | int ret; | ||
1201 | |||
1202 | BUILD_BUG_ON(TVSO(vscr) != TVSO(vr[32])); | ||
1203 | |||
1204 | if (!cpu_has_feature(CPU_FTR_TM)) | ||
1205 | return -ENODEV; | ||
1206 | |||
1207 | if (!MSR_TM_ACTIVE(target->thread.regs->msr)) | ||
1208 | return -ENODATA; | ||
1209 | |||
1210 | /* Flush the state */ | ||
1211 | flush_fp_to_thread(target); | ||
1212 | flush_altivec_to_thread(target); | ||
1213 | flush_tmregs_to_thread(target); | ||
1214 | |||
1215 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, | ||
1216 | &target->thread.vr_state, 0, | ||
1217 | 33 * sizeof(vector128)); | ||
1218 | if (!ret) { | ||
1219 | /* | ||
1220 | * Copy out only the low-order word of vrsave. | ||
1221 | */ | ||
1222 | union { | ||
1223 | elf_vrreg_t reg; | ||
1224 | u32 word; | ||
1225 | } vrsave; | ||
1226 | memset(&vrsave, 0, sizeof(vrsave)); | ||
1227 | vrsave.word = target->thread.vrsave; | ||
1228 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &vrsave, | ||
1229 | 33 * sizeof(vector128), -1); | ||
1230 | } | ||
1231 | |||
1232 | return ret; | ||
1233 | } | ||
1234 | |||
1235 | /** | ||
1236 | * tm_cvmx_set - set CMVX registers | ||
1237 | * @target: The target task. | ||
1238 | * @regset: The user regset structure. | ||
1239 | * @pos: The buffer position. | ||
1240 | * @count: Number of bytes to copy. | ||
1241 | * @kbuf: Kernel buffer to copy into. | ||
1242 | * @ubuf: User buffer to copy from. | ||
1243 | * | ||
1244 | * This function sets in transaction checkpointed VMX registers. | ||
1245 | * | ||
1246 | * When the transaction is active 'vr_state' and 'vr_save' hold | ||
1247 | * the checkpointed values for the current transaction to fall | ||
1248 | * back on if it aborts in between. The userspace interface buffer | ||
1249 | * layout is as follows. | ||
1250 | * | ||
1251 | * struct data { | ||
1252 | * vector128 vr[32]; | ||
1253 | * vector128 vscr; | ||
1254 | * vector128 vrsave; | ||
1255 | *}; | ||
1256 | */ | ||
1257 | static int tm_cvmx_set(struct task_struct *target, | ||
1258 | const struct user_regset *regset, | ||
1259 | unsigned int pos, unsigned int count, | ||
1260 | const void *kbuf, const void __user *ubuf) | ||
1261 | { | ||
1262 | int ret; | ||
1263 | |||
1264 | BUILD_BUG_ON(TVSO(vscr) != TVSO(vr[32])); | ||
1265 | |||
1266 | if (!cpu_has_feature(CPU_FTR_TM)) | ||
1267 | return -ENODEV; | ||
1268 | |||
1269 | if (!MSR_TM_ACTIVE(target->thread.regs->msr)) | ||
1270 | return -ENODATA; | ||
1271 | |||
1272 | flush_fp_to_thread(target); | ||
1273 | flush_altivec_to_thread(target); | ||
1274 | flush_tmregs_to_thread(target); | ||
1275 | |||
1276 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
1277 | &target->thread.vr_state, 0, | ||
1278 | 33 * sizeof(vector128)); | ||
1279 | if (!ret && count > 0) { | ||
1280 | /* | ||
1281 | * We use only the low-order word of vrsave. | ||
1282 | */ | ||
1283 | union { | ||
1284 | elf_vrreg_t reg; | ||
1285 | u32 word; | ||
1286 | } vrsave; | ||
1287 | memset(&vrsave, 0, sizeof(vrsave)); | ||
1288 | vrsave.word = target->thread.vrsave; | ||
1289 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &vrsave, | ||
1290 | 33 * sizeof(vector128), -1); | ||
1291 | if (!ret) | ||
1292 | target->thread.vrsave = vrsave.word; | ||
1293 | } | ||
1294 | |||
1295 | return ret; | ||
1296 | } | ||
1150 | #endif | 1297 | #endif |
1151 | 1298 | ||
1152 | /* | 1299 | /* |
@@ -1167,6 +1314,7 @@ enum powerpc_regset { | |||
1167 | #ifdef CONFIG_PPC_TRANSACTIONAL_MEM | 1314 | #ifdef CONFIG_PPC_TRANSACTIONAL_MEM |
1168 | REGSET_TM_CGPR, /* TM checkpointed GPR registers */ | 1315 | REGSET_TM_CGPR, /* TM checkpointed GPR registers */ |
1169 | REGSET_TM_CFPR, /* TM checkpointed FPR registers */ | 1316 | REGSET_TM_CFPR, /* TM checkpointed FPR registers */ |
1317 | REGSET_TM_CVMX, /* TM checkpointed VMX registers */ | ||
1170 | #endif | 1318 | #endif |
1171 | }; | 1319 | }; |
1172 | 1320 | ||
@@ -1213,6 +1361,11 @@ static const struct user_regset native_regsets[] = { | |||
1213 | .size = sizeof(double), .align = sizeof(double), | 1361 | .size = sizeof(double), .align = sizeof(double), |
1214 | .active = tm_cfpr_active, .get = tm_cfpr_get, .set = tm_cfpr_set | 1362 | .active = tm_cfpr_active, .get = tm_cfpr_get, .set = tm_cfpr_set |
1215 | }, | 1363 | }, |
1364 | [REGSET_TM_CVMX] = { | ||
1365 | .core_note_type = NT_PPC_TM_CVMX, .n = ELF_NVMX, | ||
1366 | .size = sizeof(vector128), .align = sizeof(vector128), | ||
1367 | .active = tm_cvmx_active, .get = tm_cvmx_get, .set = tm_cvmx_set | ||
1368 | }, | ||
1216 | #endif | 1369 | #endif |
1217 | }; | 1370 | }; |
1218 | 1371 | ||
@@ -1450,6 +1603,11 @@ static const struct user_regset compat_regsets[] = { | |||
1450 | .size = sizeof(double), .align = sizeof(double), | 1603 | .size = sizeof(double), .align = sizeof(double), |
1451 | .active = tm_cfpr_active, .get = tm_cfpr_get, .set = tm_cfpr_set | 1604 | .active = tm_cfpr_active, .get = tm_cfpr_get, .set = tm_cfpr_set |
1452 | }, | 1605 | }, |
1606 | [REGSET_TM_CVMX] = { | ||
1607 | .core_note_type = NT_PPC_TM_CVMX, .n = ELF_NVMX, | ||
1608 | .size = sizeof(vector128), .align = sizeof(vector128), | ||
1609 | .active = tm_cvmx_active, .get = tm_cvmx_get, .set = tm_cvmx_set | ||
1610 | }, | ||
1453 | #endif | 1611 | #endif |
1454 | }; | 1612 | }; |
1455 | 1613 | ||