ptrace-view.c (23667B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2 3#include <linux/regset.h> 4#include <linux/elf.h> 5#include <linux/nospec.h> 6#include <linux/pkeys.h> 7 8#include "ptrace-decl.h" 9 10struct pt_regs_offset { 11 const char *name; 12 int offset; 13}; 14 15#define STR(s) #s /* convert to string */ 16#define REG_OFFSET_NAME(r) {.name = #r, .offset = offsetof(struct pt_regs, r)} 17#define GPR_OFFSET_NAME(num) \ 18 {.name = STR(r##num), .offset = offsetof(struct pt_regs, gpr[num])}, \ 19 {.name = STR(gpr##num), .offset = offsetof(struct pt_regs, gpr[num])} 20#define REG_OFFSET_END {.name = NULL, .offset = 0} 21 22static const struct pt_regs_offset regoffset_table[] = { 23 GPR_OFFSET_NAME(0), 24 GPR_OFFSET_NAME(1), 25 GPR_OFFSET_NAME(2), 26 GPR_OFFSET_NAME(3), 27 GPR_OFFSET_NAME(4), 28 GPR_OFFSET_NAME(5), 29 GPR_OFFSET_NAME(6), 30 GPR_OFFSET_NAME(7), 31 GPR_OFFSET_NAME(8), 32 GPR_OFFSET_NAME(9), 33 GPR_OFFSET_NAME(10), 34 GPR_OFFSET_NAME(11), 35 GPR_OFFSET_NAME(12), 36 GPR_OFFSET_NAME(13), 37 GPR_OFFSET_NAME(14), 38 GPR_OFFSET_NAME(15), 39 GPR_OFFSET_NAME(16), 40 GPR_OFFSET_NAME(17), 41 GPR_OFFSET_NAME(18), 42 GPR_OFFSET_NAME(19), 43 GPR_OFFSET_NAME(20), 44 GPR_OFFSET_NAME(21), 45 GPR_OFFSET_NAME(22), 46 GPR_OFFSET_NAME(23), 47 GPR_OFFSET_NAME(24), 48 GPR_OFFSET_NAME(25), 49 GPR_OFFSET_NAME(26), 50 GPR_OFFSET_NAME(27), 51 GPR_OFFSET_NAME(28), 52 GPR_OFFSET_NAME(29), 53 GPR_OFFSET_NAME(30), 54 GPR_OFFSET_NAME(31), 55 REG_OFFSET_NAME(nip), 56 REG_OFFSET_NAME(msr), 57 REG_OFFSET_NAME(ctr), 58 REG_OFFSET_NAME(link), 59 REG_OFFSET_NAME(xer), 60 REG_OFFSET_NAME(ccr), 61#ifdef CONFIG_PPC64 62 REG_OFFSET_NAME(softe), 63#else 64 REG_OFFSET_NAME(mq), 65#endif 66 REG_OFFSET_NAME(trap), 67 REG_OFFSET_NAME(dar), 68 REG_OFFSET_NAME(dsisr), 69 REG_OFFSET_END, 70}; 71 72/** 73 * regs_query_register_offset() - query register offset from its name 74 * @name: the name of a register 75 * 76 * regs_query_register_offset() returns the offset of a register in struct 77 * pt_regs from its name. If the name is invalid, this returns -EINVAL; 78 */ 79int regs_query_register_offset(const char *name) 80{ 81 const struct pt_regs_offset *roff; 82 for (roff = regoffset_table; roff->name != NULL; roff++) 83 if (!strcmp(roff->name, name)) 84 return roff->offset; 85 return -EINVAL; 86} 87 88/** 89 * regs_query_register_name() - query register name from its offset 90 * @offset: the offset of a register in struct pt_regs. 91 * 92 * regs_query_register_name() returns the name of a register from its 93 * offset in struct pt_regs. If the @offset is invalid, this returns NULL; 94 */ 95const char *regs_query_register_name(unsigned int offset) 96{ 97 const struct pt_regs_offset *roff; 98 for (roff = regoffset_table; roff->name != NULL; roff++) 99 if (roff->offset == offset) 100 return roff->name; 101 return NULL; 102} 103 104/* 105 * does not yet catch signals sent when the child dies. 106 * in exit.c or in signal.c. 107 */ 108 109static unsigned long get_user_msr(struct task_struct *task) 110{ 111 return task->thread.regs->msr | task->thread.fpexc_mode; 112} 113 114static __always_inline int set_user_msr(struct task_struct *task, unsigned long msr) 115{ 116 unsigned long newmsr = (task->thread.regs->msr & ~MSR_DEBUGCHANGE) | 117 (msr & MSR_DEBUGCHANGE); 118 regs_set_return_msr(task->thread.regs, newmsr); 119 return 0; 120} 121 122#ifdef CONFIG_PPC64 123static int get_user_dscr(struct task_struct *task, unsigned long *data) 124{ 125 *data = task->thread.dscr; 126 return 0; 127} 128 129static int set_user_dscr(struct task_struct *task, unsigned long dscr) 130{ 131 task->thread.dscr = dscr; 132 task->thread.dscr_inherit = 1; 133 return 0; 134} 135#else 136static int get_user_dscr(struct task_struct *task, unsigned long *data) 137{ 138 return -EIO; 139} 140 141static int set_user_dscr(struct task_struct *task, unsigned long dscr) 142{ 143 return -EIO; 144} 145#endif 146 147/* 148 * We prevent mucking around with the reserved area of trap 149 * which are used internally by the kernel. 150 */ 151static __always_inline int set_user_trap(struct task_struct *task, unsigned long trap) 152{ 153 set_trap(task->thread.regs, trap); 154 return 0; 155} 156 157/* 158 * Get contents of register REGNO in task TASK. 159 */ 160int ptrace_get_reg(struct task_struct *task, int regno, unsigned long *data) 161{ 162 unsigned int regs_max; 163 164 if (task->thread.regs == NULL || !data) 165 return -EIO; 166 167 if (regno == PT_MSR) { 168 *data = get_user_msr(task); 169 return 0; 170 } 171 172 if (regno == PT_DSCR) 173 return get_user_dscr(task, data); 174 175 /* 176 * softe copies paca->irq_soft_mask variable state. Since irq_soft_mask is 177 * no more used as a flag, lets force usr to always see the softe value as 1 178 * which means interrupts are not soft disabled. 179 */ 180 if (IS_ENABLED(CONFIG_PPC64) && regno == PT_SOFTE) { 181 *data = 1; 182 return 0; 183 } 184 185 regs_max = sizeof(struct user_pt_regs) / sizeof(unsigned long); 186 if (regno < regs_max) { 187 regno = array_index_nospec(regno, regs_max); 188 *data = ((unsigned long *)task->thread.regs)[regno]; 189 return 0; 190 } 191 192 return -EIO; 193} 194 195/* 196 * Write contents of register REGNO in task TASK. 197 */ 198int ptrace_put_reg(struct task_struct *task, int regno, unsigned long data) 199{ 200 if (task->thread.regs == NULL) 201 return -EIO; 202 203 if (regno == PT_MSR) 204 return set_user_msr(task, data); 205 if (regno == PT_TRAP) 206 return set_user_trap(task, data); 207 if (regno == PT_DSCR) 208 return set_user_dscr(task, data); 209 210 if (regno <= PT_MAX_PUT_REG) { 211 regno = array_index_nospec(regno, PT_MAX_PUT_REG + 1); 212 ((unsigned long *)task->thread.regs)[regno] = data; 213 return 0; 214 } 215 return -EIO; 216} 217 218static int gpr_get(struct task_struct *target, const struct user_regset *regset, 219 struct membuf to) 220{ 221 struct membuf to_msr = membuf_at(&to, offsetof(struct pt_regs, msr)); 222#ifdef CONFIG_PPC64 223 struct membuf to_softe = membuf_at(&to, offsetof(struct pt_regs, softe)); 224#endif 225 if (target->thread.regs == NULL) 226 return -EIO; 227 228 membuf_write(&to, target->thread.regs, sizeof(struct user_pt_regs)); 229 230 membuf_store(&to_msr, get_user_msr(target)); 231#ifdef CONFIG_PPC64 232 membuf_store(&to_softe, 0x1ul); 233#endif 234 return membuf_zero(&to, ELF_NGREG * sizeof(unsigned long) - 235 sizeof(struct user_pt_regs)); 236} 237 238static int gpr_set(struct task_struct *target, const struct user_regset *regset, 239 unsigned int pos, unsigned int count, const void *kbuf, 240 const void __user *ubuf) 241{ 242 unsigned long reg; 243 int ret; 244 245 if (target->thread.regs == NULL) 246 return -EIO; 247 248 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 249 target->thread.regs, 250 0, PT_MSR * sizeof(reg)); 251 252 if (!ret && count > 0) { 253 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, ®, 254 PT_MSR * sizeof(reg), 255 (PT_MSR + 1) * sizeof(reg)); 256 if (!ret) 257 ret = set_user_msr(target, reg); 258 } 259 260 BUILD_BUG_ON(offsetof(struct pt_regs, orig_gpr3) != 261 offsetof(struct pt_regs, msr) + sizeof(long)); 262 263 if (!ret) 264 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 265 &target->thread.regs->orig_gpr3, 266 PT_ORIG_R3 * sizeof(reg), 267 (PT_MAX_PUT_REG + 1) * sizeof(reg)); 268 269 if (PT_MAX_PUT_REG + 1 < PT_TRAP && !ret) 270 ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 271 (PT_MAX_PUT_REG + 1) * sizeof(reg), 272 PT_TRAP * sizeof(reg)); 273 274 if (!ret && count > 0) { 275 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, ®, 276 PT_TRAP * sizeof(reg), 277 (PT_TRAP + 1) * sizeof(reg)); 278 if (!ret) 279 ret = set_user_trap(target, reg); 280 } 281 282 if (!ret) 283 ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 284 (PT_TRAP + 1) * sizeof(reg), -1); 285 286 return ret; 287} 288 289#ifdef CONFIG_PPC64 290static int ppr_get(struct task_struct *target, const struct user_regset *regset, 291 struct membuf to) 292{ 293 return membuf_write(&to, &target->thread.regs->ppr, sizeof(u64)); 294} 295 296static int ppr_set(struct task_struct *target, const struct user_regset *regset, 297 unsigned int pos, unsigned int count, const void *kbuf, 298 const void __user *ubuf) 299{ 300 return user_regset_copyin(&pos, &count, &kbuf, &ubuf, 301 &target->thread.regs->ppr, 0, sizeof(u64)); 302} 303 304static int dscr_get(struct task_struct *target, const struct user_regset *regset, 305 struct membuf to) 306{ 307 return membuf_write(&to, &target->thread.dscr, sizeof(u64)); 308} 309static int dscr_set(struct task_struct *target, const struct user_regset *regset, 310 unsigned int pos, unsigned int count, const void *kbuf, 311 const void __user *ubuf) 312{ 313 return user_regset_copyin(&pos, &count, &kbuf, &ubuf, 314 &target->thread.dscr, 0, sizeof(u64)); 315} 316#endif 317#ifdef CONFIG_PPC_BOOK3S_64 318static int tar_get(struct task_struct *target, const struct user_regset *regset, 319 struct membuf to) 320{ 321 return membuf_write(&to, &target->thread.tar, sizeof(u64)); 322} 323static int tar_set(struct task_struct *target, const struct user_regset *regset, 324 unsigned int pos, unsigned int count, const void *kbuf, 325 const void __user *ubuf) 326{ 327 return user_regset_copyin(&pos, &count, &kbuf, &ubuf, 328 &target->thread.tar, 0, sizeof(u64)); 329} 330 331static int ebb_active(struct task_struct *target, const struct user_regset *regset) 332{ 333 if (!cpu_has_feature(CPU_FTR_ARCH_207S)) 334 return -ENODEV; 335 336 if (target->thread.used_ebb) 337 return regset->n; 338 339 return 0; 340} 341 342static int ebb_get(struct task_struct *target, const struct user_regset *regset, 343 struct membuf to) 344{ 345 /* Build tests */ 346 BUILD_BUG_ON(TSO(ebbrr) + sizeof(unsigned long) != TSO(ebbhr)); 347 BUILD_BUG_ON(TSO(ebbhr) + sizeof(unsigned long) != TSO(bescr)); 348 349 if (!cpu_has_feature(CPU_FTR_ARCH_207S)) 350 return -ENODEV; 351 352 if (!target->thread.used_ebb) 353 return -ENODATA; 354 355 return membuf_write(&to, &target->thread.ebbrr, 3 * sizeof(unsigned long)); 356} 357 358static int ebb_set(struct task_struct *target, const struct user_regset *regset, 359 unsigned int pos, unsigned int count, const void *kbuf, 360 const void __user *ubuf) 361{ 362 int ret = 0; 363 364 /* Build tests */ 365 BUILD_BUG_ON(TSO(ebbrr) + sizeof(unsigned long) != TSO(ebbhr)); 366 BUILD_BUG_ON(TSO(ebbhr) + sizeof(unsigned long) != TSO(bescr)); 367 368 if (!cpu_has_feature(CPU_FTR_ARCH_207S)) 369 return -ENODEV; 370 371 if (target->thread.used_ebb) 372 return -ENODATA; 373 374 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &target->thread.ebbrr, 375 0, sizeof(unsigned long)); 376 377 if (!ret) 378 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 379 &target->thread.ebbhr, sizeof(unsigned long), 380 2 * sizeof(unsigned long)); 381 382 if (!ret) 383 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 384 &target->thread.bescr, 2 * sizeof(unsigned long), 385 3 * sizeof(unsigned long)); 386 387 return ret; 388} 389static int pmu_active(struct task_struct *target, const struct user_regset *regset) 390{ 391 if (!cpu_has_feature(CPU_FTR_ARCH_207S)) 392 return -ENODEV; 393 394 return regset->n; 395} 396 397static int pmu_get(struct task_struct *target, const struct user_regset *regset, 398 struct membuf to) 399{ 400 /* Build tests */ 401 BUILD_BUG_ON(TSO(siar) + sizeof(unsigned long) != TSO(sdar)); 402 BUILD_BUG_ON(TSO(sdar) + sizeof(unsigned long) != TSO(sier)); 403 BUILD_BUG_ON(TSO(sier) + sizeof(unsigned long) != TSO(mmcr2)); 404 BUILD_BUG_ON(TSO(mmcr2) + sizeof(unsigned long) != TSO(mmcr0)); 405 406 if (!cpu_has_feature(CPU_FTR_ARCH_207S)) 407 return -ENODEV; 408 409 return membuf_write(&to, &target->thread.siar, 5 * sizeof(unsigned long)); 410} 411 412static int pmu_set(struct task_struct *target, const struct user_regset *regset, 413 unsigned int pos, unsigned int count, const void *kbuf, 414 const void __user *ubuf) 415{ 416 int ret = 0; 417 418 /* Build tests */ 419 BUILD_BUG_ON(TSO(siar) + sizeof(unsigned long) != TSO(sdar)); 420 BUILD_BUG_ON(TSO(sdar) + sizeof(unsigned long) != TSO(sier)); 421 BUILD_BUG_ON(TSO(sier) + sizeof(unsigned long) != TSO(mmcr2)); 422 BUILD_BUG_ON(TSO(mmcr2) + sizeof(unsigned long) != TSO(mmcr0)); 423 424 if (!cpu_has_feature(CPU_FTR_ARCH_207S)) 425 return -ENODEV; 426 427 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &target->thread.siar, 428 0, sizeof(unsigned long)); 429 430 if (!ret) 431 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 432 &target->thread.sdar, sizeof(unsigned long), 433 2 * sizeof(unsigned long)); 434 435 if (!ret) 436 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 437 &target->thread.sier, 2 * sizeof(unsigned long), 438 3 * sizeof(unsigned long)); 439 440 if (!ret) 441 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 442 &target->thread.mmcr2, 3 * sizeof(unsigned long), 443 4 * sizeof(unsigned long)); 444 445 if (!ret) 446 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 447 &target->thread.mmcr0, 4 * sizeof(unsigned long), 448 5 * sizeof(unsigned long)); 449 return ret; 450} 451#endif 452 453#ifdef CONFIG_PPC_MEM_KEYS 454static int pkey_active(struct task_struct *target, const struct user_regset *regset) 455{ 456 if (!arch_pkeys_enabled()) 457 return -ENODEV; 458 459 return regset->n; 460} 461 462static int pkey_get(struct task_struct *target, const struct user_regset *regset, 463 struct membuf to) 464{ 465 466 if (!arch_pkeys_enabled()) 467 return -ENODEV; 468 469 membuf_store(&to, target->thread.regs->amr); 470 membuf_store(&to, target->thread.regs->iamr); 471 return membuf_store(&to, default_uamor); 472} 473 474static int pkey_set(struct task_struct *target, const struct user_regset *regset, 475 unsigned int pos, unsigned int count, const void *kbuf, 476 const void __user *ubuf) 477{ 478 u64 new_amr; 479 int ret; 480 481 if (!arch_pkeys_enabled()) 482 return -ENODEV; 483 484 /* Only the AMR can be set from userspace */ 485 if (pos != 0 || count != sizeof(new_amr)) 486 return -EINVAL; 487 488 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 489 &new_amr, 0, sizeof(new_amr)); 490 if (ret) 491 return ret; 492 493 /* 494 * UAMOR determines which bits of the AMR can be set from userspace. 495 * UAMOR value 0b11 indicates that the AMR value can be modified 496 * from userspace. If the kernel is using a specific key, we avoid 497 * userspace modifying the AMR value for that key by masking them 498 * via UAMOR 0b00. 499 * 500 * Pick the AMR values for the keys that kernel is using. This 501 * will be indicated by the ~default_uamor bits. 502 */ 503 target->thread.regs->amr = (new_amr & default_uamor) | 504 (target->thread.regs->amr & ~default_uamor); 505 506 return 0; 507} 508#endif /* CONFIG_PPC_MEM_KEYS */ 509 510static const struct user_regset native_regsets[] = { 511 [REGSET_GPR] = { 512 .core_note_type = NT_PRSTATUS, .n = ELF_NGREG, 513 .size = sizeof(long), .align = sizeof(long), 514 .regset_get = gpr_get, .set = gpr_set 515 }, 516 [REGSET_FPR] = { 517 .core_note_type = NT_PRFPREG, .n = ELF_NFPREG, 518 .size = sizeof(double), .align = sizeof(double), 519 .regset_get = fpr_get, .set = fpr_set 520 }, 521#ifdef CONFIG_ALTIVEC 522 [REGSET_VMX] = { 523 .core_note_type = NT_PPC_VMX, .n = 34, 524 .size = sizeof(vector128), .align = sizeof(vector128), 525 .active = vr_active, .regset_get = vr_get, .set = vr_set 526 }, 527#endif 528#ifdef CONFIG_VSX 529 [REGSET_VSX] = { 530 .core_note_type = NT_PPC_VSX, .n = 32, 531 .size = sizeof(double), .align = sizeof(double), 532 .active = vsr_active, .regset_get = vsr_get, .set = vsr_set 533 }, 534#endif 535#ifdef CONFIG_SPE 536 [REGSET_SPE] = { 537 .core_note_type = NT_PPC_SPE, .n = 35, 538 .size = sizeof(u32), .align = sizeof(u32), 539 .active = evr_active, .regset_get = evr_get, .set = evr_set 540 }, 541#endif 542#ifdef CONFIG_PPC_TRANSACTIONAL_MEM 543 [REGSET_TM_CGPR] = { 544 .core_note_type = NT_PPC_TM_CGPR, .n = ELF_NGREG, 545 .size = sizeof(long), .align = sizeof(long), 546 .active = tm_cgpr_active, .regset_get = tm_cgpr_get, .set = tm_cgpr_set 547 }, 548 [REGSET_TM_CFPR] = { 549 .core_note_type = NT_PPC_TM_CFPR, .n = ELF_NFPREG, 550 .size = sizeof(double), .align = sizeof(double), 551 .active = tm_cfpr_active, .regset_get = tm_cfpr_get, .set = tm_cfpr_set 552 }, 553 [REGSET_TM_CVMX] = { 554 .core_note_type = NT_PPC_TM_CVMX, .n = ELF_NVMX, 555 .size = sizeof(vector128), .align = sizeof(vector128), 556 .active = tm_cvmx_active, .regset_get = tm_cvmx_get, .set = tm_cvmx_set 557 }, 558 [REGSET_TM_CVSX] = { 559 .core_note_type = NT_PPC_TM_CVSX, .n = ELF_NVSX, 560 .size = sizeof(double), .align = sizeof(double), 561 .active = tm_cvsx_active, .regset_get = tm_cvsx_get, .set = tm_cvsx_set 562 }, 563 [REGSET_TM_SPR] = { 564 .core_note_type = NT_PPC_TM_SPR, .n = ELF_NTMSPRREG, 565 .size = sizeof(u64), .align = sizeof(u64), 566 .active = tm_spr_active, .regset_get = tm_spr_get, .set = tm_spr_set 567 }, 568 [REGSET_TM_CTAR] = { 569 .core_note_type = NT_PPC_TM_CTAR, .n = 1, 570 .size = sizeof(u64), .align = sizeof(u64), 571 .active = tm_tar_active, .regset_get = tm_tar_get, .set = tm_tar_set 572 }, 573 [REGSET_TM_CPPR] = { 574 .core_note_type = NT_PPC_TM_CPPR, .n = 1, 575 .size = sizeof(u64), .align = sizeof(u64), 576 .active = tm_ppr_active, .regset_get = tm_ppr_get, .set = tm_ppr_set 577 }, 578 [REGSET_TM_CDSCR] = { 579 .core_note_type = NT_PPC_TM_CDSCR, .n = 1, 580 .size = sizeof(u64), .align = sizeof(u64), 581 .active = tm_dscr_active, .regset_get = tm_dscr_get, .set = tm_dscr_set 582 }, 583#endif 584#ifdef CONFIG_PPC64 585 [REGSET_PPR] = { 586 .core_note_type = NT_PPC_PPR, .n = 1, 587 .size = sizeof(u64), .align = sizeof(u64), 588 .regset_get = ppr_get, .set = ppr_set 589 }, 590 [REGSET_DSCR] = { 591 .core_note_type = NT_PPC_DSCR, .n = 1, 592 .size = sizeof(u64), .align = sizeof(u64), 593 .regset_get = dscr_get, .set = dscr_set 594 }, 595#endif 596#ifdef CONFIG_PPC_BOOK3S_64 597 [REGSET_TAR] = { 598 .core_note_type = NT_PPC_TAR, .n = 1, 599 .size = sizeof(u64), .align = sizeof(u64), 600 .regset_get = tar_get, .set = tar_set 601 }, 602 [REGSET_EBB] = { 603 .core_note_type = NT_PPC_EBB, .n = ELF_NEBB, 604 .size = sizeof(u64), .align = sizeof(u64), 605 .active = ebb_active, .regset_get = ebb_get, .set = ebb_set 606 }, 607 [REGSET_PMR] = { 608 .core_note_type = NT_PPC_PMU, .n = ELF_NPMU, 609 .size = sizeof(u64), .align = sizeof(u64), 610 .active = pmu_active, .regset_get = pmu_get, .set = pmu_set 611 }, 612#endif 613#ifdef CONFIG_PPC_MEM_KEYS 614 [REGSET_PKEY] = { 615 .core_note_type = NT_PPC_PKEY, .n = ELF_NPKEY, 616 .size = sizeof(u64), .align = sizeof(u64), 617 .active = pkey_active, .regset_get = pkey_get, .set = pkey_set 618 }, 619#endif 620}; 621 622const struct user_regset_view user_ppc_native_view = { 623 .name = UTS_MACHINE, .e_machine = ELF_ARCH, .ei_osabi = ELF_OSABI, 624 .regsets = native_regsets, .n = ARRAY_SIZE(native_regsets) 625}; 626 627#include <linux/compat.h> 628 629int gpr32_get_common(struct task_struct *target, 630 const struct user_regset *regset, 631 struct membuf to, unsigned long *regs) 632{ 633 int i; 634 635 for (i = 0; i < PT_MSR; i++) 636 membuf_store(&to, (u32)regs[i]); 637 membuf_store(&to, (u32)get_user_msr(target)); 638 for (i++ ; i < PT_REGS_COUNT; i++) 639 membuf_store(&to, (u32)regs[i]); 640 return membuf_zero(&to, (ELF_NGREG - PT_REGS_COUNT) * sizeof(u32)); 641} 642 643int gpr32_set_common(struct task_struct *target, 644 const struct user_regset *regset, 645 unsigned int pos, unsigned int count, 646 const void *kbuf, const void __user *ubuf, 647 unsigned long *regs) 648{ 649 const compat_ulong_t *k = kbuf; 650 const compat_ulong_t __user *u = ubuf; 651 compat_ulong_t reg; 652 653 if (!kbuf && !user_read_access_begin(u, count)) 654 return -EFAULT; 655 656 pos /= sizeof(reg); 657 count /= sizeof(reg); 658 659 if (kbuf) 660 for (; count > 0 && pos < PT_MSR; --count) 661 regs[pos++] = *k++; 662 else 663 for (; count > 0 && pos < PT_MSR; --count) { 664 unsafe_get_user(reg, u++, Efault); 665 regs[pos++] = reg; 666 } 667 668 669 if (count > 0 && pos == PT_MSR) { 670 if (kbuf) 671 reg = *k++; 672 else 673 unsafe_get_user(reg, u++, Efault); 674 set_user_msr(target, reg); 675 ++pos; 676 --count; 677 } 678 679 if (kbuf) { 680 for (; count > 0 && pos <= PT_MAX_PUT_REG; --count) 681 regs[pos++] = *k++; 682 for (; count > 0 && pos < PT_TRAP; --count, ++pos) 683 ++k; 684 } else { 685 for (; count > 0 && pos <= PT_MAX_PUT_REG; --count) { 686 unsafe_get_user(reg, u++, Efault); 687 regs[pos++] = reg; 688 } 689 for (; count > 0 && pos < PT_TRAP; --count, ++pos) 690 unsafe_get_user(reg, u++, Efault); 691 } 692 693 if (count > 0 && pos == PT_TRAP) { 694 if (kbuf) 695 reg = *k++; 696 else 697 unsafe_get_user(reg, u++, Efault); 698 set_user_trap(target, reg); 699 ++pos; 700 --count; 701 } 702 if (!kbuf) 703 user_read_access_end(); 704 705 kbuf = k; 706 ubuf = u; 707 pos *= sizeof(reg); 708 count *= sizeof(reg); 709 return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 710 (PT_TRAP + 1) * sizeof(reg), -1); 711 712Efault: 713 user_read_access_end(); 714 return -EFAULT; 715} 716 717static int gpr32_get(struct task_struct *target, 718 const struct user_regset *regset, 719 struct membuf to) 720{ 721 if (target->thread.regs == NULL) 722 return -EIO; 723 724 return gpr32_get_common(target, regset, to, 725 &target->thread.regs->gpr[0]); 726} 727 728static int gpr32_set(struct task_struct *target, 729 const struct user_regset *regset, 730 unsigned int pos, unsigned int count, 731 const void *kbuf, const void __user *ubuf) 732{ 733 if (target->thread.regs == NULL) 734 return -EIO; 735 736 return gpr32_set_common(target, regset, pos, count, kbuf, ubuf, 737 &target->thread.regs->gpr[0]); 738} 739 740/* 741 * These are the regset flavors matching the CONFIG_PPC32 native set. 742 */ 743static const struct user_regset compat_regsets[] = { 744 [REGSET_GPR] = { 745 .core_note_type = NT_PRSTATUS, .n = ELF_NGREG, 746 .size = sizeof(compat_long_t), .align = sizeof(compat_long_t), 747 .regset_get = gpr32_get, .set = gpr32_set 748 }, 749 [REGSET_FPR] = { 750 .core_note_type = NT_PRFPREG, .n = ELF_NFPREG, 751 .size = sizeof(double), .align = sizeof(double), 752 .regset_get = fpr_get, .set = fpr_set 753 }, 754#ifdef CONFIG_ALTIVEC 755 [REGSET_VMX] = { 756 .core_note_type = NT_PPC_VMX, .n = 34, 757 .size = sizeof(vector128), .align = sizeof(vector128), 758 .active = vr_active, .regset_get = vr_get, .set = vr_set 759 }, 760#endif 761#ifdef CONFIG_SPE 762 [REGSET_SPE] = { 763 .core_note_type = NT_PPC_SPE, .n = 35, 764 .size = sizeof(u32), .align = sizeof(u32), 765 .active = evr_active, .regset_get = evr_get, .set = evr_set 766 }, 767#endif 768#ifdef CONFIG_PPC_TRANSACTIONAL_MEM 769 [REGSET_TM_CGPR] = { 770 .core_note_type = NT_PPC_TM_CGPR, .n = ELF_NGREG, 771 .size = sizeof(long), .align = sizeof(long), 772 .active = tm_cgpr_active, 773 .regset_get = tm_cgpr32_get, .set = tm_cgpr32_set 774 }, 775 [REGSET_TM_CFPR] = { 776 .core_note_type = NT_PPC_TM_CFPR, .n = ELF_NFPREG, 777 .size = sizeof(double), .align = sizeof(double), 778 .active = tm_cfpr_active, .regset_get = tm_cfpr_get, .set = tm_cfpr_set 779 }, 780 [REGSET_TM_CVMX] = { 781 .core_note_type = NT_PPC_TM_CVMX, .n = ELF_NVMX, 782 .size = sizeof(vector128), .align = sizeof(vector128), 783 .active = tm_cvmx_active, .regset_get = tm_cvmx_get, .set = tm_cvmx_set 784 }, 785 [REGSET_TM_CVSX] = { 786 .core_note_type = NT_PPC_TM_CVSX, .n = ELF_NVSX, 787 .size = sizeof(double), .align = sizeof(double), 788 .active = tm_cvsx_active, .regset_get = tm_cvsx_get, .set = tm_cvsx_set 789 }, 790 [REGSET_TM_SPR] = { 791 .core_note_type = NT_PPC_TM_SPR, .n = ELF_NTMSPRREG, 792 .size = sizeof(u64), .align = sizeof(u64), 793 .active = tm_spr_active, .regset_get = tm_spr_get, .set = tm_spr_set 794 }, 795 [REGSET_TM_CTAR] = { 796 .core_note_type = NT_PPC_TM_CTAR, .n = 1, 797 .size = sizeof(u64), .align = sizeof(u64), 798 .active = tm_tar_active, .regset_get = tm_tar_get, .set = tm_tar_set 799 }, 800 [REGSET_TM_CPPR] = { 801 .core_note_type = NT_PPC_TM_CPPR, .n = 1, 802 .size = sizeof(u64), .align = sizeof(u64), 803 .active = tm_ppr_active, .regset_get = tm_ppr_get, .set = tm_ppr_set 804 }, 805 [REGSET_TM_CDSCR] = { 806 .core_note_type = NT_PPC_TM_CDSCR, .n = 1, 807 .size = sizeof(u64), .align = sizeof(u64), 808 .active = tm_dscr_active, .regset_get = tm_dscr_get, .set = tm_dscr_set 809 }, 810#endif 811#ifdef CONFIG_PPC64 812 [REGSET_PPR] = { 813 .core_note_type = NT_PPC_PPR, .n = 1, 814 .size = sizeof(u64), .align = sizeof(u64), 815 .regset_get = ppr_get, .set = ppr_set 816 }, 817 [REGSET_DSCR] = { 818 .core_note_type = NT_PPC_DSCR, .n = 1, 819 .size = sizeof(u64), .align = sizeof(u64), 820 .regset_get = dscr_get, .set = dscr_set 821 }, 822#endif 823#ifdef CONFIG_PPC_BOOK3S_64 824 [REGSET_TAR] = { 825 .core_note_type = NT_PPC_TAR, .n = 1, 826 .size = sizeof(u64), .align = sizeof(u64), 827 .regset_get = tar_get, .set = tar_set 828 }, 829 [REGSET_EBB] = { 830 .core_note_type = NT_PPC_EBB, .n = ELF_NEBB, 831 .size = sizeof(u64), .align = sizeof(u64), 832 .active = ebb_active, .regset_get = ebb_get, .set = ebb_set 833 }, 834#endif 835}; 836 837static const struct user_regset_view user_ppc_compat_view = { 838 .name = "ppc", .e_machine = EM_PPC, .ei_osabi = ELF_OSABI, 839 .regsets = compat_regsets, .n = ARRAY_SIZE(compat_regsets) 840}; 841 842const struct user_regset_view *task_user_regset_view(struct task_struct *task) 843{ 844 if (IS_ENABLED(CONFIG_COMPAT) && is_tsk_32bit_task(task)) 845 return &user_ppc_compat_view; 846 return &user_ppc_native_view; 847}