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 29 twd_fxsr_to_i387(const struct user_fxsr_struct *fxsave) 30 { 31 struct _fpxreg *st = NULL; 32 unsigned long twd = (unsigned long) fxsave->twd; 33 unsigned long tag; 34 unsigned long ret = 0xffff0000; 35 int i; 36 37 #define FPREG_ADDR(f, n) ((char *)&(f)->st_space + (n) * 16) 38 39 for (i = 0; i < 8; i++) { 40 if (twd & 0x1) { 41 st = (struct _fpxreg *) FPREG_ADDR(fxsave, i); 42 43 switch (st->exponent & 0x7fff) { 44 case 0x7fff: 45 tag = 2; /* Special */ 46 break; 47 case 0x0000: 48 if (!st->significand[0] && 49 !st->significand[1] && 50 !st->significand[2] && 51 !st->significand[3]) { 52 tag = 1; /* Zero */ 53 } else { 54 tag = 2; /* Special */ 55 } 56 break; 57 default: 58 if (st->significand[3] & 0x8000) 59 tag = 0; /* Valid */ 60 else 61 tag = 2; /* Special */ 62 break; 63 } 64 } else { 65 tag = 3; /* Empty */ 66 } 67 ret |= (tag << (2 * i)); 68 twd = twd >> 1; 69 } 70 return ret; 71 } 72 73 /* 74 * Get/set the old 32bit i387 registers (pre-FPX) 75 * 76 * We provide simple wrappers for mcontext.c, they are only defined locally 77 * because mcontext.c is userspace facing and needs to a different definition 78 * of the structures. 79 */ 80 static int _um_i387_from_fxsr(struct membuf to, 81 const struct user_fxsr_struct *fxsave) 82 { 83 int i; 84 85 membuf_store(&to, (unsigned long)fxsave->cwd | 0xffff0000ul); 86 membuf_store(&to, (unsigned long)fxsave->swd | 0xffff0000ul); 87 membuf_store(&to, twd_fxsr_to_i387(fxsave)); 88 membuf_store(&to, fxsave->fip); 89 membuf_store(&to, fxsave->fcs | ((unsigned long)fxsave->fop << 16)); 90 membuf_store(&to, fxsave->foo); 91 membuf_store(&to, fxsave->fos); 92 93 for (i = 0; i < 8; i++) 94 membuf_write(&to, (void *)fxsave->st_space + i * 16, 10); 95 96 return 0; 97 } 98 99 int um_i387_from_fxsr(struct user_i387_struct *i387, 100 const struct user_fxsr_struct *fxsave); 101 102 int um_i387_from_fxsr(struct user_i387_struct *i387, 103 const struct user_fxsr_struct *fxsave) 104 { 105 struct membuf to = { 106 .p = i387, 107 .left = sizeof(*i387), 108 }; 109 110 return _um_i387_from_fxsr(to, fxsave); 111 } 112 113 static int fpregs_legacy_get(struct task_struct *target, 114 const struct user_regset *regset, 115 struct membuf to) 116 { 117 struct user_fxsr_struct *fxsave = (void *)target->thread.regs.regs.fp; 118 119 return _um_i387_from_fxsr(to, fxsave); 120 } 121 122 int um_fxsr_from_i387(struct user_fxsr_struct *fxsave, 123 const struct user_i387_struct *from); 124 125 int um_fxsr_from_i387(struct user_fxsr_struct *fxsave, 126 const struct user_i387_struct *from) 127 { 128 int i; 129 130 fxsave->cwd = (unsigned short)(from->cwd & 0xffff); 131 fxsave->swd = (unsigned short)(from->swd & 0xffff); 132 fxsave->twd = twd_i387_to_fxsr((unsigned short)(from->twd & 0xffff)); 133 fxsave->fip = from->fip; 134 fxsave->fop = (unsigned short)((from->fcs & 0xffff0000ul) >> 16); 135 fxsave->fcs = (from->fcs & 0xffff); 136 fxsave->foo = from->foo; 137 fxsave->fos = from->fos; 138 139 for (i = 0; i < 8; i++) { 140 memcpy((void *)fxsave->st_space + i * 16, 141 (void *)from->st_space + i * 10, 10); 142 } 143 144 return 0; 145 } 146 147 static int fpregs_legacy_set(struct task_struct *target, 148 const struct user_regset *regset, 149 unsigned int pos, unsigned int count, 150 const void *kbuf, const void __user *ubuf) 151 { 152 struct user_fxsr_struct *fxsave = (void *)target->thread.regs.regs.fp; 153 const struct user_i387_struct *from; 154 struct user_i387_struct buf; 155 156 if (ubuf) { 157 if (copy_from_user(&buf, ubuf, sizeof(buf))) 158 return -EFAULT; 159 from = &buf; 160 } else { 161 from = kbuf; 162 } 163 164 return um_fxsr_from_i387(fxsave, from); 165 } 166 #endif 167 168 static int genregs_get(struct task_struct *target, 169 const struct user_regset *regset, 170 struct membuf to) 171 { 172 int reg; 173 174 for (reg = 0; to.left; reg++) 175 membuf_store(&to, getreg(target, reg * sizeof(unsigned long))); 176 return 0; 177 } 178 179 static int genregs_set(struct task_struct *target, 180 const struct user_regset *regset, 181 unsigned int pos, unsigned int count, 182 const void *kbuf, const void __user *ubuf) 183 { 184 int ret = 0; 185 186 if (kbuf) { 187 const unsigned long *k = kbuf; 188 189 while (count >= sizeof(*k) && !ret) { 190 ret = putreg(target, pos, *k++); 191 count -= sizeof(*k); 192 pos += sizeof(*k); 193 } 194 } else { 195 const unsigned long __user *u = ubuf; 196 197 while (count >= sizeof(*u) && !ret) { 198 unsigned long word; 199 200 ret = __get_user(word, u++); 201 if (ret) 202 break; 203 ret = putreg(target, pos, word); 204 count -= sizeof(*u); 205 pos += sizeof(*u); 206 } 207 } 208 return ret; 209 } 210 211 static int generic_fpregs_active(struct task_struct *target, const struct user_regset *regset) 212 { 213 return regset->n; 214 } 215 216 static int generic_fpregs_get(struct task_struct *target, 217 const struct user_regset *regset, 218 struct membuf to) 219 { 220 void *fpregs = task_pt_regs(target)->regs.fp; 221 222 membuf_write(&to, fpregs, regset->size * regset->n); 223 return 0; 224 } 225 226 static int generic_fpregs_set(struct task_struct *target, 227 const struct user_regset *regset, 228 unsigned int pos, unsigned int count, 229 const void *kbuf, const void __user *ubuf) 230 { 231 void *fpregs = task_pt_regs(target)->regs.fp; 232 233 return user_regset_copyin(&pos, &count, &kbuf, &ubuf, 234 fpregs, 0, regset->size * regset->n); 235 } 236 237 static struct user_regset uml_regsets[] __ro_after_init = { 238 [REGSET_GENERAL] = { 239 .core_note_type = NT_PRSTATUS, 240 .n = sizeof(struct user_regs_struct) / sizeof(long), 241 .size = sizeof(long), 242 .align = sizeof(long), 243 .regset_get = genregs_get, 244 .set = genregs_set 245 }, 246 #ifdef CONFIG_X86_32 247 /* Old FP registers, they are needed in signal frames */ 248 [REGSET_FP_LEGACY] = { 249 .core_note_type = NT_PRFPREG, 250 .n = sizeof(struct user_i387_ia32_struct) / sizeof(long), 251 .size = sizeof(long), 252 .align = sizeof(long), 253 .active = generic_fpregs_active, 254 .regset_get = fpregs_legacy_get, 255 .set = fpregs_legacy_set, 256 }, 257 #endif 258 [REGSET_FP] = { 259 #ifdef CONFIG_X86_32 260 .core_note_type = NT_PRXFPREG, 261 .n = sizeof(struct user32_fxsr_struct) / sizeof(long), 262 #else 263 .core_note_type = NT_PRFPREG, 264 .n = sizeof(struct user_i387_struct) / sizeof(long), 265 #endif 266 .size = sizeof(long), 267 .align = sizeof(long), 268 .active = generic_fpregs_active, 269 .regset_get = generic_fpregs_get, 270 .set = generic_fpregs_set, 271 }, 272 [REGSET_XSTATE] = { 273 .core_note_type = NT_X86_XSTATE, 274 .size = sizeof(long), 275 .align = sizeof(long), 276 .active = generic_fpregs_active, 277 .regset_get = generic_fpregs_get, 278 .set = generic_fpregs_set, 279 }, 280 /* TODO: Add TLS regset for 32bit */ 281 }; 282 283 static const struct user_regset_view user_uml_view = { 284 #ifdef CONFIG_X86_32 285 .name = "i386", .e_machine = EM_386, 286 #else 287 .name = "x86_64", .e_machine = EM_X86_64, 288 #endif 289 .regsets = uml_regsets, .n = ARRAY_SIZE(uml_regsets) 290 }; 291 292 const struct user_regset_view * 293 task_user_regset_view(struct task_struct *tsk) 294 { 295 return &user_uml_view; 296 } 297 298 static int __init init_regset_xstate_info(void) 299 { 300 uml_regsets[REGSET_XSTATE].n = 301 host_fp_size / uml_regsets[REGSET_XSTATE].size; 302 303 return 0; 304 } 305 arch_initcall(init_regset_xstate_info); 306