diff options
author | Shaohua Li <shaohua.li@intel.com> | 2008-02-28 03:09:42 -0500 |
---|---|---|
committer | Tony Luck <tony.luck@intel.com> | 2008-03-12 19:28:02 -0400 |
commit | 4cd8dc83581906948ff4cfa65007e64496b5a7c8 (patch) | |
tree | fa3265bc11dcf158731b06419b29ed1fa5fd578c /arch | |
parent | 6cb53d7a6f40858181facde0f52587731d2e621f (diff) |
[IA64] remove duplicate code for register access
We have duplicate code to access registers (access_uarea and regset
way). They just have different layout, so remove duplicate code.
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.c | 522 |
1 files changed, 200 insertions, 322 deletions
diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index 4c104170ca4d..2a9943b5947f 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c | |||
@@ -745,25 +745,6 @@ ia64_sync_fph (struct task_struct *task) | |||
745 | psr->dfh = 1; | 745 | psr->dfh = 1; |
746 | } | 746 | } |
747 | 747 | ||
748 | static int | ||
749 | access_fr (struct unw_frame_info *info, int regnum, int hi, | ||
750 | unsigned long *data, int write_access) | ||
751 | { | ||
752 | struct ia64_fpreg fpval; | ||
753 | int ret; | ||
754 | |||
755 | ret = unw_get_fr(info, regnum, &fpval); | ||
756 | if (ret < 0) | ||
757 | return ret; | ||
758 | |||
759 | if (write_access) { | ||
760 | fpval.u.bits[hi] = *data; | ||
761 | ret = unw_set_fr(info, regnum, fpval); | ||
762 | } else | ||
763 | *data = fpval.u.bits[hi]; | ||
764 | return ret; | ||
765 | } | ||
766 | |||
767 | /* | 748 | /* |
768 | * Change the machine-state of CHILD such that it will return via the normal | 749 | * Change the machine-state of CHILD such that it will return via the normal |
769 | * kernel exit-path, rather than the syscall-exit path. | 750 | * kernel exit-path, rather than the syscall-exit path. |
@@ -865,309 +846,7 @@ access_nat_bits (struct task_struct *child, struct pt_regs *pt, | |||
865 | 846 | ||
866 | static int | 847 | static int |
867 | access_uarea (struct task_struct *child, unsigned long addr, | 848 | access_uarea (struct task_struct *child, unsigned long addr, |
868 | unsigned long *data, int write_access) | 849 | unsigned long *data, int write_access); |
869 | { | ||
870 | unsigned long *ptr, regnum, urbs_end, cfm; | ||
871 | struct switch_stack *sw; | ||
872 | struct pt_regs *pt; | ||
873 | # define pt_reg_addr(pt, reg) ((void *) \ | ||
874 | ((unsigned long) (pt) \ | ||
875 | + offsetof(struct pt_regs, reg))) | ||
876 | |||
877 | |||
878 | pt = task_pt_regs(child); | ||
879 | sw = (struct switch_stack *) (child->thread.ksp + 16); | ||
880 | |||
881 | if ((addr & 0x7) != 0) { | ||
882 | dprintk("ptrace: unaligned register address 0x%lx\n", addr); | ||
883 | return -1; | ||
884 | } | ||
885 | |||
886 | if (addr < PT_F127 + 16) { | ||
887 | /* accessing fph */ | ||
888 | if (write_access) | ||
889 | ia64_sync_fph(child); | ||
890 | else | ||
891 | ia64_flush_fph(child); | ||
892 | ptr = (unsigned long *) | ||
893 | ((unsigned long) &child->thread.fph + addr); | ||
894 | } else if ((addr >= PT_F10) && (addr < PT_F11 + 16)) { | ||
895 | /* scratch registers untouched by kernel (saved in pt_regs) */ | ||
896 | ptr = pt_reg_addr(pt, f10) + (addr - PT_F10); | ||
897 | } else if (addr >= PT_F12 && addr < PT_F15 + 16) { | ||
898 | /* | ||
899 | * Scratch registers untouched by kernel (saved in | ||
900 | * switch_stack). | ||
901 | */ | ||
902 | ptr = (unsigned long *) ((long) sw | ||
903 | + (addr - PT_NAT_BITS - 32)); | ||
904 | } else if (addr < PT_AR_LC + 8) { | ||
905 | /* preserved state: */ | ||
906 | struct unw_frame_info info; | ||
907 | char nat = 0; | ||
908 | int ret; | ||
909 | |||
910 | unw_init_from_blocked_task(&info, child); | ||
911 | if (unw_unwind_to_user(&info) < 0) | ||
912 | return -1; | ||
913 | |||
914 | switch (addr) { | ||
915 | case PT_NAT_BITS: | ||
916 | return access_nat_bits(child, pt, &info, | ||
917 | data, write_access); | ||
918 | |||
919 | case PT_R4: case PT_R5: case PT_R6: case PT_R7: | ||
920 | if (write_access) { | ||
921 | /* read NaT bit first: */ | ||
922 | unsigned long dummy; | ||
923 | |||
924 | ret = unw_get_gr(&info, (addr - PT_R4)/8 + 4, | ||
925 | &dummy, &nat); | ||
926 | if (ret < 0) | ||
927 | return ret; | ||
928 | } | ||
929 | return unw_access_gr(&info, (addr - PT_R4)/8 + 4, data, | ||
930 | &nat, write_access); | ||
931 | |||
932 | case PT_B1: case PT_B2: case PT_B3: | ||
933 | case PT_B4: case PT_B5: | ||
934 | return unw_access_br(&info, (addr - PT_B1)/8 + 1, data, | ||
935 | write_access); | ||
936 | |||
937 | case PT_AR_EC: | ||
938 | return unw_access_ar(&info, UNW_AR_EC, data, | ||
939 | write_access); | ||
940 | |||
941 | case PT_AR_LC: | ||
942 | return unw_access_ar(&info, UNW_AR_LC, data, | ||
943 | write_access); | ||
944 | |||
945 | default: | ||
946 | if (addr >= PT_F2 && addr < PT_F5 + 16) | ||
947 | return access_fr(&info, (addr - PT_F2)/16 + 2, | ||
948 | (addr & 8) != 0, data, | ||
949 | write_access); | ||
950 | else if (addr >= PT_F16 && addr < PT_F31 + 16) | ||
951 | return access_fr(&info, | ||
952 | (addr - PT_F16)/16 + 16, | ||
953 | (addr & 8) != 0, | ||
954 | data, write_access); | ||
955 | else { | ||
956 | dprintk("ptrace: rejecting access to register " | ||
957 | "address 0x%lx\n", addr); | ||
958 | return -1; | ||
959 | } | ||
960 | } | ||
961 | } else if (addr < PT_F9+16) { | ||
962 | /* scratch state */ | ||
963 | switch (addr) { | ||
964 | case PT_AR_BSP: | ||
965 | /* | ||
966 | * By convention, we use PT_AR_BSP to refer to | ||
967 | * the end of the user-level backing store. | ||
968 | * Use ia64_rse_skip_regs(PT_AR_BSP, -CFM.sof) | ||
969 | * to get the real value of ar.bsp at the time | ||
970 | * the kernel was entered. | ||
971 | * | ||
972 | * Furthermore, when changing the contents of | ||
973 | * PT_AR_BSP (or PT_CFM) while the task is | ||
974 | * blocked in a system call, convert the state | ||
975 | * so that the non-system-call exit | ||
976 | * path is used. This ensures that the proper | ||
977 | * state will be picked up when resuming | ||
978 | * execution. However, it *also* means that | ||
979 | * once we write PT_AR_BSP/PT_CFM, it won't be | ||
980 | * possible to modify the syscall arguments of | ||
981 | * the pending system call any longer. This | ||
982 | * shouldn't be an issue because modifying | ||
983 | * PT_AR_BSP/PT_CFM generally implies that | ||
984 | * we're either abandoning the pending system | ||
985 | * call or that we defer it's re-execution | ||
986 | * (e.g., due to GDB doing an inferior | ||
987 | * function call). | ||
988 | */ | ||
989 | urbs_end = ia64_get_user_rbs_end(child, pt, &cfm); | ||
990 | if (write_access) { | ||
991 | if (*data != urbs_end) { | ||
992 | if (in_syscall(pt)) | ||
993 | convert_to_non_syscall(child, | ||
994 | pt, | ||
995 | cfm); | ||
996 | /* | ||
997 | * Simulate user-level write | ||
998 | * of ar.bsp: | ||
999 | */ | ||
1000 | pt->loadrs = 0; | ||
1001 | pt->ar_bspstore = *data; | ||
1002 | } | ||
1003 | } else | ||
1004 | *data = urbs_end; | ||
1005 | return 0; | ||
1006 | |||
1007 | case PT_CFM: | ||
1008 | urbs_end = ia64_get_user_rbs_end(child, pt, &cfm); | ||
1009 | if (write_access) { | ||
1010 | if (((cfm ^ *data) & PFM_MASK) != 0) { | ||
1011 | if (in_syscall(pt)) | ||
1012 | convert_to_non_syscall(child, | ||
1013 | pt, | ||
1014 | cfm); | ||
1015 | pt->cr_ifs = ((pt->cr_ifs & ~PFM_MASK) | ||
1016 | | (*data & PFM_MASK)); | ||
1017 | } | ||
1018 | } else | ||
1019 | *data = cfm; | ||
1020 | return 0; | ||
1021 | |||
1022 | case PT_CR_IPSR: | ||
1023 | if (write_access) { | ||
1024 | unsigned long tmp = *data; | ||
1025 | /* psr.ri==3 is a reserved value: SDM 2:25 */ | ||
1026 | if ((tmp & IA64_PSR_RI) == IA64_PSR_RI) | ||
1027 | tmp &= ~IA64_PSR_RI; | ||
1028 | pt->cr_ipsr = ((tmp & IPSR_MASK) | ||
1029 | | (pt->cr_ipsr & ~IPSR_MASK)); | ||
1030 | } else | ||
1031 | *data = (pt->cr_ipsr & IPSR_MASK); | ||
1032 | return 0; | ||
1033 | |||
1034 | case PT_AR_RSC: | ||
1035 | if (write_access) | ||
1036 | pt->ar_rsc = *data | (3 << 2); /* force PL3 */ | ||
1037 | else | ||
1038 | *data = pt->ar_rsc; | ||
1039 | return 0; | ||
1040 | |||
1041 | case PT_AR_RNAT: | ||
1042 | ptr = pt_reg_addr(pt, ar_rnat); | ||
1043 | break; | ||
1044 | case PT_R1: | ||
1045 | ptr = pt_reg_addr(pt, r1); | ||
1046 | break; | ||
1047 | case PT_R2: case PT_R3: | ||
1048 | ptr = pt_reg_addr(pt, r2) + (addr - PT_R2); | ||
1049 | break; | ||
1050 | case PT_R8: case PT_R9: case PT_R10: case PT_R11: | ||
1051 | ptr = pt_reg_addr(pt, r8) + (addr - PT_R8); | ||
1052 | break; | ||
1053 | case PT_R12: case PT_R13: | ||
1054 | ptr = pt_reg_addr(pt, r12) + (addr - PT_R12); | ||
1055 | break; | ||
1056 | case PT_R14: | ||
1057 | ptr = pt_reg_addr(pt, r14); | ||
1058 | break; | ||
1059 | case PT_R15: | ||
1060 | ptr = pt_reg_addr(pt, r15); | ||
1061 | break; | ||
1062 | case PT_R16: case PT_R17: case PT_R18: case PT_R19: | ||
1063 | case PT_R20: case PT_R21: case PT_R22: case PT_R23: | ||
1064 | case PT_R24: case PT_R25: case PT_R26: case PT_R27: | ||
1065 | case PT_R28: case PT_R29: case PT_R30: case PT_R31: | ||
1066 | ptr = pt_reg_addr(pt, r16) + (addr - PT_R16); | ||
1067 | break; | ||
1068 | case PT_B0: | ||
1069 | ptr = pt_reg_addr(pt, b0); | ||
1070 | break; | ||
1071 | case PT_B6: | ||
1072 | ptr = pt_reg_addr(pt, b6); | ||
1073 | break; | ||
1074 | case PT_B7: | ||
1075 | ptr = pt_reg_addr(pt, b7); | ||
1076 | break; | ||
1077 | case PT_F6: case PT_F6+8: case PT_F7: case PT_F7+8: | ||
1078 | case PT_F8: case PT_F8+8: case PT_F9: case PT_F9+8: | ||
1079 | ptr = pt_reg_addr(pt, f6) + (addr - PT_F6); | ||
1080 | break; | ||
1081 | case PT_AR_BSPSTORE: | ||
1082 | ptr = pt_reg_addr(pt, ar_bspstore); | ||
1083 | break; | ||
1084 | case PT_AR_UNAT: | ||
1085 | ptr = pt_reg_addr(pt, ar_unat); | ||
1086 | break; | ||
1087 | case PT_AR_PFS: | ||
1088 | ptr = pt_reg_addr(pt, ar_pfs); | ||
1089 | break; | ||
1090 | case PT_AR_CCV: | ||
1091 | ptr = pt_reg_addr(pt, ar_ccv); | ||
1092 | break; | ||
1093 | case PT_AR_FPSR: | ||
1094 | ptr = pt_reg_addr(pt, ar_fpsr); | ||
1095 | break; | ||
1096 | case PT_CR_IIP: | ||
1097 | ptr = pt_reg_addr(pt, cr_iip); | ||
1098 | break; | ||
1099 | case PT_PR: | ||
1100 | ptr = pt_reg_addr(pt, pr); | ||
1101 | break; | ||
1102 | /* scratch register */ | ||
1103 | |||
1104 | default: | ||
1105 | /* disallow accessing anything else... */ | ||
1106 | dprintk("ptrace: rejecting access to register " | ||
1107 | "address 0x%lx\n", addr); | ||
1108 | return -1; | ||
1109 | } | ||
1110 | } else if (addr <= PT_AR_SSD) { | ||
1111 | ptr = pt_reg_addr(pt, ar_csd) + (addr - PT_AR_CSD); | ||
1112 | } else { | ||
1113 | /* access debug registers */ | ||
1114 | |||
1115 | if (addr >= PT_IBR) { | ||
1116 | regnum = (addr - PT_IBR) >> 3; | ||
1117 | ptr = &child->thread.ibr[0]; | ||
1118 | } else { | ||
1119 | regnum = (addr - PT_DBR) >> 3; | ||
1120 | ptr = &child->thread.dbr[0]; | ||
1121 | } | ||
1122 | |||
1123 | if (regnum >= 8) { | ||
1124 | dprintk("ptrace: rejecting access to register " | ||
1125 | "address 0x%lx\n", addr); | ||
1126 | return -1; | ||
1127 | } | ||
1128 | #ifdef CONFIG_PERFMON | ||
1129 | /* | ||
1130 | * Check if debug registers are used by perfmon. This | ||
1131 | * test must be done once we know that we can do the | ||
1132 | * operation, i.e. the arguments are all valid, but | ||
1133 | * before we start modifying the state. | ||
1134 | * | ||
1135 | * Perfmon needs to keep a count of how many processes | ||
1136 | * are trying to modify the debug registers for system | ||
1137 | * wide monitoring sessions. | ||
1138 | * | ||
1139 | * We also include read access here, because they may | ||
1140 | * cause the PMU-installed debug register state | ||
1141 | * (dbr[], ibr[]) to be reset. The two arrays are also | ||
1142 | * used by perfmon, but we do not use | ||
1143 | * IA64_THREAD_DBG_VALID. The registers are restored | ||
1144 | * by the PMU context switch code. | ||
1145 | */ | ||
1146 | if (pfm_use_debug_registers(child)) return -1; | ||
1147 | #endif | ||
1148 | |||
1149 | if (!(child->thread.flags & IA64_THREAD_DBG_VALID)) { | ||
1150 | child->thread.flags |= IA64_THREAD_DBG_VALID; | ||
1151 | memset(child->thread.dbr, 0, | ||
1152 | sizeof(child->thread.dbr)); | ||
1153 | memset(child->thread.ibr, 0, | ||
1154 | sizeof(child->thread.ibr)); | ||
1155 | } | ||
1156 | |||
1157 | ptr += regnum; | ||
1158 | |||
1159 | if ((regnum & 1) && write_access) { | ||
1160 | /* don't let the user set kernel-level breakpoints: */ | ||
1161 | *ptr = *data & ~(7UL << 56); | ||
1162 | return 0; | ||
1163 | } | ||
1164 | } | ||
1165 | if (write_access) | ||
1166 | *ptr = *data; | ||
1167 | else | ||
1168 | *data = *ptr; | ||
1169 | return 0; | ||
1170 | } | ||
1171 | 850 | ||
1172 | static long | 851 | static long |
1173 | ptrace_getregs (struct task_struct *child, struct pt_all_user_regs __user *ppr) | 852 | ptrace_getregs (struct task_struct *child, struct pt_all_user_regs __user *ppr) |
@@ -2290,6 +1969,205 @@ static int fpregs_set(struct task_struct *target, | |||
2290 | kbuf, ubuf); | 1969 | kbuf, ubuf); |
2291 | } | 1970 | } |
2292 | 1971 | ||
1972 | static int | ||
1973 | access_uarea(struct task_struct *child, unsigned long addr, | ||
1974 | unsigned long *data, int write_access) | ||
1975 | { | ||
1976 | unsigned int pos = -1; /* an invalid value */ | ||
1977 | int ret; | ||
1978 | unsigned long *ptr, regnum; | ||
1979 | |||
1980 | if ((addr & 0x7) != 0) { | ||
1981 | dprintk("ptrace: unaligned register address 0x%lx\n", addr); | ||
1982 | return -1; | ||
1983 | } | ||
1984 | if ((addr >= PT_NAT_BITS + 8 && addr < PT_F2) || | ||
1985 | (addr >= PT_R7 + 8 && addr < PT_B1) || | ||
1986 | (addr >= PT_AR_LC + 8 && addr < PT_CR_IPSR) || | ||
1987 | (addr >= PT_AR_SSD + 8 && addr < PT_DBR)) { | ||
1988 | dprintk("ptrace: rejecting access to register " | ||
1989 | "address 0x%lx\n", addr); | ||
1990 | return -1; | ||
1991 | } | ||
1992 | |||
1993 | switch (addr) { | ||
1994 | case PT_F32 ... (PT_F127 + 15): | ||
1995 | pos = addr - PT_F32 + ELF_FP_OFFSET(32); | ||
1996 | break; | ||
1997 | case PT_F2 ... (PT_F5 + 15): | ||
1998 | pos = addr - PT_F2 + ELF_FP_OFFSET(2); | ||
1999 | break; | ||
2000 | case PT_F10 ... (PT_F31 + 15): | ||
2001 | pos = addr - PT_F10 + ELF_FP_OFFSET(10); | ||
2002 | break; | ||
2003 | case PT_F6 ... (PT_F9 + 15): | ||
2004 | pos = addr - PT_F6 + ELF_FP_OFFSET(6); | ||
2005 | break; | ||
2006 | } | ||
2007 | |||
2008 | if (pos != -1) { | ||
2009 | if (write_access) | ||
2010 | ret = fpregs_set(child, NULL, pos, | ||
2011 | sizeof(unsigned long), data, NULL); | ||
2012 | else | ||
2013 | ret = fpregs_get(child, NULL, pos, | ||
2014 | sizeof(unsigned long), data, NULL); | ||
2015 | if (ret != 0) | ||
2016 | return -1; | ||
2017 | return 0; | ||
2018 | } | ||
2019 | |||
2020 | switch (addr) { | ||
2021 | case PT_NAT_BITS: | ||
2022 | pos = ELF_NAT_OFFSET; | ||
2023 | break; | ||
2024 | case PT_R4 ... PT_R7: | ||
2025 | pos = addr - PT_R4 + ELF_GR_OFFSET(4); | ||
2026 | break; | ||
2027 | case PT_B1 ... PT_B5: | ||
2028 | pos = addr - PT_B1 + ELF_BR_OFFSET(1); | ||
2029 | break; | ||
2030 | case PT_AR_EC: | ||
2031 | pos = ELF_AR_EC_OFFSET; | ||
2032 | break; | ||
2033 | case PT_AR_LC: | ||
2034 | pos = ELF_AR_LC_OFFSET; | ||
2035 | break; | ||
2036 | case PT_CR_IPSR: | ||
2037 | pos = ELF_CR_IPSR_OFFSET; | ||
2038 | break; | ||
2039 | case PT_CR_IIP: | ||
2040 | pos = ELF_CR_IIP_OFFSET; | ||
2041 | break; | ||
2042 | case PT_CFM: | ||
2043 | pos = ELF_CFM_OFFSET; | ||
2044 | break; | ||
2045 | case PT_AR_UNAT: | ||
2046 | pos = ELF_AR_UNAT_OFFSET; | ||
2047 | break; | ||
2048 | case PT_AR_PFS: | ||
2049 | pos = ELF_AR_PFS_OFFSET; | ||
2050 | break; | ||
2051 | case PT_AR_RSC: | ||
2052 | pos = ELF_AR_RSC_OFFSET; | ||
2053 | break; | ||
2054 | case PT_AR_RNAT: | ||
2055 | pos = ELF_AR_RNAT_OFFSET; | ||
2056 | break; | ||
2057 | case PT_AR_BSPSTORE: | ||
2058 | pos = ELF_AR_BSPSTORE_OFFSET; | ||
2059 | break; | ||
2060 | case PT_PR: | ||
2061 | pos = ELF_PR_OFFSET; | ||
2062 | break; | ||
2063 | case PT_B6: | ||
2064 | pos = ELF_BR_OFFSET(6); | ||
2065 | break; | ||
2066 | case PT_AR_BSP: | ||
2067 | pos = ELF_AR_BSP_OFFSET; | ||
2068 | break; | ||
2069 | case PT_R1 ... PT_R3: | ||
2070 | pos = addr - PT_R1 + ELF_GR_OFFSET(1); | ||
2071 | break; | ||
2072 | case PT_R12 ... PT_R15: | ||
2073 | pos = addr - PT_R12 + ELF_GR_OFFSET(12); | ||
2074 | break; | ||
2075 | case PT_R8 ... PT_R11: | ||
2076 | pos = addr - PT_R8 + ELF_GR_OFFSET(8); | ||
2077 | break; | ||
2078 | case PT_R16 ... PT_R31: | ||
2079 | pos = addr - PT_R16 + ELF_GR_OFFSET(16); | ||
2080 | break; | ||
2081 | case PT_AR_CCV: | ||
2082 | pos = ELF_AR_CCV_OFFSET; | ||
2083 | break; | ||
2084 | case PT_AR_FPSR: | ||
2085 | pos = ELF_AR_FPSR_OFFSET; | ||
2086 | break; | ||
2087 | case PT_B0: | ||
2088 | pos = ELF_BR_OFFSET(0); | ||
2089 | break; | ||
2090 | case PT_B7: | ||
2091 | pos = ELF_BR_OFFSET(7); | ||
2092 | break; | ||
2093 | case PT_AR_CSD: | ||
2094 | pos = ELF_AR_CSD_OFFSET; | ||
2095 | break; | ||
2096 | case PT_AR_SSD: | ||
2097 | pos = ELF_AR_SSD_OFFSET; | ||
2098 | break; | ||
2099 | } | ||
2100 | |||
2101 | if (pos != -1) { | ||
2102 | if (write_access) | ||
2103 | ret = gpregs_set(child, NULL, pos, | ||
2104 | sizeof(unsigned long), data, NULL); | ||
2105 | else | ||
2106 | ret = gpregs_get(child, NULL, pos, | ||
2107 | sizeof(unsigned long), data, NULL); | ||
2108 | if (ret != 0) | ||
2109 | return -1; | ||
2110 | return 0; | ||
2111 | } | ||
2112 | |||
2113 | /* access debug registers */ | ||
2114 | if (addr >= PT_IBR) { | ||
2115 | regnum = (addr - PT_IBR) >> 3; | ||
2116 | ptr = &child->thread.ibr[0]; | ||
2117 | } else { | ||
2118 | regnum = (addr - PT_DBR) >> 3; | ||
2119 | ptr = &child->thread.dbr[0]; | ||
2120 | } | ||
2121 | |||
2122 | if (regnum >= 8) { | ||
2123 | dprintk("ptrace: rejecting access to register " | ||
2124 | "address 0x%lx\n", addr); | ||
2125 | return -1; | ||
2126 | } | ||
2127 | #ifdef CONFIG_PERFMON | ||
2128 | /* | ||
2129 | * Check if debug registers are used by perfmon. This | ||
2130 | * test must be done once we know that we can do the | ||
2131 | * operation, i.e. the arguments are all valid, but | ||
2132 | * before we start modifying the state. | ||
2133 | * | ||
2134 | * Perfmon needs to keep a count of how many processes | ||
2135 | * are trying to modify the debug registers for system | ||
2136 | * wide monitoring sessions. | ||
2137 | * | ||
2138 | * We also include read access here, because they may | ||
2139 | * cause the PMU-installed debug register state | ||
2140 | * (dbr[], ibr[]) to be reset. The two arrays are also | ||
2141 | * used by perfmon, but we do not use | ||
2142 | * IA64_THREAD_DBG_VALID. The registers are restored | ||
2143 | * by the PMU context switch code. | ||
2144 | */ | ||
2145 | if (pfm_use_debug_registers(child)) | ||
2146 | return -1; | ||
2147 | #endif | ||
2148 | |||
2149 | if (!(child->thread.flags & IA64_THREAD_DBG_VALID)) { | ||
2150 | child->thread.flags |= IA64_THREAD_DBG_VALID; | ||
2151 | memset(child->thread.dbr, 0, | ||
2152 | sizeof(child->thread.dbr)); | ||
2153 | memset(child->thread.ibr, 0, | ||
2154 | sizeof(child->thread.ibr)); | ||
2155 | } | ||
2156 | |||
2157 | ptr += regnum; | ||
2158 | |||
2159 | if ((regnum & 1) && write_access) { | ||
2160 | /* don't let the user set kernel-level breakpoints: */ | ||
2161 | *ptr = *data & ~(7UL << 56); | ||
2162 | return 0; | ||
2163 | } | ||
2164 | if (write_access) | ||
2165 | *ptr = *data; | ||
2166 | else | ||
2167 | *data = *ptr; | ||
2168 | return 0; | ||
2169 | } | ||
2170 | |||
2293 | static const struct user_regset native_regsets[] = { | 2171 | static const struct user_regset native_regsets[] = { |
2294 | { | 2172 | { |
2295 | .core_note_type = NT_PRSTATUS, | 2173 | .core_note_type = NT_PRSTATUS, |