1 /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 /* 3 * LoongArch emulation of Linux signals 4 * 5 * Copyright (c) 2021 Loongson Technology Corporation Limited 6 */ 7 8 #include "qemu/osdep.h" 9 #include "qemu.h" 10 #include "user-internals.h" 11 #include "signal-common.h" 12 #include "linux-user/trace.h" 13 #include "target/loongarch/internals.h" 14 #include "target/loongarch/vec.h" 15 #include "vdso-asmoffset.h" 16 17 /* FP context was used */ 18 #define SC_USED_FP (1 << 0) 19 20 struct target_sigcontext { 21 abi_ulong sc_pc; 22 abi_ulong sc_regs[32]; 23 abi_uint sc_flags; 24 abi_ulong sc_extcontext[0] QEMU_ALIGNED(16); 25 }; 26 27 QEMU_BUILD_BUG_ON(sizeof(struct target_sigcontext) != sizeof_sigcontext); 28 QEMU_BUILD_BUG_ON(offsetof(struct target_sigcontext, sc_pc) 29 != offsetof_sigcontext_pc); 30 QEMU_BUILD_BUG_ON(offsetof(struct target_sigcontext, sc_regs) 31 != offsetof_sigcontext_gr); 32 33 #define FPU_CTX_MAGIC 0x46505501 34 #define FPU_CTX_ALIGN 8 35 struct target_fpu_context { 36 abi_ulong regs[32]; 37 abi_ulong fcc; 38 abi_uint fcsr; 39 } QEMU_ALIGNED(FPU_CTX_ALIGN); 40 41 QEMU_BUILD_BUG_ON(offsetof(struct target_fpu_context, regs) 42 != offsetof_fpucontext_fr); 43 44 #define LSX_CTX_MAGIC 0x53580001 45 #define LSX_CTX_ALIGN 16 46 struct target_lsx_context { 47 abi_ulong regs[2 * 32]; 48 abi_ulong fcc; 49 abi_uint fcsr; 50 } QEMU_ALIGNED(LSX_CTX_ALIGN); 51 52 #define LASX_CTX_MAGIC 0x41535801 53 #define LASX_CTX_ALIGN 32 54 struct target_lasx_context { 55 abi_ulong regs[4 * 32]; 56 abi_ulong fcc; 57 abi_uint fcsr; 58 } QEMU_ALIGNED(LASX_CTX_ALIGN); 59 60 #define CONTEXT_INFO_ALIGN 16 61 struct target_sctx_info { 62 abi_uint magic; 63 abi_uint size; 64 abi_ulong padding; 65 } QEMU_ALIGNED(CONTEXT_INFO_ALIGN); 66 67 QEMU_BUILD_BUG_ON(sizeof(struct target_sctx_info) != sizeof_sctx_info); 68 69 struct target_ucontext { 70 abi_ulong tuc_flags; 71 abi_ptr tuc_link; 72 target_stack_t tuc_stack; 73 target_sigset_t tuc_sigmask; 74 uint8_t __unused[1024 / 8 - sizeof(target_sigset_t)]; 75 struct target_sigcontext tuc_mcontext; 76 }; 77 78 struct target_rt_sigframe { 79 struct target_siginfo rs_info; 80 struct target_ucontext rs_uc; 81 }; 82 83 QEMU_BUILD_BUG_ON(sizeof(struct target_rt_sigframe) 84 != sizeof_rt_sigframe); 85 QEMU_BUILD_BUG_ON(offsetof(struct target_rt_sigframe, rs_uc.tuc_mcontext) 86 != offsetof_sigcontext); 87 88 /* 89 * These two structures are not present in guest memory, are private 90 * to the signal implementation, but are largely copied from the 91 * kernel's signal implementation. 92 */ 93 struct ctx_layout { 94 void *haddr; 95 abi_ptr gaddr; 96 unsigned int size; 97 }; 98 99 struct extctx_layout { 100 unsigned long size; 101 unsigned int flags; 102 struct ctx_layout fpu; 103 struct ctx_layout lsx; 104 struct ctx_layout lasx; 105 struct ctx_layout end; 106 }; 107 108 static abi_ptr extframe_alloc(struct extctx_layout *extctx, 109 struct ctx_layout *sctx, unsigned size, 110 unsigned align, abi_ptr orig_sp) 111 { 112 abi_ptr sp = orig_sp; 113 114 sp -= sizeof(struct target_sctx_info) + size; 115 align = MAX(align, CONTEXT_INFO_ALIGN); 116 sp = ROUND_DOWN(sp, align); 117 sctx->gaddr = sp; 118 119 size = orig_sp - sp; 120 sctx->size = size; 121 extctx->size += size; 122 123 return sp; 124 } 125 126 static abi_ptr setup_extcontext(CPULoongArchState *env, 127 struct extctx_layout *extctx, abi_ptr sp) 128 { 129 memset(extctx, 0, sizeof(struct extctx_layout)); 130 131 /* Grow down, alloc "end" context info first. */ 132 sp = extframe_alloc(extctx, &extctx->end, 0, CONTEXT_INFO_ALIGN, sp); 133 134 /* For qemu, there is no lazy fp context switch, so fp always present. */ 135 extctx->flags = SC_USED_FP; 136 137 if (FIELD_EX64(env->CSR_EUEN, CSR_EUEN, ASXE)) { 138 sp = extframe_alloc(extctx, &extctx->lasx, 139 sizeof(struct target_lasx_context), LASX_CTX_ALIGN, sp); 140 } else if (FIELD_EX64(env->CSR_EUEN, CSR_EUEN, SXE)) { 141 sp = extframe_alloc(extctx, &extctx->lsx, 142 sizeof(struct target_lsx_context), LSX_CTX_ALIGN, sp); 143 } else { 144 sp = extframe_alloc(extctx, &extctx->fpu, 145 sizeof(struct target_fpu_context), FPU_CTX_ALIGN, sp); 146 } 147 148 return sp; 149 } 150 151 static void setup_sigframe(CPULoongArchState *env, 152 struct target_sigcontext *sc, 153 struct extctx_layout *extctx) 154 { 155 struct target_sctx_info *info; 156 int i; 157 158 __put_user(extctx->flags, &sc->sc_flags); 159 __put_user(env->pc, &sc->sc_pc); 160 __put_user(0, &sc->sc_regs[0]); 161 for (i = 1; i < 32; ++i) { 162 __put_user(env->gpr[i], &sc->sc_regs[i]); 163 } 164 165 /* 166 * Set extension context 167 */ 168 169 if (FIELD_EX64(env->CSR_EUEN, CSR_EUEN, ASXE)) { 170 struct target_lasx_context *lasx_ctx; 171 info = extctx->lasx.haddr; 172 173 __put_user(LASX_CTX_MAGIC, &info->magic); 174 __put_user(extctx->lasx.size, &info->size); 175 176 lasx_ctx = (struct target_lasx_context *)(info + 1); 177 178 for (i = 0; i < 32; ++i) { 179 __put_user(env->fpr[i].vreg.UD(0), &lasx_ctx->regs[4 * i]); 180 __put_user(env->fpr[i].vreg.UD(1), &lasx_ctx->regs[4 * i + 1]); 181 __put_user(env->fpr[i].vreg.UD(2), &lasx_ctx->regs[4 * i + 2]); 182 __put_user(env->fpr[i].vreg.UD(3), &lasx_ctx->regs[4 * i + 3]); 183 } 184 __put_user(read_fcc(env), &lasx_ctx->fcc); 185 __put_user(env->fcsr0, &lasx_ctx->fcsr); 186 } else if (FIELD_EX64(env->CSR_EUEN, CSR_EUEN, SXE)) { 187 struct target_lsx_context *lsx_ctx; 188 info = extctx->lsx.haddr; 189 190 __put_user(LSX_CTX_MAGIC, &info->magic); 191 __put_user(extctx->lsx.size, &info->size); 192 193 lsx_ctx = (struct target_lsx_context *)(info + 1); 194 195 for (i = 0; i < 32; ++i) { 196 __put_user(env->fpr[i].vreg.UD(0), &lsx_ctx->regs[2 * i]); 197 __put_user(env->fpr[i].vreg.UD(1), &lsx_ctx->regs[2 * i + 1]); 198 } 199 __put_user(read_fcc(env), &lsx_ctx->fcc); 200 __put_user(env->fcsr0, &lsx_ctx->fcsr); 201 } else { 202 struct target_fpu_context *fpu_ctx; 203 info = extctx->fpu.haddr; 204 205 __put_user(FPU_CTX_MAGIC, &info->magic); 206 __put_user(extctx->fpu.size, &info->size); 207 208 fpu_ctx = (struct target_fpu_context *)(info + 1); 209 210 for (i = 0; i < 32; ++i) { 211 __put_user(env->fpr[i].vreg.UD(0), &fpu_ctx->regs[i]); 212 } 213 __put_user(read_fcc(env), &fpu_ctx->fcc); 214 __put_user(env->fcsr0, &fpu_ctx->fcsr); 215 } 216 217 /* 218 * Set end context 219 */ 220 info = extctx->end.haddr; 221 __put_user(0, &info->magic); 222 __put_user(0, &info->size); 223 } 224 225 static bool parse_extcontext(struct extctx_layout *extctx, abi_ptr frame) 226 { 227 memset(extctx, 0, sizeof(*extctx)); 228 229 while (1) { 230 abi_uint magic, size; 231 232 if (get_user_u32(magic, frame) || get_user_u32(size, frame + 4)) { 233 return false; 234 } 235 236 switch (magic) { 237 case 0: /* END */ 238 extctx->end.gaddr = frame; 239 extctx->end.size = size; 240 extctx->size += size; 241 return true; 242 243 case FPU_CTX_MAGIC: 244 if (size < (sizeof(struct target_sctx_info) + 245 sizeof(struct target_fpu_context))) { 246 return false; 247 } 248 extctx->fpu.gaddr = frame; 249 extctx->fpu.size = size; 250 extctx->size += size; 251 break; 252 case LSX_CTX_MAGIC: 253 if (size < (sizeof(struct target_sctx_info) + 254 sizeof(struct target_lsx_context))) { 255 return false; 256 } 257 extctx->lsx.gaddr = frame; 258 extctx->lsx.size = size; 259 extctx->size += size; 260 break; 261 case LASX_CTX_MAGIC: 262 if (size < (sizeof(struct target_sctx_info) + 263 sizeof(struct target_lasx_context))) { 264 return false; 265 } 266 extctx->lasx.gaddr = frame; 267 extctx->lasx.size = size; 268 extctx->size += size; 269 break; 270 default: 271 return false; 272 } 273 274 frame += size; 275 } 276 } 277 278 static void restore_sigframe(CPULoongArchState *env, 279 struct target_sigcontext *sc, 280 struct extctx_layout *extctx) 281 { 282 int i; 283 abi_ulong fcc; 284 285 __get_user(env->pc, &sc->sc_pc); 286 for (i = 1; i < 32; ++i) { 287 __get_user(env->gpr[i], &sc->sc_regs[i]); 288 } 289 290 if (extctx->lasx.haddr) { 291 struct target_lasx_context *lasx_ctx = 292 extctx->lasx.haddr + sizeof(struct target_sctx_info); 293 294 for (i = 0; i < 32; ++i) { 295 __get_user(env->fpr[i].vreg.UD(0), &lasx_ctx->regs[4 * i]); 296 __get_user(env->fpr[i].vreg.UD(1), &lasx_ctx->regs[4 * i + 1]); 297 __get_user(env->fpr[i].vreg.UD(2), &lasx_ctx->regs[4 * i + 2]); 298 __get_user(env->fpr[i].vreg.UD(3), &lasx_ctx->regs[4 * i + 3]); 299 } 300 __get_user(fcc, &lasx_ctx->fcc); 301 write_fcc(env, fcc); 302 __get_user(env->fcsr0, &lasx_ctx->fcsr); 303 restore_fp_status(env); 304 } else if (extctx->lsx.haddr) { 305 struct target_lsx_context *lsx_ctx = 306 extctx->lsx.haddr + sizeof(struct target_sctx_info); 307 308 for (i = 0; i < 32; ++i) { 309 __get_user(env->fpr[i].vreg.UD(0), &lsx_ctx->regs[2 * i]); 310 __get_user(env->fpr[i].vreg.UD(1), &lsx_ctx->regs[2 * i + 1]); 311 } 312 __get_user(fcc, &lsx_ctx->fcc); 313 write_fcc(env, fcc); 314 __get_user(env->fcsr0, &lsx_ctx->fcsr); 315 restore_fp_status(env); 316 } else if (extctx->fpu.haddr) { 317 struct target_fpu_context *fpu_ctx = 318 extctx->fpu.haddr + sizeof(struct target_sctx_info); 319 320 for (i = 0; i < 32; ++i) { 321 __get_user(env->fpr[i].vreg.UD(0), &fpu_ctx->regs[i]); 322 } 323 __get_user(fcc, &fpu_ctx->fcc); 324 write_fcc(env, fcc); 325 __get_user(env->fcsr0, &fpu_ctx->fcsr); 326 restore_fp_status(env); 327 } 328 } 329 330 /* 331 * Determine which stack to use. 332 */ 333 static abi_ptr get_sigframe(struct target_sigaction *ka, 334 CPULoongArchState *env, 335 struct extctx_layout *extctx) 336 { 337 abi_ulong sp; 338 339 sp = target_sigsp(get_sp_from_cpustate(env), ka); 340 sp = ROUND_DOWN(sp, 16); 341 sp = setup_extcontext(env, extctx, sp); 342 sp -= sizeof(struct target_rt_sigframe); 343 344 assert(QEMU_IS_ALIGNED(sp, 16)); 345 346 return sp; 347 } 348 349 void setup_rt_frame(int sig, struct target_sigaction *ka, 350 target_siginfo_t *info, 351 target_sigset_t *set, CPULoongArchState *env) 352 { 353 struct target_rt_sigframe *frame; 354 struct extctx_layout extctx; 355 abi_ptr frame_addr; 356 int i; 357 358 frame_addr = get_sigframe(ka, env, &extctx); 359 trace_user_setup_rt_frame(env, frame_addr); 360 361 frame = lock_user(VERIFY_WRITE, frame_addr, 362 sizeof(*frame) + extctx.size, 0); 363 if (!frame) { 364 force_sigsegv(sig); 365 return; 366 } 367 368 if (FIELD_EX64(env->CSR_EUEN, CSR_EUEN, ASXE)) { 369 extctx.lasx.haddr = (void *)frame + (extctx.lasx.gaddr - frame_addr); 370 extctx.end.haddr = (void *)frame + (extctx.end.gaddr - frame_addr); 371 } else if (FIELD_EX64(env->CSR_EUEN, CSR_EUEN, SXE)) { 372 extctx.lsx.haddr = (void *)frame + (extctx.lsx.gaddr - frame_addr); 373 extctx.end.haddr = (void *)frame + (extctx.end.gaddr - frame_addr); 374 } else { 375 extctx.fpu.haddr = (void *)frame + (extctx.fpu.gaddr - frame_addr); 376 extctx.end.haddr = (void *)frame + (extctx.end.gaddr - frame_addr); 377 } 378 379 tswap_siginfo(&frame->rs_info, info); 380 381 __put_user(0, &frame->rs_uc.tuc_flags); 382 __put_user(0, &frame->rs_uc.tuc_link); 383 target_save_altstack(&frame->rs_uc.tuc_stack, env); 384 385 setup_sigframe(env, &frame->rs_uc.tuc_mcontext, &extctx); 386 387 for (i = 0; i < TARGET_NSIG_WORDS; i++) { 388 __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]); 389 } 390 391 env->gpr[4] = sig; 392 env->gpr[5] = frame_addr + offsetof(struct target_rt_sigframe, rs_info); 393 env->gpr[6] = frame_addr + offsetof(struct target_rt_sigframe, rs_uc); 394 env->gpr[3] = frame_addr; 395 env->gpr[1] = default_rt_sigreturn; 396 397 env->pc = ka->_sa_handler; 398 unlock_user(frame, frame_addr, sizeof(*frame) + extctx.size); 399 } 400 401 long do_rt_sigreturn(CPULoongArchState *env) 402 { 403 struct target_rt_sigframe *frame; 404 struct extctx_layout extctx; 405 abi_ulong frame_addr; 406 sigset_t blocked; 407 408 frame_addr = env->gpr[3]; 409 trace_user_do_rt_sigreturn(env, frame_addr); 410 411 if (!parse_extcontext(&extctx, frame_addr + sizeof(*frame))) { 412 goto badframe; 413 } 414 415 frame = lock_user(VERIFY_READ, frame_addr, 416 sizeof(*frame) + extctx.size, 1); 417 if (!frame) { 418 goto badframe; 419 } 420 421 if (extctx.lasx.gaddr) { 422 extctx.lasx.haddr = (void *)frame + (extctx.lasx.gaddr - frame_addr); 423 } else if (extctx.lsx.gaddr) { 424 extctx.lsx.haddr = (void *)frame + (extctx.lsx.gaddr - frame_addr); 425 } else if (extctx.fpu.gaddr) { 426 extctx.fpu.haddr = (void *)frame + (extctx.fpu.gaddr - frame_addr); 427 } 428 429 target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask); 430 set_sigmask(&blocked); 431 432 restore_sigframe(env, &frame->rs_uc.tuc_mcontext, &extctx); 433 434 target_restore_altstack(&frame->rs_uc.tuc_stack, env); 435 436 unlock_user(frame, frame_addr, 0); 437 return -QEMU_ESIGRETURN; 438 439 badframe: 440 force_sig(TARGET_SIGSEGV); 441 return -QEMU_ESIGRETURN; 442 } 443 444 void setup_sigtramp(abi_ulong sigtramp_page) 445 { 446 uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 8, 0); 447 assert(tramp != NULL); 448 449 __put_user(0x03822c0b, tramp + 0); /* ori a7, zero, 0x8b */ 450 __put_user(0x002b0000, tramp + 1); /* syscall 0 */ 451 452 default_rt_sigreturn = sigtramp_page; 453 unlock_user(tramp, sigtramp_page, 8); 454 } 455