1 /* $NetBSD: process_machdep.c,v 1.50 2023/11/20 03:05:48 simonb Exp $ */
2
3 /*
4 * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Charles M. Hannum.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 /*
33 * This file may seem a bit stylized, but that so that it's easier to port.
34 * Functions to be implemented here are:
35 *
36 * process_read_regs(proc, regs)
37 * Get the current user-visible register set from the process
38 * and copy it into the regs structure (<machine/reg.h>).
39 * The process is stopped at the time read_regs is called.
40 *
41 * process_write_regs(proc, regs)
42 * Update the current register set from the passed in regs
43 * structure. Take care to avoid clobbering special CPU
44 * registers or privileged bits in the PSL.
45 * The process is stopped at the time write_regs is called.
46 *
47 * process_read_fpregs(proc, regs, sz)
48 * Get the current user-visible register set from the process
49 * and copy it into the regs structure (<machine/reg.h>).
50 * The process is stopped at the time read_fpregs is called.
51 *
52 * process_write_fpregs(proc, regs, sz)
53 * Update the current register set from the passed in regs
54 * structure. Take care to avoid clobbering special CPU
55 * registers or privileged bits in the PSL.
56 * The process is stopped at the time write_fpregs is called.
57 *
58 * process_read_dbregs(proc, regs, sz)
59 * Get the current user-visible register set from the process
60 * and copy it into the regs structure (<machine/reg.h>).
61 * The process is stopped at the time read_dbregs is called.
62 *
63 * process_write_dbregs(proc, regs, sz)
64 * Update the current register set from the passed in regs
65 * structure. Take care to avoid clobbering special CPU
66 * registers or privileged bits in the PSL.
67 * The process is stopped at the time write_dbregs is called.
68 *
69 * process_sstep(proc)
70 * Arrange for the process to trap after executing a single instruction.
71 *
72 * process_set_pc(proc)
73 * Set the process's program counter.
74 */
75
76 #include <sys/cdefs.h>
77 __KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.50 2023/11/20 03:05:48 simonb Exp $");
78
79 #ifdef _KERNEL_OPT
80 #include "opt_xen.h"
81 #endif
82
83 #include <sys/param.h>
84 #include <sys/systm.h>
85 #include <sys/time.h>
86 #include <sys/kernel.h>
87 #include <sys/proc.h>
88 #include <sys/ptrace.h>
89 #include <sys/compat_stub.h>
90
91 #include <uvm/uvm_extern.h>
92
93 #include <compat/netbsd32/netbsd32.h>
94 #include <machine/psl.h>
95 #include <machine/reg.h>
96 #include <machine/segments.h>
97 #include <x86/dbregs.h>
98 #include <x86/fpu.h>
99
100 struct netbsd32_process_doxmmregs_hook_t netbsd32_process_doxmmregs_hook;
101
102 static inline struct trapframe *process_frame(struct lwp *);
103
104 static inline struct trapframe *
process_frame(struct lwp * l)105 process_frame(struct lwp *l)
106 {
107
108 return l->l_md.md_regs;
109 }
110
111 int
process_read_regs(struct lwp * l,struct reg * regp)112 process_read_regs(struct lwp *l, struct reg *regp)
113 {
114 struct trapframe *tf = process_frame(l);
115 long *regs = regp->regs;
116 const bool pk32 = (l->l_proc->p_flag & PK_32) != 0;
117
118 regs[_REG_RDI] = tf->tf_rdi;
119 regs[_REG_RSI] = tf->tf_rsi;
120 regs[_REG_RDX] = tf->tf_rdx;
121 regs[_REG_R10] = tf->tf_r10;
122 regs[_REG_R8] = tf->tf_r8;
123 regs[_REG_R9] = tf->tf_r9;
124 /* argX not touched */
125 regs[_REG_RCX] = tf->tf_rcx;
126 regs[_REG_R11] = tf->tf_r11;
127 regs[_REG_R12] = tf->tf_r12;
128 regs[_REG_R13] = tf->tf_r13;
129 regs[_REG_R14] = tf->tf_r14;
130 regs[_REG_R15] = tf->tf_r15;
131 regs[_REG_RBP] = tf->tf_rbp;
132 regs[_REG_RBX] = tf->tf_rbx;
133 regs[_REG_RAX] = tf->tf_rax;
134 if (pk32) {
135 regs[_REG_GS] = tf->tf_gs & 0xffff;
136 regs[_REG_FS] = tf->tf_fs & 0xffff;
137 regs[_REG_ES] = tf->tf_es & 0xffff;
138 regs[_REG_DS] = tf->tf_ds & 0xffff;
139 regs[_REG_CS] = tf->tf_cs & 0xffff;
140 regs[_REG_SS] = tf->tf_ss & 0xffff;
141 } else {
142 regs[_REG_GS] = 0;
143 regs[_REG_FS] = 0;
144 regs[_REG_ES] = GSEL(GUDATA_SEL, SEL_UPL);
145 regs[_REG_DS] = GSEL(GUDATA_SEL, SEL_UPL);
146 regs[_REG_CS] = LSEL(LUCODE_SEL, SEL_UPL);
147 regs[_REG_SS] = LSEL(LUDATA_SEL, SEL_UPL);
148 }
149 regs[_REG_TRAPNO] = tf->tf_trapno;
150 regs[_REG_ERR] = tf->tf_err;
151 regs[_REG_RIP] = tf->tf_rip;
152 regs[_REG_RFLAGS] = tf->tf_rflags;
153 regs[_REG_RSP] = tf->tf_rsp;
154
155 return 0;
156 }
157
158 int
process_read_fpregs(struct lwp * l,struct fpreg * regs,size_t * sz)159 process_read_fpregs(struct lwp *l, struct fpreg *regs, size_t *sz)
160 {
161
162 process_read_fpregs_xmm(l, ®s->fxstate);
163
164 return 0;
165 }
166
167 int
process_read_dbregs(struct lwp * l,struct dbreg * regs,size_t * sz)168 process_read_dbregs(struct lwp *l, struct dbreg *regs, size_t *sz)
169 {
170
171 x86_dbregs_read(l, regs);
172
173 return 0;
174 }
175
176 int
process_write_regs(struct lwp * l,const struct reg * regp)177 process_write_regs(struct lwp *l, const struct reg *regp)
178 {
179 struct trapframe *tf = process_frame(l);
180 int error;
181 const long *regs = regp->regs;
182 const bool pk32 = (l->l_proc->p_flag & PK_32) != 0;
183
184 /*
185 * Check for security violations. Note that struct regs is compatible
186 * with the __gregs array in mcontext_t.
187 */
188 if (pk32) {
189 MODULE_HOOK_CALL(netbsd32_reg_validate_hook, (l, regp), EINVAL,
190 error);
191 } else {
192 error = cpu_mcontext_validate(l, (const mcontext_t *)regs);
193 }
194 if (error != 0)
195 return error;
196
197 tf->tf_rdi = regs[_REG_RDI];
198 tf->tf_rsi = regs[_REG_RSI];
199 tf->tf_rdx = regs[_REG_RDX];
200 tf->tf_r10 = regs[_REG_R10];
201 tf->tf_r8 = regs[_REG_R8];
202 tf->tf_r9 = regs[_REG_R9];
203 /* argX not touched */
204 tf->tf_rcx = regs[_REG_RCX];
205 tf->tf_r11 = regs[_REG_R11];
206 tf->tf_r12 = regs[_REG_R12];
207 tf->tf_r13 = regs[_REG_R13];
208 tf->tf_r14 = regs[_REG_R14];
209 tf->tf_r15 = regs[_REG_R15];
210 tf->tf_rbp = regs[_REG_RBP];
211 tf->tf_rbx = regs[_REG_RBX];
212 tf->tf_rax = regs[_REG_RAX];
213 if (pk32) {
214 tf->tf_gs = regs[_REG_GS] & 0xffff;
215 tf->tf_fs = regs[_REG_FS] & 0xffff;
216 tf->tf_es = regs[_REG_ES] & 0xffff;
217 tf->tf_ds = regs[_REG_DS] & 0xffff;
218 tf->tf_cs = regs[_REG_CS] & 0xffff;
219 tf->tf_ss = regs[_REG_SS] & 0xffff;
220 } else {
221 tf->tf_gs = 0;
222 tf->tf_fs = 0;
223 tf->tf_es = GSEL(GUDATA_SEL, SEL_UPL);
224 tf->tf_ds = GSEL(GUDATA_SEL, SEL_UPL);
225 tf->tf_cs = LSEL(LUCODE_SEL, SEL_UPL);
226 tf->tf_ss = LSEL(LUDATA_SEL, SEL_UPL);
227 }
228 /* trapno, err not touched */
229 tf->tf_rip = regs[_REG_RIP];
230 tf->tf_rflags = regs[_REG_RFLAGS];
231 tf->tf_rsp = regs[_REG_RSP];
232
233 return 0;
234 }
235
236 int
process_write_fpregs(struct lwp * l,const struct fpreg * regs,size_t sz)237 process_write_fpregs(struct lwp *l, const struct fpreg *regs, size_t sz)
238 {
239
240 process_write_fpregs_xmm(l, ®s->fxstate);
241 return 0;
242 }
243
244 int
process_write_dbregs(struct lwp * l,const struct dbreg * regs,size_t sz)245 process_write_dbregs(struct lwp *l, const struct dbreg *regs, size_t sz)
246 {
247 int error;
248
249 /*
250 * Check for security violations.
251 */
252 error = x86_dbregs_validate(regs);
253 if (error != 0)
254 return error;
255
256 x86_dbregs_write(l, regs);
257
258 return 0;
259 }
260
261 int
process_sstep(struct lwp * l,int sstep)262 process_sstep(struct lwp *l, int sstep)
263 {
264 struct trapframe *tf = process_frame(l);
265
266 if (sstep)
267 tf->tf_rflags |= PSL_T;
268 else
269 tf->tf_rflags &= ~PSL_T;
270
271 return 0;
272 }
273
274 int
process_set_pc(struct lwp * l,void * addr)275 process_set_pc(struct lwp *l, void *addr)
276 {
277 struct trapframe *tf = process_frame(l);
278 const bool pk32 = (l->l_proc->p_flag & PK_32) != 0;
279 const uint64_t rip = (uint64_t)addr;
280
281 if (rip >= (pk32 ? VM_MAXUSER_ADDRESS32 : VM_MAXUSER_ADDRESS))
282 return EINVAL;
283 tf->tf_rip = rip;
284
285 return 0;
286 }
287
288 #ifdef __HAVE_PTRACE_MACHDEP
289 static int
process_machdep_read_xstate(struct lwp * l,struct xstate * regs)290 process_machdep_read_xstate(struct lwp *l, struct xstate *regs)
291 {
292 return process_read_xstate(l, regs);
293 }
294
295 static int
process_machdep_write_xstate(struct lwp * l,const struct xstate * regs)296 process_machdep_write_xstate(struct lwp *l, const struct xstate *regs)
297 {
298 int error;
299
300 /*
301 * Check for security violations.
302 */
303 error = process_verify_xstate(regs);
304 if (error != 0)
305 return error;
306
307 return process_write_xstate(l, regs);
308 }
309
310 int
ptrace_machdep_dorequest(struct lwp * l,struct lwp ** lt,int req,void * addr,int data)311 ptrace_machdep_dorequest(
312 struct lwp *l,
313 struct lwp **lt,
314 int req,
315 void *addr,
316 int data
317 )
318 {
319 struct uio uio;
320 struct iovec iov;
321 struct vmspace *vm;
322 int error;
323 bool write = false;
324
325 switch (req) {
326 case PT_SETXSTATE:
327 write = true;
328
329 /* FALLTHROUGH */
330 case PT_GETXSTATE:
331 /* write = false done above. */
332 if ((error = ptrace_update_lwp((*lt)->l_proc, lt, data)) != 0)
333 return error;
334 if (!process_machdep_validfpu((*lt)->l_proc))
335 return EINVAL;
336 if (__predict_false(l->l_proc->p_flag & PK_32)) {
337 struct netbsd32_iovec user_iov;
338 if ((error = copyin(addr, &user_iov, sizeof(user_iov)))
339 != 0)
340 return error;
341
342 iov.iov_base = NETBSD32PTR64(user_iov.iov_base);
343 iov.iov_len = user_iov.iov_len;
344 } else {
345 struct iovec user_iov;
346 if ((error = copyin(addr, &user_iov, sizeof(user_iov)))
347 != 0)
348 return error;
349
350 iov.iov_base = user_iov.iov_base;
351 iov.iov_len = user_iov.iov_len;
352 }
353
354 error = proc_vmspace_getref(l->l_proc, &vm);
355 if (error)
356 return error;
357 if (iov.iov_len > sizeof(struct xstate))
358 iov.iov_len = sizeof(struct xstate);
359 uio.uio_iov = &iov;
360 uio.uio_iovcnt = 1;
361 uio.uio_offset = 0;
362 uio.uio_resid = iov.iov_len;
363 uio.uio_rw = write ? UIO_WRITE : UIO_READ;
364 uio.uio_vmspace = vm;
365 error = process_machdep_doxstate(l, *lt, &uio);
366 uvmspace_free(vm);
367 return error;
368
369 case PT_SETXMMREGS: /* only for COMPAT_NETBSD32 */
370 write = true;
371
372 /* FALLTHROUGH */
373 case PT_GETXMMREGS: /* only for COMPAT_NETBSD32 */
374 /* write = false done above. */
375 if ((error = ptrace_update_lwp((*lt)->l_proc, lt, data)) != 0)
376 return error;
377 MODULE_HOOK_CALL(netbsd32_process_doxmmregs_hook,
378 (l, *lt, addr, write), EINVAL, error);
379 return error;
380 }
381
382 #ifdef DIAGNOSTIC
383 panic("ptrace_machdep: impossible");
384 #endif
385
386 return 0;
387 }
388
389 /*
390 * The following functions are used by both ptrace(2) and procfs.
391 */
392
393 int
process_machdep_doxstate(struct lwp * curl,struct lwp * l,struct uio * uio)394 process_machdep_doxstate(struct lwp *curl, struct lwp *l, struct uio *uio)
395 /* curl: tracer */
396 /* l: traced */
397 {
398 int error;
399 struct xstate r; /* XXX FIXME big stack object */
400 char *kv;
401 ssize_t kl;
402
403 memset(&r, 0, sizeof(r));
404 kl = MIN(uio->uio_iov->iov_len, sizeof(r));
405 kv = (char *) &r;
406
407 kv += uio->uio_offset;
408 kl -= uio->uio_offset;
409 if (kl > uio->uio_resid)
410 kl = uio->uio_resid;
411
412 if (kl < 0)
413 error = EINVAL;
414 else
415 error = process_machdep_read_xstate(l, &r);
416 if (error == 0)
417 error = uiomove(kv, kl, uio);
418 if (error == 0 && uio->uio_rw == UIO_WRITE)
419 error = process_machdep_write_xstate(l, &r);
420
421 uio->uio_offset = 0;
422 return error;
423 }
424
425 int
process_machdep_validfpu(struct proc * p)426 process_machdep_validfpu(struct proc *p)
427 {
428
429 if (p->p_flag & PK_SYSTEM)
430 return 0;
431
432 return 1;
433 }
434 #endif /* __HAVE_PTRACE_MACHDEP */
435