1146818Sdfr/*-
2146818Sdfr * Copyright (c) 2005 Doug Rabson
3146818Sdfr * All rights reserved.
4146818Sdfr *
5146818Sdfr * Redistribution and use in source and binary forms, with or without
6146818Sdfr * modification, are permitted provided that the following conditions
7146818Sdfr * are met:
8146818Sdfr * 1. Redistributions of source code must retain the above copyright
9146818Sdfr *    notice, this list of conditions and the following disclaimer.
10146818Sdfr * 2. Redistributions in binary form must reproduce the above copyright
11146818Sdfr *    notice, this list of conditions and the following disclaimer in the
12146818Sdfr *    documentation and/or other materials provided with the distribution.
13146818Sdfr *
14146818Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15146818Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16146818Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17146818Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18146818Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19146818Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20146818Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21146818Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22146818Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23146818Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24146818Sdfr * SUCH DAMAGE.
25146818Sdfr *
26146818Sdfr */
27146818Sdfr
28146818Sdfr#include <sys/cdefs.h>
29146818Sdfr__FBSDID("$FreeBSD: stable/11/sys/i386/i386/ptrace_machdep.c 314210 2017-02-24 16:02:01Z kib $");
30146818Sdfr
31148694Stobez#include "opt_cpu.h"
32148694Stobez
33146818Sdfr#include <sys/param.h>
34146818Sdfr#include <sys/systm.h>
35273995Sjhb#include <sys/malloc.h>
36146818Sdfr#include <sys/proc.h>
37146818Sdfr#include <sys/ptrace.h>
38284919Skib#include <machine/frame.h>
39146818Sdfr#include <machine/md_var.h>
40146818Sdfr#include <machine/pcb.h>
41146818Sdfr
42273995Sjhbstatic int
43273995Sjhbcpu_ptrace_xstate(struct thread *td, int req, void *addr, int data)
44273995Sjhb{
45274817Sjhb	struct ptrace_xstate_info info;
46273995Sjhb	char *savefpu;
47273995Sjhb	int error;
48273995Sjhb
49273995Sjhb	if (!use_xsave)
50273995Sjhb		return (EOPNOTSUPP);
51273995Sjhb
52273995Sjhb	switch (req) {
53274817Sjhb	case PT_GETXSTATE_OLD:
54273995Sjhb		npxgetregs(td);
55273995Sjhb		savefpu = (char *)(get_pcb_user_save_td(td) + 1);
56273995Sjhb		error = copyout(savefpu, addr,
57273995Sjhb		    cpu_max_ext_state_size - sizeof(union savefpu));
58273995Sjhb		break;
59273995Sjhb
60274817Sjhb	case PT_SETXSTATE_OLD:
61273995Sjhb		if (data > cpu_max_ext_state_size - sizeof(union savefpu)) {
62273995Sjhb			error = EINVAL;
63273995Sjhb			break;
64273995Sjhb		}
65273995Sjhb		savefpu = malloc(data, M_TEMP, M_WAITOK);
66273995Sjhb		error = copyin(addr, savefpu, data);
67273995Sjhb		if (error == 0) {
68273995Sjhb			npxgetregs(td);
69273995Sjhb			error = npxsetxstate(td, savefpu, data);
70273995Sjhb		}
71273995Sjhb		free(savefpu, M_TEMP);
72273995Sjhb		break;
73273995Sjhb
74274817Sjhb	case PT_GETXSTATE_INFO:
75274817Sjhb		if (data != sizeof(info)) {
76274817Sjhb			error  = EINVAL;
77274817Sjhb			break;
78274817Sjhb		}
79274817Sjhb		info.xsave_len = cpu_max_ext_state_size;
80274817Sjhb		info.xsave_mask = xsave_mask;
81274817Sjhb		error = copyout(&info, addr, data);
82274817Sjhb		break;
83274817Sjhb
84274817Sjhb	case PT_GETXSTATE:
85274817Sjhb		npxgetregs(td);
86274817Sjhb		savefpu = (char *)(get_pcb_user_save_td(td));
87274817Sjhb		error = copyout(savefpu, addr, cpu_max_ext_state_size);
88274817Sjhb		break;
89274817Sjhb
90274817Sjhb	case PT_SETXSTATE:
91278976Sjhb		if (data < sizeof(union savefpu) ||
92278976Sjhb		    data > cpu_max_ext_state_size) {
93274817Sjhb			error = EINVAL;
94274817Sjhb			break;
95274817Sjhb		}
96274817Sjhb		savefpu = malloc(data, M_TEMP, M_WAITOK);
97274817Sjhb		error = copyin(addr, savefpu, data);
98274817Sjhb		if (error == 0)
99274817Sjhb			error = npxsetregs(td, (union savefpu *)savefpu,
100274817Sjhb			    savefpu + sizeof(union savefpu), data -
101274817Sjhb			    sizeof(union savefpu));
102274817Sjhb		free(savefpu, M_TEMP);
103274817Sjhb		break;
104274817Sjhb
105273995Sjhb	default:
106273995Sjhb		error = EINVAL;
107273995Sjhb		break;
108273995Sjhb	}
109273995Sjhb
110273995Sjhb	return (error);
111273995Sjhb}
112273995Sjhb
113284919Skibstatic int
114284919Skibcpu_ptrace_xmm(struct thread *td, int req, void *addr, int data)
115146818Sdfr{
116159087Sdavidxu	struct savexmm *fpstate;
117146818Sdfr	int error;
118146818Sdfr
119146818Sdfr	if (!cpu_fxsr)
120146818Sdfr		return (EINVAL);
121146818Sdfr
122273995Sjhb	fpstate = &get_pcb_user_save_td(td)->sv_xmm;
123146818Sdfr	switch (req) {
124146818Sdfr	case PT_GETXMMREGS:
125238675Skib		npxgetregs(td);
126159087Sdavidxu		error = copyout(fpstate, addr, sizeof(*fpstate));
127146818Sdfr		break;
128146818Sdfr
129146818Sdfr	case PT_SETXMMREGS:
130238675Skib		npxgetregs(td);
131159087Sdavidxu		error = copyin(addr, fpstate, sizeof(*fpstate));
132159087Sdavidxu		fpstate->sv_env.en_mxcsr &= cpu_mxcsr_mask;
133146818Sdfr		break;
134146818Sdfr
135274817Sjhb	case PT_GETXSTATE_OLD:
136274817Sjhb	case PT_SETXSTATE_OLD:
137274817Sjhb	case PT_GETXSTATE_INFO:
138273995Sjhb	case PT_GETXSTATE:
139273995Sjhb	case PT_SETXSTATE:
140273995Sjhb		error = cpu_ptrace_xstate(td, req, addr, data);
141273995Sjhb		break;
142273995Sjhb
143146818Sdfr	default:
144146818Sdfr		return (EINVAL);
145146818Sdfr	}
146146818Sdfr
147146818Sdfr	return (error);
148146818Sdfr}
149284919Skib
150284919Skibint
151284919Skibcpu_ptrace(struct thread *td, int req, void *addr, int data)
152284919Skib{
153284919Skib	struct segment_descriptor *sdp, sd;
154284919Skib	register_t r;
155284919Skib	int error;
156284919Skib
157284919Skib	switch (req) {
158284919Skib	case PT_GETXMMREGS:
159284919Skib	case PT_SETXMMREGS:
160284919Skib	case PT_GETXSTATE_OLD:
161284919Skib	case PT_SETXSTATE_OLD:
162284919Skib	case PT_GETXSTATE_INFO:
163284919Skib	case PT_GETXSTATE:
164284919Skib	case PT_SETXSTATE:
165284919Skib		error = cpu_ptrace_xmm(td, req, addr, data);
166284919Skib		break;
167284919Skib
168284919Skib	case PT_GETFSBASE:
169284919Skib	case PT_GETGSBASE:
170284919Skib		sdp = req == PT_GETFSBASE ? &td->td_pcb->pcb_fsd :
171284919Skib		    &td->td_pcb->pcb_gsd;
172284919Skib		r = sdp->sd_hibase << 24 | sdp->sd_lobase;
173284919Skib		error = copyout(&r, addr, sizeof(r));
174284919Skib		break;
175284919Skib
176284919Skib	case PT_SETFSBASE:
177284919Skib	case PT_SETGSBASE:
178284919Skib		error = copyin(addr, &r, sizeof(r));
179284919Skib		if (error != 0)
180284919Skib			break;
181284919Skib		fill_based_sd(&sd, r);
182284919Skib		if (req == PT_SETFSBASE) {
183284919Skib			td->td_pcb->pcb_fsd = sd;
184284919Skib			td->td_frame->tf_fs = GSEL(GUFS_SEL, SEL_UPL);
185284919Skib		} else {
186284919Skib			td->td_pcb->pcb_gsd = sd;
187284919Skib			td->td_pcb->pcb_gs = GSEL(GUGS_SEL, SEL_UPL);
188284919Skib		}
189284919Skib		break;
190284919Skib
191284919Skib	default:
192284919Skib		return (EINVAL);
193284919Skib	}
194284919Skib
195284919Skib	return (error);
196284919Skib}
197