Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/x86/um/os-Linux/mcontext.c
26493 views
1
// SPDX-License-Identifier: GPL-2.0
2
#define __FRAME_OFFSETS
3
#include <linux/errno.h>
4
#include <linux/string.h>
5
#include <sys/ucontext.h>
6
#include <asm/ptrace.h>
7
#include <asm/sigcontext.h>
8
#include <sysdep/ptrace.h>
9
#include <sysdep/mcontext.h>
10
#include <arch.h>
11
12
void get_regs_from_mc(struct uml_pt_regs *regs, mcontext_t *mc)
13
{
14
#ifdef __i386__
15
#define COPY2(X,Y) regs->gp[X] = mc->gregs[REG_##Y]
16
#define COPY(X) regs->gp[X] = mc->gregs[REG_##X]
17
#define COPY_SEG(X) regs->gp[X] = mc->gregs[REG_##X] & 0xffff;
18
#define COPY_SEG_CPL3(X) regs->gp[X] = (mc->gregs[REG_##X] & 0xffff) | 3;
19
COPY_SEG(GS); COPY_SEG(FS); COPY_SEG(ES); COPY_SEG(DS);
20
COPY(EDI); COPY(ESI); COPY(EBP);
21
COPY2(UESP, ESP); /* sic */
22
COPY(EBX); COPY(EDX); COPY(ECX); COPY(EAX);
23
COPY(EIP); COPY_SEG_CPL3(CS); COPY(EFL); COPY_SEG_CPL3(SS);
24
#undef COPY2
25
#undef COPY
26
#undef COPY_SEG
27
#undef COPY_SEG_CPL3
28
#else
29
#define COPY2(X,Y) regs->gp[X/sizeof(unsigned long)] = mc->gregs[REG_##Y]
30
#define COPY(X) regs->gp[X/sizeof(unsigned long)] = mc->gregs[REG_##X]
31
COPY(R8); COPY(R9); COPY(R10); COPY(R11);
32
COPY(R12); COPY(R13); COPY(R14); COPY(R15);
33
COPY(RDI); COPY(RSI); COPY(RBP); COPY(RBX);
34
COPY(RDX); COPY(RAX); COPY(RCX); COPY(RSP);
35
COPY(RIP);
36
COPY2(EFLAGS, EFL);
37
COPY2(CS, CSGSFS);
38
regs->gp[SS / sizeof(unsigned long)] = mc->gregs[REG_CSGSFS] >> 48;
39
#undef COPY2
40
#undef COPY
41
#endif
42
}
43
44
void mc_set_rip(void *_mc, void *target)
45
{
46
mcontext_t *mc = _mc;
47
48
#ifdef __i386__
49
mc->gregs[REG_EIP] = (unsigned long)target;
50
#else
51
mc->gregs[REG_RIP] = (unsigned long)target;
52
#endif
53
}
54
55
/* Same thing, but the copy macros are turned around. */
56
void get_mc_from_regs(struct uml_pt_regs *regs, mcontext_t *mc, int single_stepping)
57
{
58
#ifdef __i386__
59
#define COPY2(X,Y) mc->gregs[REG_##Y] = regs->gp[X]
60
#define COPY(X) mc->gregs[REG_##X] = regs->gp[X]
61
#define COPY_SEG(X) mc->gregs[REG_##X] = regs->gp[X] & 0xffff;
62
#define COPY_SEG_CPL3(X) mc->gregs[REG_##X] = (regs->gp[X] & 0xffff) | 3;
63
COPY_SEG(GS); COPY_SEG(FS); COPY_SEG(ES); COPY_SEG(DS);
64
COPY(EDI); COPY(ESI); COPY(EBP);
65
COPY2(UESP, ESP); /* sic */
66
COPY(EBX); COPY(EDX); COPY(ECX); COPY(EAX);
67
COPY(EIP); COPY_SEG_CPL3(CS); COPY(EFL); COPY_SEG_CPL3(SS);
68
#else
69
#define COPY2(X,Y) mc->gregs[REG_##Y] = regs->gp[X/sizeof(unsigned long)]
70
#define COPY(X) mc->gregs[REG_##X] = regs->gp[X/sizeof(unsigned long)]
71
COPY(R8); COPY(R9); COPY(R10); COPY(R11);
72
COPY(R12); COPY(R13); COPY(R14); COPY(R15);
73
COPY(RDI); COPY(RSI); COPY(RBP); COPY(RBX);
74
COPY(RDX); COPY(RAX); COPY(RCX); COPY(RSP);
75
COPY(RIP);
76
COPY2(EFLAGS, EFL);
77
mc->gregs[REG_CSGSFS] = mc->gregs[REG_CSGSFS] & 0xffffffffffffl;
78
mc->gregs[REG_CSGSFS] |= (regs->gp[SS / sizeof(unsigned long)] & 0xffff) << 48;
79
#endif
80
81
if (single_stepping)
82
mc->gregs[REG_EFL] |= X86_EFLAGS_TF;
83
else
84
mc->gregs[REG_EFL] &= ~X86_EFLAGS_TF;
85
}
86
87
#ifdef CONFIG_X86_32
88
struct _xstate_64 {
89
struct _fpstate_64 fpstate;
90
struct _header xstate_hdr;
91
struct _ymmh_state ymmh;
92
/* New processor state extensions go here: */
93
};
94
95
/* Not quite the right structures as these contain more information */
96
int um_i387_from_fxsr(struct _fpstate_32 *i387,
97
const struct _fpstate_64 *fxsave);
98
int um_fxsr_from_i387(struct _fpstate_64 *fxsave,
99
const struct _fpstate_32 *from);
100
#else
101
#define _xstate_64 _xstate
102
#endif
103
104
static struct _fpstate *get_fpstate(struct stub_data *data,
105
mcontext_t *mcontext,
106
int *fp_size)
107
{
108
struct _fpstate *res;
109
110
/* Assume floating point registers are on the same page */
111
res = (void *)(((unsigned long)mcontext->fpregs &
112
(UM_KERN_PAGE_SIZE - 1)) +
113
(unsigned long)&data->sigstack[0]);
114
115
if ((void *)res + sizeof(struct _fpstate) >
116
(void *)data->sigstack + sizeof(data->sigstack))
117
return NULL;
118
119
if (res->sw_reserved.magic1 != FP_XSTATE_MAGIC1) {
120
*fp_size = sizeof(struct _fpstate);
121
} else {
122
char *magic2_addr;
123
124
magic2_addr = (void *)res;
125
magic2_addr += res->sw_reserved.extended_size;
126
magic2_addr -= FP_XSTATE_MAGIC2_SIZE;
127
128
/* We still need to be within our stack */
129
if ((void *)magic2_addr >
130
(void *)data->sigstack + sizeof(data->sigstack))
131
return NULL;
132
133
/* If we do not read MAGIC2, then we did something wrong */
134
if (*(__u32 *)magic2_addr != FP_XSTATE_MAGIC2)
135
return NULL;
136
137
/* Remove MAGIC2 from the size, we do not save/restore it */
138
*fp_size = res->sw_reserved.extended_size -
139
FP_XSTATE_MAGIC2_SIZE;
140
}
141
142
return res;
143
}
144
145
int get_stub_state(struct uml_pt_regs *regs, struct stub_data *data,
146
unsigned long *fp_size_out)
147
{
148
mcontext_t *mcontext;
149
struct _fpstate *fpstate_stub;
150
struct _xstate_64 *xstate_stub;
151
int fp_size, xstate_size;
152
153
/* mctx_offset is verified by wait_stub_done_seccomp */
154
mcontext = (void *)&data->sigstack[data->mctx_offset];
155
156
get_regs_from_mc(regs, mcontext);
157
158
fpstate_stub = get_fpstate(data, mcontext, &fp_size);
159
if (!fpstate_stub)
160
return -EINVAL;
161
162
#ifdef CONFIG_X86_32
163
xstate_stub = (void *)&fpstate_stub->_fxsr_env;
164
xstate_size = fp_size - offsetof(struct _fpstate_32, _fxsr_env);
165
#else
166
xstate_stub = (void *)fpstate_stub;
167
xstate_size = fp_size;
168
#endif
169
170
if (fp_size_out)
171
*fp_size_out = xstate_size;
172
173
if (xstate_size > host_fp_size)
174
return -ENOSPC;
175
176
memcpy(&regs->fp, xstate_stub, xstate_size);
177
178
/* We do not need to read the x86_64 FS_BASE/GS_BASE registers as
179
* we do not permit userspace to set them directly.
180
*/
181
182
#ifdef CONFIG_X86_32
183
/* Read the i387 legacy FP registers */
184
if (um_fxsr_from_i387((void *)&regs->fp, fpstate_stub))
185
return -EINVAL;
186
#endif
187
188
return 0;
189
}
190
191
/* Copied because we cannot include regset.h here. */
192
struct task_struct;
193
struct user_regset;
194
struct membuf {
195
void *p;
196
size_t left;
197
};
198
199
int fpregs_legacy_get(struct task_struct *target,
200
const struct user_regset *regset,
201
struct membuf to);
202
203
int set_stub_state(struct uml_pt_regs *regs, struct stub_data *data,
204
int single_stepping)
205
{
206
mcontext_t *mcontext;
207
struct _fpstate *fpstate_stub;
208
struct _xstate_64 *xstate_stub;
209
int fp_size, xstate_size;
210
211
/* mctx_offset is verified by wait_stub_done_seccomp */
212
mcontext = (void *)&data->sigstack[data->mctx_offset];
213
214
if ((unsigned long)mcontext < (unsigned long)data->sigstack ||
215
(unsigned long)mcontext >
216
(unsigned long) data->sigstack +
217
sizeof(data->sigstack) - sizeof(*mcontext))
218
return -EINVAL;
219
220
get_mc_from_regs(regs, mcontext, single_stepping);
221
222
fpstate_stub = get_fpstate(data, mcontext, &fp_size);
223
if (!fpstate_stub)
224
return -EINVAL;
225
226
#ifdef CONFIG_X86_32
227
xstate_stub = (void *)&fpstate_stub->_fxsr_env;
228
xstate_size = fp_size - offsetof(struct _fpstate_32, _fxsr_env);
229
#else
230
xstate_stub = (void *)fpstate_stub;
231
xstate_size = fp_size;
232
#endif
233
234
memcpy(xstate_stub, &regs->fp, xstate_size);
235
236
#ifdef __i386__
237
/*
238
* On x86, the GDT entries are updated by arch_set_tls.
239
*/
240
241
/* Store the i387 legacy FP registers which the host will use */
242
if (um_i387_from_fxsr(fpstate_stub, (void *)&regs->fp))
243
return -EINVAL;
244
#else
245
/*
246
* On x86_64, we need to sync the FS_BASE/GS_BASE registers using the
247
* arch specific data.
248
*/
249
if (data->arch_data.fs_base != regs->gp[FS_BASE / sizeof(unsigned long)]) {
250
data->arch_data.fs_base = regs->gp[FS_BASE / sizeof(unsigned long)];
251
data->arch_data.sync |= STUB_SYNC_FS_BASE;
252
}
253
if (data->arch_data.gs_base != regs->gp[GS_BASE / sizeof(unsigned long)]) {
254
data->arch_data.gs_base = regs->gp[GS_BASE / sizeof(unsigned long)];
255
data->arch_data.sync |= STUB_SYNC_GS_BASE;
256
}
257
#endif
258
259
return 0;
260
}
261
262