11// SPDX-License-Identifier: GPL-2.0
2- #include <sys/ucontext.h>
32#define __FRAME_OFFSETS
3+ #include <linux/errno.h>
4+ #include <linux/string.h>
5+ #include <sys/ucontext.h>
46#include <asm/ptrace.h>
7+ #include <asm/sigcontext.h>
58#include <sysdep/ptrace.h>
69#include <sysdep/mcontext.h>
710#include <arch.h>
@@ -18,6 +21,10 @@ void get_regs_from_mc(struct uml_pt_regs *regs, mcontext_t *mc)
1821 COPY2 (UESP , ESP ); /* sic */
1922 COPY (EBX ); COPY (EDX ); COPY (ECX ); COPY (EAX );
2023 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
2128#else
2229#define COPY2 (X ,Y ) regs->gp[X/sizeof(unsigned long)] = mc->gregs[REG_##Y]
2330#define COPY (X ) regs->gp[X/sizeof(unsigned long)] = mc->gregs[REG_##X]
@@ -29,6 +36,8 @@ void get_regs_from_mc(struct uml_pt_regs *regs, mcontext_t *mc)
2936 COPY2 (EFLAGS , EFL );
3037 COPY2 (CS , CSGSFS );
3138 regs -> gp [SS / sizeof (unsigned long )] = mc -> gregs [REG_CSGSFS ] >> 48 ;
39+ #undef COPY2
40+ #undef COPY
3241#endif
3342}
3443
@@ -42,3 +51,210 @@ void mc_set_rip(void *_mc, void *target)
4251 mc -> gregs [REG_RIP ] = (unsigned long )target ;
4352#endif
4453}
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 (fpstate_stub , & regs -> fp , fp_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+ }
0 commit comments