1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Author: Hanlu Li <lihanlu@loongson.cn> 4 * Huacai Chen <chenhuacai@loongson.cn> 5 * 6 * Copyright (C) 2020-2022 Loongson Technology Corporation Limited 7 * 8 * Derived from MIPS: 9 * Copyright (C) 1992 Ross Biro 10 * Copyright (C) Linus Torvalds 11 * Copyright (C) 1994, 95, 96, 97, 98, 2000 Ralf Baechle 12 * Copyright (C) 1996 David S. Miller 13 * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com 14 * Copyright (C) 1999 MIPS Technologies, Inc. 15 * Copyright (C) 2000 Ulf Carlsson 16 */ 17 #include <linux/kernel.h> 18 #include <linux/audit.h> 19 #include <linux/compiler.h> 20 #include <linux/context_tracking.h> 21 #include <linux/elf.h> 22 #include <linux/errno.h> 23 #include <linux/hw_breakpoint.h> 24 #include <linux/mm.h> 25 #include <linux/nospec.h> 26 #include <linux/ptrace.h> 27 #include <linux/regset.h> 28 #include <linux/sched.h> 29 #include <linux/sched/task_stack.h> 30 #include <linux/security.h> 31 #include <linux/smp.h> 32 #include <linux/stddef.h> 33 #include <linux/seccomp.h> 34 #include <linux/thread_info.h> 35 #include <linux/uaccess.h> 36 37 #include <asm/byteorder.h> 38 #include <asm/cpu.h> 39 #include <asm/cpu-info.h> 40 #include <asm/fpu.h> 41 #include <asm/loongarch.h> 42 #include <asm/page.h> 43 #include <asm/pgtable.h> 44 #include <asm/processor.h> 45 #include <asm/ptrace.h> 46 #include <asm/reg.h> 47 #include <asm/syscall.h> 48 49 static void init_fp_ctx(struct task_struct *target) 50 { 51 /* The target already has context */ 52 if (tsk_used_math(target)) 53 return; 54 55 /* Begin with data registers set to all 1s... */ 56 memset(&target->thread.fpu.fpr, ~0, sizeof(target->thread.fpu.fpr)); 57 set_stopped_child_used_math(target); 58 } 59 60 /* 61 * Called by kernel/ptrace.c when detaching.. 62 * 63 * Make sure single step bits etc are not set. 64 */ 65 void ptrace_disable(struct task_struct *child) 66 { 67 /* Don't load the watchpoint registers for the ex-child. */ 68 clear_tsk_thread_flag(child, TIF_LOAD_WATCH); 69 clear_tsk_thread_flag(child, TIF_SINGLESTEP); 70 } 71 72 /* regset get/set implementations */ 73 74 static int gpr_get(struct task_struct *target, 75 const struct user_regset *regset, 76 struct membuf to) 77 { 78 int r; 79 struct pt_regs *regs = task_pt_regs(target); 80 81 r = membuf_write(&to, ®s->regs, sizeof(u64) * GPR_NUM); 82 r = membuf_write(&to, ®s->orig_a0, sizeof(u64)); 83 r = membuf_write(&to, ®s->csr_era, sizeof(u64)); 84 r = membuf_write(&to, ®s->csr_badvaddr, sizeof(u64)); 85 86 return r; 87 } 88 89 static int gpr_set(struct task_struct *target, 90 const struct user_regset *regset, 91 unsigned int pos, unsigned int count, 92 const void *kbuf, const void __user *ubuf) 93 { 94 int err; 95 int a0_start = sizeof(u64) * GPR_NUM; 96 int era_start = a0_start + sizeof(u64); 97 int badvaddr_start = era_start + sizeof(u64); 98 struct pt_regs *regs = task_pt_regs(target); 99 100 err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 101 ®s->regs, 102 0, a0_start); 103 err |= user_regset_copyin(&pos, &count, &kbuf, &ubuf, 104 ®s->orig_a0, 105 a0_start, a0_start + sizeof(u64)); 106 err |= user_regset_copyin(&pos, &count, &kbuf, &ubuf, 107 ®s->csr_era, 108 era_start, era_start + sizeof(u64)); 109 err |= user_regset_copyin(&pos, &count, &kbuf, &ubuf, 110 ®s->csr_badvaddr, 111 badvaddr_start, badvaddr_start + sizeof(u64)); 112 113 return err; 114 } 115 116 117 /* 118 * Get the general floating-point registers. 119 */ 120 static int gfpr_get(struct task_struct *target, struct membuf *to) 121 { 122 return membuf_write(to, &target->thread.fpu.fpr, 123 sizeof(elf_fpreg_t) * NUM_FPU_REGS); 124 } 125 126 static int gfpr_get_simd(struct task_struct *target, struct membuf *to) 127 { 128 int i, r; 129 u64 fpr_val; 130 131 BUILD_BUG_ON(sizeof(fpr_val) != sizeof(elf_fpreg_t)); 132 for (i = 0; i < NUM_FPU_REGS; i++) { 133 fpr_val = get_fpr64(&target->thread.fpu.fpr[i], 0); 134 r = membuf_write(to, &fpr_val, sizeof(elf_fpreg_t)); 135 } 136 137 return r; 138 } 139 140 /* 141 * Choose the appropriate helper for general registers, and then copy 142 * the FCC and FCSR registers separately. 143 */ 144 static int fpr_get(struct task_struct *target, 145 const struct user_regset *regset, 146 struct membuf to) 147 { 148 int r; 149 150 if (sizeof(target->thread.fpu.fpr[0]) == sizeof(elf_fpreg_t)) 151 r = gfpr_get(target, &to); 152 else 153 r = gfpr_get_simd(target, &to); 154 155 r = membuf_write(&to, &target->thread.fpu.fcc, sizeof(target->thread.fpu.fcc)); 156 r = membuf_write(&to, &target->thread.fpu.fcsr, sizeof(target->thread.fpu.fcsr)); 157 158 return r; 159 } 160 161 static int gfpr_set(struct task_struct *target, 162 unsigned int *pos, unsigned int *count, 163 const void **kbuf, const void __user **ubuf) 164 { 165 return user_regset_copyin(pos, count, kbuf, ubuf, 166 &target->thread.fpu.fpr, 167 0, NUM_FPU_REGS * sizeof(elf_fpreg_t)); 168 } 169 170 static int gfpr_set_simd(struct task_struct *target, 171 unsigned int *pos, unsigned int *count, 172 const void **kbuf, const void __user **ubuf) 173 { 174 int i, err; 175 u64 fpr_val; 176 177 BUILD_BUG_ON(sizeof(fpr_val) != sizeof(elf_fpreg_t)); 178 for (i = 0; i < NUM_FPU_REGS && *count > 0; i++) { 179 err = user_regset_copyin(pos, count, kbuf, ubuf, 180 &fpr_val, i * sizeof(elf_fpreg_t), 181 (i + 1) * sizeof(elf_fpreg_t)); 182 if (err) 183 return err; 184 set_fpr64(&target->thread.fpu.fpr[i], 0, fpr_val); 185 } 186 187 return 0; 188 } 189 190 /* 191 * Choose the appropriate helper for general registers, and then copy 192 * the FCC register separately. 193 */ 194 static int fpr_set(struct task_struct *target, 195 const struct user_regset *regset, 196 unsigned int pos, unsigned int count, 197 const void *kbuf, const void __user *ubuf) 198 { 199 const int fcc_start = NUM_FPU_REGS * sizeof(elf_fpreg_t); 200 const int fcsr_start = fcc_start + sizeof(u64); 201 int err; 202 203 BUG_ON(count % sizeof(elf_fpreg_t)); 204 if (pos + count > sizeof(elf_fpregset_t)) 205 return -EIO; 206 207 init_fp_ctx(target); 208 209 if (sizeof(target->thread.fpu.fpr[0]) == sizeof(elf_fpreg_t)) 210 err = gfpr_set(target, &pos, &count, &kbuf, &ubuf); 211 else 212 err = gfpr_set_simd(target, &pos, &count, &kbuf, &ubuf); 213 if (err) 214 return err; 215 216 err |= user_regset_copyin(&pos, &count, &kbuf, &ubuf, 217 &target->thread.fpu.fcc, fcc_start, 218 fcc_start + sizeof(u64)); 219 err |= user_regset_copyin(&pos, &count, &kbuf, &ubuf, 220 &target->thread.fpu.fcsr, fcsr_start, 221 fcsr_start + sizeof(u32)); 222 223 return err; 224 } 225 226 static int cfg_get(struct task_struct *target, 227 const struct user_regset *regset, 228 struct membuf to) 229 { 230 int i, r; 231 u32 cfg_val; 232 233 i = 0; 234 while (to.left > 0) { 235 cfg_val = read_cpucfg(i++); 236 r = membuf_write(&to, &cfg_val, sizeof(u32)); 237 } 238 239 return r; 240 } 241 242 /* 243 * CFG registers are read-only. 244 */ 245 static int cfg_set(struct task_struct *target, 246 const struct user_regset *regset, 247 unsigned int pos, unsigned int count, 248 const void *kbuf, const void __user *ubuf) 249 { 250 return 0; 251 } 252 253 #ifdef CONFIG_HAVE_HW_BREAKPOINT 254 255 /* 256 * Handle hitting a HW-breakpoint. 257 */ 258 static void ptrace_hbptriggered(struct perf_event *bp, 259 struct perf_sample_data *data, 260 struct pt_regs *regs) 261 { 262 int i; 263 struct arch_hw_breakpoint *bkpt = counter_arch_bp(bp); 264 265 for (i = 0; i < LOONGARCH_MAX_BRP; ++i) 266 if (current->thread.hbp_break[i] == bp) 267 break; 268 269 for (i = 0; i < LOONGARCH_MAX_WRP; ++i) 270 if (current->thread.hbp_watch[i] == bp) 271 break; 272 273 force_sig_ptrace_errno_trap(i, (void __user *)bkpt->address); 274 } 275 276 static struct perf_event *ptrace_hbp_get_event(unsigned int note_type, 277 struct task_struct *tsk, 278 unsigned long idx) 279 { 280 struct perf_event *bp; 281 282 switch (note_type) { 283 case NT_LOONGARCH_HW_BREAK: 284 if (idx >= LOONGARCH_MAX_BRP) 285 return ERR_PTR(-EINVAL); 286 idx = array_index_nospec(idx, LOONGARCH_MAX_BRP); 287 bp = tsk->thread.hbp_break[idx]; 288 break; 289 case NT_LOONGARCH_HW_WATCH: 290 if (idx >= LOONGARCH_MAX_WRP) 291 return ERR_PTR(-EINVAL); 292 idx = array_index_nospec(idx, LOONGARCH_MAX_WRP); 293 bp = tsk->thread.hbp_watch[idx]; 294 break; 295 } 296 297 return bp; 298 } 299 300 static int ptrace_hbp_set_event(unsigned int note_type, 301 struct task_struct *tsk, 302 unsigned long idx, 303 struct perf_event *bp) 304 { 305 switch (note_type) { 306 case NT_LOONGARCH_HW_BREAK: 307 if (idx >= LOONGARCH_MAX_BRP) 308 return -EINVAL; 309 idx = array_index_nospec(idx, LOONGARCH_MAX_BRP); 310 tsk->thread.hbp_break[idx] = bp; 311 break; 312 case NT_LOONGARCH_HW_WATCH: 313 if (idx >= LOONGARCH_MAX_WRP) 314 return -EINVAL; 315 idx = array_index_nospec(idx, LOONGARCH_MAX_WRP); 316 tsk->thread.hbp_watch[idx] = bp; 317 break; 318 } 319 320 return 0; 321 } 322 323 static struct perf_event *ptrace_hbp_create(unsigned int note_type, 324 struct task_struct *tsk, 325 unsigned long idx) 326 { 327 int err, type; 328 struct perf_event *bp; 329 struct perf_event_attr attr; 330 331 switch (note_type) { 332 case NT_LOONGARCH_HW_BREAK: 333 type = HW_BREAKPOINT_X; 334 break; 335 case NT_LOONGARCH_HW_WATCH: 336 type = HW_BREAKPOINT_RW; 337 break; 338 default: 339 return ERR_PTR(-EINVAL); 340 } 341 342 ptrace_breakpoint_init(&attr); 343 344 /* 345 * Initialise fields to sane defaults 346 * (i.e. values that will pass validation). 347 */ 348 attr.bp_addr = 0; 349 attr.bp_len = HW_BREAKPOINT_LEN_4; 350 attr.bp_type = type; 351 attr.disabled = 1; 352 353 bp = register_user_hw_breakpoint(&attr, ptrace_hbptriggered, NULL, tsk); 354 if (IS_ERR(bp)) 355 return bp; 356 357 err = ptrace_hbp_set_event(note_type, tsk, idx, bp); 358 if (err) 359 return ERR_PTR(err); 360 361 return bp; 362 } 363 364 static int ptrace_hbp_fill_attr_ctrl(unsigned int note_type, 365 struct arch_hw_breakpoint_ctrl ctrl, 366 struct perf_event_attr *attr) 367 { 368 int err, len, type, offset; 369 370 err = arch_bp_generic_fields(ctrl, &len, &type, &offset); 371 if (err) 372 return err; 373 374 switch (note_type) { 375 case NT_LOONGARCH_HW_BREAK: 376 if ((type & HW_BREAKPOINT_X) != type) 377 return -EINVAL; 378 break; 379 case NT_LOONGARCH_HW_WATCH: 380 if ((type & HW_BREAKPOINT_RW) != type) 381 return -EINVAL; 382 break; 383 default: 384 return -EINVAL; 385 } 386 387 attr->bp_len = len; 388 attr->bp_type = type; 389 attr->bp_addr += offset; 390 391 return 0; 392 } 393 394 static int ptrace_hbp_get_resource_info(unsigned int note_type, u64 *info) 395 { 396 u8 num; 397 u64 reg = 0; 398 399 switch (note_type) { 400 case NT_LOONGARCH_HW_BREAK: 401 num = hw_breakpoint_slots(TYPE_INST); 402 break; 403 case NT_LOONGARCH_HW_WATCH: 404 num = hw_breakpoint_slots(TYPE_DATA); 405 break; 406 default: 407 return -EINVAL; 408 } 409 410 *info = reg | num; 411 412 return 0; 413 } 414 415 static struct perf_event *ptrace_hbp_get_initialised_bp(unsigned int note_type, 416 struct task_struct *tsk, 417 unsigned long idx) 418 { 419 struct perf_event *bp = ptrace_hbp_get_event(note_type, tsk, idx); 420 421 if (!bp) 422 bp = ptrace_hbp_create(note_type, tsk, idx); 423 424 return bp; 425 } 426 427 static int ptrace_hbp_get_ctrl(unsigned int note_type, 428 struct task_struct *tsk, 429 unsigned long idx, u32 *ctrl) 430 { 431 struct perf_event *bp = ptrace_hbp_get_event(note_type, tsk, idx); 432 433 if (IS_ERR(bp)) 434 return PTR_ERR(bp); 435 436 *ctrl = bp ? encode_ctrl_reg(counter_arch_bp(bp)->ctrl) : 0; 437 438 return 0; 439 } 440 441 static int ptrace_hbp_get_mask(unsigned int note_type, 442 struct task_struct *tsk, 443 unsigned long idx, u64 *mask) 444 { 445 struct perf_event *bp = ptrace_hbp_get_event(note_type, tsk, idx); 446 447 if (IS_ERR(bp)) 448 return PTR_ERR(bp); 449 450 *mask = bp ? counter_arch_bp(bp)->mask : 0; 451 452 return 0; 453 } 454 455 static int ptrace_hbp_get_addr(unsigned int note_type, 456 struct task_struct *tsk, 457 unsigned long idx, u64 *addr) 458 { 459 struct perf_event *bp = ptrace_hbp_get_event(note_type, tsk, idx); 460 461 if (IS_ERR(bp)) 462 return PTR_ERR(bp); 463 464 *addr = bp ? counter_arch_bp(bp)->address : 0; 465 466 return 0; 467 } 468 469 static int ptrace_hbp_set_ctrl(unsigned int note_type, 470 struct task_struct *tsk, 471 unsigned long idx, u32 uctrl) 472 { 473 int err; 474 struct perf_event *bp; 475 struct perf_event_attr attr; 476 struct arch_hw_breakpoint_ctrl ctrl; 477 478 bp = ptrace_hbp_get_initialised_bp(note_type, tsk, idx); 479 if (IS_ERR(bp)) 480 return PTR_ERR(bp); 481 482 attr = bp->attr; 483 decode_ctrl_reg(uctrl, &ctrl); 484 err = ptrace_hbp_fill_attr_ctrl(note_type, ctrl, &attr); 485 if (err) 486 return err; 487 488 return modify_user_hw_breakpoint(bp, &attr); 489 } 490 491 static int ptrace_hbp_set_mask(unsigned int note_type, 492 struct task_struct *tsk, 493 unsigned long idx, u64 mask) 494 { 495 struct perf_event *bp; 496 struct perf_event_attr attr; 497 struct arch_hw_breakpoint *info; 498 499 bp = ptrace_hbp_get_initialised_bp(note_type, tsk, idx); 500 if (IS_ERR(bp)) 501 return PTR_ERR(bp); 502 503 attr = bp->attr; 504 info = counter_arch_bp(bp); 505 info->mask = mask; 506 507 return modify_user_hw_breakpoint(bp, &attr); 508 } 509 510 static int ptrace_hbp_set_addr(unsigned int note_type, 511 struct task_struct *tsk, 512 unsigned long idx, u64 addr) 513 { 514 struct perf_event *bp; 515 struct perf_event_attr attr; 516 517 bp = ptrace_hbp_get_initialised_bp(note_type, tsk, idx); 518 if (IS_ERR(bp)) 519 return PTR_ERR(bp); 520 521 attr = bp->attr; 522 attr.bp_addr = addr; 523 524 return modify_user_hw_breakpoint(bp, &attr); 525 } 526 527 #define PTRACE_HBP_ADDR_SZ sizeof(u64) 528 #define PTRACE_HBP_MASK_SZ sizeof(u64) 529 #define PTRACE_HBP_CTRL_SZ sizeof(u32) 530 #define PTRACE_HBP_PAD_SZ sizeof(u32) 531 532 static int hw_break_get(struct task_struct *target, 533 const struct user_regset *regset, 534 struct membuf to) 535 { 536 u64 info; 537 u32 ctrl; 538 u64 addr, mask; 539 int ret, idx = 0; 540 unsigned int note_type = regset->core_note_type; 541 542 /* Resource info */ 543 ret = ptrace_hbp_get_resource_info(note_type, &info); 544 if (ret) 545 return ret; 546 547 membuf_write(&to, &info, sizeof(info)); 548 549 /* (address, mask, ctrl) registers */ 550 while (to.left) { 551 ret = ptrace_hbp_get_addr(note_type, target, idx, &addr); 552 if (ret) 553 return ret; 554 555 ret = ptrace_hbp_get_mask(note_type, target, idx, &mask); 556 if (ret) 557 return ret; 558 559 ret = ptrace_hbp_get_ctrl(note_type, target, idx, &ctrl); 560 if (ret) 561 return ret; 562 563 membuf_store(&to, addr); 564 membuf_store(&to, mask); 565 membuf_store(&to, ctrl); 566 membuf_zero(&to, sizeof(u32)); 567 idx++; 568 } 569 570 return 0; 571 } 572 573 static int hw_break_set(struct task_struct *target, 574 const struct user_regset *regset, 575 unsigned int pos, unsigned int count, 576 const void *kbuf, const void __user *ubuf) 577 { 578 u32 ctrl; 579 u64 addr, mask; 580 int ret, idx = 0, offset, limit; 581 unsigned int note_type = regset->core_note_type; 582 583 /* Resource info */ 584 offset = offsetof(struct user_watch_state, dbg_regs); 585 user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 0, offset); 586 587 /* (address, mask, ctrl) registers */ 588 limit = regset->n * regset->size; 589 while (count && offset < limit) { 590 if (count < PTRACE_HBP_ADDR_SZ) 591 return -EINVAL; 592 593 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &addr, 594 offset, offset + PTRACE_HBP_ADDR_SZ); 595 if (ret) 596 return ret; 597 598 ret = ptrace_hbp_set_addr(note_type, target, idx, addr); 599 if (ret) 600 return ret; 601 offset += PTRACE_HBP_ADDR_SZ; 602 603 if (!count) 604 break; 605 606 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &mask, 607 offset, offset + PTRACE_HBP_MASK_SZ); 608 if (ret) 609 return ret; 610 611 ret = ptrace_hbp_set_mask(note_type, target, idx, mask); 612 if (ret) 613 return ret; 614 offset += PTRACE_HBP_MASK_SZ; 615 616 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &ctrl, 617 offset, offset + PTRACE_HBP_CTRL_SZ); 618 if (ret) 619 return ret; 620 621 ret = ptrace_hbp_set_ctrl(note_type, target, idx, ctrl); 622 if (ret) 623 return ret; 624 offset += PTRACE_HBP_CTRL_SZ; 625 626 user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 627 offset, offset + PTRACE_HBP_PAD_SZ); 628 offset += PTRACE_HBP_PAD_SZ; 629 630 idx++; 631 } 632 633 return 0; 634 } 635 636 #endif 637 638 struct pt_regs_offset { 639 const char *name; 640 int offset; 641 }; 642 643 #define REG_OFFSET_NAME(n, r) {.name = #n, .offset = offsetof(struct pt_regs, r)} 644 #define REG_OFFSET_END {.name = NULL, .offset = 0} 645 646 static const struct pt_regs_offset regoffset_table[] = { 647 REG_OFFSET_NAME(r0, regs[0]), 648 REG_OFFSET_NAME(r1, regs[1]), 649 REG_OFFSET_NAME(r2, regs[2]), 650 REG_OFFSET_NAME(r3, regs[3]), 651 REG_OFFSET_NAME(r4, regs[4]), 652 REG_OFFSET_NAME(r5, regs[5]), 653 REG_OFFSET_NAME(r6, regs[6]), 654 REG_OFFSET_NAME(r7, regs[7]), 655 REG_OFFSET_NAME(r8, regs[8]), 656 REG_OFFSET_NAME(r9, regs[9]), 657 REG_OFFSET_NAME(r10, regs[10]), 658 REG_OFFSET_NAME(r11, regs[11]), 659 REG_OFFSET_NAME(r12, regs[12]), 660 REG_OFFSET_NAME(r13, regs[13]), 661 REG_OFFSET_NAME(r14, regs[14]), 662 REG_OFFSET_NAME(r15, regs[15]), 663 REG_OFFSET_NAME(r16, regs[16]), 664 REG_OFFSET_NAME(r17, regs[17]), 665 REG_OFFSET_NAME(r18, regs[18]), 666 REG_OFFSET_NAME(r19, regs[19]), 667 REG_OFFSET_NAME(r20, regs[20]), 668 REG_OFFSET_NAME(r21, regs[21]), 669 REG_OFFSET_NAME(r22, regs[22]), 670 REG_OFFSET_NAME(r23, regs[23]), 671 REG_OFFSET_NAME(r24, regs[24]), 672 REG_OFFSET_NAME(r25, regs[25]), 673 REG_OFFSET_NAME(r26, regs[26]), 674 REG_OFFSET_NAME(r27, regs[27]), 675 REG_OFFSET_NAME(r28, regs[28]), 676 REG_OFFSET_NAME(r29, regs[29]), 677 REG_OFFSET_NAME(r30, regs[30]), 678 REG_OFFSET_NAME(r31, regs[31]), 679 REG_OFFSET_NAME(orig_a0, orig_a0), 680 REG_OFFSET_NAME(csr_era, csr_era), 681 REG_OFFSET_NAME(csr_badvaddr, csr_badvaddr), 682 REG_OFFSET_NAME(csr_crmd, csr_crmd), 683 REG_OFFSET_NAME(csr_prmd, csr_prmd), 684 REG_OFFSET_NAME(csr_euen, csr_euen), 685 REG_OFFSET_NAME(csr_ecfg, csr_ecfg), 686 REG_OFFSET_NAME(csr_estat, csr_estat), 687 REG_OFFSET_END, 688 }; 689 690 /** 691 * regs_query_register_offset() - query register offset from its name 692 * @name: the name of a register 693 * 694 * regs_query_register_offset() returns the offset of a register in struct 695 * pt_regs from its name. If the name is invalid, this returns -EINVAL; 696 */ 697 int regs_query_register_offset(const char *name) 698 { 699 const struct pt_regs_offset *roff; 700 701 for (roff = regoffset_table; roff->name != NULL; roff++) 702 if (!strcmp(roff->name, name)) 703 return roff->offset; 704 return -EINVAL; 705 } 706 707 enum loongarch_regset { 708 REGSET_GPR, 709 REGSET_FPR, 710 REGSET_CPUCFG, 711 #ifdef CONFIG_HAVE_HW_BREAKPOINT 712 REGSET_HW_BREAK, 713 REGSET_HW_WATCH, 714 #endif 715 }; 716 717 static const struct user_regset loongarch64_regsets[] = { 718 [REGSET_GPR] = { 719 .core_note_type = NT_PRSTATUS, 720 .n = ELF_NGREG, 721 .size = sizeof(elf_greg_t), 722 .align = sizeof(elf_greg_t), 723 .regset_get = gpr_get, 724 .set = gpr_set, 725 }, 726 [REGSET_FPR] = { 727 .core_note_type = NT_PRFPREG, 728 .n = ELF_NFPREG, 729 .size = sizeof(elf_fpreg_t), 730 .align = sizeof(elf_fpreg_t), 731 .regset_get = fpr_get, 732 .set = fpr_set, 733 }, 734 [REGSET_CPUCFG] = { 735 .core_note_type = NT_LOONGARCH_CPUCFG, 736 .n = 64, 737 .size = sizeof(u32), 738 .align = sizeof(u32), 739 .regset_get = cfg_get, 740 .set = cfg_set, 741 }, 742 #ifdef CONFIG_HAVE_HW_BREAKPOINT 743 [REGSET_HW_BREAK] = { 744 .core_note_type = NT_LOONGARCH_HW_BREAK, 745 .n = sizeof(struct user_watch_state) / sizeof(u32), 746 .size = sizeof(u32), 747 .align = sizeof(u32), 748 .regset_get = hw_break_get, 749 .set = hw_break_set, 750 }, 751 [REGSET_HW_WATCH] = { 752 .core_note_type = NT_LOONGARCH_HW_WATCH, 753 .n = sizeof(struct user_watch_state) / sizeof(u32), 754 .size = sizeof(u32), 755 .align = sizeof(u32), 756 .regset_get = hw_break_get, 757 .set = hw_break_set, 758 }, 759 #endif 760 }; 761 762 static const struct user_regset_view user_loongarch64_view = { 763 .name = "loongarch64", 764 .e_machine = ELF_ARCH, 765 .regsets = loongarch64_regsets, 766 .n = ARRAY_SIZE(loongarch64_regsets), 767 }; 768 769 770 const struct user_regset_view *task_user_regset_view(struct task_struct *task) 771 { 772 return &user_loongarch64_view; 773 } 774 775 static inline int read_user(struct task_struct *target, unsigned long addr, 776 unsigned long __user *data) 777 { 778 unsigned long tmp = 0; 779 780 switch (addr) { 781 case 0 ... 31: 782 tmp = task_pt_regs(target)->regs[addr]; 783 break; 784 case ARG0: 785 tmp = task_pt_regs(target)->orig_a0; 786 break; 787 case PC: 788 tmp = task_pt_regs(target)->csr_era; 789 break; 790 case BADVADDR: 791 tmp = task_pt_regs(target)->csr_badvaddr; 792 break; 793 default: 794 return -EIO; 795 } 796 797 return put_user(tmp, data); 798 } 799 800 static inline int write_user(struct task_struct *target, unsigned long addr, 801 unsigned long data) 802 { 803 switch (addr) { 804 case 0 ... 31: 805 task_pt_regs(target)->regs[addr] = data; 806 break; 807 case ARG0: 808 task_pt_regs(target)->orig_a0 = data; 809 break; 810 case PC: 811 task_pt_regs(target)->csr_era = data; 812 break; 813 case BADVADDR: 814 task_pt_regs(target)->csr_badvaddr = data; 815 break; 816 default: 817 return -EIO; 818 } 819 820 return 0; 821 } 822 823 long arch_ptrace(struct task_struct *child, long request, 824 unsigned long addr, unsigned long data) 825 { 826 int ret; 827 unsigned long __user *datap = (void __user *) data; 828 829 switch (request) { 830 case PTRACE_PEEKUSR: 831 ret = read_user(child, addr, datap); 832 break; 833 834 case PTRACE_POKEUSR: 835 ret = write_user(child, addr, data); 836 break; 837 838 default: 839 ret = ptrace_request(child, request, addr, data); 840 break; 841 } 842 843 return ret; 844 } 845 846 #ifdef CONFIG_HAVE_HW_BREAKPOINT 847 static void ptrace_triggered(struct perf_event *bp, 848 struct perf_sample_data *data, struct pt_regs *regs) 849 { 850 struct perf_event_attr attr; 851 852 attr = bp->attr; 853 attr.disabled = true; 854 modify_user_hw_breakpoint(bp, &attr); 855 } 856 857 static int set_single_step(struct task_struct *tsk, unsigned long addr) 858 { 859 struct perf_event *bp; 860 struct perf_event_attr attr; 861 struct arch_hw_breakpoint *info; 862 struct thread_struct *thread = &tsk->thread; 863 864 bp = thread->hbp_break[0]; 865 if (!bp) { 866 ptrace_breakpoint_init(&attr); 867 868 attr.bp_addr = addr; 869 attr.bp_len = HW_BREAKPOINT_LEN_8; 870 attr.bp_type = HW_BREAKPOINT_X; 871 872 bp = register_user_hw_breakpoint(&attr, ptrace_triggered, 873 NULL, tsk); 874 if (IS_ERR(bp)) 875 return PTR_ERR(bp); 876 877 thread->hbp_break[0] = bp; 878 } else { 879 int err; 880 881 attr = bp->attr; 882 attr.bp_addr = addr; 883 884 /* Reenable breakpoint */ 885 attr.disabled = false; 886 err = modify_user_hw_breakpoint(bp, &attr); 887 if (unlikely(err)) 888 return err; 889 890 csr_write64(attr.bp_addr, LOONGARCH_CSR_IB0ADDR); 891 } 892 info = counter_arch_bp(bp); 893 info->mask = TASK_SIZE - 1; 894 895 return 0; 896 } 897 898 /* ptrace API */ 899 void user_enable_single_step(struct task_struct *task) 900 { 901 struct thread_info *ti = task_thread_info(task); 902 903 set_single_step(task, task_pt_regs(task)->csr_era); 904 task->thread.single_step = task_pt_regs(task)->csr_era; 905 set_ti_thread_flag(ti, TIF_SINGLESTEP); 906 } 907 908 void user_disable_single_step(struct task_struct *task) 909 { 910 clear_tsk_thread_flag(task, TIF_SINGLESTEP); 911 } 912 #endif 913