1330567Sgordon/*	$OpenBSD: process_machdep.c,v 1.30 2023/01/30 10:49:05 jsg Exp $	*/
2330567Sgordon/*	$NetBSD: process_machdep.c,v 1.22 1996/05/03 19:42:25 christos Exp $	*/
3330567Sgordon
4330567Sgordon/*
5330567Sgordon * Copyright (c) 1995, 1996 Charles M. Hannum.  All rights reserved.
6330567Sgordon * Copyright (c) 1993 The Regents of the University of California.
7330567Sgordon * Copyright (c) 1993 Jan-Simon Pendry
8330567Sgordon * All rights reserved.
9258945Sroberto *
10258945Sroberto * This code is derived from software contributed to Berkeley by
11258945Sroberto * Jan-Simon Pendry.
12298770Sdelphij *
13316722Sdelphij * Redistribution and use in source and binary forms, with or without
14258945Sroberto * modification, are permitted provided that the following conditions
15330567Sgordon * are met:
16330567Sgordon * 1. Redistributions of source code must retain the above copyright
17330567Sgordon *    notice, this list of conditions and the following disclaimer.
18330567Sgordon * 2. Redistributions in binary form must reproduce the above copyright
19330567Sgordon *    notice, this list of conditions and the following disclaimer in the
20330567Sgordon *    documentation and/or other materials provided with the distribution.
21330567Sgordon * 3. Neither the name of the University nor the names of its contributors
22330567Sgordon *    may be used to endorse or promote products derived from this software
23330567Sgordon *    without specific prior written permission.
24330567Sgordon *
25330567Sgordon * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26258945Sroberto * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27280849Scy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28258945Sroberto * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29330567Sgordon * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30330567Sgordon * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31330567Sgordon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32330567Sgordon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33330567Sgordon * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34330567Sgordon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35330567Sgordon * SUCH DAMAGE.
36330567Sgordon *
37330567Sgordon * From:
38330567Sgordon *	Id: procfs_i386.c,v 4.1 1993/12/17 10:47:45 jsp Rel
39330567Sgordon */
40330567Sgordon
41330567Sgordon/*
42330567Sgordon * This file may seem a bit stylized, but that so that it's easier to port.
43330567Sgordon * Functions to be implemented here are:
44330567Sgordon *
45330567Sgordon * process_read_regs(proc, regs)
46330567Sgordon *	Get the current user-visible register set from the process
47330567Sgordon *	and copy it into the regs structure (<machine/reg.h>).
48330567Sgordon *	The process is stopped at the time read_regs is called.
49330567Sgordon *
50330567Sgordon * process_write_regs(proc, regs)
51330567Sgordon *	Update the current register set from the passed in regs
52330567Sgordon *	structure.  Take care to avoid clobbering special CPU
53330567Sgordon *	registers or privileged bits in the PSL.
54330567Sgordon *	The process is stopped at the time write_regs is called.
55330567Sgordon *
56330567Sgordon * process_sstep(proc)
57330567Sgordon *	Arrange for the process to trap after executing a single instruction.
58330567Sgordon *
59330567Sgordon * process_set_pc(proc)
60330567Sgordon *	Set the process's program counter.
61330567Sgordon */
62330567Sgordon
63330567Sgordon#include <sys/param.h>
64330567Sgordon#include <sys/systm.h>
65330567Sgordon#include <sys/proc.h>
66330567Sgordon#include <sys/user.h>
67330567Sgordon#include <sys/ptrace.h>
68330567Sgordon
69330567Sgordon#include <machine/psl.h>
70330567Sgordon#include <machine/reg.h>
71330567Sgordon#include <machine/segments.h>
72330567Sgordon
73330567Sgordon#include "npx.h"
74330567Sgordon
75330567Sgordonstatic __inline struct trapframe *process_frame(struct proc *);
76330567Sgordonstatic __inline union savefpu *process_fpframe(struct proc *);
77330567Sgordonvoid process_fninit_xmm(struct savexmm *);
78330567Sgordon
79330567Sgordonstatic __inline struct trapframe *
80330567Sgordonprocess_frame(struct proc *p)
81330567Sgordon{
82330567Sgordon
83330567Sgordon	return (p->p_md.md_regs);
84330567Sgordon}
85330567Sgordon
86330567Sgordonstatic __inline union savefpu *
87330567Sgordonprocess_fpframe(struct proc *p)
88330567Sgordon{
89330567Sgordon
90330567Sgordon	return (&p->p_addr->u_pcb.pcb_savefpu);
91330567Sgordon}
92330567Sgordon
93330567Sgordonvoid
94330567Sgordonprocess_xmm_to_s87(const struct savexmm *sxmm, struct save87 *s87)
95330567Sgordon{
96330567Sgordon	int i;
97330567Sgordon
98330567Sgordon	/* FPU control/status */
99330567Sgordon	s87->sv_env.en_cw = sxmm->sv_env.en_cw;
100330567Sgordon	s87->sv_env.en_sw = sxmm->sv_env.en_sw;
101330567Sgordon	/* tag word handled below */
102330567Sgordon	s87->sv_env.en_fip = sxmm->sv_env.en_fip;
103330567Sgordon	s87->sv_env.en_fcs = sxmm->sv_env.en_fcs;
104330567Sgordon	s87->sv_env.en_opcode = sxmm->sv_env.en_opcode;
105330567Sgordon	s87->sv_env.en_foo = sxmm->sv_env.en_foo;
106330567Sgordon	s87->sv_env.en_fos = sxmm->sv_env.en_fos;
107330567Sgordon
108330567Sgordon	/* Tag word and registers. */
109330567Sgordon	for (i = 0; i < 8; i++) {
110330567Sgordon		if (sxmm->sv_env.en_tw & (1U << i))
111330567Sgordon			s87->sv_env.en_tw &= ~(3U << (i * 2));
112330567Sgordon		else
113330567Sgordon			s87->sv_env.en_tw |= (3U << (i * 2));
114330567Sgordon
115330567Sgordon		if (sxmm->sv_ex_tw & (1U << i))
116330567Sgordon			s87->sv_ex_tw &= ~(3U << (i * 2));
117330567Sgordon		else
118330567Sgordon			s87->sv_ex_tw |= (3U << (i * 2));
119330567Sgordon
120330567Sgordon		memcpy(&s87->sv_ac[i].fp_bytes, &sxmm->sv_ac[i].fp_bytes,
121330567Sgordon		    sizeof(s87->sv_ac[i].fp_bytes));
122330567Sgordon	}
123330567Sgordon
124330567Sgordon	s87->sv_ex_sw = sxmm->sv_ex_sw;
125330567Sgordon}
126330567Sgordon
127330567Sgordonvoid
128330567Sgordonprocess_fninit_xmm(struct savexmm *sxmm)
129330567Sgordon{
130258945Sroberto	memset(sxmm, 0, sizeof(*sxmm));
131258945Sroberto	sxmm->sv_env.en_cw = __INITIAL_NPXCW__;
132330567Sgordon	sxmm->sv_env.en_mxcsr = __INITIAL_MXCSR__;
133330567Sgordon	sxmm->sv_env.en_mxcsr_mask = fpu_mxcsr_mask;
134330567Sgordon	sxmm->sv_env.en_sw = 0x0000;
135330567Sgordon	sxmm->sv_env.en_tw = 0x00;
136330567Sgordon}
137258945Sroberto
138258945Srobertoint
139330567Sgordonprocess_read_regs(struct proc *p, struct reg *regs)
140330567Sgordon{
141258945Sroberto	struct trapframe *tf = process_frame(p);
142330567Sgordon
143258945Sroberto	regs->r_gs = tf->tf_gs & 0xffff;
144258945Sroberto	regs->r_fs = tf->tf_fs & 0xffff;
145258945Sroberto	regs->r_es = tf->tf_es & 0xffff;
146258945Sroberto	regs->r_ds = tf->tf_ds & 0xffff;
147330567Sgordon	regs->r_eflags = tf->tf_eflags;
148330567Sgordon	regs->r_edi = tf->tf_edi;
149330567Sgordon	regs->r_esi = tf->tf_esi;
150330567Sgordon	regs->r_ebp = tf->tf_ebp;
151330567Sgordon	regs->r_ebx = tf->tf_ebx;
152330567Sgordon	regs->r_edx = tf->tf_edx;
153330567Sgordon	regs->r_ecx = tf->tf_ecx;
154330567Sgordon	regs->r_eax = tf->tf_eax;
155330567Sgordon	regs->r_eip = tf->tf_eip;
156330567Sgordon	regs->r_cs = tf->tf_cs & 0xffff;
157258945Sroberto	regs->r_esp = tf->tf_esp;
158258945Sroberto	regs->r_ss = tf->tf_ss & 0xffff;
159258945Sroberto
160258945Sroberto	return (0);
161330567Sgordon}
162258945Sroberto
163330567Sgordonint
164258945Srobertoprocess_read_fpregs(struct proc *p, struct fpreg *regs)
165258945Sroberto{
166258945Sroberto	union savefpu *frame = process_fpframe(p);
167258945Sroberto
168330567Sgordon	if (p->p_md.md_flags & MDP_USEDFPU) {
169330567Sgordon#if NNPX > 0
170330567Sgordon		npxsave_proc(p, 1);
171330567Sgordon#endif
172258945Sroberto	} else {
173258945Sroberto		/* Fake a FNINIT. */
174330567Sgordon		if (i386_use_fxsave) {
175330567Sgordon			process_fninit_xmm(&frame->sv_xmm);
176330567Sgordon		} else {
177330567Sgordon			memset(&frame->sv_87, 0, sizeof(frame->sv_87));
178330567Sgordon			frame->sv_87.sv_env.en_cw = __INITIAL_NPXCW__;
179330567Sgordon			frame->sv_87.sv_env.en_sw = 0x0000;
180330567Sgordon			frame->sv_87.sv_env.en_tw = 0xffff;
181330567Sgordon		}
182330567Sgordon		p->p_md.md_flags |= MDP_USEDFPU;
183330567Sgordon	}
184330567Sgordon
185330567Sgordon	if (i386_use_fxsave) {
186330567Sgordon		struct save87 s87;
187330567Sgordon
188330567Sgordon		/* XXX Yuck */
189330567Sgordon		process_xmm_to_s87(&frame->sv_xmm, &s87);
190330567Sgordon		memcpy(regs, &s87, sizeof(*regs));
191330567Sgordon	} else
192330567Sgordon		memcpy(regs, &frame->sv_87, sizeof(*regs));
193330567Sgordon
194258945Sroberto	return (0);
195258945Sroberto}
196258945Sroberto
197258945Sroberto#ifdef PTRACE
198258945Sroberto
199258945Srobertovoid
200258945Srobertoprocess_s87_to_xmm(const struct save87 *s87, struct savexmm *sxmm)
201258945Sroberto{
202258945Sroberto	int i;
203258945Sroberto
204258945Sroberto	/* FPU control/status */
205258945Sroberto	sxmm->sv_env.en_cw = s87->sv_env.en_cw;
206258945Sroberto	sxmm->sv_env.en_sw = s87->sv_env.en_sw;
207258945Sroberto	/* tag word handled below */
208258945Sroberto	sxmm->sv_env.en_fip = s87->sv_env.en_fip;
209258945Sroberto	sxmm->sv_env.en_fcs = s87->sv_env.en_fcs;
210258945Sroberto	sxmm->sv_env.en_opcode = s87->sv_env.en_opcode;
211258945Sroberto	sxmm->sv_env.en_foo = s87->sv_env.en_foo;
212258945Sroberto	sxmm->sv_env.en_fos = s87->sv_env.en_fos;
213258945Sroberto
214258945Sroberto	/* Tag word and registers. */
215258945Sroberto	for (i = 0; i < 8; i++) {
216330567Sgordon		if (((s87->sv_env.en_tw >> (i * 2)) & 3) == 3)
217258945Sroberto			sxmm->sv_env.en_tw &= ~(1U << i);
218258945Sroberto		else
219258945Sroberto			sxmm->sv_env.en_tw |= (1U << i);
220258945Sroberto
221258945Sroberto		if (((s87->sv_ex_tw >> (i * 2)) & 3) == 3)
222258945Sroberto			sxmm->sv_ex_tw &= ~(1U << i);
223258945Sroberto		else
224258945Sroberto			sxmm->sv_ex_tw |= (1U << i);
225330567Sgordon
226258945Sroberto		memcpy(&sxmm->sv_ac[i].fp_bytes, &s87->sv_ac[i].fp_bytes,
227330567Sgordon		    sizeof(sxmm->sv_ac[i].fp_bytes));
228258945Sroberto	}
229258945Sroberto
230258945Sroberto	sxmm->sv_ex_sw = s87->sv_ex_sw;
231330567Sgordon}
232330567Sgordon
233330567Sgordonint
234258945Srobertoprocess_write_regs(struct proc *p, struct reg *regs)
235280849Scy{
236258945Sroberto	struct trapframe *tf = process_frame(p);
237258945Sroberto
238258945Sroberto	/*
239258945Sroberto	 * Check for security violations.
240280849Scy	 */
241258945Sroberto	if (((regs->r_eflags ^ tf->tf_eflags) & PSL_USERSTATIC) != 0 ||
242258945Sroberto	    !USERMODE(regs->r_cs, regs->r_eflags))
243258945Sroberto		return (EINVAL);
244258945Sroberto
245258945Sroberto	tf->tf_gs = regs->r_gs & 0xffff;
246258945Sroberto	tf->tf_fs = regs->r_fs & 0xffff;
247258945Sroberto	tf->tf_es = regs->r_es & 0xffff;
248280849Scy	tf->tf_ds = regs->r_ds & 0xffff;
249258945Sroberto	tf->tf_eflags = regs->r_eflags;
250258945Sroberto	tf->tf_edi = regs->r_edi;
251258945Sroberto	tf->tf_esi = regs->r_esi;
252258945Sroberto	tf->tf_ebp = regs->r_ebp;
253258945Sroberto	tf->tf_ebx = regs->r_ebx;
254258945Sroberto	tf->tf_edx = regs->r_edx;
255258945Sroberto	tf->tf_ecx = regs->r_ecx;
256258945Sroberto	tf->tf_eax = regs->r_eax;
257258945Sroberto	tf->tf_eip = regs->r_eip;
258280849Scy	tf->tf_cs = regs->r_cs & 0xffff;
259330567Sgordon	tf->tf_esp = regs->r_esp;
260330567Sgordon	tf->tf_ss = regs->r_ss & 0xffff;
261330567Sgordon
262258945Sroberto	return (0);
263258945Sroberto}
264330567Sgordon
265258945Srobertoint
266258945Srobertoprocess_write_fpregs(struct proc *p, struct fpreg *regs)
267258945Sroberto{
268258945Sroberto	union savefpu *frame = process_fpframe(p);
269258945Sroberto
270258945Sroberto	if (p->p_md.md_flags & MDP_USEDFPU) {
271258945Sroberto#if NNPX > 0
272258945Sroberto		npxsave_proc(p, 0);
273258945Sroberto#endif
274258945Sroberto	} else {
275258945Sroberto		/*
276258945Sroberto		 * Make sure MXCSR and the XMM registers are
277258945Sroberto		 * initialized to sane defaults.
278258945Sroberto		 */
279258945Sroberto		if (i386_use_fxsave)
280258945Sroberto			process_fninit_xmm(&frame->sv_xmm);
281258945Sroberto		p->p_md.md_flags |= MDP_USEDFPU;
282258945Sroberto	}
283258945Sroberto
284330567Sgordon	if (i386_use_fxsave) {
285330567Sgordon		struct save87 s87;
286330567Sgordon
287330567Sgordon		/* XXX Yuck. */
288330567Sgordon		memcpy(&s87, regs, sizeof(*regs));
289330567Sgordon		process_s87_to_xmm(&s87, &frame->sv_xmm);
290330567Sgordon	} else
291258945Sroberto		memcpy(&frame->sv_87, regs, sizeof(*regs));
292258945Sroberto
293258945Sroberto	return (0);
294258945Sroberto}
295258945Sroberto
296258945Srobertoint
297258945Srobertoprocess_read_xmmregs(struct proc *p, struct xmmregs *regs)
298258945Sroberto{
299258945Sroberto	union savefpu *frame = process_fpframe(p);
300258945Sroberto
301330567Sgordon	if (!i386_use_fxsave)
302330567Sgordon		return (EINVAL);
303330567Sgordon
304330567Sgordon	if (p->p_md.md_flags & MDP_USEDFPU) {
305258945Sroberto#if NNPX > 0
306258945Sroberto		npxsave_proc(p, 1);
307258945Sroberto#endif
308258945Sroberto	} else {
309258945Sroberto		/* Fake a FNINIT. */
310330567Sgordon		process_fninit_xmm(&frame->sv_xmm);
311258945Sroberto		p->p_md.md_flags |= MDP_USEDFPU;
312258945Sroberto	}
313258945Sroberto
314258945Sroberto	memcpy(regs, &frame->sv_xmm, sizeof(*regs));
315330567Sgordon	return (0);
316258945Sroberto}
317258945Sroberto
318258945Srobertoint
319258945Srobertoprocess_write_xmmregs(struct proc *p, const struct xmmregs *regs)
320258945Sroberto{
321258945Sroberto	union savefpu *frame = process_fpframe(p);
322258945Sroberto
323258945Sroberto	if (!i386_use_fxsave)
324258945Sroberto		return (EINVAL);
325258945Sroberto
326258945Sroberto	if (p->p_md.md_flags & MDP_USEDFPU) {
327258945Sroberto#if NNPX > 0
328258945Sroberto		npxsave_proc(p, 0);
329258945Sroberto#endif
330258945Sroberto	} else
331258945Sroberto		p->p_md.md_flags |= MDP_USEDFPU;
332258945Sroberto
333258945Sroberto	memcpy(&frame->sv_xmm, regs, sizeof(*regs));
334258945Sroberto	frame->sv_xmm.sv_env.en_mxcsr &= fpu_mxcsr_mask;
335258945Sroberto	return (0);
336}
337
338int
339process_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
351int
352process_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