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(®s->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, ®s->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