xref: /netbsd/sys/arch/amd64/amd64/process_machdep.c (revision 6550d01e)
1 /*	$NetBSD: process_machdep.c,v 1.18 2010/12/20 00:25:24 matt 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_sstep(proc)
48  *	Arrange for the process to trap after executing a single instruction.
49  *
50  * process_set_pc(proc)
51  *	Set the process's program counter.
52  */
53 
54 
55 #include <sys/cdefs.h>
56 __KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.18 2010/12/20 00:25:24 matt Exp $");
57 
58 #include <sys/param.h>
59 #include <sys/systm.h>
60 #include <sys/time.h>
61 #include <sys/kernel.h>
62 #include <sys/proc.h>
63 #include <sys/vnode.h>
64 #include <sys/ptrace.h>
65 
66 #include <machine/psl.h>
67 #include <machine/reg.h>
68 #include <machine/segments.h>
69 #include <machine/fpu.h>
70 
71 static inline struct trapframe *process_frame(struct lwp *);
72 static inline struct fxsave64 *process_fpframe(struct lwp *);
73 #if 0
74 static inline int verr_gdt(struct pmap *, int sel);
75 static inline int verr_ldt(struct pmap *, int sel);
76 #endif
77 
78 static inline struct trapframe *
79 process_frame(struct lwp *l)
80 {
81 
82 	return (l->l_md.md_regs);
83 }
84 
85 static inline struct fxsave64 *
86 process_fpframe(struct lwp *l)
87 {
88 	struct pcb *pcb = lwp_getpcb(l);
89 
90 	return &pcb->pcb_savefpu.fp_fxsave;
91 }
92 
93 int
94 process_read_regs(struct lwp *l, struct reg *regs)
95 {
96 	struct trapframe *tf = process_frame(l);
97 
98 #define copy_to_reg(reg, REG, idx) regs->regs[_REG_##REG] = tf->tf_##reg;
99 	_FRAME_GREG(copy_to_reg)
100 #undef copy_to_reg
101 
102 	return (0);
103 }
104 
105 int
106 process_read_fpregs(struct lwp *l, struct fpreg *regs)
107 {
108 	struct fxsave64 *frame = process_fpframe(l);
109 
110 	if (l->l_md.md_flags & MDP_USEDFPU) {
111 		fpusave_lwp(l, true);
112 	} else {
113 		uint16_t cw;
114 		uint32_t mxcsr, mxcsr_mask;
115 
116 		/*
117 		 * Fake a FNINIT.
118 		 * The initial control word was already set by setregs(), so
119 		 * save it temporarily.
120 		 */
121 		cw = frame->fx_fcw;
122 		mxcsr = frame->fx_mxcsr;
123 		mxcsr_mask = frame->fx_mxcsr_mask;
124 		memset(frame, 0, sizeof(*regs));
125 		frame->fx_fcw = cw;
126 		frame->fx_fsw = 0x0000;
127 		frame->fx_ftw = 0xff;
128 		frame->fx_mxcsr = mxcsr;
129 		frame->fx_mxcsr_mask = mxcsr_mask;
130 		l->l_md.md_flags |= MDP_USEDFPU;
131 	}
132 
133 	memcpy(&regs->fxstate, frame, sizeof(*regs));
134 	return (0);
135 }
136 
137 int
138 process_write_regs(struct lwp *l, const struct reg *regp)
139 {
140 	struct trapframe *tf = process_frame(l);
141 	int error;
142 	const long *regs = regp->regs;
143 
144 	/*
145 	 * Check for security violations.
146 	 * Note that struct regs is compatible with
147 	 * the __gregs array in mcontext_t.
148 	 */
149 	error = check_mcontext(l, (const mcontext_t *)regs, tf);
150 	if (error != 0)
151 		return error;
152 
153 #define copy_to_frame(reg, REG, idx) tf->tf_##reg = regs[_REG_##REG];
154 	_FRAME_GREG(copy_to_frame)
155 #undef copy_to_frame
156 
157 	return (0);
158 }
159 
160 int
161 process_write_fpregs(struct lwp *l, const struct fpreg *regs)
162 {
163 	struct fxsave64 *frame = process_fpframe(l);
164 
165 	if (l->l_md.md_flags & MDP_USEDFPU) {
166 		fpusave_lwp(l, false);
167 	} else {
168 		l->l_md.md_flags |= MDP_USEDFPU;
169 	}
170 
171 	memcpy(frame, &regs->fxstate, sizeof(*regs));
172 	return (0);
173 }
174 
175 int
176 process_sstep(struct lwp *l, int sstep)
177 {
178 	struct trapframe *tf = process_frame(l);
179 
180 	if (sstep)
181 		tf->tf_rflags |= PSL_T;
182 	else
183 		tf->tf_rflags &= ~PSL_T;
184 
185 	return (0);
186 }
187 
188 int
189 process_set_pc(struct lwp *l, void *addr)
190 {
191 	struct trapframe *tf = process_frame(l);
192 
193 	if ((uint64_t)addr > VM_MAXUSER_ADDRESS)
194 		return EINVAL;
195 	tf->tf_rip = (uint64_t)addr;
196 
197 	return (0);
198 }
199