1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 1994-1998,2003 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * Copyright 2013 David Hoeppner. All rights reserved.
29 */
30
31 #include <sys/types.h>
32 #include <sys/t_lock.h>
33 #include <sys/klwp.h>
34 #include <sys/proc.h>
35 #include <sys/ucontext.h>
36 #include <sys/procfs.h>
37 #include <sys/privregs.h>
38 #include <sys/fp.h>
39 #include <sys/cpuvar.h>
40 #include <sys/cmn_err.h>
41 #include <sys/disp.h>
42 #include <sys/systm.h>
43 #include <sys/archsystm.h>
44 #include <sys/note.h>
45
46 /*
47 * Clear the struct ucontext extra register state pointer.
48 */
49 void
50 xregs_clrptr(klwp_id_t lwp, ucontext_t *uc)
51 {
52 uc->uc_xrs.xrs_id = 0;
53 uc->uc_xrs.xrs_ptr = NULL;
54 }
55
56 /*
57 * Indicate whether or not an extra register state
58 * pointer is associated with a struct ucontext.
59 */
60 int
61 xregs_hasptr(klwp_id_t lwp, ucontext_t *uc)
62 {
63 _NOTE(ARGUNUSED(lwp));
64
65 return (uc->uc_xrs.xrs_id == XRS_ID);
66 }
67
68 /*
69 * Get the struct ucontext extra register state pointer field.
70 */
71 caddr_t
72 xregs_getptr(klwp_id_t lwp, ucontext_t *uc)
73 {
74 _NOTE(ARGUNUSED(lwp));
75
76 if (uc->uc_xrs.xrs_id == XRS_ID)
77 return (uc->uc_xrs.xrs_ptr);
78
79 return (NULL);
80 }
81
82 /*
83 * Set the struct ucontext extra register state pointer field.
84 */
85 void
86 xregs_setptr(klwp_id_t lwp, ucontext_t *uc, caddr_t xrp)
87 {
88 _NOTE(ARGUNUSED(lwp));
89
90 uc->uc_xrs.xrs_id = XRS_ID;
91 uc->uc_xrs.xrs_ptr = xrp;
92 }
93
94 #if defined(_SYSCALL32_IMPL)
95
96 void
97 xregs_clrptr32(klwp_id_t lwp, ucontext32_t *uc)
98 {
99 _NOTE(ARGUNUSED(lwp));
100
101 uc->uc_xrs.xrs_id = 0;
102 uc->uc_xrs.xrs_ptr = NULL;
103 }
104
105 int
106 xregs_hasptr32(klwp_id_t lwp, ucontext32_t *uc)
107 {
108 _NOTE(ARGUNUSED(lwp));
109
110 return (uc->uc_xrs.xrs_id == XRS_ID);
111 }
112
113 caddr32_t
114 xregs_getptr32(klwp_id_t lwp, ucontext32_t *uc)
115 {
116 _NOTE(ARGUNUSED(lwp));
117
118 if (uc->uc_xrs.xrs_id == XRS_ID)
119 return (uc->uc_xrs.xrs_ptr);
120
121 return (0);
122 }
123
124 void
125 xregs_setptr32(klwp_id_t lwp, ucontext32_t *uc, caddr32_t xrp)
126 {
127 _NOTE(ARGUNUSED(lwp));
128
129 uc->uc_xrs.xrs_id = XRS_ID;
130 uc->uc_xrs.xrs_ptr = xrp;
131 }
132
133 #endif /* _SYSCALL32_IMPL */
134
135 /*
136 * Fill in the extra register state area specified with the
137 * specified lwp's floating point extra register state information.
138 */
139 void
140 xregs_getfpregs(klwp_id_t lwp, caddr_t xrp)
141 {
142 prxregset_t *xregs = (prxregset_t *)xrp;
143 kfpu_t *fp = lwptofpu(lwp);
144
145 if (xregs == NULL)
146 return;
147
148 kpreempt_disable();
149
150 xregs->pr_type = XR_TYPE_XSAVE;
151
152 kpreempt_enable();
153 }
154
155 /*
156 * Fill in the extra register state area specified with
157 * the specified kwp's extra register state information.
158 */
159 void
160 xregs_get(klwp_id_t lwp, caddr_t xrp)
161 {
162
163 if (xrp != NULL) {
164 bzero(xrp, sizeof (prxregset_t));
165 xregs_getfpregs(lwp, xrp);
166 }
167 }
168
169 /*
170 * Set the specified lwp's floating-point extra
171 * register state based on the specified input.
172 */
173 void
174 xregs_setfpregs(klwp_id_t lwp, caddr_t xrp)
175 {
176 prxregset_t *xregs = (prxregset_t *)xrp;
177 kfpu_t *fp = lwptofpu(lwp);
178 fpu_ctx_t *fpu = &lwp->lwp_pcb.pcb_fpu;
179
180 if (xregs == NULL)
181 return;
182
183 #if defined(DEBUG)
184 if (xregs->pr_type != XR_TYPE_XSAVE) {
185 cmn_err(CE_WARN,
186 "xregs_setfpregs: pr_type is %d and should be %d",
187 xregs->pr_type, XR_TYPE_XSAVE);
188 }
189 #endif /* DEBUG */
190
191 if (fpu->fpu_flags & FPU_EN) {
192 kpreempt_disable();
193 (void) kcopy(&xregs->pr_un.pr_xsave.pr_ymm,
194 &fp->kfpu_u.kfpu_xs.xs_ymm,
195 sizeof (&xregs->pr_un.pr_xsave.pr_ymm));
196
197 /*
198 * If not the current lwp then resume() will handle it.
199 */
200 if (lwp != ttolwp(curthread)) {
201 /* Force resume to reload fp regs */
202 kpreempt_enable();
203 return;
204 }
205
206 if (fpu_exists) {
207 }
208
209 kpreempt_enable();
210 }
211 }
212
213 /*
214 * Set the specified lwp's extra register
215 * state based on the specified input.
216 */
217 void
218 xregs_set(klwp_id_t lwp, caddr_t xrp)
219 {
220 if (xrp != NULL) {
221 xregs_setfpregs(lwp, xrp);
222 }
223 }
224
225 /*
226 * Return the size of the extra register state.
227 */
228 int
229 xregs_getsize(proc_t *p)
230 {
231 return (sizeof (prxregset_t));
232 }