Author | Tokens | Token Proportion | Commits | Commit Proportion |
---|---|---|---|---|
Benjamin Berg | 1046 | 70.15% | 3 | 17.65% |
Jeff Dike | 423 | 28.37% | 7 | 41.18% |
Al Viro | 13 | 0.87% | 3 | 17.65% |
Ingo van Lil | 4 | 0.27% | 1 | 5.88% |
Eli Cooper | 3 | 0.20% | 1 | 5.88% |
Phil Carmody | 1 | 0.07% | 1 | 5.88% |
Greg Kroah-Hartman | 1 | 0.07% | 1 | 5.88% |
Total | 1491 | 17 |
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
// SPDX-License-Identifier: GPL-2.0 #include <linux/sched.h> #include <linux/elf.h> #include <linux/regset.h> #include <asm/user32.h> #include <asm/sigcontext.h> #ifdef CONFIG_X86_32 /* * FPU tag word conversions. */ static inline unsigned short twd_i387_to_fxsr(unsigned short twd) { unsigned int tmp; /* to avoid 16 bit prefixes in the code */ /* Transform each pair of bits into 01 (valid) or 00 (empty) */ tmp = ~twd; tmp = (tmp | (tmp>>1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */ /* and move the valid bits to the lower byte. */ tmp = (tmp | (tmp >> 1)) & 0x3333; /* 00VV00VV00VV00VV */ tmp = (tmp | (tmp >> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */ tmp = (tmp | (tmp >> 4)) & 0x00ff; /* 00000000VVVVVVVV */ return tmp; } static inline unsigned long twd_fxsr_to_i387(struct user_fxsr_struct *fxsave) { struct _fpxreg *st = NULL; unsigned long twd = (unsigned long) fxsave->twd; unsigned long tag; unsigned long ret = 0xffff0000; int i; #define FPREG_ADDR(f, n) ((char *)&(f)->st_space + (n) * 16) for (i = 0; i < 8; i++) { if (twd & 0x1) { st = (struct _fpxreg *) FPREG_ADDR(fxsave, i); switch (st->exponent & 0x7fff) { case 0x7fff: tag = 2; /* Special */ break; case 0x0000: if (!st->significand[0] && !st->significand[1] && !st->significand[2] && !st->significand[3]) { tag = 1; /* Zero */ } else { tag = 2; /* Special */ } break; default: if (st->significand[3] & 0x8000) tag = 0; /* Valid */ else tag = 2; /* Special */ break; } } else { tag = 3; /* Empty */ } ret |= (tag << (2 * i)); twd = twd >> 1; } return ret; } /* Get/set the old 32bit i387 registers (pre-FPX) */ static int fpregs_legacy_get(struct task_struct *target, const struct user_regset *regset, struct membuf to) { struct user_fxsr_struct *fxsave = (void *)target->thread.regs.regs.fp; int i; membuf_store(&to, (unsigned long)fxsave->cwd | 0xffff0000ul); membuf_store(&to, (unsigned long)fxsave->swd | 0xffff0000ul); membuf_store(&to, twd_fxsr_to_i387(fxsave)); membuf_store(&to, fxsave->fip); membuf_store(&to, fxsave->fcs | ((unsigned long)fxsave->fop << 16)); membuf_store(&to, fxsave->foo); membuf_store(&to, fxsave->fos); for (i = 0; i < 8; i++) membuf_write(&to, (void *)fxsave->st_space + i * 16, 10); return 0; } static int fpregs_legacy_set(struct task_struct *target, const struct user_regset *regset, unsigned int pos, unsigned int count, const void *kbuf, const void __user *ubuf) { struct user_fxsr_struct *fxsave = (void *)target->thread.regs.regs.fp; const struct user_i387_struct *from; struct user_i387_struct buf; int i; if (ubuf) { if (copy_from_user(&buf, ubuf, sizeof(buf))) return -EFAULT; from = &buf; } else { from = kbuf; } fxsave->cwd = (unsigned short)(from->cwd & 0xffff); fxsave->swd = (unsigned short)(from->swd & 0xffff); fxsave->twd = twd_i387_to_fxsr((unsigned short)(from->twd & 0xffff)); fxsave->fip = from->fip; fxsave->fop = (unsigned short)((from->fcs & 0xffff0000ul) >> 16); fxsave->fcs = (from->fcs & 0xffff); fxsave->foo = from->foo; fxsave->fos = from->fos; for (i = 0; i < 8; i++) { memcpy((void *)fxsave->st_space + i * 16, (void *)from->st_space + i * 10, 10); } return 0; } #endif static int genregs_get(struct task_struct *target, const struct user_regset *regset, struct membuf to) { int reg; for (reg = 0; to.left; reg++) membuf_store(&to, getreg(target, reg * sizeof(unsigned long))); return 0; } static int genregs_set(struct task_struct *target, const struct user_regset *regset, unsigned int pos, unsigned int count, const void *kbuf, const void __user *ubuf) { int ret = 0; if (kbuf) { const unsigned long *k = kbuf; while (count >= sizeof(*k) && !ret) { ret = putreg(target, pos, *k++); count -= sizeof(*k); pos += sizeof(*k); } } else { const unsigned long __user *u = ubuf; while (count >= sizeof(*u) && !ret) { unsigned long word; ret = __get_user(word, u++); if (ret) break; ret = putreg(target, pos, word); count -= sizeof(*u); pos += sizeof(*u); } } return ret; } static int generic_fpregs_active(struct task_struct *target, const struct user_regset *regset) { return regset->n; } static int generic_fpregs_get(struct task_struct *target, const struct user_regset *regset, struct membuf to) { void *fpregs = task_pt_regs(target)->regs.fp; membuf_write(&to, fpregs, regset->size * regset->n); return 0; } static int generic_fpregs_set(struct task_struct *target, const struct user_regset *regset, unsigned int pos, unsigned int count, const void *kbuf, const void __user *ubuf) { void *fpregs = task_pt_regs(target)->regs.fp; return user_regset_copyin(&pos, &count, &kbuf, &ubuf, fpregs, 0, regset->size * regset->n); } static struct user_regset uml_regsets[] __ro_after_init = { [REGSET_GENERAL] = { .core_note_type = NT_PRSTATUS, .n = sizeof(struct user_regs_struct) / sizeof(long), .size = sizeof(long), .align = sizeof(long), .regset_get = genregs_get, .set = genregs_set }, #ifdef CONFIG_X86_32 /* Old FP registers, they are needed in signal frames */ [REGSET_FP_LEGACY] = { .core_note_type = NT_PRFPREG, .n = sizeof(struct user_i387_ia32_struct) / sizeof(long), .size = sizeof(long), .align = sizeof(long), .active = generic_fpregs_active, .regset_get = fpregs_legacy_get, .set = fpregs_legacy_set, }, #endif [REGSET_FP] = { #ifdef CONFIG_X86_32 .core_note_type = NT_PRXFPREG, .n = sizeof(struct user32_fxsr_struct) / sizeof(long), #else .core_note_type = NT_PRFPREG, .n = sizeof(struct user_i387_struct) / sizeof(long), #endif .size = sizeof(long), .align = sizeof(long), .active = generic_fpregs_active, .regset_get = generic_fpregs_get, .set = generic_fpregs_set, }, [REGSET_XSTATE] = { .core_note_type = NT_X86_XSTATE, .size = sizeof(long), .align = sizeof(long), .active = generic_fpregs_active, .regset_get = generic_fpregs_get, .set = generic_fpregs_set, }, /* TODO: Add TLS regset for 32bit */ }; static const struct user_regset_view user_uml_view = { #ifdef CONFIG_X86_32 .name = "i386", .e_machine = EM_386, #else .name = "x86_64", .e_machine = EM_X86_64, #endif .regsets = uml_regsets, .n = ARRAY_SIZE(uml_regsets) }; const struct user_regset_view * task_user_regset_view(struct task_struct *tsk) { return &user_uml_view; } static int __init init_regset_xstate_info(void) { uml_regsets[REGSET_XSTATE].n = host_fp_size / uml_regsets[REGSET_XSTATE].size; return 0; } arch_initcall(init_regset_xstate_info);
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with Cregit http://github.com/cregit/cregit
Version 2.0-RC1