xref: /openbsd/sys/arch/i386/i386/process_machdep.c (revision f4e70637)
1 /*	$OpenBSD: process_machdep.c,v 1.30 2023/01/30 10:49:05 jsg Exp $	*/
2 /*	$NetBSD: process_machdep.c,v 1.22 1996/05/03 19:42:25 christos Exp $	*/
3 
4 /*
5  * Copyright (c) 1995, 1996 Charles M. Hannum.  All rights reserved.
6  * Copyright (c) 1993 The Regents of the University of California.
7  * Copyright (c) 1993 Jan-Simon Pendry
8  * All rights reserved.
9  *
10  * This code is derived from software contributed to Berkeley by
11  * Jan-Simon Pendry.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  * 3. Neither the name of the University nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  *
37  * From:
38  *	Id: procfs_i386.c,v 4.1 1993/12/17 10:47:45 jsp Rel
39  */
40 
41 /*
42  * This file may seem a bit stylized, but that so that it's easier to port.
43  * Functions to be implemented here are:
44  *
45  * process_read_regs(proc, regs)
46  *	Get the current user-visible register set from the process
47  *	and copy it into the regs structure (<machine/reg.h>).
48  *	The process is stopped at the time read_regs is called.
49  *
50  * process_write_regs(proc, regs)
51  *	Update the current register set from the passed in regs
52  *	structure.  Take care to avoid clobbering special CPU
53  *	registers or privileged bits in the PSL.
54  *	The process is stopped at the time write_regs is called.
55  *
56  * process_sstep(proc)
57  *	Arrange for the process to trap after executing a single instruction.
58  *
59  * process_set_pc(proc)
60  *	Set the process's program counter.
61  */
62 
63 #include <sys/param.h>
64 #include <sys/systm.h>
65 #include <sys/proc.h>
66 #include <sys/user.h>
67 #include <sys/ptrace.h>
68 
69 #include <machine/psl.h>
70 #include <machine/reg.h>
71 #include <machine/segments.h>
72 
73 #include "npx.h"
74 
75 static __inline struct trapframe *process_frame(struct proc *);
76 static __inline union savefpu *process_fpframe(struct proc *);
77 void process_fninit_xmm(struct savexmm *);
78 
79 static __inline struct trapframe *
process_frame(struct proc * p)80 process_frame(struct proc *p)
81 {
82 
83 	return (p->p_md.md_regs);
84 }
85 
86 static __inline union savefpu *
process_fpframe(struct proc * p)87 process_fpframe(struct proc *p)
88 {
89 
90 	return (&p->p_addr->u_pcb.pcb_savefpu);
91 }
92 
93 void
process_xmm_to_s87(const struct savexmm * sxmm,struct save87 * s87)94 process_xmm_to_s87(const struct savexmm *sxmm, struct save87 *s87)
95 {
96 	int i;
97 
98 	/* FPU control/status */
99 	s87->sv_env.en_cw = sxmm->sv_env.en_cw;
100 	s87->sv_env.en_sw = sxmm->sv_env.en_sw;
101 	/* tag word handled below */
102 	s87->sv_env.en_fip = sxmm->sv_env.en_fip;
103 	s87->sv_env.en_fcs = sxmm->sv_env.en_fcs;
104 	s87->sv_env.en_opcode = sxmm->sv_env.en_opcode;
105 	s87->sv_env.en_foo = sxmm->sv_env.en_foo;
106 	s87->sv_env.en_fos = sxmm->sv_env.en_fos;
107 
108 	/* Tag word and registers. */
109 	for (i = 0; i < 8; i++) {
110 		if (sxmm->sv_env.en_tw & (1U << i))
111 			s87->sv_env.en_tw &= ~(3U << (i * 2));
112 		else
113 			s87->sv_env.en_tw |= (3U << (i * 2));
114 
115 		if (sxmm->sv_ex_tw & (1U << i))
116 			s87->sv_ex_tw &= ~(3U << (i * 2));
117 		else
118 			s87->sv_ex_tw |= (3U << (i * 2));
119 
120 		memcpy(&s87->sv_ac[i].fp_bytes, &sxmm->sv_ac[i].fp_bytes,
121 		    sizeof(s87->sv_ac[i].fp_bytes));
122 	}
123 
124 	s87->sv_ex_sw = sxmm->sv_ex_sw;
125 }
126 
127 void
process_fninit_xmm(struct savexmm * sxmm)128 process_fninit_xmm(struct savexmm *sxmm)
129 {
130 	memset(sxmm, 0, sizeof(*sxmm));
131 	sxmm->sv_env.en_cw = __INITIAL_NPXCW__;
132 	sxmm->sv_env.en_mxcsr = __INITIAL_MXCSR__;
133 	sxmm->sv_env.en_mxcsr_mask = fpu_mxcsr_mask;
134 	sxmm->sv_env.en_sw = 0x0000;
135 	sxmm->sv_env.en_tw = 0x00;
136 }
137 
138 int
process_read_regs(struct proc * p,struct reg * regs)139 process_read_regs(struct proc *p, struct reg *regs)
140 {
141 	struct trapframe *tf = process_frame(p);
142 
143 	regs->r_gs = tf->tf_gs & 0xffff;
144 	regs->r_fs = tf->tf_fs & 0xffff;
145 	regs->r_es = tf->tf_es & 0xffff;
146 	regs->r_ds = tf->tf_ds & 0xffff;
147 	regs->r_eflags = tf->tf_eflags;
148 	regs->r_edi = tf->tf_edi;
149 	regs->r_esi = tf->tf_esi;
150 	regs->r_ebp = tf->tf_ebp;
151 	regs->r_ebx = tf->tf_ebx;
152 	regs->r_edx = tf->tf_edx;
153 	regs->r_ecx = tf->tf_ecx;
154 	regs->r_eax = tf->tf_eax;
155 	regs->r_eip = tf->tf_eip;
156 	regs->r_cs = tf->tf_cs & 0xffff;
157 	regs->r_esp = tf->tf_esp;
158 	regs->r_ss = tf->tf_ss & 0xffff;
159 
160 	return (0);
161 }
162 
163 int
process_read_fpregs(struct proc * p,struct fpreg * regs)164 process_read_fpregs(struct proc *p, struct fpreg *regs)
165 {
166 	union savefpu *frame = process_fpframe(p);
167 
168 	if (p->p_md.md_flags & MDP_USEDFPU) {
169 #if NNPX > 0
170 		npxsave_proc(p, 1);
171 #endif
172 	} else {
173 		/* Fake a FNINIT. */
174 		if (i386_use_fxsave) {
175 			process_fninit_xmm(&frame->sv_xmm);
176 		} else {
177 			memset(&frame->sv_87, 0, sizeof(frame->sv_87));
178 			frame->sv_87.sv_env.en_cw = __INITIAL_NPXCW__;
179 			frame->sv_87.sv_env.en_sw = 0x0000;
180 			frame->sv_87.sv_env.en_tw = 0xffff;
181 		}
182 		p->p_md.md_flags |= MDP_USEDFPU;
183 	}
184 
185 	if (i386_use_fxsave) {
186 		struct save87 s87;
187 
188 		/* XXX Yuck */
189 		process_xmm_to_s87(&frame->sv_xmm, &s87);
190 		memcpy(regs, &s87, sizeof(*regs));
191 	} else
192 		memcpy(regs, &frame->sv_87, sizeof(*regs));
193 
194 	return (0);
195 }
196 
197 #ifdef PTRACE
198 
199 void
process_s87_to_xmm(const struct save87 * s87,struct savexmm * sxmm)200 process_s87_to_xmm(const struct save87 *s87, struct savexmm *sxmm)
201 {
202 	int i;
203 
204 	/* FPU control/status */
205 	sxmm->sv_env.en_cw = s87->sv_env.en_cw;
206 	sxmm->sv_env.en_sw = s87->sv_env.en_sw;
207 	/* tag word handled below */
208 	sxmm->sv_env.en_fip = s87->sv_env.en_fip;
209 	sxmm->sv_env.en_fcs = s87->sv_env.en_fcs;
210 	sxmm->sv_env.en_opcode = s87->sv_env.en_opcode;
211 	sxmm->sv_env.en_foo = s87->sv_env.en_foo;
212 	sxmm->sv_env.en_fos = s87->sv_env.en_fos;
213 
214 	/* Tag word and registers. */
215 	for (i = 0; i < 8; i++) {
216 		if (((s87->sv_env.en_tw >> (i * 2)) & 3) == 3)
217 			sxmm->sv_env.en_tw &= ~(1U << i);
218 		else
219 			sxmm->sv_env.en_tw |= (1U << i);
220 
221 		if (((s87->sv_ex_tw >> (i * 2)) & 3) == 3)
222 			sxmm->sv_ex_tw &= ~(1U << i);
223 		else
224 			sxmm->sv_ex_tw |= (1U << i);
225 
226 		memcpy(&sxmm->sv_ac[i].fp_bytes, &s87->sv_ac[i].fp_bytes,
227 		    sizeof(sxmm->sv_ac[i].fp_bytes));
228 	}
229 
230 	sxmm->sv_ex_sw = s87->sv_ex_sw;
231 }
232 
233 int
process_write_regs(struct proc * p,struct reg * regs)234 process_write_regs(struct proc *p, struct reg *regs)
235 {
236 	struct trapframe *tf = process_frame(p);
237 
238 	/*
239 	 * Check for security violations.
240 	 */
241 	if (((regs->r_eflags ^ tf->tf_eflags) & PSL_USERSTATIC) != 0 ||
242 	    !USERMODE(regs->r_cs, regs->r_eflags))
243 		return (EINVAL);
244 
245 	tf->tf_gs = regs->r_gs & 0xffff;
246 	tf->tf_fs = regs->r_fs & 0xffff;
247 	tf->tf_es = regs->r_es & 0xffff;
248 	tf->tf_ds = regs->r_ds & 0xffff;
249 	tf->tf_eflags = regs->r_eflags;
250 	tf->tf_edi = regs->r_edi;
251 	tf->tf_esi = regs->r_esi;
252 	tf->tf_ebp = regs->r_ebp;
253 	tf->tf_ebx = regs->r_ebx;
254 	tf->tf_edx = regs->r_edx;
255 	tf->tf_ecx = regs->r_ecx;
256 	tf->tf_eax = regs->r_eax;
257 	tf->tf_eip = regs->r_eip;
258 	tf->tf_cs = regs->r_cs & 0xffff;
259 	tf->tf_esp = regs->r_esp;
260 	tf->tf_ss = regs->r_ss & 0xffff;
261 
262 	return (0);
263 }
264 
265 int
process_write_fpregs(struct proc * p,struct fpreg * regs)266 process_write_fpregs(struct proc *p, struct fpreg *regs)
267 {
268 	union savefpu *frame = process_fpframe(p);
269 
270 	if (p->p_md.md_flags & MDP_USEDFPU) {
271 #if NNPX > 0
272 		npxsave_proc(p, 0);
273 #endif
274 	} else {
275 		/*
276 		 * Make sure MXCSR and the XMM registers are
277 		 * initialized to sane defaults.
278 		 */
279 		if (i386_use_fxsave)
280 			process_fninit_xmm(&frame->sv_xmm);
281 		p->p_md.md_flags |= MDP_USEDFPU;
282 	}
283 
284 	if (i386_use_fxsave) {
285 		struct save87 s87;
286 
287 		/* XXX Yuck. */
288 		memcpy(&s87, regs, sizeof(*regs));
289 		process_s87_to_xmm(&s87, &frame->sv_xmm);
290 	} else
291 		memcpy(&frame->sv_87, regs, sizeof(*regs));
292 
293 	return (0);
294 }
295 
296 int
process_read_xmmregs(struct proc * p,struct xmmregs * regs)297 process_read_xmmregs(struct proc *p, struct xmmregs *regs)
298 {
299 	union savefpu *frame = process_fpframe(p);
300 
301 	if (!i386_use_fxsave)
302 		return (EINVAL);
303 
304 	if (p->p_md.md_flags & MDP_USEDFPU) {
305 #if NNPX > 0
306 		npxsave_proc(p, 1);
307 #endif
308 	} else {
309 		/* Fake a FNINIT. */
310 		process_fninit_xmm(&frame->sv_xmm);
311 		p->p_md.md_flags |= MDP_USEDFPU;
312 	}
313 
314 	memcpy(regs, &frame->sv_xmm, sizeof(*regs));
315 	return (0);
316 }
317 
318 int
process_write_xmmregs(struct proc * p,const struct xmmregs * regs)319 process_write_xmmregs(struct proc *p, const struct xmmregs *regs)
320 {
321 	union savefpu *frame = process_fpframe(p);
322 
323 	if (!i386_use_fxsave)
324 		return (EINVAL);
325 
326 	if (p->p_md.md_flags & MDP_USEDFPU) {
327 #if NNPX > 0
328 		npxsave_proc(p, 0);
329 #endif
330 	} else
331 		p->p_md.md_flags |= MDP_USEDFPU;
332 
333 	memcpy(&frame->sv_xmm, regs, sizeof(*regs));
334 	frame->sv_xmm.sv_env.en_mxcsr &= fpu_mxcsr_mask;
335 	return (0);
336 }
337 
338 int
process_sstep(struct proc * p,int sstep)339 process_sstep(struct proc *p, int sstep)
340 {
341 	struct trapframe *tf = process_frame(p);
342 
343 	if (sstep)
344 		tf->tf_eflags |= PSL_T;
345 	else
346 		tf->tf_eflags &= ~PSL_T;
347 
348 	return (0);
349 }
350 
351 int
process_set_pc(struct proc * p,caddr_t addr)352 process_set_pc(struct proc *p, caddr_t addr)
353 {
354 	struct trapframe *tf = process_frame(p);
355 
356 	tf->tf_eip = (int)addr;
357 
358 	return (0);
359 }
360 
361 #endif	/* PTRACE */
362