aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorShaohua Li <shaohua.li@intel.com>2008-02-28 03:47:50 -0500
committerTony Luck <tony.luck@intel.com>2008-03-12 19:26:23 -0400
commitc70f8f68676866d778564de337bec6b8734c3850 (patch)
tree527ddecf32f9e055698f21b60f6a250fca5d9a3c /arch
parentbaadac8b10c5ac15ce3d26b68fa266c8889b163f (diff)
[IA64] regset: 64-bit support
This is the 64-bit regset implementation under IA64. Basically register read/write, which is derived from current ptrace register read/write. Signed-off-by: Shaohua Li <shaohua.li@intel.com> Signed-off-by: Tony Luck <tony.luck@intel.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/ia64/kernel/ptrace.c690
1 files changed, 690 insertions, 0 deletions
diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c
index ab784ec4319d..7136c7811efc 100644
--- a/arch/ia64/kernel/ptrace.c
+++ b/arch/ia64/kernel/ptrace.c
@@ -3,6 +3,9 @@
3 * 3 *
4 * Copyright (C) 1999-2005 Hewlett-Packard Co 4 * Copyright (C) 1999-2005 Hewlett-Packard Co
5 * David Mosberger-Tang <davidm@hpl.hp.com> 5 * David Mosberger-Tang <davidm@hpl.hp.com>
6 * Copyright (C) 2006 Intel Co
7 * 2006-08-12 - IA64 Native Utrace implementation support added by
8 * Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
6 * 9 *
7 * Derived from the x86 and Alpha versions. 10 * Derived from the x86 and Alpha versions.
8 */ 11 */
@@ -17,6 +20,8 @@
17#include <linux/security.h> 20#include <linux/security.h>
18#include <linux/audit.h> 21#include <linux/audit.h>
19#include <linux/signal.h> 22#include <linux/signal.h>
23#include <linux/regset.h>
24#include <linux/elf.h>
20 25
21#include <asm/pgtable.h> 26#include <asm/pgtable.h>
22#include <asm/processor.h> 27#include <asm/processor.h>
@@ -1626,3 +1631,688 @@ syscall_trace_leave (long arg0, long arg1, long arg2, long arg3,
1626 if (test_thread_flag(TIF_RESTORE_RSE)) 1631 if (test_thread_flag(TIF_RESTORE_RSE))
1627 ia64_sync_krbs(); 1632 ia64_sync_krbs();
1628} 1633}
1634
1635/* Utrace implementation starts here */
1636struct regset_get {
1637 void *kbuf;
1638 void __user *ubuf;
1639};
1640
1641struct regset_set {
1642 const void *kbuf;
1643 const void __user *ubuf;
1644};
1645
1646struct regset_getset {
1647 struct task_struct *target;
1648 const struct user_regset *regset;
1649 union {
1650 struct regset_get get;
1651 struct regset_set set;
1652 } u;
1653 unsigned int pos;
1654 unsigned int count;
1655 int ret;
1656};
1657
1658static int
1659access_elf_gpreg(struct task_struct *target, struct unw_frame_info *info,
1660 unsigned long addr, unsigned long *data, int write_access)
1661{
1662 struct pt_regs *pt;
1663 unsigned long *ptr = NULL;
1664 int ret;
1665 char nat = 0;
1666
1667 pt = task_pt_regs(target);
1668 switch (addr) {
1669 case ELF_GR_OFFSET(1):
1670 ptr = &pt->r1;
1671 break;
1672 case ELF_GR_OFFSET(2):
1673 case ELF_GR_OFFSET(3):
1674 ptr = (void *)&pt->r2 + (addr - ELF_GR_OFFSET(2));
1675 break;
1676 case ELF_GR_OFFSET(4) ... ELF_GR_OFFSET(7):
1677 if (write_access) {
1678 /* read NaT bit first: */
1679 unsigned long dummy;
1680
1681 ret = unw_get_gr(info, addr/8, &dummy, &nat);
1682 if (ret < 0)
1683 return ret;
1684 }
1685 return unw_access_gr(info, addr/8, data, &nat, write_access);
1686 case ELF_GR_OFFSET(8) ... ELF_GR_OFFSET(11):
1687 ptr = (void *)&pt->r8 + addr - ELF_GR_OFFSET(8);
1688 break;
1689 case ELF_GR_OFFSET(12):
1690 case ELF_GR_OFFSET(13):
1691 ptr = (void *)&pt->r12 + addr - ELF_GR_OFFSET(12);
1692 break;
1693 case ELF_GR_OFFSET(14):
1694 ptr = &pt->r14;
1695 break;
1696 case ELF_GR_OFFSET(15):
1697 ptr = &pt->r15;
1698 }
1699 if (write_access)
1700 *ptr = *data;
1701 else
1702 *data = *ptr;
1703 return 0;
1704}
1705
1706static int
1707access_elf_breg(struct task_struct *target, struct unw_frame_info *info,
1708 unsigned long addr, unsigned long *data, int write_access)
1709{
1710 struct pt_regs *pt;
1711 unsigned long *ptr = NULL;
1712
1713 pt = task_pt_regs(target);
1714 switch (addr) {
1715 case ELF_BR_OFFSET(0):
1716 ptr = &pt->b0;
1717 break;
1718 case ELF_BR_OFFSET(1) ... ELF_BR_OFFSET(5):
1719 return unw_access_br(info, (addr - ELF_BR_OFFSET(0))/8,
1720 data, write_access);
1721 case ELF_BR_OFFSET(6):
1722 ptr = &pt->b6;
1723 break;
1724 case ELF_BR_OFFSET(7):
1725 ptr = &pt->b7;
1726 }
1727 if (write_access)
1728 *ptr = *data;
1729 else
1730 *data = *ptr;
1731 return 0;
1732}
1733
1734static int
1735access_elf_areg(struct task_struct *target, struct unw_frame_info *info,
1736 unsigned long addr, unsigned long *data, int write_access)
1737{
1738 struct pt_regs *pt;
1739 unsigned long cfm, urbs_end;
1740 unsigned long *ptr = NULL;
1741
1742 pt = task_pt_regs(target);
1743 if (addr >= ELF_AR_RSC_OFFSET && addr <= ELF_AR_SSD_OFFSET) {
1744 switch (addr) {
1745 case ELF_AR_RSC_OFFSET:
1746 /* force PL3 */
1747 if (write_access)
1748 pt->ar_rsc = *data | (3 << 2);
1749 else
1750 *data = pt->ar_rsc;
1751 return 0;
1752 case ELF_AR_BSP_OFFSET:
1753 /*
1754 * By convention, we use PT_AR_BSP to refer to
1755 * the end of the user-level backing store.
1756 * Use ia64_rse_skip_regs(PT_AR_BSP, -CFM.sof)
1757 * to get the real value of ar.bsp at the time
1758 * the kernel was entered.
1759 *
1760 * Furthermore, when changing the contents of
1761 * PT_AR_BSP (or PT_CFM) while the task is
1762 * blocked in a system call, convert the state
1763 * so that the non-system-call exit
1764 * path is used. This ensures that the proper
1765 * state will be picked up when resuming
1766 * execution. However, it *also* means that
1767 * once we write PT_AR_BSP/PT_CFM, it won't be
1768 * possible to modify the syscall arguments of
1769 * the pending system call any longer. This
1770 * shouldn't be an issue because modifying
1771 * PT_AR_BSP/PT_CFM generally implies that
1772 * we're either abandoning the pending system
1773 * call or that we defer it's re-execution
1774 * (e.g., due to GDB doing an inferior
1775 * function call).
1776 */
1777 urbs_end = ia64_get_user_rbs_end(target, pt, &cfm);
1778 if (write_access) {
1779 if (*data != urbs_end) {
1780 if (in_syscall(pt))
1781 convert_to_non_syscall(target,
1782 pt,
1783 cfm);
1784 /*
1785 * Simulate user-level write
1786 * of ar.bsp:
1787 */
1788 pt->loadrs = 0;
1789 pt->ar_bspstore = *data;
1790 }
1791 } else
1792 *data = urbs_end;
1793 return 0;
1794 case ELF_AR_BSPSTORE_OFFSET:
1795 ptr = &pt->ar_bspstore;
1796 break;
1797 case ELF_AR_RNAT_OFFSET:
1798 ptr = &pt->ar_rnat;
1799 break;
1800 case ELF_AR_CCV_OFFSET:
1801 ptr = &pt->ar_ccv;
1802 break;
1803 case ELF_AR_UNAT_OFFSET:
1804 ptr = &pt->ar_unat;
1805 break;
1806 case ELF_AR_FPSR_OFFSET:
1807 ptr = &pt->ar_fpsr;
1808 break;
1809 case ELF_AR_PFS_OFFSET:
1810 ptr = &pt->ar_pfs;
1811 break;
1812 case ELF_AR_LC_OFFSET:
1813 return unw_access_ar(info, UNW_AR_LC, data,
1814 write_access);
1815 case ELF_AR_EC_OFFSET:
1816 return unw_access_ar(info, UNW_AR_EC, data,
1817 write_access);
1818 case ELF_AR_CSD_OFFSET:
1819 ptr = &pt->ar_csd;
1820 break;
1821 case ELF_AR_SSD_OFFSET:
1822 ptr = &pt->ar_ssd;
1823 }
1824 } else if (addr >= ELF_CR_IIP_OFFSET && addr <= ELF_CR_IPSR_OFFSET) {
1825 switch (addr) {
1826 case ELF_CR_IIP_OFFSET:
1827 ptr = &pt->cr_iip;
1828 break;
1829 case ELF_CFM_OFFSET:
1830 urbs_end = ia64_get_user_rbs_end(target, pt, &cfm);
1831 if (write_access) {
1832 if (((cfm ^ *data) & PFM_MASK) != 0) {
1833 if (in_syscall(pt))
1834 convert_to_non_syscall(target,
1835 pt,
1836 cfm);
1837 pt->cr_ifs = ((pt->cr_ifs & ~PFM_MASK)
1838 | (*data & PFM_MASK));
1839 }
1840 } else
1841 *data = cfm;
1842 return 0;
1843 case ELF_CR_IPSR_OFFSET:
1844 if (write_access) {
1845 unsigned long tmp = *data;
1846 /* psr.ri==3 is a reserved value: SDM 2:25 */
1847 if ((tmp & IA64_PSR_RI) == IA64_PSR_RI)
1848 tmp &= ~IA64_PSR_RI;
1849 pt->cr_ipsr = ((tmp & IPSR_MASK)
1850 | (pt->cr_ipsr & ~IPSR_MASK));
1851 } else
1852 *data = (pt->cr_ipsr & IPSR_MASK);
1853 return 0;
1854 }
1855 } else if (addr == ELF_NAT_OFFSET)
1856 return access_nat_bits(target, pt, info,
1857 data, write_access);
1858 else if (addr == ELF_PR_OFFSET)
1859 ptr = &pt->pr;
1860 else
1861 return -1;
1862
1863 if (write_access)
1864 *ptr = *data;
1865 else
1866 *data = *ptr;
1867
1868 return 0;
1869}
1870
1871static int
1872access_elf_reg(struct task_struct *target, struct unw_frame_info *info,
1873 unsigned long addr, unsigned long *data, int write_access)
1874{
1875 if (addr >= ELF_GR_OFFSET(1) && addr <= ELF_GR_OFFSET(15))
1876 return access_elf_gpreg(target, info, addr, data, write_access);
1877 else if (addr >= ELF_BR_OFFSET(0) && addr <= ELF_BR_OFFSET(7))
1878 return access_elf_breg(target, info, addr, data, write_access);
1879 else
1880 return access_elf_areg(target, info, addr, data, write_access);
1881}
1882
1883void do_gpregs_get(struct unw_frame_info *info, void *arg)
1884{
1885 struct pt_regs *pt;
1886 struct regset_getset *dst = arg;
1887 elf_greg_t tmp[16];
1888 unsigned int i, index, min_copy;
1889
1890 if (unw_unwind_to_user(info) < 0)
1891 return;
1892
1893 /*
1894 * coredump format:
1895 * r0-r31
1896 * NaT bits (for r0-r31; bit N == 1 iff rN is a NaT)
1897 * predicate registers (p0-p63)
1898 * b0-b7
1899 * ip cfm user-mask
1900 * ar.rsc ar.bsp ar.bspstore ar.rnat
1901 * ar.ccv ar.unat ar.fpsr ar.pfs ar.lc ar.ec
1902 */
1903
1904
1905 /* Skip r0 */
1906 if (dst->count > 0 && dst->pos < ELF_GR_OFFSET(1)) {
1907 dst->ret = user_regset_copyout_zero(&dst->pos, &dst->count,
1908 &dst->u.get.kbuf,
1909 &dst->u.get.ubuf,
1910 0, ELF_GR_OFFSET(1));
1911 if (dst->ret || dst->count == 0)
1912 return;
1913 }
1914
1915 /* gr1 - gr15 */
1916 if (dst->count > 0 && dst->pos < ELF_GR_OFFSET(16)) {
1917 index = (dst->pos - ELF_GR_OFFSET(1)) / sizeof(elf_greg_t);
1918 min_copy = ELF_GR_OFFSET(16) > (dst->pos + dst->count) ?
1919 (dst->pos + dst->count) : ELF_GR_OFFSET(16);
1920 for (i = dst->pos; i < min_copy; i += sizeof(elf_greg_t),
1921 index++)
1922 if (access_elf_reg(dst->target, info, i,
1923 &tmp[index], 0) < 0) {
1924 dst->ret = -EIO;
1925 return;
1926 }
1927 dst->ret = user_regset_copyout(&dst->pos, &dst->count,
1928 &dst->u.get.kbuf, &dst->u.get.ubuf, tmp,
1929 ELF_GR_OFFSET(1), ELF_GR_OFFSET(16));
1930 if (dst->ret || dst->count == 0)
1931 return;
1932 }
1933
1934 /* r16-r31 */
1935 if (dst->count > 0 && dst->pos < ELF_NAT_OFFSET) {
1936 pt = task_pt_regs(dst->target);
1937 dst->ret = user_regset_copyout(&dst->pos, &dst->count,
1938 &dst->u.get.kbuf, &dst->u.get.ubuf, &pt->r16,
1939 ELF_GR_OFFSET(16), ELF_NAT_OFFSET);
1940 if (dst->ret || dst->count == 0)
1941 return;
1942 }
1943
1944 /* nat, pr, b0 - b7 */
1945 if (dst->count > 0 && dst->pos < ELF_CR_IIP_OFFSET) {
1946 index = (dst->pos - ELF_NAT_OFFSET) / sizeof(elf_greg_t);
1947 min_copy = ELF_CR_IIP_OFFSET > (dst->pos + dst->count) ?
1948 (dst->pos + dst->count) : ELF_CR_IIP_OFFSET;
1949 for (i = dst->pos; i < min_copy; i += sizeof(elf_greg_t),
1950 index++)
1951 if (access_elf_reg(dst->target, info, i,
1952 &tmp[index], 0) < 0) {
1953 dst->ret = -EIO;
1954 return;
1955 }
1956 dst->ret = user_regset_copyout(&dst->pos, &dst->count,
1957 &dst->u.get.kbuf, &dst->u.get.ubuf, tmp,
1958 ELF_NAT_OFFSET, ELF_CR_IIP_OFFSET);
1959 if (dst->ret || dst->count == 0)
1960 return;
1961 }
1962
1963 /* ip cfm psr ar.rsc ar.bsp ar.bspstore ar.rnat
1964 * ar.ccv ar.unat ar.fpsr ar.pfs ar.lc ar.ec ar.csd ar.ssd
1965 */
1966 if (dst->count > 0 && dst->pos < (ELF_AR_END_OFFSET)) {
1967 index = (dst->pos - ELF_CR_IIP_OFFSET) / sizeof(elf_greg_t);
1968 min_copy = ELF_AR_END_OFFSET > (dst->pos + dst->count) ?
1969 (dst->pos + dst->count) : ELF_AR_END_OFFSET;
1970 for (i = dst->pos; i < min_copy; i += sizeof(elf_greg_t),
1971 index++)
1972 if (access_elf_reg(dst->target, info, i,
1973 &tmp[index], 0) < 0) {
1974 dst->ret = -EIO;
1975 return;
1976 }
1977 dst->ret = user_regset_copyout(&dst->pos, &dst->count,
1978 &dst->u.get.kbuf, &dst->u.get.ubuf, tmp,
1979 ELF_CR_IIP_OFFSET, ELF_AR_END_OFFSET);
1980 }
1981}
1982
1983void do_gpregs_set(struct unw_frame_info *info, void *arg)
1984{
1985 struct pt_regs *pt;
1986 struct regset_getset *dst = arg;
1987 elf_greg_t tmp[16];
1988 unsigned int i, index;
1989
1990 if (unw_unwind_to_user(info) < 0)
1991 return;
1992
1993 /* Skip r0 */
1994 if (dst->count > 0 && dst->pos < ELF_GR_OFFSET(1)) {
1995 dst->ret = user_regset_copyin_ignore(&dst->pos, &dst->count,
1996 &dst->u.set.kbuf,
1997 &dst->u.set.ubuf,
1998 0, ELF_GR_OFFSET(1));
1999 if (dst->ret || dst->count == 0)
2000 return;
2001 }
2002
2003 /* gr1-gr15 */
2004 if (dst->count > 0 && dst->pos < ELF_GR_OFFSET(16)) {
2005 i = dst->pos;
2006 index = (dst->pos - ELF_GR_OFFSET(1)) / sizeof(elf_greg_t);
2007 dst->ret = user_regset_copyin(&dst->pos, &dst->count,
2008 &dst->u.set.kbuf, &dst->u.set.ubuf, tmp,
2009 ELF_GR_OFFSET(1), ELF_GR_OFFSET(16));
2010 if (dst->ret)
2011 return;
2012 for ( ; i < dst->pos; i += sizeof(elf_greg_t), index++)
2013 if (access_elf_reg(dst->target, info, i,
2014 &tmp[index], 1) < 0) {
2015 dst->ret = -EIO;
2016 return;
2017 }
2018 if (dst->count == 0)
2019 return;
2020 }
2021
2022 /* gr16-gr31 */
2023 if (dst->count > 0 && dst->pos < ELF_NAT_OFFSET) {
2024 pt = task_pt_regs(dst->target);
2025 dst->ret = user_regset_copyin(&dst->pos, &dst->count,
2026 &dst->u.set.kbuf, &dst->u.set.ubuf, &pt->r16,
2027 ELF_GR_OFFSET(16), ELF_NAT_OFFSET);
2028 if (dst->ret || dst->count == 0)
2029 return;
2030 }
2031
2032 /* nat, pr, b0 - b7 */
2033 if (dst->count > 0 && dst->pos < ELF_CR_IIP_OFFSET) {
2034 i = dst->pos;
2035 index = (dst->pos - ELF_NAT_OFFSET) / sizeof(elf_greg_t);
2036 dst->ret = user_regset_copyin(&dst->pos, &dst->count,
2037 &dst->u.set.kbuf, &dst->u.set.ubuf, tmp,
2038 ELF_NAT_OFFSET, ELF_CR_IIP_OFFSET);
2039 if (dst->ret)
2040 return;
2041 for (; i < dst->pos; i += sizeof(elf_greg_t), index++)
2042 if (access_elf_reg(dst->target, info, i,
2043 &tmp[index], 1) < 0) {
2044 dst->ret = -EIO;
2045 return;
2046 }
2047 if (dst->count == 0)
2048 return;
2049 }
2050
2051 /* ip cfm psr ar.rsc ar.bsp ar.bspstore ar.rnat
2052 * ar.ccv ar.unat ar.fpsr ar.pfs ar.lc ar.ec ar.csd ar.ssd
2053 */
2054 if (dst->count > 0 && dst->pos < (ELF_AR_END_OFFSET)) {
2055 i = dst->pos;
2056 index = (dst->pos - ELF_CR_IIP_OFFSET) / sizeof(elf_greg_t);
2057 dst->ret = user_regset_copyin(&dst->pos, &dst->count,
2058 &dst->u.set.kbuf, &dst->u.set.ubuf, tmp,
2059 ELF_CR_IIP_OFFSET, ELF_AR_END_OFFSET);
2060 if (dst->ret)
2061 return;
2062 for ( ; i < dst->pos; i += sizeof(elf_greg_t), index++)
2063 if (access_elf_reg(dst->target, info, i,
2064 &tmp[index], 1) < 0) {
2065 dst->ret = -EIO;
2066 return;
2067 }
2068 }
2069}
2070
2071#define ELF_FP_OFFSET(i) (i * sizeof(elf_fpreg_t))
2072
2073void do_fpregs_get(struct unw_frame_info *info, void *arg)
2074{
2075 struct regset_getset *dst = arg;
2076 struct task_struct *task = dst->target;
2077 elf_fpreg_t tmp[30];
2078 int index, min_copy, i;
2079
2080 if (unw_unwind_to_user(info) < 0)
2081 return;
2082
2083 /* Skip pos 0 and 1 */
2084 if (dst->count > 0 && dst->pos < ELF_FP_OFFSET(2)) {
2085 dst->ret = user_regset_copyout_zero(&dst->pos, &dst->count,
2086 &dst->u.get.kbuf,
2087 &dst->u.get.ubuf,
2088 0, ELF_FP_OFFSET(2));
2089 if (dst->count == 0 || dst->ret)
2090 return;
2091 }
2092
2093 /* fr2-fr31 */
2094 if (dst->count > 0 && dst->pos < ELF_FP_OFFSET(32)) {
2095 index = (dst->pos - ELF_FP_OFFSET(2)) / sizeof(elf_fpreg_t);
2096
2097 min_copy = min(((unsigned int)ELF_FP_OFFSET(32)),
2098 dst->pos + dst->count);
2099 for (i = dst->pos; i < min_copy; i += sizeof(elf_fpreg_t),
2100 index++)
2101 if (unw_get_fr(info, i / sizeof(elf_fpreg_t),
2102 &tmp[index])) {
2103 dst->ret = -EIO;
2104 return;
2105 }
2106 dst->ret = user_regset_copyout(&dst->pos, &dst->count,
2107 &dst->u.get.kbuf, &dst->u.get.ubuf, tmp,
2108 ELF_FP_OFFSET(2), ELF_FP_OFFSET(32));
2109 if (dst->count == 0 || dst->ret)
2110 return;
2111 }
2112
2113 /* fph */
2114 if (dst->count > 0) {
2115 ia64_flush_fph(dst->target);
2116 if (task->thread.flags & IA64_THREAD_FPH_VALID)
2117 dst->ret = user_regset_copyout(
2118 &dst->pos, &dst->count,
2119 &dst->u.get.kbuf, &dst->u.get.ubuf,
2120 &dst->target->thread.fph,
2121 ELF_FP_OFFSET(32), -1);
2122 else
2123 /* Zero fill instead. */
2124 dst->ret = user_regset_copyout_zero(
2125 &dst->pos, &dst->count,
2126 &dst->u.get.kbuf, &dst->u.get.ubuf,
2127 ELF_FP_OFFSET(32), -1);
2128 }
2129}
2130
2131void do_fpregs_set(struct unw_frame_info *info, void *arg)
2132{
2133 struct regset_getset *dst = arg;
2134 elf_fpreg_t fpreg, tmp[30];
2135 int index, start, end;
2136
2137 if (unw_unwind_to_user(info) < 0)
2138 return;
2139
2140 /* Skip pos 0 and 1 */
2141 if (dst->count > 0 && dst->pos < ELF_FP_OFFSET(2)) {
2142 dst->ret = user_regset_copyin_ignore(&dst->pos, &dst->count,
2143 &dst->u.set.kbuf,
2144 &dst->u.set.ubuf,
2145 0, ELF_FP_OFFSET(2));
2146 if (dst->count == 0 || dst->ret)
2147 return;
2148 }
2149
2150 /* fr2-fr31 */
2151 if (dst->count > 0 && dst->pos < ELF_FP_OFFSET(32)) {
2152 start = dst->pos;
2153 end = min(((unsigned int)ELF_FP_OFFSET(32)),
2154 dst->pos + dst->count);
2155 dst->ret = user_regset_copyin(&dst->pos, &dst->count,
2156 &dst->u.set.kbuf, &dst->u.set.ubuf, tmp,
2157 ELF_FP_OFFSET(2), ELF_FP_OFFSET(32));
2158 if (dst->ret)
2159 return;
2160
2161 if (start & 0xF) { /* only write high part */
2162 if (unw_get_fr(info, start / sizeof(elf_fpreg_t),
2163 &fpreg)) {
2164 dst->ret = -EIO;
2165 return;
2166 }
2167 tmp[start / sizeof(elf_fpreg_t) - 2].u.bits[0]
2168 = fpreg.u.bits[0];
2169 start &= ~0xFUL;
2170 }
2171 if (end & 0xF) { /* only write low part */
2172 if (unw_get_fr(info, end / sizeof(elf_fpreg_t),
2173 &fpreg)) {
2174 dst->ret = -EIO;
2175 return;
2176 }
2177 tmp[end / sizeof(elf_fpreg_t) - 2].u.bits[1]
2178 = fpreg.u.bits[1];
2179 end = (end + 0xF) & ~0xFUL;
2180 }
2181
2182 for ( ; start < end ; start += sizeof(elf_fpreg_t)) {
2183 index = start / sizeof(elf_fpreg_t);
2184 if (unw_set_fr(info, index, tmp[index - 2])) {
2185 dst->ret = -EIO;
2186 return;
2187 }
2188 }
2189 if (dst->ret || dst->count == 0)
2190 return;
2191 }
2192
2193 /* fph */
2194 if (dst->count > 0 && dst->pos < ELF_FP_OFFSET(128)) {
2195 ia64_sync_fph(dst->target);
2196 dst->ret = user_regset_copyin(&dst->pos, &dst->count,
2197 &dst->u.set.kbuf,
2198 &dst->u.set.ubuf,
2199 &dst->target->thread.fph,
2200 ELF_FP_OFFSET(32), -1);
2201 }
2202}
2203
2204static int
2205do_regset_call(void (*call)(struct unw_frame_info *, void *),
2206 struct task_struct *target,
2207 const struct user_regset *regset,
2208 unsigned int pos, unsigned int count,
2209 const void *kbuf, const void __user *ubuf)
2210{
2211 struct regset_getset info = { .target = target, .regset = regset,
2212 .pos = pos, .count = count,
2213 .u.set = { .kbuf = kbuf, .ubuf = ubuf },
2214 .ret = 0 };
2215
2216 if (target == current)
2217 unw_init_running(call, &info);
2218 else {
2219 struct unw_frame_info ufi;
2220 memset(&ufi, 0, sizeof(ufi));
2221 unw_init_from_blocked_task(&ufi, target);
2222 (*call)(&ufi, &info);
2223 }
2224
2225 return info.ret;
2226}
2227
2228static int
2229gpregs_get(struct task_struct *target,
2230 const struct user_regset *regset,
2231 unsigned int pos, unsigned int count,
2232 void *kbuf, void __user *ubuf)
2233{
2234 return do_regset_call(do_gpregs_get, target, regset, pos, count,
2235 kbuf, ubuf);
2236}
2237
2238static int gpregs_set(struct task_struct *target,
2239 const struct user_regset *regset,
2240 unsigned int pos, unsigned int count,
2241 const void *kbuf, const void __user *ubuf)
2242{
2243 return do_regset_call(do_gpregs_set, target, regset, pos, count,
2244 kbuf, ubuf);
2245}
2246
2247static void do_gpregs_writeback(struct unw_frame_info *info, void *arg)
2248{
2249 do_sync_rbs(info, ia64_sync_user_rbs);
2250}
2251
2252/*
2253 * This is called to write back the register backing store.
2254 * ptrace does this before it stops, so that a tracer reading the user
2255 * memory after the thread stops will get the current register data.
2256 */
2257static int
2258gpregs_writeback(struct task_struct *target,
2259 const struct user_regset *regset,
2260 int now)
2261{
2262 if (test_and_set_tsk_thread_flag(target, TIF_RESTORE_RSE))
2263 return 0;
2264 tsk_set_notify_resume(target);
2265 return do_regset_call(do_gpregs_writeback, target, regset, 0, 0,
2266 NULL, NULL);
2267}
2268
2269static int
2270fpregs_active(struct task_struct *target, const struct user_regset *regset)
2271{
2272 return (target->thread.flags & IA64_THREAD_FPH_VALID) ? 128 : 32;
2273}
2274
2275static int fpregs_get(struct task_struct *target,
2276 const struct user_regset *regset,
2277 unsigned int pos, unsigned int count,
2278 void *kbuf, void __user *ubuf)
2279{
2280 return do_regset_call(do_fpregs_get, target, regset, pos, count,
2281 kbuf, ubuf);
2282}
2283
2284static int fpregs_set(struct task_struct *target,
2285 const struct user_regset *regset,
2286 unsigned int pos, unsigned int count,
2287 const void *kbuf, const void __user *ubuf)
2288{
2289 return do_regset_call(do_fpregs_set, target, regset, pos, count,
2290 kbuf, ubuf);
2291}
2292
2293static const struct user_regset native_regsets[] = {
2294 {
2295 .core_note_type = NT_PRSTATUS,
2296 .n = ELF_NGREG,
2297 .size = sizeof(elf_greg_t), .align = sizeof(elf_greg_t),
2298 .get = gpregs_get, .set = gpregs_set,
2299 .writeback = gpregs_writeback
2300 },
2301 {
2302 .core_note_type = NT_PRFPREG,
2303 .n = ELF_NFPREG,
2304 .size = sizeof(elf_fpreg_t), .align = sizeof(elf_fpreg_t),
2305 .get = fpregs_get, .set = fpregs_set, .active = fpregs_active
2306 },
2307};
2308
2309static const struct user_regset_view user_ia64_view = {
2310 .name = "ia64",
2311 .e_machine = EM_IA_64,
2312 .regsets = native_regsets, .n = ARRAY_SIZE(native_regsets)
2313};
2314
2315const struct user_regset_view *task_user_regset_view(struct task_struct *tsk)
2316{
2317 return &user_ia64_view;
2318}