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 fcsr_start = 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 err |= user_regset_copyin(&pos, &count, &kbuf, &ubuf, 213 &target->thread.fpu.fcc, fcc_start, 214 fcc_start + sizeof(u64)); 215 err |= user_regset_copyin(&pos, &count, &kbuf, &ubuf, 216 &target->thread.fpu.fcsr, fcsr_start, 217 fcsr_start + sizeof(u32)); 218 219 return err; 220 } 221 222 static int cfg_get(struct task_struct *target, 223 const struct user_regset *regset, 224 struct membuf to) 225 { 226 int i, r; 227 u32 cfg_val; 228 229 i = 0; 230 while (to.left > 0) { 231 cfg_val = read_cpucfg(i++); 232 r = membuf_write(&to, &cfg_val, sizeof(u32)); 233 } 234 235 return r; 236 } 237 238 /* 239 * CFG registers are read-only. 240 */ 241 static int cfg_set(struct task_struct *target, 242 const struct user_regset *regset, 243 unsigned int pos, unsigned int count, 244 const void *kbuf, const void __user *ubuf) 245 { 246 return 0; 247 } 248 249 struct pt_regs_offset { 250 const char *name; 251 int offset; 252 }; 253 254 #define REG_OFFSET_NAME(n, r) {.name = #n, .offset = offsetof(struct pt_regs, r)} 255 #define REG_OFFSET_END {.name = NULL, .offset = 0} 256 257 static const struct pt_regs_offset regoffset_table[] = { 258 REG_OFFSET_NAME(r0, regs[0]), 259 REG_OFFSET_NAME(r1, regs[1]), 260 REG_OFFSET_NAME(r2, regs[2]), 261 REG_OFFSET_NAME(r3, regs[3]), 262 REG_OFFSET_NAME(r4, regs[4]), 263 REG_OFFSET_NAME(r5, regs[5]), 264 REG_OFFSET_NAME(r6, regs[6]), 265 REG_OFFSET_NAME(r7, regs[7]), 266 REG_OFFSET_NAME(r8, regs[8]), 267 REG_OFFSET_NAME(r9, regs[9]), 268 REG_OFFSET_NAME(r10, regs[10]), 269 REG_OFFSET_NAME(r11, regs[11]), 270 REG_OFFSET_NAME(r12, regs[12]), 271 REG_OFFSET_NAME(r13, regs[13]), 272 REG_OFFSET_NAME(r14, regs[14]), 273 REG_OFFSET_NAME(r15, regs[15]), 274 REG_OFFSET_NAME(r16, regs[16]), 275 REG_OFFSET_NAME(r17, regs[17]), 276 REG_OFFSET_NAME(r18, regs[18]), 277 REG_OFFSET_NAME(r19, regs[19]), 278 REG_OFFSET_NAME(r20, regs[20]), 279 REG_OFFSET_NAME(r21, regs[21]), 280 REG_OFFSET_NAME(r22, regs[22]), 281 REG_OFFSET_NAME(r23, regs[23]), 282 REG_OFFSET_NAME(r24, regs[24]), 283 REG_OFFSET_NAME(r25, regs[25]), 284 REG_OFFSET_NAME(r26, regs[26]), 285 REG_OFFSET_NAME(r27, regs[27]), 286 REG_OFFSET_NAME(r28, regs[28]), 287 REG_OFFSET_NAME(r29, regs[29]), 288 REG_OFFSET_NAME(r30, regs[30]), 289 REG_OFFSET_NAME(r31, regs[31]), 290 REG_OFFSET_NAME(orig_a0, orig_a0), 291 REG_OFFSET_NAME(csr_era, csr_era), 292 REG_OFFSET_NAME(csr_badvaddr, csr_badvaddr), 293 REG_OFFSET_NAME(csr_crmd, csr_crmd), 294 REG_OFFSET_NAME(csr_prmd, csr_prmd), 295 REG_OFFSET_NAME(csr_euen, csr_euen), 296 REG_OFFSET_NAME(csr_ecfg, csr_ecfg), 297 REG_OFFSET_NAME(csr_estat, csr_estat), 298 REG_OFFSET_END, 299 }; 300 301 /** 302 * regs_query_register_offset() - query register offset from its name 303 * @name: the name of a register 304 * 305 * regs_query_register_offset() returns the offset of a register in struct 306 * pt_regs from its name. If the name is invalid, this returns -EINVAL; 307 */ 308 int regs_query_register_offset(const char *name) 309 { 310 const struct pt_regs_offset *roff; 311 312 for (roff = regoffset_table; roff->name != NULL; roff++) 313 if (!strcmp(roff->name, name)) 314 return roff->offset; 315 return -EINVAL; 316 } 317 318 enum loongarch_regset { 319 REGSET_GPR, 320 REGSET_FPR, 321 REGSET_CPUCFG, 322 }; 323 324 static const struct user_regset loongarch64_regsets[] = { 325 [REGSET_GPR] = { 326 .core_note_type = NT_PRSTATUS, 327 .n = ELF_NGREG, 328 .size = sizeof(elf_greg_t), 329 .align = sizeof(elf_greg_t), 330 .regset_get = gpr_get, 331 .set = gpr_set, 332 }, 333 [REGSET_FPR] = { 334 .core_note_type = NT_PRFPREG, 335 .n = ELF_NFPREG, 336 .size = sizeof(elf_fpreg_t), 337 .align = sizeof(elf_fpreg_t), 338 .regset_get = fpr_get, 339 .set = fpr_set, 340 }, 341 [REGSET_CPUCFG] = { 342 .core_note_type = NT_LOONGARCH_CPUCFG, 343 .n = 64, 344 .size = sizeof(u32), 345 .align = sizeof(u32), 346 .regset_get = cfg_get, 347 .set = cfg_set, 348 }, 349 }; 350 351 static const struct user_regset_view user_loongarch64_view = { 352 .name = "loongarch64", 353 .e_machine = ELF_ARCH, 354 .regsets = loongarch64_regsets, 355 .n = ARRAY_SIZE(loongarch64_regsets), 356 }; 357 358 359 const struct user_regset_view *task_user_regset_view(struct task_struct *task) 360 { 361 return &user_loongarch64_view; 362 } 363 364 static inline int read_user(struct task_struct *target, unsigned long addr, 365 unsigned long __user *data) 366 { 367 unsigned long tmp = 0; 368 369 switch (addr) { 370 case 0 ... 31: 371 tmp = task_pt_regs(target)->regs[addr]; 372 break; 373 case ARG0: 374 tmp = task_pt_regs(target)->orig_a0; 375 break; 376 case PC: 377 tmp = task_pt_regs(target)->csr_era; 378 break; 379 case BADVADDR: 380 tmp = task_pt_regs(target)->csr_badvaddr; 381 break; 382 default: 383 return -EIO; 384 } 385 386 return put_user(tmp, data); 387 } 388 389 static inline int write_user(struct task_struct *target, unsigned long addr, 390 unsigned long data) 391 { 392 switch (addr) { 393 case 0 ... 31: 394 task_pt_regs(target)->regs[addr] = data; 395 break; 396 case ARG0: 397 task_pt_regs(target)->orig_a0 = data; 398 break; 399 case PC: 400 task_pt_regs(target)->csr_era = data; 401 break; 402 case BADVADDR: 403 task_pt_regs(target)->csr_badvaddr = data; 404 break; 405 default: 406 return -EIO; 407 } 408 409 return 0; 410 } 411 412 long arch_ptrace(struct task_struct *child, long request, 413 unsigned long addr, unsigned long data) 414 { 415 int ret; 416 unsigned long __user *datap = (void __user *) data; 417 418 switch (request) { 419 case PTRACE_PEEKUSR: 420 ret = read_user(child, addr, datap); 421 break; 422 423 case PTRACE_POKEUSR: 424 ret = write_user(child, addr, data); 425 break; 426 427 default: 428 ret = ptrace_request(child, request, addr, data); 429 break; 430 } 431 432 return ret; 433 } 434