1*4882a593Smuzhiyun /* SPDX-License-Identifier: GPL-2.0 */
2*4882a593Smuzhiyun #ifndef _ASM_IA64_UNWIND_H
3*4882a593Smuzhiyun #define _ASM_IA64_UNWIND_H
4*4882a593Smuzhiyun
5*4882a593Smuzhiyun /*
6*4882a593Smuzhiyun * Copyright (C) 1999-2000, 2003 Hewlett-Packard Co
7*4882a593Smuzhiyun * David Mosberger-Tang <davidm@hpl.hp.com>
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * A simple API for unwinding kernel stacks. This is used for
10*4882a593Smuzhiyun * debugging and error reporting purposes. The kernel doesn't need
11*4882a593Smuzhiyun * full-blown stack unwinding with all the bells and whitles, so there
12*4882a593Smuzhiyun * is not much point in implementing the full IA-64 unwind API (though
13*4882a593Smuzhiyun * it would of course be possible to implement the kernel API on top
14*4882a593Smuzhiyun * of it).
15*4882a593Smuzhiyun */
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun struct task_struct; /* forward declaration */
18*4882a593Smuzhiyun struct switch_stack; /* forward declaration */
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun enum unw_application_register {
21*4882a593Smuzhiyun UNW_AR_BSP,
22*4882a593Smuzhiyun UNW_AR_BSPSTORE,
23*4882a593Smuzhiyun UNW_AR_PFS,
24*4882a593Smuzhiyun UNW_AR_RNAT,
25*4882a593Smuzhiyun UNW_AR_UNAT,
26*4882a593Smuzhiyun UNW_AR_LC,
27*4882a593Smuzhiyun UNW_AR_EC,
28*4882a593Smuzhiyun UNW_AR_FPSR,
29*4882a593Smuzhiyun UNW_AR_RSC,
30*4882a593Smuzhiyun UNW_AR_CCV,
31*4882a593Smuzhiyun UNW_AR_CSD,
32*4882a593Smuzhiyun UNW_AR_SSD
33*4882a593Smuzhiyun };
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun /*
36*4882a593Smuzhiyun * The following declarations are private to the unwind
37*4882a593Smuzhiyun * implementation:
38*4882a593Smuzhiyun */
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun struct unw_stack {
41*4882a593Smuzhiyun unsigned long limit;
42*4882a593Smuzhiyun unsigned long top;
43*4882a593Smuzhiyun };
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun #define UNW_FLAG_INTERRUPT_FRAME (1UL << 0)
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun /*
48*4882a593Smuzhiyun * No user of this module should every access this structure directly
49*4882a593Smuzhiyun * as it is subject to change. It is declared here solely so we can
50*4882a593Smuzhiyun * use automatic variables.
51*4882a593Smuzhiyun */
52*4882a593Smuzhiyun struct unw_frame_info {
53*4882a593Smuzhiyun struct unw_stack regstk;
54*4882a593Smuzhiyun struct unw_stack memstk;
55*4882a593Smuzhiyun unsigned int flags;
56*4882a593Smuzhiyun short hint;
57*4882a593Smuzhiyun short prev_script;
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun /* current frame info: */
60*4882a593Smuzhiyun unsigned long bsp; /* backing store pointer value */
61*4882a593Smuzhiyun unsigned long sp; /* stack pointer value */
62*4882a593Smuzhiyun unsigned long psp; /* previous sp value */
63*4882a593Smuzhiyun unsigned long ip; /* instruction pointer value */
64*4882a593Smuzhiyun unsigned long pr; /* current predicate values */
65*4882a593Smuzhiyun unsigned long *cfm_loc; /* cfm save location (or NULL) */
66*4882a593Smuzhiyun unsigned long pt; /* struct pt_regs location */
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun struct task_struct *task;
69*4882a593Smuzhiyun struct switch_stack *sw;
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun /* preserved state: */
72*4882a593Smuzhiyun unsigned long *bsp_loc; /* previous bsp save location */
73*4882a593Smuzhiyun unsigned long *bspstore_loc;
74*4882a593Smuzhiyun unsigned long *pfs_loc;
75*4882a593Smuzhiyun unsigned long *rnat_loc;
76*4882a593Smuzhiyun unsigned long *rp_loc;
77*4882a593Smuzhiyun unsigned long *pri_unat_loc;
78*4882a593Smuzhiyun unsigned long *unat_loc;
79*4882a593Smuzhiyun unsigned long *pr_loc;
80*4882a593Smuzhiyun unsigned long *lc_loc;
81*4882a593Smuzhiyun unsigned long *fpsr_loc;
82*4882a593Smuzhiyun struct unw_ireg {
83*4882a593Smuzhiyun unsigned long *loc;
84*4882a593Smuzhiyun struct unw_ireg_nat {
85*4882a593Smuzhiyun unsigned long type : 3; /* enum unw_nat_type */
86*4882a593Smuzhiyun signed long off : 61; /* NaT word is at loc+nat.off */
87*4882a593Smuzhiyun } nat;
88*4882a593Smuzhiyun } r4, r5, r6, r7;
89*4882a593Smuzhiyun unsigned long *b1_loc, *b2_loc, *b3_loc, *b4_loc, *b5_loc;
90*4882a593Smuzhiyun struct ia64_fpreg *f2_loc, *f3_loc, *f4_loc, *f5_loc, *fr_loc[16];
91*4882a593Smuzhiyun };
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun /*
94*4882a593Smuzhiyun * The official API follows below:
95*4882a593Smuzhiyun */
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun struct unw_table_entry {
98*4882a593Smuzhiyun u64 start_offset;
99*4882a593Smuzhiyun u64 end_offset;
100*4882a593Smuzhiyun u64 info_offset;
101*4882a593Smuzhiyun };
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun /*
104*4882a593Smuzhiyun * Initialize unwind support.
105*4882a593Smuzhiyun */
106*4882a593Smuzhiyun extern void unw_init (void);
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun extern void *unw_add_unwind_table (const char *name, unsigned long segment_base, unsigned long gp,
109*4882a593Smuzhiyun const void *table_start, const void *table_end);
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun extern void unw_remove_unwind_table (void *handle);
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun /*
114*4882a593Smuzhiyun * Prepare to unwind blocked task t.
115*4882a593Smuzhiyun */
116*4882a593Smuzhiyun extern void unw_init_from_blocked_task (struct unw_frame_info *info, struct task_struct *t);
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun extern void unw_init_frame_info (struct unw_frame_info *info, struct task_struct *t,
119*4882a593Smuzhiyun struct switch_stack *sw);
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun /*
122*4882a593Smuzhiyun * Prepare to unwind the currently running thread.
123*4882a593Smuzhiyun */
124*4882a593Smuzhiyun extern void unw_init_running (void (*callback)(struct unw_frame_info *info, void *arg), void *arg);
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun /*
127*4882a593Smuzhiyun * Unwind to previous to frame. Returns 0 if successful, negative
128*4882a593Smuzhiyun * number in case of an error.
129*4882a593Smuzhiyun */
130*4882a593Smuzhiyun extern int unw_unwind (struct unw_frame_info *info);
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun /*
133*4882a593Smuzhiyun * Unwind until the return pointer is in user-land (or until an error
134*4882a593Smuzhiyun * occurs). Returns 0 if successful, negative number in case of
135*4882a593Smuzhiyun * error.
136*4882a593Smuzhiyun */
137*4882a593Smuzhiyun extern int unw_unwind_to_user (struct unw_frame_info *info);
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun #define unw_is_intr_frame(info) (((info)->flags & UNW_FLAG_INTERRUPT_FRAME) != 0)
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun static inline int
unw_get_ip(struct unw_frame_info * info,unsigned long * valp)142*4882a593Smuzhiyun unw_get_ip (struct unw_frame_info *info, unsigned long *valp)
143*4882a593Smuzhiyun {
144*4882a593Smuzhiyun *valp = (info)->ip;
145*4882a593Smuzhiyun return 0;
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun static inline int
unw_get_sp(struct unw_frame_info * info,unsigned long * valp)149*4882a593Smuzhiyun unw_get_sp (struct unw_frame_info *info, unsigned long *valp)
150*4882a593Smuzhiyun {
151*4882a593Smuzhiyun *valp = (info)->sp;
152*4882a593Smuzhiyun return 0;
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun static inline int
unw_get_psp(struct unw_frame_info * info,unsigned long * valp)156*4882a593Smuzhiyun unw_get_psp (struct unw_frame_info *info, unsigned long *valp)
157*4882a593Smuzhiyun {
158*4882a593Smuzhiyun *valp = (info)->psp;
159*4882a593Smuzhiyun return 0;
160*4882a593Smuzhiyun }
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun static inline int
unw_get_bsp(struct unw_frame_info * info,unsigned long * valp)163*4882a593Smuzhiyun unw_get_bsp (struct unw_frame_info *info, unsigned long *valp)
164*4882a593Smuzhiyun {
165*4882a593Smuzhiyun *valp = (info)->bsp;
166*4882a593Smuzhiyun return 0;
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun static inline int
unw_get_cfm(struct unw_frame_info * info,unsigned long * valp)170*4882a593Smuzhiyun unw_get_cfm (struct unw_frame_info *info, unsigned long *valp)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun *valp = *(info)->cfm_loc;
173*4882a593Smuzhiyun return 0;
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun static inline int
unw_set_cfm(struct unw_frame_info * info,unsigned long val)177*4882a593Smuzhiyun unw_set_cfm (struct unw_frame_info *info, unsigned long val)
178*4882a593Smuzhiyun {
179*4882a593Smuzhiyun *(info)->cfm_loc = val;
180*4882a593Smuzhiyun return 0;
181*4882a593Smuzhiyun }
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun static inline int
unw_get_rp(struct unw_frame_info * info,unsigned long * val)184*4882a593Smuzhiyun unw_get_rp (struct unw_frame_info *info, unsigned long *val)
185*4882a593Smuzhiyun {
186*4882a593Smuzhiyun if (!info->rp_loc)
187*4882a593Smuzhiyun return -1;
188*4882a593Smuzhiyun *val = *info->rp_loc;
189*4882a593Smuzhiyun return 0;
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun extern int unw_access_gr (struct unw_frame_info *, int, unsigned long *, char *, int);
193*4882a593Smuzhiyun extern int unw_access_br (struct unw_frame_info *, int, unsigned long *, int);
194*4882a593Smuzhiyun extern int unw_access_fr (struct unw_frame_info *, int, struct ia64_fpreg *, int);
195*4882a593Smuzhiyun extern int unw_access_ar (struct unw_frame_info *, int, unsigned long *, int);
196*4882a593Smuzhiyun extern int unw_access_pr (struct unw_frame_info *, unsigned long *, int);
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun static inline int
unw_set_gr(struct unw_frame_info * i,int n,unsigned long v,char nat)199*4882a593Smuzhiyun unw_set_gr (struct unw_frame_info *i, int n, unsigned long v, char nat)
200*4882a593Smuzhiyun {
201*4882a593Smuzhiyun return unw_access_gr(i, n, &v, &nat, 1);
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun static inline int
unw_set_br(struct unw_frame_info * i,int n,unsigned long v)205*4882a593Smuzhiyun unw_set_br (struct unw_frame_info *i, int n, unsigned long v)
206*4882a593Smuzhiyun {
207*4882a593Smuzhiyun return unw_access_br(i, n, &v, 1);
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun static inline int
unw_set_fr(struct unw_frame_info * i,int n,struct ia64_fpreg v)211*4882a593Smuzhiyun unw_set_fr (struct unw_frame_info *i, int n, struct ia64_fpreg v)
212*4882a593Smuzhiyun {
213*4882a593Smuzhiyun return unw_access_fr(i, n, &v, 1);
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun static inline int
unw_set_ar(struct unw_frame_info * i,int n,unsigned long v)217*4882a593Smuzhiyun unw_set_ar (struct unw_frame_info *i, int n, unsigned long v)
218*4882a593Smuzhiyun {
219*4882a593Smuzhiyun return unw_access_ar(i, n, &v, 1);
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun static inline int
unw_set_pr(struct unw_frame_info * i,unsigned long v)223*4882a593Smuzhiyun unw_set_pr (struct unw_frame_info *i, unsigned long v)
224*4882a593Smuzhiyun {
225*4882a593Smuzhiyun return unw_access_pr(i, &v, 1);
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun #define unw_get_gr(i,n,v,nat) unw_access_gr(i,n,v,nat,0)
229*4882a593Smuzhiyun #define unw_get_br(i,n,v) unw_access_br(i,n,v,0)
230*4882a593Smuzhiyun #define unw_get_fr(i,n,v) unw_access_fr(i,n,v,0)
231*4882a593Smuzhiyun #define unw_get_ar(i,n,v) unw_access_ar(i,n,v,0)
232*4882a593Smuzhiyun #define unw_get_pr(i,v) unw_access_pr(i,v,0)
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun #endif /* _ASM_UNWIND_H */
235