10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
26 /* All Rights Reserved */
27 /*
28 * Copyright (c) 2018, Joyent, Inc.
29 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
30 * Copyright 2022 Oxide Computer Company
31 */
32
33 #include <sys/param.h>
34 #include <sys/types.h>
35 #include <sys/vmparam.h>
36 #include <sys/systm.h>
37 #include <sys/signal.h>
38 #include <sys/stack.h>
39 #include <sys/regset.h>
40 #include <sys/privregs.h>
41 #include <sys/frame.h>
42 #include <sys/proc.h>
43 #include <sys/psw.h>
44 #include <sys/siginfo.h>
45 #include <sys/cpuvar.h>
46 #include <sys/asm_linkage.h>
47 #include <sys/kmem.h>
48 #include <sys/errno.h>
49 #include <sys/bootconf.h>
50 #include <sys/archsystm.h>
222 src->fp_reg_set.fpchip_state.xstatus;
223 }
224
225 static void
226 fpregset_32ton(const fpregset32_t *src, fpregset_t *dst)
227 {
228 fpregset32_to_fxsave(src, (struct fxsave_state *)dst);
229 dst->fp_reg_set.fpchip_state.status =
230 src->fp_reg_set.fpchip_state.status;
231 dst->fp_reg_set.fpchip_state.xstatus =
232 src->fp_reg_set.fpchip_state.xstatus;
233 }
234 #endif
235
236 /*
237 * Set floating-point registers from a native fpregset_t.
238 */
239 void
240 setfpregs(klwp_t *lwp, fpregset_t *fp)
241 {
242 struct fpu_ctx *fpu = &lwp->lwp_pcb.pcb_fpu;
243
244 if (fpu->fpu_flags & FPU_EN) {
245 if (!(fpu->fpu_flags & FPU_VALID)) {
246 /*
247 * FPU context is still active, release the
248 * ownership.
249 */
250 fp_free(fpu);
251 }
252 }
253 /*
254 * Else: if we are trying to change the FPU state of a thread which
255 * hasn't yet initialized floating point, store the state in
256 * the pcb and indicate that the state is valid. When the
257 * thread enables floating point, it will use this state instead
258 * of the default state.
259 */
260
261 switch (fp_save_mech) {
262 case FP_FXSAVE:
263 fpregset_to_fxsave(fp, fpu->fpu_regs.kfpu_u.kfpu_fx);
264 fpu->fpu_regs.kfpu_xstatus =
265 fp->fp_reg_set.fpchip_state.xstatus;
266 break;
267
268 case FP_XSAVE:
269 fpregset_to_fxsave(fp,
270 &fpu->fpu_regs.kfpu_u.kfpu_xs->xs_fxsave);
271 fpu->fpu_regs.kfpu_xstatus =
272 fp->fp_reg_set.fpchip_state.xstatus;
273 fpu->fpu_regs.kfpu_u.kfpu_xs->xs_header.xsh_xstate_bv |=
274 (XFEATURE_LEGACY_FP | XFEATURE_SSE);
275 break;
276 default:
277 panic("Invalid fp_save_mech");
278 /*NOTREACHED*/
279 }
280
281 fpu->fpu_regs.kfpu_status = fp->fp_reg_set.fpchip_state.status;
282 fpu->fpu_flags |= FPU_VALID;
283 PCB_SET_UPDATE_FPU(&lwp->lwp_pcb);
284 }
285
286 /*
287 * Get floating-point registers into a native fpregset_t.
288 */
289 void
290 getfpregs(klwp_t *lwp, fpregset_t *fp)
291 {
292 struct fpu_ctx *fpu = &lwp->lwp_pcb.pcb_fpu;
293
294 kpreempt_disable();
295 if (fpu->fpu_flags & FPU_EN) {
296 /*
297 * If we have FPU hw and the thread's pcb doesn't have
298 * a valid FPU state then get the state from the hw.
299 */
300 if (fpu_exists && ttolwp(curthread) == lwp &&
301 !(fpu->fpu_flags & FPU_VALID))
302 fp_save(fpu); /* get the current FPU state */
303 }
304
305 /*
306 * There are 3 possible cases we have to be aware of here:
307 *
308 * 1. FPU is enabled. FPU state is stored in the current LWP.
309 *
310 * 2. FPU is not enabled, and there have been no intervening /proc
311 * modifications. Return initial FPU state.
312 *
313 * 3. FPU is not enabled, but a /proc consumer has modified FPU state.
314 * FPU state is stored in the current LWP.
315 */
316 if ((fpu->fpu_flags & FPU_EN) || (fpu->fpu_flags & FPU_VALID)) {
317 /*
318 * Cases 1 and 3.
319 */
320 switch (fp_save_mech) {
321 case FP_FXSAVE:
322 fxsave_to_fpregset(fpu->fpu_regs.kfpu_u.kfpu_fx, fp);
323 fp->fp_reg_set.fpchip_state.xstatus =
324 fpu->fpu_regs.kfpu_xstatus;
325 break;
326 case FP_XSAVE:
327 fxsave_to_fpregset(
328 &fpu->fpu_regs.kfpu_u.kfpu_xs->xs_fxsave, fp);
329 fp->fp_reg_set.fpchip_state.xstatus =
330 fpu->fpu_regs.kfpu_xstatus;
331 break;
332 default:
333 panic("Invalid fp_save_mech");
334 /*NOTREACHED*/
335 }
336 fp->fp_reg_set.fpchip_state.status = fpu->fpu_regs.kfpu_status;
337 } else {
338 /*
339 * Case 2.
340 */
341 switch (fp_save_mech) {
342 case FP_FXSAVE:
343 case FP_XSAVE:
344 /*
345 * For now, we don't have any AVX specific field in ABI.
346 * If we add any in the future, we need to initial them
347 * as well.
348 */
349 fxsave_to_fpregset(&sse_initial, fp);
350 fp->fp_reg_set.fpchip_state.xstatus =
351 fpu->fpu_regs.kfpu_xstatus;
352 break;
353 default:
354 panic("Invalid fp_save_mech");
355 /*NOTREACHED*/
356 }
357 fp->fp_reg_set.fpchip_state.status = fpu->fpu_regs.kfpu_status;
358 }
359 kpreempt_enable();
360 }
361
362 #if defined(_SYSCALL32_IMPL)
363
364 /*
365 * Set floating-point registers from an fpregset32_t.
366 */
367 void
368 setfpregs32(klwp_t *lwp, fpregset32_t *fp)
369 {
370 fpregset_t fpregs;
371
372 fpregset_32ton(fp, &fpregs);
373 setfpregs(lwp, &fpregs);
374 }
375
376 /*
377 * Get floating-point registers into an fpregset32_t.
378 */
379 void
511 dmc->gregs[REG_RIP] = (greg_t)(uint32_t)smc->gregs[EIP];
512 dmc->gregs[REG_CS] = (greg_t)(uint32_t)smc->gregs[CS];
513 dmc->gregs[REG_RFL] = (greg_t)(uint32_t)smc->gregs[EFL];
514 dmc->gregs[REG_RSP] = (greg_t)(uint32_t)smc->gregs[UESP];
515 dmc->gregs[REG_SS] = (greg_t)(uint32_t)smc->gregs[SS];
516
517 /*
518 * A valid fpregs is only copied in if uc.uc_flags has UC_FPU set
519 * otherwise there is no guarantee that anything in fpregs is valid.
520 */
521 if (src->uc_flags & UC_FPU)
522 fpregset_32ton(&src->uc_mcontext.fpregs,
523 &dst->uc_mcontext.fpregs);
524
525 /*
526 * Copy the brand-private data:
527 */
528 dst->uc_brand_data[0] = (void *)(uintptr_t)src->uc_brand_data[0];
529 dst->uc_brand_data[1] = (void *)(uintptr_t)src->uc_brand_data[1];
530 dst->uc_brand_data[2] = (void *)(uintptr_t)src->uc_brand_data[2];
531 }
532
533 #endif /* _SYSCALL32_IMPL */
534
535 /*
536 * Return the user-level PC.
537 * If in a system call, return the address of the syscall trap.
538 */
539 greg_t
540 getuserpc()
541 {
542 greg_t upc = lwptoregs(ttolwp(curthread))->r_pc;
543 uint32_t insn;
544
545 if (curthread->t_sysnum == 0)
546 return (upc);
547
548 /*
549 * We might've gotten here from sysenter (0xf 0x34),
550 * syscall (0xf 0x5) or lcall (0x9a 0 0 0 0 0x27 0).
551 *
552 * Go peek at the binary to figure it out..
553 */
554 if (fuword32((void *)(upc - 2), &insn) != -1 &&
555 (insn & 0xffff) == 0x340f || (insn & 0xffff) == 0x050f)
556 return (upc - 2);
557 return (upc - 7);
558 }
559
560 /*
|
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
26 /* All Rights Reserved */
27 /*
28 * Copyright (c) 2018, Joyent, Inc.
29 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
30 * Copyright 2023 Oxide Computer Company
31 */
32
33 #include <sys/param.h>
34 #include <sys/types.h>
35 #include <sys/vmparam.h>
36 #include <sys/systm.h>
37 #include <sys/signal.h>
38 #include <sys/stack.h>
39 #include <sys/regset.h>
40 #include <sys/privregs.h>
41 #include <sys/frame.h>
42 #include <sys/proc.h>
43 #include <sys/psw.h>
44 #include <sys/siginfo.h>
45 #include <sys/cpuvar.h>
46 #include <sys/asm_linkage.h>
47 #include <sys/kmem.h>
48 #include <sys/errno.h>
49 #include <sys/bootconf.h>
50 #include <sys/archsystm.h>
222 src->fp_reg_set.fpchip_state.xstatus;
223 }
224
225 static void
226 fpregset_32ton(const fpregset32_t *src, fpregset_t *dst)
227 {
228 fpregset32_to_fxsave(src, (struct fxsave_state *)dst);
229 dst->fp_reg_set.fpchip_state.status =
230 src->fp_reg_set.fpchip_state.status;
231 dst->fp_reg_set.fpchip_state.xstatus =
232 src->fp_reg_set.fpchip_state.xstatus;
233 }
234 #endif
235
236 /*
237 * Set floating-point registers from a native fpregset_t.
238 */
239 void
240 setfpregs(klwp_t *lwp, fpregset_t *fp)
241 {
242 fpu_set_fpregset(lwp, fp);
243 }
244
245 /*
246 * Get floating-point registers into a native fpregset_t.
247 */
248 void
249 getfpregs(klwp_t *lwp, fpregset_t *fp)
250 {
251 bzero(fp, sizeof (*fp));
252 fpu_get_fpregset(lwp, fp);
253 }
254
255 #if defined(_SYSCALL32_IMPL)
256
257 /*
258 * Set floating-point registers from an fpregset32_t.
259 */
260 void
261 setfpregs32(klwp_t *lwp, fpregset32_t *fp)
262 {
263 fpregset_t fpregs;
264
265 fpregset_32ton(fp, &fpregs);
266 setfpregs(lwp, &fpregs);
267 }
268
269 /*
270 * Get floating-point registers into an fpregset32_t.
271 */
272 void
404 dmc->gregs[REG_RIP] = (greg_t)(uint32_t)smc->gregs[EIP];
405 dmc->gregs[REG_CS] = (greg_t)(uint32_t)smc->gregs[CS];
406 dmc->gregs[REG_RFL] = (greg_t)(uint32_t)smc->gregs[EFL];
407 dmc->gregs[REG_RSP] = (greg_t)(uint32_t)smc->gregs[UESP];
408 dmc->gregs[REG_SS] = (greg_t)(uint32_t)smc->gregs[SS];
409
410 /*
411 * A valid fpregs is only copied in if uc.uc_flags has UC_FPU set
412 * otherwise there is no guarantee that anything in fpregs is valid.
413 */
414 if (src->uc_flags & UC_FPU)
415 fpregset_32ton(&src->uc_mcontext.fpregs,
416 &dst->uc_mcontext.fpregs);
417
418 /*
419 * Copy the brand-private data:
420 */
421 dst->uc_brand_data[0] = (void *)(uintptr_t)src->uc_brand_data[0];
422 dst->uc_brand_data[1] = (void *)(uintptr_t)src->uc_brand_data[1];
423 dst->uc_brand_data[2] = (void *)(uintptr_t)src->uc_brand_data[2];
424
425 if (src->uc_flags & UC_XSAVE) {
426 dst->uc_xsave = (long)(uint32_t)src->uc_xsave;
427 } else {
428 dst->uc_xsave = 0;
429 }
430 }
431
432 #endif /* _SYSCALL32_IMPL */
433
434 /*
435 * Return the user-level PC.
436 * If in a system call, return the address of the syscall trap.
437 */
438 greg_t
439 getuserpc(void)
440 {
441 greg_t upc = lwptoregs(ttolwp(curthread))->r_pc;
442 uint32_t insn;
443
444 if (curthread->t_sysnum == 0)
445 return (upc);
446
447 /*
448 * We might've gotten here from sysenter (0xf 0x34),
449 * syscall (0xf 0x5) or lcall (0x9a 0 0 0 0 0x27 0).
450 *
451 * Go peek at the binary to figure it out..
452 */
453 if (fuword32((void *)(upc - 2), &insn) != -1 &&
454 (insn & 0xffff) == 0x340f || (insn & 0xffff) == 0x050f)
455 return (upc - 2);
456 return (upc - 7);
457 }
458
459 /*
|