xref: /openbsd/sys/arch/amd64/amd64/process_machdep.c (revision deef986e)
1 /*	$OpenBSD: process_machdep.c,v 1.18 2024/11/27 05:25:56 anton Exp $	*/
2 /*	$NetBSD: process_machdep.c,v 1.1 2003/04/26 18:39:31 fvdl Exp $	*/
3 
4 /*-
5  * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Charles M. Hannum.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34  * This file may seem a bit stylized, but that so that it's easier to port.
35  * Functions to be implemented here are:
36  *
37  * process_read_regs(proc, regs)
38  *	Get the current user-visible register set from the process
39  *	and copy it into the regs structure (<machine/reg.h>).
40  *	The process is stopped at the time read_regs is called.
41  *
42  * process_write_regs(proc, regs)
43  *	Update the current register set from the passed in regs
44  *	structure.  Take care to avoid clobbering special CPU
45  *	registers or privileged bits in the PSL.
46  *	The process is stopped at the time write_regs is called.
47  *
48  * process_sstep(proc)
49  *	Arrange for the process to trap after executing a single instruction.
50  *
51  * process_set_pc(proc)
52  *	Set the process's program counter.
53  */
54 
55 
56 #include <sys/param.h>
57 #include <sys/systm.h>
58 #include <sys/proc.h>
59 #include <sys/ptrace.h>
60 #include <sys/user.h>
61 
62 #include <uvm/uvm_extern.h>
63 
64 #include <machine/reg.h>
65 #include <machine/fpu.h>
66 
67 static __inline struct trapframe *process_frame(struct proc *);
68 static __inline struct fxsave64 *process_fpframe(struct proc *);
69 
70 static __inline struct trapframe *
process_frame(struct proc * p)71 process_frame(struct proc *p)
72 {
73 
74 	return (p->p_md.md_regs);
75 }
76 
77 static __inline struct fxsave64 *
process_fpframe(struct proc * p)78 process_fpframe(struct proc *p)
79 {
80 
81 	return (&p->p_addr->u_pcb.pcb_savefpu.fp_fxsave);
82 }
83 
84 int
process_read_regs(struct proc * p,struct reg * regs)85 process_read_regs(struct proc *p, struct reg *regs)
86 {
87 	struct trapframe *tf = process_frame(p);
88 
89         regs->r_rdi = tf->tf_rdi;
90         regs->r_rsi = tf->tf_rsi;
91         regs->r_rdx = tf->tf_rdx;
92         regs->r_rcx = tf->tf_rcx;
93         regs->r_r8  = tf->tf_r8;
94         regs->r_r9  = tf->tf_r9;
95         regs->r_r10 = tf->tf_r10;
96         regs->r_r11 = tf->tf_r11;
97         regs->r_r12 = tf->tf_r12;
98         regs->r_r13 = tf->tf_r13;
99         regs->r_r14 = tf->tf_r14;
100         regs->r_r15 = tf->tf_r15;
101         regs->r_rbp = tf->tf_rbp;
102         regs->r_rbx = tf->tf_rbx;
103         regs->r_rax = tf->tf_rax;
104         regs->r_rsp = tf->tf_rsp;
105         regs->r_rip = tf->tf_rip;
106         regs->r_rflags = tf->tf_rflags;
107         regs->r_cs  = tf->tf_cs;
108         regs->r_ss  = tf->tf_ss;
109         regs->r_ds  = GSEL(GUDATA_SEL, SEL_UPL);
110         regs->r_es  = GSEL(GUDATA_SEL, SEL_UPL);
111         regs->r_fs  = GSEL(GUDATA_SEL, SEL_UPL);
112         regs->r_gs  = GSEL(GUDATA_SEL, SEL_UPL);
113 
114 	return (0);
115 }
116 
117 int
process_read_fpregs(struct proc * p,struct fpreg * regs)118 process_read_fpregs(struct proc *p, struct fpreg *regs)
119 {
120 	struct fxsave64 *frame = process_fpframe(p);
121 
122 	memcpy(&regs->fxstate, frame, sizeof(*regs));
123 	return (0);
124 }
125 
126 #ifdef	PTRACE
127 
128 int
process_write_regs(struct proc * p,struct reg * regs)129 process_write_regs(struct proc *p, struct reg *regs)
130 {
131 	struct trapframe *tf = process_frame(p);
132 
133 	/*
134 	 * Check for security violations.
135 	 */
136 	if (check_context(regs, tf))
137 		return (EINVAL);
138 
139         tf->tf_rdi = regs->r_rdi;
140         tf->tf_rsi = regs->r_rsi;
141         tf->tf_rdx = regs->r_rdx;
142         tf->tf_rcx = regs->r_rcx;
143         tf->tf_r8  = regs->r_r8;
144         tf->tf_r9  = regs->r_r9;
145         tf->tf_r10 = regs->r_r10;
146         tf->tf_r11 = regs->r_r11;
147         tf->tf_r12 = regs->r_r12;
148         tf->tf_r13 = regs->r_r13;
149         tf->tf_r14 = regs->r_r14;
150         tf->tf_r15 = regs->r_r15;
151         tf->tf_rbp = regs->r_rbp;
152         tf->tf_rbx = regs->r_rbx;
153         tf->tf_rax = regs->r_rax;
154         tf->tf_rsp = regs->r_rsp;
155         tf->tf_rip = regs->r_rip;
156         tf->tf_rflags = regs->r_rflags;
157         tf->tf_cs  = regs->r_cs;
158         tf->tf_ss  = regs->r_ss;
159 
160 	/* force target to return via iretq so all registers are updated */
161 	p->p_md.md_flags |= MDP_IRET;
162 
163 	return (0);
164 }
165 
166 int
process_write_fpregs(struct proc * p,struct fpreg * regs)167 process_write_fpregs(struct proc *p, struct fpreg *regs)
168 {
169 	struct fxsave64 *frame = process_fpframe(p);
170 
171 	memcpy(frame, &regs->fxstate, sizeof(*regs));
172 	frame->fx_mxcsr &= fpu_mxcsr_mask;
173 
174 	/* force target to return via iretq so bogus xstate can be handled */
175 	p->p_md.md_flags |= MDP_IRET;
176 	return (0);
177 }
178 
179 int
process_sstep(struct proc * p,int sstep)180 process_sstep(struct proc *p, int sstep)
181 {
182 	struct trapframe *tf = process_frame(p);
183 
184 	if (sstep)
185 		tf->tf_rflags |= PSL_T;
186 	else
187 		tf->tf_rflags &= ~PSL_T;
188 
189 	return (0);
190 }
191 
192 int
process_set_pc(struct proc * p,caddr_t addr)193 process_set_pc(struct proc *p, caddr_t addr)
194 {
195 	struct trapframe *tf = process_frame(p);
196 
197 	if ((u_int64_t)addr > VM_MAXUSER_ADDRESS)
198 		return EINVAL;
199 	tf->tf_rip = (u_int64_t)addr;
200 
201 	return (0);
202 }
203 
204 int
process_read_xstate_info(struct proc * p,void * addr)205 process_read_xstate_info(struct proc *p, void *addr)
206 {
207 	struct ptrace_xstate_info *info = addr;
208 
209 	if (xsave_mask == 0)
210 		return (ENOTSUP);
211 
212 	info->xsave_mask = xsave_mask;
213 	info->xsave_len = fpu_save_len;
214 	return (0);
215 }
216 
217 struct xsave_area {
218 	uint8_t	legacy_region[512];
219 
220 	struct xsave_header {
221 		uint64_t	xstate_bv;
222 		uint64_t	xcomp_bv;
223 		uint8_t		rsvd0[48];
224 	} xsave_header;
225 
226 	uint8_t	extended_region[];
227 } __attribute__((packed));
228 
229 #define XSTATE_COMPONENT_X87	(1ULL << 0)
230 #define XSTATE_COMPONENT_SSE	(1ULL << 1)
231 #define XSTATE_COMPONENT_AVX	(1ULL << 2)
232 
233 int
process_read_xstate(struct proc * p,void * addr)234 process_read_xstate(struct proc *p, void *addr)
235 {
236 	struct xsave_area *area =
237 	    (struct xsave_area *)&p->p_addr->u_pcb.pcb_savefpu;
238 
239 	if (xsave_mask == 0)
240 		return (ENOTSUP);
241 
242 	memcpy(addr, area, fpu_save_len);
243 	return (0);
244 }
245 
246 int
process_write_xstate(struct proc * p,void * addr)247 process_write_xstate(struct proc *p, void *addr)
248 {
249 	struct xsave_area *area =
250 	    (struct xsave_area *)&p->p_addr->u_pcb.pcb_savefpu;
251 	struct xsave_area *new_area = (struct xsave_area *)addr;
252 	uint32_t offset_extended_region = offsetof(struct xsave_area,
253 	    extended_region);
254 	uint32_t a, b, c, d;
255 
256 	if (xsave_mask == 0)
257 		return (ENOTSUP);
258 
259 	/*
260 	 * Honor changes to x87, SSE and AVX components and mark them as in use.
261 	 * Required to ensure any changes are restored once the traced process
262 	 * continues execution.
263 	 */
264 	if ((xsave_mask & XSTATE_COMPONENT_X87) ||
265 	    (xsave_mask & XSTATE_COMPONENT_SSE)) {
266 		memcpy(area->legacy_region, new_area->legacy_region,
267 		    sizeof(area->legacy_region));
268 		area->xsave_header.xstate_bv |= xsave_mask &
269 		    (XSTATE_COMPONENT_X87 | XSTATE_COMPONENT_SSE);
270 	}
271 	if (xsave_mask & XSTATE_COMPONENT_AVX) {
272 		CPUID_LEAF(0xd, 2, a, b, c, d);
273 		if (offset_extended_region == b &&
274 		    offset_extended_region + a <= fpu_save_len) {
275 			memcpy(area->extended_region,
276 			    new_area->extended_region, a);
277 			area->xsave_header.xstate_bv |= XSTATE_COMPONENT_AVX;
278 		}
279 	}
280 
281 	return (0);
282 }
283 
284 #endif	/* PTRACE */
285