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/mm.h> 24 #include <linux/ptrace.h> 25 #include <linux/regset.h> 26 #include <linux/sched.h> 27 #include <linux/sched/task_stack.h> 28 #include <linux/security.h> 29 #include <linux/smp.h> 30 #include <linux/stddef.h> 31 #include <linux/seccomp.h> 32 #include <linux/uaccess.h> 33 34 #include <asm/byteorder.h> 35 #include <asm/cpu.h> 36 #include <asm/cpu-info.h> 37 #include <asm/fpu.h> 38 #include <asm/loongarch.h> 39 #include <asm/page.h> 40 #include <asm/pgtable.h> 41 #include <asm/processor.h> 42 #include <asm/reg.h> 43 #include <asm/syscall.h> 44 45 static void init_fp_ctx(struct task_struct *target) 46 { 47 /* The target already has context */ 48 if (tsk_used_math(target)) 49 return; 50 51 /* Begin with data registers set to all 1s... */ 52 memset(&target->thread.fpu.fpr, ~0, sizeof(target->thread.fpu.fpr)); 53 set_stopped_child_used_math(target); 54 } 55 56 /* 57 * Called by kernel/ptrace.c when detaching.. 58 * 59 * Make sure single step bits etc are not set. 60 */ 61 void ptrace_disable(struct task_struct *child) 62 { 63 /* Don't load the watchpoint registers for the ex-child. */ 64 clear_tsk_thread_flag(child, TIF_LOAD_WATCH); 65 clear_tsk_thread_flag(child, TIF_SINGLESTEP); 66 } 67 68 /* regset get/set implementations */ 69 70 static int gpr_get(struct task_struct *target, 71 const struct user_regset *regset, 72 struct membuf to) 73 { 74 int r; 75 struct pt_regs *regs = task_pt_regs(target); 76 77 r = membuf_write(&to, ®s->regs, sizeof(u64) * GPR_NUM); 78 r = membuf_write(&to, ®s->orig_a0, sizeof(u64)); 79 r = membuf_write(&to, ®s->csr_era, sizeof(u64)); 80 r = membuf_write(&to, ®s->csr_badvaddr, sizeof(u64)); 81 82 return r; 83 } 84 85 static int gpr_set(struct task_struct *target, 86 const struct user_regset *regset, 87 unsigned int pos, unsigned int count, 88 const void *kbuf, const void __user *ubuf) 89 { 90 int err; 91 int a0_start = sizeof(u64) * GPR_NUM; 92 int era_start = a0_start + sizeof(u64); 93 int badvaddr_start = era_start + sizeof(u64); 94 struct pt_regs *regs = task_pt_regs(target); 95 96 err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 97 ®s->regs, 98 0, a0_start); 99 err |= user_regset_copyin(&pos, &count, &kbuf, &ubuf, 100 ®s->orig_a0, 101 a0_start, a0_start + sizeof(u64)); 102 err |= user_regset_copyin(&pos, &count, &kbuf, &ubuf, 103 ®s->csr_era, 104 era_start, era_start + sizeof(u64)); 105 err |= user_regset_copyin(&pos, &count, &kbuf, &ubuf, 106 ®s->csr_badvaddr, 107 badvaddr_start, badvaddr_start + sizeof(u64)); 108 109 return err; 110 } 111 112 113 /* 114 * Get the general floating-point registers. 115 */ 116 static int gfpr_get(struct task_struct *target, struct membuf *to) 117 { 118 return membuf_write(to, &target->thread.fpu.fpr, 119 sizeof(elf_fpreg_t) * NUM_FPU_REGS); 120 } 121 122 static int gfpr_get_simd(struct task_struct *target, struct membuf *to) 123 { 124 int i, r; 125 u64 fpr_val; 126 127 BUILD_BUG_ON(sizeof(fpr_val) != sizeof(elf_fpreg_t)); 128 for (i = 0; i < NUM_FPU_REGS; i++) { 129 fpr_val = get_fpr64(&target->thread.fpu.fpr[i], 0); 130 r = membuf_write(to, &fpr_val, sizeof(elf_fpreg_t)); 131 } 132 133 return r; 134 } 135 136 /* 137 * Choose the appropriate helper for general registers, and then copy 138 * the FCC and FCSR registers separately. 139 */ 140 static int fpr_get(struct task_struct *target, 141 const struct user_regset *regset, 142 struct membuf to) 143 { 144 int r; 145 146 if (sizeof(target->thread.fpu.fpr[0]) == sizeof(elf_fpreg_t)) 147 r = gfpr_get(target, &to); 148 else 149 r = gfpr_get_simd(target, &to); 150 151 r = membuf_write(&to, &target->thread.fpu.fcc, sizeof(target->thread.fpu.fcc)); 152 r = membuf_write(&to, &target->thread.fpu.fcsr, sizeof(target->thread.fpu.fcsr)); 153 154 return r; 155 } 156 157 static int gfpr_set(struct task_struct *target, 158 unsigned int *pos, unsigned int *count, 159 const void **kbuf, const void __user **ubuf) 160 { 161 return user_regset_copyin(pos, count, kbuf, ubuf, 162 &target->thread.fpu.fpr, 163 0, NUM_FPU_REGS * sizeof(elf_fpreg_t)); 164 } 165 166 static int gfpr_set_simd(struct task_struct *target, 167 unsigned int *pos, unsigned int *count, 168 const void **kbuf, const void __user **ubuf) 169 { 170 int i, err; 171 u64 fpr_val; 172 173 BUILD_BUG_ON(sizeof(fpr_val) != sizeof(elf_fpreg_t)); 174 for (i = 0; i < NUM_FPU_REGS && *count > 0; i++) { 175 err = user_regset_copyin(pos, count, kbuf, ubuf, 176 &fpr_val, i * sizeof(elf_fpreg_t), 177 (i + 1) * sizeof(elf_fpreg_t)); 178 if (err) 179 return err; 180 set_fpr64(&target->thread.fpu.fpr[i], 0, fpr_val); 181 } 182 183 return 0; 184 } 185 186 /* 187 * Choose the appropriate helper for general registers, and then copy 188 * the FCC register separately. 189 */ 190 static int fpr_set(struct task_struct *target, 191 const struct user_regset *regset, 192 unsigned int pos, unsigned int count, 193 const void *kbuf, const void __user *ubuf) 194 { 195 const int fcc_start = NUM_FPU_REGS * sizeof(elf_fpreg_t); 196 const int fcc_end = fcc_start + sizeof(u64); 197 int err; 198 199 BUG_ON(count % sizeof(elf_fpreg_t)); 200 if (pos + count > sizeof(elf_fpregset_t)) 201 return -EIO; 202 203 init_fp_ctx(target); 204 205 if (sizeof(target->thread.fpu.fpr[0]) == sizeof(elf_fpreg_t)) 206 err = gfpr_set(target, &pos, &count, &kbuf, &ubuf); 207 else 208 err = gfpr_set_simd(target, &pos, &count, &kbuf, &ubuf); 209 if (err) 210 return err; 211 212 if (count > 0) 213 err |= user_regset_copyin(&pos, &count, &kbuf, &ubuf, 214 &target->thread.fpu.fcc, 215 fcc_start, fcc_end); 216 217 return err; 218 } 219 220 static int cfg_get(struct task_struct *target, 221 const struct user_regset *regset, 222 struct membuf to) 223 { 224 int i, r; 225 u32 cfg_val; 226 227 i = 0; 228 while (to.left > 0) { 229 cfg_val = read_cpucfg(i++); 230 r = membuf_write(&to, &cfg_val, sizeof(u32)); 231 } 232 233 return r; 234 } 235 236 /* 237 * CFG registers are read-only. 238 */ 239 static int cfg_set(struct task_struct *target, 240 const struct user_regset *regset, 241 unsigned int pos, unsigned int count, 242 const void *kbuf, const void __user *ubuf) 243 { 244 return 0; 245 } 246 247 struct pt_regs_offset { 248 const char *name; 249 int offset; 250 }; 251 252 #define REG_OFFSET_NAME(n, r) {.name = #n, .offset = offsetof(struct pt_regs, r)} 253 #define REG_OFFSET_END {.name = NULL, .offset = 0} 254 255 static const struct pt_regs_offset regoffset_table[] = { 256 REG_OFFSET_NAME(r0, regs[0]), 257 REG_OFFSET_NAME(r1, regs[1]), 258 REG_OFFSET_NAME(r2, regs[2]), 259 REG_OFFSET_NAME(r3, regs[3]), 260 REG_OFFSET_NAME(r4, regs[4]), 261 REG_OFFSET_NAME(r5, regs[5]), 262 REG_OFFSET_NAME(r6, regs[6]), 263 REG_OFFSET_NAME(r7, regs[7]), 264 REG_OFFSET_NAME(r8, regs[8]), 265 REG_OFFSET_NAME(r9, regs[9]), 266 REG_OFFSET_NAME(r10, regs[10]), 267 REG_OFFSET_NAME(r11, regs[11]), 268 REG_OFFSET_NAME(r12, regs[12]), 269 REG_OFFSET_NAME(r13, regs[13]), 270 REG_OFFSET_NAME(r14, regs[14]), 271 REG_OFFSET_NAME(r15, regs[15]), 272 REG_OFFSET_NAME(r16, regs[16]), 273 REG_OFFSET_NAME(r17, regs[17]), 274 REG_OFFSET_NAME(r18, regs[18]), 275 REG_OFFSET_NAME(r19, regs[19]), 276 REG_OFFSET_NAME(r20, regs[20]), 277 REG_OFFSET_NAME(r21, regs[21]), 278 REG_OFFSET_NAME(r22, regs[22]), 279 REG_OFFSET_NAME(r23, regs[23]), 280 REG_OFFSET_NAME(r24, regs[24]), 281 REG_OFFSET_NAME(r25, regs[25]), 282 REG_OFFSET_NAME(r26, regs[26]), 283 REG_OFFSET_NAME(r27, regs[27]), 284 REG_OFFSET_NAME(r28, regs[28]), 285 REG_OFFSET_NAME(r29, regs[29]), 286 REG_OFFSET_NAME(r30, regs[30]), 287 REG_OFFSET_NAME(r31, regs[31]), 288 REG_OFFSET_NAME(orig_a0, orig_a0), 289 REG_OFFSET_NAME(csr_era, csr_era), 290 REG_OFFSET_NAME(csr_badvaddr, csr_badvaddr), 291 REG_OFFSET_NAME(csr_crmd, csr_crmd), 292 REG_OFFSET_NAME(csr_prmd, csr_prmd), 293 REG_OFFSET_NAME(csr_euen, csr_euen), 294 REG_OFFSET_NAME(csr_ecfg, csr_ecfg), 295 REG_OFFSET_NAME(csr_estat, csr_estat), 296 REG_OFFSET_END, 297 }; 298 299 /** 300 * regs_query_register_offset() - query register offset from its name 301 * @name: the name of a register 302 * 303 * regs_query_register_offset() returns the offset of a register in struct 304 * pt_regs from its name. If the name is invalid, this returns -EINVAL; 305 */ 306 int regs_query_register_offset(const char *name) 307 { 308 const struct pt_regs_offset *roff; 309 310 for (roff = regoffset_table; roff->name != NULL; roff++) 311 if (!strcmp(roff->name, name)) 312 return roff->offset; 313 return -EINVAL; 314 } 315 316 enum loongarch_regset { 317 REGSET_GPR, 318 REGSET_FPR, 319 REGSET_CPUCFG, 320 }; 321 322 static const struct user_regset loongarch64_regsets[] = { 323 [REGSET_GPR] = { 324 .core_note_type = NT_PRSTATUS, 325 .n = ELF_NGREG, 326 .size = sizeof(elf_greg_t), 327 .align = sizeof(elf_greg_t), 328 .regset_get = gpr_get, 329 .set = gpr_set, 330 }, 331 [REGSET_FPR] = { 332 .core_note_type = NT_PRFPREG, 333 .n = ELF_NFPREG, 334 .size = sizeof(elf_fpreg_t), 335 .align = sizeof(elf_fpreg_t), 336 .regset_get = fpr_get, 337 .set = fpr_set, 338 }, 339 [REGSET_CPUCFG] = { 340 .core_note_type = NT_LOONGARCH_CPUCFG, 341 .n = 64, 342 .size = sizeof(u32), 343 .align = sizeof(u32), 344 .regset_get = cfg_get, 345 .set = cfg_set, 346 }, 347 }; 348 349 static const struct user_regset_view user_loongarch64_view = { 350 .name = "loongarch64", 351 .e_machine = ELF_ARCH, 352 .regsets = loongarch64_regsets, 353 .n = ARRAY_SIZE(loongarch64_regsets), 354 }; 355 356 357 const struct user_regset_view *task_user_regset_view(struct task_struct *task) 358 { 359 return &user_loongarch64_view; 360 } 361 362 static inline int read_user(struct task_struct *target, unsigned long addr, 363 unsigned long __user *data) 364 { 365 unsigned long tmp = 0; 366 367 switch (addr) { 368 case 0 ... 31: 369 tmp = task_pt_regs(target)->regs[addr]; 370 break; 371 case ARG0: 372 tmp = task_pt_regs(target)->orig_a0; 373 break; 374 case PC: 375 tmp = task_pt_regs(target)->csr_era; 376 break; 377 case BADVADDR: 378 tmp = task_pt_regs(target)->csr_badvaddr; 379 break; 380 default: 381 return -EIO; 382 } 383 384 return put_user(tmp, data); 385 } 386 387 static inline int write_user(struct task_struct *target, unsigned long addr, 388 unsigned long data) 389 { 390 switch (addr) { 391 case 0 ... 31: 392 task_pt_regs(target)->regs[addr] = data; 393 break; 394 case ARG0: 395 task_pt_regs(target)->orig_a0 = data; 396 break; 397 case PC: 398 task_pt_regs(target)->csr_era = data; 399 break; 400 case BADVADDR: 401 task_pt_regs(target)->csr_badvaddr = data; 402 break; 403 default: 404 return -EIO; 405 } 406 407 return 0; 408 } 409 410 long arch_ptrace(struct task_struct *child, long request, 411 unsigned long addr, unsigned long data) 412 { 413 int ret; 414 unsigned long __user *datap = (void __user *) data; 415 416 switch (request) { 417 case PTRACE_PEEKUSR: 418 ret = read_user(child, addr, datap); 419 break; 420 421 case PTRACE_POKEUSR: 422 ret = write_user(child, addr, data); 423 break; 424 425 default: 426 ret = ptrace_request(child, request, addr, data); 427 break; 428 } 429 430 return ret; 431 } 432