Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

um: switch to regset API and depend on XSTATE

The PTRACE_GETREGSET API has now existed since Linux 2.6.33. The XSAVE
CPU feature should also be sufficiently common to be able to rely on it.

With this, define our internal FP state to be the hosts XSAVE data. Add
discovery for the hosts XSAVE size and place the FP registers at the end
of task_struct so that we can adjust the size at runtime.

Next we can implement the regset API on top and update the signal
handling as well as ptrace APIs to use them. Also switch coredump
creation to use the regset API and finally set HAVE_ARCH_TRACEHOOK.

This considerably improves the signal frames. Previously they might not
have contained all the registers (i386) and also did not have the
sizes and magic values set to the correct values to permit userspace to
decode the frame.

As a side effect, this will permit UML to run on hosts with newer CPU
extensions (such as AMX) that need even more register state.

Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
Link: https://patch.msgid.link/20241023094120.4083426-1-benjamin@sipsolutions.net
Signed-off-by: Johannes Berg <johannes.berg@intel.com>

authored by

Benjamin Berg and committed by
Johannes Berg
3f17fed2 0b8b2668

+473 -475
+2
arch/um/Kconfig
··· 5 5 config UML 6 6 bool 7 7 default y 8 + select ARCH_WANTS_DYNAMIC_TASK_STRUCT 8 9 select ARCH_HAS_CPU_FINALIZE_INIT 9 10 select ARCH_HAS_FORTIFY_SOURCE 10 11 select ARCH_HAS_GCOV_PROFILE_ALL ··· 33 32 select HAVE_ARCH_VMAP_STACK 34 33 select HAVE_RUST 35 34 select ARCH_HAS_UBSAN 35 + select HAVE_ARCH_TRACEHOOK 36 36 37 37 config MMU 38 38 bool
+3 -1
arch/um/include/asm/processor-generic.h
··· 20 20 struct mm_struct; 21 21 22 22 struct thread_struct { 23 - struct pt_regs regs; 24 23 struct pt_regs *segv_regs; 25 24 struct task_struct *prev_sched; 26 25 struct arch_thread arch; ··· 30 31 void *arg; 31 32 } thread; 32 33 } request; 34 + 35 + /* Contains variable sized FP registers */ 36 + struct pt_regs regs; 33 37 }; 34 38 35 39 #define INIT_THREAD \
+7 -15
arch/um/kernel/process.c
··· 187 187 kmalloc_ok = save_kmalloc_ok; 188 188 } 189 189 190 + int arch_dup_task_struct(struct task_struct *dst, 191 + struct task_struct *src) 192 + { 193 + memcpy(dst, src, arch_task_struct_size); 194 + return 0; 195 + } 196 + 190 197 void um_idle_sleep(void) 191 198 { 192 199 if (time_travel_mode != TT_MODE_OFF) ··· 294 287 295 288 return 0; 296 289 } 297 - 298 - int elf_core_copy_task_fpregs(struct task_struct *t, elf_fpregset_t *fpu) 299 - { 300 - #ifdef CONFIG_X86_32 301 - extern int have_fpx_regs; 302 - 303 - /* FIXME: A plain copy does not work on i386 with have_fpx_regs */ 304 - if (have_fpx_regs) 305 - return 0; 306 - #endif 307 - memcpy(fpu, &t->thread.regs.regs.fp, sizeof(*fpu)); 308 - 309 - return 1; 310 - } 311 -
+2
arch/um/kernel/um_arch.c
··· 402 402 os_info("Kernel virtual memory size shrunk to %lu bytes\n", 403 403 virtmem_size); 404 404 405 + arch_task_struct_size = sizeof(struct task_struct) + host_fp_size; 406 + 405 407 os_flush_stdout(); 406 408 407 409 return start_uml();
+8 -3
arch/um/os-Linux/registers.c
··· 10 10 #include <sysdep/ptrace.h> 11 11 #include <sysdep/ptrace_user.h> 12 12 #include <registers.h> 13 + #include <stdlib.h> 13 14 14 15 /* This is set once at boot time and not changed thereafter */ 15 16 16 17 static unsigned long exec_regs[MAX_REG_NR]; 17 - static unsigned long exec_fp_regs[FP_SIZE]; 18 + static unsigned long *exec_fp_regs; 18 19 19 20 int init_pid_registers(int pid) 20 21 { ··· 25 24 if (err < 0) 26 25 return -errno; 27 26 28 - arch_init_registers(pid); 27 + err = arch_init_registers(pid); 28 + if (err < 0) 29 + return err; 30 + 31 + exec_fp_regs = malloc(host_fp_size); 29 32 get_fp_registers(pid, exec_fp_regs); 30 33 return 0; 31 34 } ··· 39 34 memcpy(regs, exec_regs, sizeof(exec_regs)); 40 35 41 36 if (fp_regs) 42 - memcpy(fp_regs, exec_fp_regs, sizeof(exec_fp_regs)); 37 + memcpy(fp_regs, exec_fp_regs, host_fp_size); 43 38 }
+1 -1
arch/x86/um/Makefile
··· 10 10 endif 11 11 12 12 obj-y = bugs_$(BITS).o delay.o fault.o \ 13 - ptrace_$(BITS).o ptrace_user.o setjmp_$(BITS).o signal.o \ 13 + ptrace.o ptrace_$(BITS).o ptrace_user.o setjmp_$(BITS).o signal.o \ 14 14 stub_segv.o \ 15 15 sys_call_table_$(BITS).o sysrq_$(BITS).o tls_$(BITS).o \ 16 16 mem_$(BITS).o subarch.o os-Linux/
+2
arch/x86/um/asm/elf.h
··· 8 8 #include <asm/user.h> 9 9 #include <skas.h> 10 10 11 + #define CORE_DUMP_USE_REGSET 12 + 11 13 #ifdef CONFIG_X86_32 12 14 13 15 #define R_386_NONE 0
+10
arch/x86/um/asm/ptrace.h
··· 2 2 #ifndef __UM_X86_PTRACE_H 3 3 #define __UM_X86_PTRACE_H 4 4 5 + /* This is here because signal.c needs the REGSET_FP_LEGACY definition */ 6 + enum { 7 + REGSET_GENERAL, 8 + #ifdef CONFIG_X86_32 9 + REGSET_FP_LEGACY, 10 + #endif 11 + REGSET_FP, 12 + REGSET_XSTATE, 13 + }; 14 + 5 15 #include <linux/compiler.h> 6 16 #ifndef CONFIG_X86_32 7 17 #define __FRAME_OFFSETS /* Needed to get the R* macros */
+36 -111
arch/x86/um/os-Linux/registers.c
··· 16 16 #include <asm/sigcontext.h> 17 17 #include <linux/elf.h> 18 18 #include <registers.h> 19 + #include <sys/mman.h> 19 20 20 - static int have_xstate_support; 21 - 22 - static int save_i387_registers(int pid, unsigned long *fp_regs) 23 - { 24 - if (ptrace(PTRACE_GETFPREGS, pid, 0, fp_regs) < 0) 25 - return -errno; 26 - return 0; 27 - } 28 - 29 - static int save_fp_registers(int pid, unsigned long *fp_regs) 30 - { 31 - #ifdef PTRACE_GETREGSET 32 - struct iovec iov; 33 - 34 - if (have_xstate_support) { 35 - iov.iov_base = fp_regs; 36 - iov.iov_len = FP_SIZE * sizeof(unsigned long); 37 - if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) < 0) 38 - return -errno; 39 - return 0; 40 - } else 41 - #endif 42 - return save_i387_registers(pid, fp_regs); 43 - } 44 - 45 - static int restore_i387_registers(int pid, unsigned long *fp_regs) 46 - { 47 - if (ptrace(PTRACE_SETFPREGS, pid, 0, fp_regs) < 0) 48 - return -errno; 49 - return 0; 50 - } 51 - 52 - static int restore_fp_registers(int pid, unsigned long *fp_regs) 53 - { 54 - #ifdef PTRACE_SETREGSET 55 - struct iovec iov; 56 - if (have_xstate_support) { 57 - iov.iov_base = fp_regs; 58 - iov.iov_len = FP_SIZE * sizeof(unsigned long); 59 - if (ptrace(PTRACE_SETREGSET, pid, NT_X86_XSTATE, &iov) < 0) 60 - return -errno; 61 - return 0; 62 - } else 63 - #endif 64 - return restore_i387_registers(pid, fp_regs); 65 - } 66 - 67 - #ifdef __i386__ 68 - int have_fpx_regs = 1; 69 - static int save_fpx_registers(int pid, unsigned long *fp_regs) 70 - { 71 - if (ptrace(PTRACE_GETFPXREGS, pid, 0, fp_regs) < 0) 72 - return -errno; 73 - return 0; 74 - } 75 - 76 - static int restore_fpx_registers(int pid, unsigned long *fp_regs) 77 - { 78 - if (ptrace(PTRACE_SETFPXREGS, pid, 0, fp_regs) < 0) 79 - return -errno; 80 - return 0; 81 - } 21 + unsigned long host_fp_size; 82 22 83 23 int get_fp_registers(int pid, unsigned long *regs) 84 24 { 85 - if (have_fpx_regs) 86 - return save_fpx_registers(pid, regs); 87 - else 88 - return save_fp_registers(pid, regs); 25 + struct iovec iov = { 26 + .iov_base = regs, 27 + .iov_len = host_fp_size, 28 + }; 29 + 30 + if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) < 0) 31 + return -errno; 32 + return 0; 89 33 } 90 34 91 35 int put_fp_registers(int pid, unsigned long *regs) 92 36 { 93 - if (have_fpx_regs) 94 - return restore_fpx_registers(pid, regs); 95 - else 96 - return restore_fp_registers(pid, regs); 37 + struct iovec iov = { 38 + .iov_base = regs, 39 + .iov_len = host_fp_size, 40 + }; 41 + 42 + if (ptrace(PTRACE_SETREGSET, pid, NT_X86_XSTATE, &iov) < 0) 43 + return -errno; 44 + return 0; 97 45 } 98 46 99 - void arch_init_registers(int pid) 47 + int arch_init_registers(int pid) 100 48 { 101 - struct user_fpxregs_struct fpx_regs; 102 - int err; 49 + struct iovec iov = { 50 + /* Just use plenty of space, it does not cost us anything */ 51 + .iov_len = 2 * 1024 * 1024, 52 + }; 53 + int ret; 103 54 104 - err = ptrace(PTRACE_GETFPXREGS, pid, 0, &fpx_regs); 105 - if (!err) 106 - return; 55 + iov.iov_base = mmap(NULL, iov.iov_len, PROT_WRITE | PROT_READ, 56 + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 57 + if (iov.iov_base == MAP_FAILED) 58 + return -ENOMEM; 107 59 108 - if (errno != EIO) 109 - panic("check_ptrace : PTRACE_GETFPXREGS failed, errno = %d", 110 - errno); 60 + /* GDB has x86_xsave_length, which uses x86_cpuid_count */ 61 + ret = ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov); 62 + if (ret) 63 + ret = -errno; 64 + munmap(iov.iov_base, 2 * 1024 * 1024); 111 65 112 - have_fpx_regs = 0; 66 + host_fp_size = iov.iov_len; 67 + 68 + return ret; 113 69 } 114 - #else 115 - 116 - int get_fp_registers(int pid, unsigned long *regs) 117 - { 118 - return save_fp_registers(pid, regs); 119 - } 120 - 121 - int put_fp_registers(int pid, unsigned long *regs) 122 - { 123 - return restore_fp_registers(pid, regs); 124 - } 125 - 126 - void arch_init_registers(int pid) 127 - { 128 - #ifdef PTRACE_GETREGSET 129 - void * fp_regs; 130 - struct iovec iov; 131 - 132 - fp_regs = malloc(FP_SIZE * sizeof(unsigned long)); 133 - if(fp_regs == NULL) 134 - return; 135 - 136 - iov.iov_base = fp_regs; 137 - iov.iov_len = FP_SIZE * sizeof(unsigned long); 138 - if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) == 0) 139 - have_xstate_support = 1; 140 - 141 - free(fp_regs); 142 - #endif 143 - } 144 - #endif 145 70 146 71 unsigned long get_thread_reg(int reg, jmp_buf *buf) 147 72 {
+267
arch/x86/um/ptrace.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #include <linux/sched.h> 4 + #include <linux/elf.h> 5 + #include <linux/regset.h> 6 + #include <asm/user32.h> 7 + #include <asm/sigcontext.h> 8 + 9 + #ifdef CONFIG_X86_32 10 + /* 11 + * FPU tag word conversions. 12 + */ 13 + 14 + static inline unsigned short twd_i387_to_fxsr(unsigned short twd) 15 + { 16 + unsigned int tmp; /* to avoid 16 bit prefixes in the code */ 17 + 18 + /* Transform each pair of bits into 01 (valid) or 00 (empty) */ 19 + tmp = ~twd; 20 + tmp = (tmp | (tmp>>1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */ 21 + /* and move the valid bits to the lower byte. */ 22 + tmp = (tmp | (tmp >> 1)) & 0x3333; /* 00VV00VV00VV00VV */ 23 + tmp = (tmp | (tmp >> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */ 24 + tmp = (tmp | (tmp >> 4)) & 0x00ff; /* 00000000VVVVVVVV */ 25 + return tmp; 26 + } 27 + 28 + static inline unsigned long twd_fxsr_to_i387(struct user_fxsr_struct *fxsave) 29 + { 30 + struct _fpxreg *st = NULL; 31 + unsigned long twd = (unsigned long) fxsave->twd; 32 + unsigned long tag; 33 + unsigned long ret = 0xffff0000; 34 + int i; 35 + 36 + #define FPREG_ADDR(f, n) ((char *)&(f)->st_space + (n) * 16) 37 + 38 + for (i = 0; i < 8; i++) { 39 + if (twd & 0x1) { 40 + st = (struct _fpxreg *) FPREG_ADDR(fxsave, i); 41 + 42 + switch (st->exponent & 0x7fff) { 43 + case 0x7fff: 44 + tag = 2; /* Special */ 45 + break; 46 + case 0x0000: 47 + if (!st->significand[0] && 48 + !st->significand[1] && 49 + !st->significand[2] && 50 + !st->significand[3]) { 51 + tag = 1; /* Zero */ 52 + } else { 53 + tag = 2; /* Special */ 54 + } 55 + break; 56 + default: 57 + if (st->significand[3] & 0x8000) 58 + tag = 0; /* Valid */ 59 + else 60 + tag = 2; /* Special */ 61 + break; 62 + } 63 + } else { 64 + tag = 3; /* Empty */ 65 + } 66 + ret |= (tag << (2 * i)); 67 + twd = twd >> 1; 68 + } 69 + return ret; 70 + } 71 + 72 + /* Get/set the old 32bit i387 registers (pre-FPX) */ 73 + static int fpregs_legacy_get(struct task_struct *target, 74 + const struct user_regset *regset, 75 + struct membuf to) 76 + { 77 + struct user_fxsr_struct *fxsave = (void *)target->thread.regs.regs.fp; 78 + int i; 79 + 80 + membuf_store(&to, (unsigned long)fxsave->cwd | 0xffff0000ul); 81 + membuf_store(&to, (unsigned long)fxsave->swd | 0xffff0000ul); 82 + membuf_store(&to, twd_fxsr_to_i387(fxsave)); 83 + membuf_store(&to, fxsave->fip); 84 + membuf_store(&to, fxsave->fcs | ((unsigned long)fxsave->fop << 16)); 85 + membuf_store(&to, fxsave->foo); 86 + membuf_store(&to, fxsave->fos); 87 + 88 + for (i = 0; i < 8; i++) 89 + membuf_write(&to, (void *)fxsave->st_space + i * 16, 10); 90 + 91 + return 0; 92 + } 93 + 94 + static int fpregs_legacy_set(struct task_struct *target, 95 + const struct user_regset *regset, 96 + unsigned int pos, unsigned int count, 97 + const void *kbuf, const void __user *ubuf) 98 + { 99 + struct user_fxsr_struct *fxsave = (void *)target->thread.regs.regs.fp; 100 + const struct user_i387_struct *from; 101 + struct user_i387_struct buf; 102 + int i; 103 + 104 + if (ubuf) { 105 + if (copy_from_user(&buf, ubuf, sizeof(buf))) 106 + return -EFAULT; 107 + from = &buf; 108 + } else { 109 + from = kbuf; 110 + } 111 + 112 + fxsave->cwd = (unsigned short)(from->cwd & 0xffff); 113 + fxsave->swd = (unsigned short)(from->swd & 0xffff); 114 + fxsave->twd = twd_i387_to_fxsr((unsigned short)(from->twd & 0xffff)); 115 + fxsave->fip = from->fip; 116 + fxsave->fop = (unsigned short)((from->fcs & 0xffff0000ul) >> 16); 117 + fxsave->fcs = (from->fcs & 0xffff); 118 + fxsave->foo = from->foo; 119 + fxsave->fos = from->fos; 120 + 121 + for (i = 0; i < 8; i++) { 122 + memcpy((void *)fxsave->st_space + i * 16, 123 + (void *)from->st_space + i * 10, 10); 124 + } 125 + 126 + return 0; 127 + } 128 + #endif 129 + 130 + static int genregs_get(struct task_struct *target, 131 + const struct user_regset *regset, 132 + struct membuf to) 133 + { 134 + int reg; 135 + 136 + for (reg = 0; to.left; reg++) 137 + membuf_store(&to, getreg(target, reg * sizeof(unsigned long))); 138 + return 0; 139 + } 140 + 141 + static int genregs_set(struct task_struct *target, 142 + const struct user_regset *regset, 143 + unsigned int pos, unsigned int count, 144 + const void *kbuf, const void __user *ubuf) 145 + { 146 + int ret = 0; 147 + 148 + if (kbuf) { 149 + const unsigned long *k = kbuf; 150 + 151 + while (count >= sizeof(*k) && !ret) { 152 + ret = putreg(target, pos, *k++); 153 + count -= sizeof(*k); 154 + pos += sizeof(*k); 155 + } 156 + } else { 157 + const unsigned long __user *u = ubuf; 158 + 159 + while (count >= sizeof(*u) && !ret) { 160 + unsigned long word; 161 + 162 + ret = __get_user(word, u++); 163 + if (ret) 164 + break; 165 + ret = putreg(target, pos, word); 166 + count -= sizeof(*u); 167 + pos += sizeof(*u); 168 + } 169 + } 170 + return ret; 171 + } 172 + 173 + static int generic_fpregs_active(struct task_struct *target, const struct user_regset *regset) 174 + { 175 + return regset->n; 176 + } 177 + 178 + static int generic_fpregs_get(struct task_struct *target, 179 + const struct user_regset *regset, 180 + struct membuf to) 181 + { 182 + void *fpregs = task_pt_regs(target)->regs.fp; 183 + 184 + membuf_write(&to, fpregs, regset->size * regset->n); 185 + return 0; 186 + } 187 + 188 + static int generic_fpregs_set(struct task_struct *target, 189 + const struct user_regset *regset, 190 + unsigned int pos, unsigned int count, 191 + const void *kbuf, const void __user *ubuf) 192 + { 193 + void *fpregs = task_pt_regs(target)->regs.fp; 194 + 195 + return user_regset_copyin(&pos, &count, &kbuf, &ubuf, 196 + fpregs, 0, regset->size * regset->n); 197 + } 198 + 199 + static struct user_regset uml_regsets[] __ro_after_init = { 200 + [REGSET_GENERAL] = { 201 + .core_note_type = NT_PRSTATUS, 202 + .n = sizeof(struct user_regs_struct) / sizeof(long), 203 + .size = sizeof(long), 204 + .align = sizeof(long), 205 + .regset_get = genregs_get, 206 + .set = genregs_set 207 + }, 208 + #ifdef CONFIG_X86_32 209 + /* Old FP registers, they are needed in signal frames */ 210 + [REGSET_FP_LEGACY] = { 211 + .core_note_type = NT_PRFPREG, 212 + .n = sizeof(struct user_i387_ia32_struct) / sizeof(long), 213 + .size = sizeof(long), 214 + .align = sizeof(long), 215 + .active = generic_fpregs_active, 216 + .regset_get = fpregs_legacy_get, 217 + .set = fpregs_legacy_set, 218 + }, 219 + #endif 220 + [REGSET_FP] = { 221 + #ifdef CONFIG_X86_32 222 + .core_note_type = NT_PRXFPREG, 223 + .n = sizeof(struct user32_fxsr_struct) / sizeof(long), 224 + #else 225 + .core_note_type = NT_PRFPREG, 226 + .n = sizeof(struct user_i387_struct) / sizeof(long), 227 + #endif 228 + .size = sizeof(long), 229 + .align = sizeof(long), 230 + .active = generic_fpregs_active, 231 + .regset_get = generic_fpregs_get, 232 + .set = generic_fpregs_set, 233 + }, 234 + [REGSET_XSTATE] = { 235 + .core_note_type = NT_X86_XSTATE, 236 + .size = sizeof(long), 237 + .align = sizeof(long), 238 + .active = generic_fpregs_active, 239 + .regset_get = generic_fpregs_get, 240 + .set = generic_fpregs_set, 241 + }, 242 + /* TODO: Add TLS regset for 32bit */ 243 + }; 244 + 245 + const struct user_regset_view user_uml_view = { 246 + #ifdef CONFIG_X86_32 247 + .name = "i386", .e_machine = EM_386, 248 + #else 249 + .name = "x86_64", .e_machine = EM_X86_64, 250 + #endif 251 + .regsets = uml_regsets, .n = ARRAY_SIZE(uml_regsets) 252 + }; 253 + 254 + const struct user_regset_view * 255 + task_user_regset_view(struct task_struct *tsk) 256 + { 257 + return &user_uml_view; 258 + } 259 + 260 + static int __init init_regset_xstate_info(void) 261 + { 262 + uml_regsets[REGSET_XSTATE].n = 263 + host_fp_size / uml_regsets[REGSET_XSTATE].size; 264 + 265 + return 0; 266 + } 267 + arch_initcall(init_regset_xstate_info);
+17 -71
arch/x86/um/ptrace_32.c
··· 6 6 #include <linux/mm.h> 7 7 #include <linux/sched.h> 8 8 #include <linux/uaccess.h> 9 + #include <linux/regset.h> 9 10 #include <asm/ptrace-abi.h> 10 11 #include <registers.h> 11 12 #include <skas.h> ··· 169 168 return put_user(tmp, (unsigned long __user *) data); 170 169 } 171 170 172 - /* FIXME: Do the required conversions instead of erroring out */ 173 - extern int have_fpx_regs; 174 - 175 - static int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) 176 - { 177 - int n; 178 - 179 - if (have_fpx_regs) 180 - return -EINVAL; 181 - 182 - n = copy_to_user(buf, &child->thread.regs.regs.fp, 183 - sizeof(struct user_i387_struct)); 184 - if(n > 0) 185 - return -EFAULT; 186 - 187 - return n; 188 - } 189 - 190 - static int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) 191 - { 192 - int n; 193 - 194 - if (have_fpx_regs) 195 - return -EINVAL; 196 - 197 - n = copy_from_user(&child->thread.regs.regs.fp, buf, 198 - sizeof(struct user_i387_struct)); 199 - if (n > 0) 200 - return -EFAULT; 201 - 202 - return 0; 203 - } 204 - 205 - static int get_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child) 206 - { 207 - int n; 208 - 209 - if (!have_fpx_regs) 210 - return -EINVAL; 211 - 212 - n = copy_to_user(buf, &child->thread.regs.regs.fp, 213 - sizeof(struct user_fxsr_struct)); 214 - if(n > 0) 215 - return -EFAULT; 216 - 217 - return n; 218 - } 219 - 220 - static int set_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child) 221 - { 222 - int n; 223 - 224 - if (!have_fpx_regs) 225 - return -EINVAL; 226 - 227 - n = copy_from_user(&child->thread.regs.regs.fp, buf, 228 - sizeof(struct user_fxsr_struct)); 229 - if (n > 0) 230 - return -EFAULT; 231 - 232 - return 0; 233 - } 234 - 235 171 long subarch_ptrace(struct task_struct *child, long request, 236 172 unsigned long addr, unsigned long data) 237 173 { ··· 176 238 void __user *datap = (void __user *) data; 177 239 switch (request) { 178 240 case PTRACE_GETFPREGS: /* Get the child FPU state. */ 179 - ret = get_fpregs(datap, child); 180 - break; 241 + return copy_regset_to_user(child, task_user_regset_view(child), 242 + REGSET_FP_LEGACY, 243 + 0, sizeof(struct user_i387_struct), 244 + datap); 181 245 case PTRACE_SETFPREGS: /* Set the child FPU state. */ 182 - ret = set_fpregs(datap, child); 183 - break; 246 + return copy_regset_from_user(child, task_user_regset_view(child), 247 + REGSET_FP_LEGACY, 248 + 0, sizeof(struct user_i387_struct), 249 + datap); 184 250 case PTRACE_GETFPXREGS: /* Get the child FPU state. */ 185 - ret = get_fpxregs(datap, child); 186 - break; 251 + return copy_regset_to_user(child, task_user_regset_view(child), 252 + REGSET_FP, 253 + 0, sizeof(struct user_fxsr_struct), 254 + datap); 187 255 case PTRACE_SETFPXREGS: /* Set the child FPU state. */ 188 - ret = set_fpxregs(datap, child); 189 - break; 256 + return copy_regset_from_user(child, task_user_regset_view(child), 257 + REGSET_FP, 258 + 0, sizeof(struct user_fxsr_struct), 259 + datap); 190 260 default: 191 261 ret = -EIO; 192 262 }
+9 -28
arch/x86/um/ptrace_64.c
··· 8 8 #include <linux/mm.h> 9 9 #include <linux/sched.h> 10 10 #include <linux/errno.h> 11 + #include <linux/regset.h> 11 12 #define __FRAME_OFFSETS 12 13 #include <asm/ptrace.h> 13 14 #include <linux/uaccess.h> ··· 189 188 return put_user(tmp, (unsigned long *) data); 190 189 } 191 190 192 - static int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) 193 - { 194 - int n; 195 - 196 - n = copy_to_user(buf, &child->thread.regs.regs.fp, 197 - sizeof(struct user_i387_struct)); 198 - if (n > 0) 199 - return -EFAULT; 200 - 201 - return n; 202 - } 203 - 204 - static int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) 205 - { 206 - int n; 207 - 208 - n = copy_from_user(&child->thread.regs.regs.fp, buf, 209 - sizeof(struct user_i387_struct)); 210 - if (n > 0) 211 - return -EFAULT; 212 - 213 - return 0; 214 - } 215 - 216 191 long subarch_ptrace(struct task_struct *child, long request, 217 192 unsigned long addr, unsigned long data) 218 193 { ··· 197 220 198 221 switch (request) { 199 222 case PTRACE_GETFPREGS: /* Get the child FPU state. */ 200 - ret = get_fpregs(datap, child); 201 - break; 223 + return copy_regset_to_user(child, task_user_regset_view(child), 224 + REGSET_FP, 225 + 0, sizeof(struct user_i387_struct), 226 + datap); 202 227 case PTRACE_SETFPREGS: /* Set the child FPU state. */ 203 - ret = set_fpregs(datap, child); 204 - break; 228 + return copy_regset_from_user(child, task_user_regset_view(child), 229 + REGSET_FP, 230 + 0, sizeof(struct user_i387_struct), 231 + datap); 205 232 case PTRACE_ARCH_PRCTL: 206 233 /* XXX Calls ptrace on the host - needs some SMP thinking */ 207 234 ret = arch_prctl(child, data, (void __user *) addr);
+7 -1
arch/x86/um/shared/sysdep/ptrace.h
··· 56 56 UPT_SYSCALL_ARG5(r), \ 57 57 UPT_SYSCALL_ARG6(r) } } ) 58 58 59 + extern unsigned long host_fp_size; 60 + 59 61 struct uml_pt_regs { 60 62 unsigned long gp[MAX_REG_NR]; 61 - unsigned long fp[MAX_FP_NR]; 62 63 struct faultinfo faultinfo; 63 64 long syscall; 64 65 int is_user; 66 + 67 + /* Dynamically sized FP registers (holds an XSTATE) */ 68 + unsigned long fp[]; 65 69 }; 66 70 67 71 #define EMPTY_UML_PT_REGS { } ··· 75 71 #define UPT_IS_USER(r) ((r)->is_user) 76 72 77 73 extern int user_context(unsigned long sp); 74 + 75 + extern int arch_init_registers(int pid); 78 76 79 77 #endif /* __SYSDEP_X86_PTRACE_H */
-4
arch/x86/um/shared/sysdep/ptrace_32.h
··· 6 6 #ifndef __SYSDEP_I386_PTRACE_H 7 7 #define __SYSDEP_I386_PTRACE_H 8 8 9 - #define MAX_FP_NR HOST_FPX_SIZE 10 - 11 9 #define UPT_SYSCALL_ARG1(r) UPT_BX(r) 12 10 #define UPT_SYSCALL_ARG2(r) UPT_CX(r) 13 11 #define UPT_SYSCALL_ARG3(r) UPT_DX(r) 14 12 #define UPT_SYSCALL_ARG4(r) UPT_SI(r) 15 13 #define UPT_SYSCALL_ARG5(r) UPT_DI(r) 16 14 #define UPT_SYSCALL_ARG6(r) UPT_BP(r) 17 - 18 - extern void arch_init_registers(int pid); 19 15 20 16 #endif
-4
arch/x86/um/shared/sysdep/ptrace_64.h
··· 8 8 #ifndef __SYSDEP_X86_64_PTRACE_H 9 9 #define __SYSDEP_X86_64_PTRACE_H 10 10 11 - #define MAX_FP_NR HOST_FP_SIZE 12 - 13 11 #define REGS_R8(r) ((r)[HOST_R8]) 14 12 #define REGS_R9(r) ((r)[HOST_R9]) 15 13 #define REGS_R10(r) ((r)[HOST_R10]) ··· 54 56 #define UPT_SYSCALL_ARG4(r) UPT_R10(r) 55 57 #define UPT_SYSCALL_ARG5(r) UPT_R8(r) 56 58 #define UPT_SYSCALL_ARG6(r) UPT_R9(r) 57 - 58 - extern void arch_init_registers(int pid); 59 59 60 60 #endif
-6
arch/x86/um/shared/sysdep/ptrace_user.h
··· 11 11 #define REGS_IP_INDEX HOST_IP 12 12 #define REGS_SP_INDEX HOST_SP 13 13 14 - #ifdef __i386__ 15 - #define FP_SIZE ((HOST_FPX_SIZE > HOST_FP_SIZE) ? HOST_FPX_SIZE : HOST_FP_SIZE) 16 - #else 17 - #define FP_SIZE HOST_FP_SIZE 18 - #endif 19 - 20 14 /* 21 15 * glibc before 2.27 does not include PTRACE_SYSEMU_SINGLESTEP in its enum, 22 16 * ensure we have a definition by (re-)defining it here.
+102 -222
arch/x86/um/signal.c
··· 16 16 #include <registers.h> 17 17 #include <skas.h> 18 18 19 + #include <linux/regset.h> 20 + #include <asm/sigframe.h> 21 + 19 22 #ifdef CONFIG_X86_32 20 - 21 - /* 22 - * FPU tag word conversions. 23 - */ 24 - 25 - static inline unsigned short twd_i387_to_fxsr(unsigned short twd) 26 - { 27 - unsigned int tmp; /* to avoid 16 bit prefixes in the code */ 28 - 29 - /* Transform each pair of bits into 01 (valid) or 00 (empty) */ 30 - tmp = ~twd; 31 - tmp = (tmp | (tmp>>1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */ 32 - /* and move the valid bits to the lower byte. */ 33 - tmp = (tmp | (tmp >> 1)) & 0x3333; /* 00VV00VV00VV00VV */ 34 - tmp = (tmp | (tmp >> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */ 35 - tmp = (tmp | (tmp >> 4)) & 0x00ff; /* 00000000VVVVVVVV */ 36 - return tmp; 37 - } 38 - 39 - static inline unsigned long twd_fxsr_to_i387(struct user_fxsr_struct *fxsave) 40 - { 41 - struct _fpxreg *st = NULL; 42 - unsigned long twd = (unsigned long) fxsave->twd; 43 - unsigned long tag; 44 - unsigned long ret = 0xffff0000; 45 - int i; 46 - 47 - #define FPREG_ADDR(f, n) ((char *)&(f)->st_space + (n) * 16) 48 - 49 - for (i = 0; i < 8; i++) { 50 - if (twd & 0x1) { 51 - st = (struct _fpxreg *) FPREG_ADDR(fxsave, i); 52 - 53 - switch (st->exponent & 0x7fff) { 54 - case 0x7fff: 55 - tag = 2; /* Special */ 56 - break; 57 - case 0x0000: 58 - if ( !st->significand[0] && 59 - !st->significand[1] && 60 - !st->significand[2] && 61 - !st->significand[3] ) { 62 - tag = 1; /* Zero */ 63 - } else { 64 - tag = 2; /* Special */ 65 - } 66 - break; 67 - default: 68 - if (st->significand[3] & 0x8000) { 69 - tag = 0; /* Valid */ 70 - } else { 71 - tag = 2; /* Special */ 72 - } 73 - break; 74 - } 75 - } else { 76 - tag = 3; /* Empty */ 77 - } 78 - ret |= (tag << (2 * i)); 79 - twd = twd >> 1; 80 - } 81 - return ret; 82 - } 83 - 84 - static int convert_fxsr_to_user(struct _fpstate __user *buf, 85 - struct user_fxsr_struct *fxsave) 86 - { 87 - unsigned long env[7]; 88 - struct _fpreg __user *to; 89 - struct _fpxreg *from; 90 - int i; 91 - 92 - env[0] = (unsigned long)fxsave->cwd | 0xffff0000ul; 93 - env[1] = (unsigned long)fxsave->swd | 0xffff0000ul; 94 - env[2] = twd_fxsr_to_i387(fxsave); 95 - env[3] = fxsave->fip; 96 - env[4] = fxsave->fcs | ((unsigned long)fxsave->fop << 16); 97 - env[5] = fxsave->foo; 98 - env[6] = fxsave->fos; 99 - 100 - if (__copy_to_user(buf, env, 7 * sizeof(unsigned long))) 101 - return 1; 102 - 103 - to = &buf->_st[0]; 104 - from = (struct _fpxreg *) &fxsave->st_space[0]; 105 - for (i = 0; i < 8; i++, to++, from++) { 106 - unsigned long __user *t = (unsigned long __user *)to; 107 - unsigned long *f = (unsigned long *)from; 108 - 109 - if (__put_user(*f, t) || 110 - __put_user(*(f + 1), t + 1) || 111 - __put_user(from->exponent, &to->exponent)) 112 - return 1; 113 - } 114 - return 0; 115 - } 116 - 117 - static int convert_fxsr_from_user(struct user_fxsr_struct *fxsave, 118 - struct _fpstate __user *buf) 119 - { 120 - unsigned long env[7]; 121 - struct _fpxreg *to; 122 - struct _fpreg __user *from; 123 - int i; 124 - 125 - if (copy_from_user( env, buf, 7 * sizeof(long))) 126 - return 1; 127 - 128 - fxsave->cwd = (unsigned short)(env[0] & 0xffff); 129 - fxsave->swd = (unsigned short)(env[1] & 0xffff); 130 - fxsave->twd = twd_i387_to_fxsr((unsigned short)(env[2] & 0xffff)); 131 - fxsave->fip = env[3]; 132 - fxsave->fop = (unsigned short)((env[4] & 0xffff0000ul) >> 16); 133 - fxsave->fcs = (env[4] & 0xffff); 134 - fxsave->foo = env[5]; 135 - fxsave->fos = env[6]; 136 - 137 - to = (struct _fpxreg *) &fxsave->st_space[0]; 138 - from = &buf->_st[0]; 139 - for (i = 0; i < 8; i++, to++, from++) { 140 - unsigned long *t = (unsigned long *)to; 141 - unsigned long __user *f = (unsigned long __user *)from; 142 - 143 - if (__get_user(*t, f) || 144 - __get_user(*(t + 1), f + 1) || 145 - __get_user(to->exponent, &from->exponent)) 146 - return 1; 147 - } 148 - return 0; 149 - } 150 - 151 - extern int have_fpx_regs; 152 - 23 + struct _xstate_64 { 24 + struct _fpstate_64 fpstate; 25 + struct _header xstate_hdr; 26 + struct _ymmh_state ymmh; 27 + /* New processor state extensions go here: */ 28 + }; 29 + #else 30 + #define _xstate_64 _xstate 153 31 #endif 154 32 155 33 static int copy_sc_from_user(struct pt_regs *regs, 156 34 struct sigcontext __user *from) 157 35 { 36 + struct _xstate_64 __user *from_fp64; 158 37 struct sigcontext sc; 159 38 int err; 160 39 ··· 82 203 #undef GETREG 83 204 84 205 #ifdef CONFIG_X86_32 85 - if (have_fpx_regs) { 86 - struct user_fxsr_struct *fpx; 87 - fpx = (void *)&regs->regs.fp; 88 - 89 - err = convert_fxsr_from_user(fpx, (void *)sc.fpstate); 90 - if (err) 91 - return 1; 92 - } else { 93 - BUILD_BUG_ON(sizeof(regs->regs.fp) > sizeof(struct _fpstate)); 94 - err = copy_from_user(regs->regs.fp, (void *)sc.fpstate, 95 - sizeof(regs->regs.fp)); 96 - if (err) 97 - return 1; 98 - } 206 + from_fp64 = ((void *)sc.fpstate) + offsetof(struct _fpstate_32, _fxsr_env); 99 207 #else 100 - { 101 - /* FIXME: Save/restore extended state (past the 16 YMM regs) */ 102 - BUILD_BUG_ON(sizeof(regs->regs.fp) < sizeof(struct _xstate)); 103 - 104 - err = copy_from_user(regs->regs.fp, (void *)sc.fpstate, 105 - sizeof(struct _xstate)); 106 - if (err) 107 - return 1; 108 - } 208 + from_fp64 = (void *)sc.fpstate; 109 209 #endif 210 + 211 + err = copy_from_user(regs->regs.fp, from_fp64, host_fp_size); 212 + if (err) 213 + return 1; 214 + 215 + #ifdef CONFIG_X86_32 216 + /* Data is duplicated and this copy is the important one */ 217 + err = copy_regset_from_user(current, 218 + task_user_regset_view(current), 219 + REGSET_FP_LEGACY, 0, 220 + sizeof(struct user_i387_struct), 221 + (void *)sc.fpstate); 222 + if (err < 0) 223 + return err; 224 + #endif 225 + 110 226 return 0; 111 227 } 112 228 ··· 109 235 struct _xstate __user *to_fp, struct pt_regs *regs, 110 236 unsigned long mask) 111 237 { 238 + struct _xstate_64 __user *to_fp64; 112 239 struct sigcontext sc; 113 240 struct faultinfo * fi = &current->thread.arch.faultinfo; 114 241 int err; ··· 161 286 return 1; 162 287 163 288 #ifdef CONFIG_X86_32 164 - if (have_fpx_regs) { 165 - struct user_fxsr_struct *fpx; 289 + err = copy_regset_to_user(current, 290 + task_user_regset_view(current), 291 + REGSET_FP_LEGACY, 0, 292 + sizeof(struct _fpstate_32), to_fp); 293 + if (err < 0) 294 + return err; 166 295 167 - fpx = (void *)&regs->regs.fp; 296 + __put_user(X86_FXSR_MAGIC, &to_fp->fpstate.magic); 168 297 169 - err = convert_fxsr_to_user(&to_fp->fpstate, fpx); 170 - if (err) 171 - return 1; 172 - 173 - err |= __put_user(fpx->swd, &to_fp->fpstate.status); 174 - err |= __put_user(X86_FXSR_MAGIC, &to_fp->fpstate.magic); 175 - if (err) 176 - return 1; 177 - 178 - } else { 179 - if (copy_to_user(to_fp, regs->regs.fp, sizeof(regs->regs.fp))) 180 - return 1; 181 - 182 - /* Need to fill in the sw_reserved bits ... */ 183 - BUILD_BUG_ON(offsetof(typeof(*to_fp), 184 - fpstate.sw_reserved.magic1) >= 185 - sizeof(struct _fpstate)); 186 - __put_user(0, &to_fp->fpstate.sw_reserved.magic1); 187 - __put_user(sizeof(struct _fpstate), 188 - &to_fp->fpstate.sw_reserved.extended_size); 189 - } 298 + BUILD_BUG_ON(offsetof(struct _xstate, xstate_hdr) != 299 + offsetof(struct _xstate_64, xstate_hdr) + 300 + offsetof(struct _fpstate_32, _fxsr_env)); 301 + to_fp64 = (void *)to_fp + offsetof(struct _fpstate_32, _fxsr_env); 190 302 #else 191 - if (copy_to_user(to_fp, regs->regs.fp, sizeof(struct _xstate))) 303 + to_fp64 = to_fp; 304 + #endif /* CONFIG_X86_32 */ 305 + 306 + if (copy_to_user(to_fp64, regs->regs.fp, host_fp_size)) 192 307 return 1; 308 + 309 + /* 310 + * Put magic/size values for userspace. We do not bother to verify them 311 + * later on, however, userspace needs them should it try to read the 312 + * XSTATE data. And ptrace does not fill in these parts. 313 + */ 314 + BUILD_BUG_ON(sizeof(int) != FP_XSTATE_MAGIC2_SIZE); 315 + #ifdef CONFIG_X86_32 316 + __put_user(offsetof(struct _fpstate_32, _fxsr_env) + 317 + host_fp_size + FP_XSTATE_MAGIC2_SIZE, 318 + &to_fp64->fpstate.sw_reserved.extended_size); 319 + #else 320 + __put_user(host_fp_size + FP_XSTATE_MAGIC2_SIZE, 321 + &to_fp64->fpstate.sw_reserved.extended_size); 193 322 #endif 323 + __put_user(host_fp_size, &to_fp64->fpstate.sw_reserved.xstate_size); 324 + 325 + __put_user(FP_XSTATE_MAGIC1, &to_fp64->fpstate.sw_reserved.magic1); 326 + __put_user(FP_XSTATE_MAGIC2, (int *)((void *)to_fp64 + host_fp_size)); 194 327 195 328 return 0; 196 329 } ··· 216 333 return err; 217 334 } 218 335 219 - struct sigframe 220 - { 221 - char __user *pretcode; 222 - int sig; 223 - struct sigcontext sc; 224 - struct _xstate fpstate; 225 - unsigned long extramask[_NSIG_WORDS-1]; 226 - char retcode[8]; 227 - }; 228 - 229 - struct rt_sigframe 230 - { 231 - char __user *pretcode; 232 - int sig; 233 - struct siginfo __user *pinfo; 234 - void __user *puc; 235 - struct siginfo info; 236 - struct ucontext uc; 237 - struct _xstate fpstate; 238 - char retcode[8]; 239 - }; 240 - 241 336 int setup_signal_stack_sc(unsigned long stack_top, struct ksignal *ksig, 242 337 struct pt_regs *regs, sigset_t *mask) 243 338 { 339 + size_t math_size = offsetof(struct _fpstate_32, _fxsr_env) + 340 + host_fp_size + FP_XSTATE_MAGIC2_SIZE; 244 341 struct sigframe __user *frame; 245 342 void __user *restorer; 246 343 int err = 0, sig = ksig->sig; 344 + unsigned long fp_to; 247 345 248 346 /* This is the same calculation as i386 - ((sp + 4) & 15) == 0 */ 249 347 stack_top = ((stack_top + 4) & -16UL) - 4; ··· 232 368 if (!access_ok(frame, sizeof(*frame))) 233 369 return 1; 234 370 371 + /* Add required space for math frame */ 372 + frame = (struct sigframe __user *)((unsigned long)frame - math_size); 373 + 235 374 restorer = frame->retcode; 236 375 if (ksig->ka.sa.sa_flags & SA_RESTORER) 237 376 restorer = ksig->ka.sa.sa_restorer; 238 377 239 - err |= __put_user(restorer, &frame->pretcode); 378 + err |= __put_user(restorer, (void **)&frame->pretcode); 240 379 err |= __put_user(sig, &frame->sig); 241 - err |= copy_sc_to_user(&frame->sc, &frame->fpstate, regs, mask->sig[0]); 380 + 381 + fp_to = (unsigned long)frame + sizeof(*frame); 382 + 383 + err |= copy_sc_to_user(&frame->sc, 384 + (struct _xstate __user *)fp_to, 385 + regs, mask->sig[0]); 242 386 if (_NSIG_WORDS > 1) 243 387 err |= __copy_to_user(&frame->extramask, &mask->sig[1], 244 388 sizeof(frame->extramask)); ··· 276 404 int setup_signal_stack_si(unsigned long stack_top, struct ksignal *ksig, 277 405 struct pt_regs *regs, sigset_t *mask) 278 406 { 407 + size_t math_size = offsetof(struct _fpstate_32, _fxsr_env) + 408 + host_fp_size + FP_XSTATE_MAGIC2_SIZE; 279 409 struct rt_sigframe __user *frame; 280 410 void __user *restorer; 281 411 int err = 0, sig = ksig->sig; 412 + unsigned long fp_to; 282 413 283 414 stack_top &= -8UL; 284 415 frame = (struct rt_sigframe __user *) stack_top - 1; 285 416 if (!access_ok(frame, sizeof(*frame))) 286 417 return 1; 287 418 419 + /* Add required space for math frame */ 420 + frame = (struct rt_sigframe __user *)((unsigned long)frame - math_size); 421 + 288 422 restorer = frame->retcode; 289 423 if (ksig->ka.sa.sa_flags & SA_RESTORER) 290 424 restorer = ksig->ka.sa.sa_restorer; 291 425 292 - err |= __put_user(restorer, &frame->pretcode); 426 + err |= __put_user(restorer, (void **)&frame->pretcode); 293 427 err |= __put_user(sig, &frame->sig); 294 - err |= __put_user(&frame->info, &frame->pinfo); 295 - err |= __put_user(&frame->uc, &frame->puc); 428 + err |= __put_user(&frame->info, (void **)&frame->pinfo); 429 + err |= __put_user(&frame->uc, (void **)&frame->puc); 296 430 err |= copy_siginfo_to_user(&frame->info, &ksig->info); 297 - err |= copy_ucontext_to_user(&frame->uc, &frame->fpstate, mask, 298 - PT_REGS_SP(regs)); 431 + 432 + fp_to = (unsigned long)frame + sizeof(*frame); 433 + 434 + err |= copy_ucontext_to_user(&frame->uc, (struct _xstate __user *)fp_to, 435 + mask, PT_REGS_SP(regs)); 299 436 300 437 /* 301 438 * This is movl $,%eax ; int $0x80 ··· 356 475 357 476 #else 358 477 359 - struct rt_sigframe 360 - { 361 - char __user *pretcode; 362 - struct ucontext uc; 363 - struct siginfo info; 364 - struct _xstate fpstate; 365 - }; 366 - 367 478 int setup_signal_stack_si(unsigned long stack_top, struct ksignal *ksig, 368 479 struct pt_regs *regs, sigset_t *set) 369 480 { 481 + unsigned long math_size = host_fp_size + FP_XSTATE_MAGIC2_SIZE; 370 482 struct rt_sigframe __user *frame; 371 483 int err = 0, sig = ksig->sig; 372 484 unsigned long fp_to; 373 485 374 486 frame = (struct rt_sigframe __user *) 375 487 round_down(stack_top - sizeof(struct rt_sigframe), 16); 488 + 489 + /* Add required space for math frame */ 490 + frame = (struct rt_sigframe __user *)((unsigned long)frame - math_size); 491 + 376 492 /* Subtract 128 for a red zone and 8 for proper alignment */ 377 493 frame = (struct rt_sigframe __user *) ((unsigned long) frame - 128 - 8); 378 494 379 - if (!access_ok(frame, sizeof(*frame))) 495 + if (!access_ok(frame, sizeof(*frame) + math_size)) 380 496 goto out; 381 497 382 498 if (ksig->ka.sa.sa_flags & SA_SIGINFO) { ··· 386 508 err |= __put_user(0, &frame->uc.uc_flags); 387 509 err |= __put_user(0, &frame->uc.uc_link); 388 510 err |= __save_altstack(&frame->uc.uc_stack, PT_REGS_SP(regs)); 389 - err |= copy_sc_to_user(&frame->uc.uc_mcontext, &frame->fpstate, regs, 390 - set->sig[0]); 391 511 392 - fp_to = (unsigned long)&frame->fpstate; 512 + fp_to = (unsigned long)frame + sizeof(*frame); 513 + 514 + err |= copy_sc_to_user(&frame->uc.uc_mcontext, 515 + (struct _xstate __user *)fp_to, 516 + regs, set->sig[0]); 393 517 394 518 err |= __put_user(fp_to, &frame->uc.uc_mcontext.fpstate); 395 519 if (sizeof(*set) == 16) {
-8
arch/x86/um/user-offsets.c
··· 20 20 void foo(void) 21 21 { 22 22 #ifdef __i386__ 23 - DEFINE_LONGS(HOST_FP_SIZE, sizeof(struct user_fpregs_struct)); 24 - DEFINE_LONGS(HOST_FPX_SIZE, sizeof(struct user_fpxregs_struct)); 25 - 26 23 DEFINE(HOST_IP, EIP); 27 24 DEFINE(HOST_SP, UESP); 28 25 DEFINE(HOST_EFLAGS, EFL); ··· 38 41 DEFINE(HOST_GS, GS); 39 42 DEFINE(HOST_ORIG_AX, ORIG_EAX); 40 43 #else 41 - #ifdef FP_XSTATE_MAGIC1 42 - DEFINE_LONGS(HOST_FP_SIZE, 2696); 43 - #else 44 - DEFINE(HOST_FP_SIZE, sizeof(struct _fpstate) / sizeof(unsigned long)); 45 - #endif 46 44 DEFINE_LONGS(HOST_BX, RBX); 47 45 DEFINE_LONGS(HOST_CX, RCX); 48 46 DEFINE_LONGS(HOST_DI, RDI);