xref: /openbmc/linux/arch/ia64/include/asm/unwind.h (revision 498495dba268b20e8eadd7fe93c140c68b6cc9d2)
1*b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */
27f30491cSTony Luck #ifndef _ASM_IA64_UNWIND_H
37f30491cSTony Luck #define _ASM_IA64_UNWIND_H
47f30491cSTony Luck 
57f30491cSTony Luck /*
67f30491cSTony Luck  * Copyright (C) 1999-2000, 2003 Hewlett-Packard Co
77f30491cSTony Luck  *	David Mosberger-Tang <davidm@hpl.hp.com>
87f30491cSTony Luck  *
97f30491cSTony Luck  * A simple API for unwinding kernel stacks.  This is used for
107f30491cSTony Luck  * debugging and error reporting purposes.  The kernel doesn't need
117f30491cSTony Luck  * full-blown stack unwinding with all the bells and whitles, so there
127f30491cSTony Luck  * is not much point in implementing the full IA-64 unwind API (though
137f30491cSTony Luck  * it would of course be possible to implement the kernel API on top
147f30491cSTony Luck  * of it).
157f30491cSTony Luck  */
167f30491cSTony Luck 
177f30491cSTony Luck struct task_struct;	/* forward declaration */
187f30491cSTony Luck struct switch_stack;	/* forward declaration */
197f30491cSTony Luck 
207f30491cSTony Luck enum unw_application_register {
217f30491cSTony Luck 	UNW_AR_BSP,
227f30491cSTony Luck 	UNW_AR_BSPSTORE,
237f30491cSTony Luck 	UNW_AR_PFS,
247f30491cSTony Luck 	UNW_AR_RNAT,
257f30491cSTony Luck 	UNW_AR_UNAT,
267f30491cSTony Luck 	UNW_AR_LC,
277f30491cSTony Luck 	UNW_AR_EC,
287f30491cSTony Luck 	UNW_AR_FPSR,
297f30491cSTony Luck 	UNW_AR_RSC,
307f30491cSTony Luck 	UNW_AR_CCV,
317f30491cSTony Luck 	UNW_AR_CSD,
327f30491cSTony Luck 	UNW_AR_SSD
337f30491cSTony Luck };
347f30491cSTony Luck 
357f30491cSTony Luck /*
367f30491cSTony Luck  * The following declarations are private to the unwind
377f30491cSTony Luck  * implementation:
387f30491cSTony Luck  */
397f30491cSTony Luck 
407f30491cSTony Luck struct unw_stack {
417f30491cSTony Luck 	unsigned long limit;
427f30491cSTony Luck 	unsigned long top;
437f30491cSTony Luck };
447f30491cSTony Luck 
457f30491cSTony Luck #define UNW_FLAG_INTERRUPT_FRAME	(1UL << 0)
467f30491cSTony Luck 
477f30491cSTony Luck /*
487f30491cSTony Luck  * No user of this module should every access this structure directly
497f30491cSTony Luck  * as it is subject to change.  It is declared here solely so we can
507f30491cSTony Luck  * use automatic variables.
517f30491cSTony Luck  */
527f30491cSTony Luck struct unw_frame_info {
537f30491cSTony Luck 	struct unw_stack regstk;
547f30491cSTony Luck 	struct unw_stack memstk;
557f30491cSTony Luck 	unsigned int flags;
567f30491cSTony Luck 	short hint;
577f30491cSTony Luck 	short prev_script;
587f30491cSTony Luck 
597f30491cSTony Luck 	/* current frame info: */
607f30491cSTony Luck 	unsigned long bsp;		/* backing store pointer value */
617f30491cSTony Luck 	unsigned long sp;		/* stack pointer value */
627f30491cSTony Luck 	unsigned long psp;		/* previous sp value */
637f30491cSTony Luck 	unsigned long ip;		/* instruction pointer value */
647f30491cSTony Luck 	unsigned long pr;		/* current predicate values */
657f30491cSTony Luck 	unsigned long *cfm_loc;		/* cfm save location (or NULL) */
667f30491cSTony Luck 	unsigned long pt;		/* struct pt_regs location */
677f30491cSTony Luck 
687f30491cSTony Luck 	struct task_struct *task;
697f30491cSTony Luck 	struct switch_stack *sw;
707f30491cSTony Luck 
717f30491cSTony Luck 	/* preserved state: */
727f30491cSTony Luck 	unsigned long *bsp_loc;		/* previous bsp save location */
737f30491cSTony Luck 	unsigned long *bspstore_loc;
747f30491cSTony Luck 	unsigned long *pfs_loc;
757f30491cSTony Luck 	unsigned long *rnat_loc;
767f30491cSTony Luck 	unsigned long *rp_loc;
777f30491cSTony Luck 	unsigned long *pri_unat_loc;
787f30491cSTony Luck 	unsigned long *unat_loc;
797f30491cSTony Luck 	unsigned long *pr_loc;
807f30491cSTony Luck 	unsigned long *lc_loc;
817f30491cSTony Luck 	unsigned long *fpsr_loc;
827f30491cSTony Luck 	struct unw_ireg {
837f30491cSTony Luck 		unsigned long *loc;
847f30491cSTony Luck 		struct unw_ireg_nat {
857f30491cSTony Luck 			unsigned long type : 3;		/* enum unw_nat_type */
867f30491cSTony Luck 			signed long off : 61;		/* NaT word is at loc+nat.off */
877f30491cSTony Luck 		} nat;
887f30491cSTony Luck 	} r4, r5, r6, r7;
897f30491cSTony Luck 	unsigned long *b1_loc, *b2_loc, *b3_loc, *b4_loc, *b5_loc;
907f30491cSTony Luck 	struct ia64_fpreg *f2_loc, *f3_loc, *f4_loc, *f5_loc, *fr_loc[16];
917f30491cSTony Luck };
927f30491cSTony Luck 
937f30491cSTony Luck /*
947f30491cSTony Luck  * The official API follows below:
957f30491cSTony Luck  */
967f30491cSTony Luck 
977f30491cSTony Luck struct unw_table_entry {
987f30491cSTony Luck 	u64 start_offset;
997f30491cSTony Luck 	u64 end_offset;
1007f30491cSTony Luck 	u64 info_offset;
1017f30491cSTony Luck };
1027f30491cSTony Luck 
1037f30491cSTony Luck /*
1047f30491cSTony Luck  * Initialize unwind support.
1057f30491cSTony Luck  */
1067f30491cSTony Luck extern void unw_init (void);
1077f30491cSTony Luck 
1087f30491cSTony Luck extern void *unw_add_unwind_table (const char *name, unsigned long segment_base, unsigned long gp,
1097f30491cSTony Luck 				   const void *table_start, const void *table_end);
1107f30491cSTony Luck 
1117f30491cSTony Luck extern void unw_remove_unwind_table (void *handle);
1127f30491cSTony Luck 
1137f30491cSTony Luck /*
1147f30491cSTony Luck  * Prepare to unwind blocked task t.
1157f30491cSTony Luck  */
1167f30491cSTony Luck extern void unw_init_from_blocked_task (struct unw_frame_info *info, struct task_struct *t);
1177f30491cSTony Luck 
1187f30491cSTony Luck extern void unw_init_frame_info (struct unw_frame_info *info, struct task_struct *t,
1197f30491cSTony Luck 				 struct switch_stack *sw);
1207f30491cSTony Luck 
1217f30491cSTony Luck /*
1227f30491cSTony Luck  * Prepare to unwind the currently running thread.
1237f30491cSTony Luck  */
1247f30491cSTony Luck extern void unw_init_running (void (*callback)(struct unw_frame_info *info, void *arg), void *arg);
1257f30491cSTony Luck 
1267f30491cSTony Luck /*
1277f30491cSTony Luck  * Unwind to previous to frame.  Returns 0 if successful, negative
1287f30491cSTony Luck  * number in case of an error.
1297f30491cSTony Luck  */
1307f30491cSTony Luck extern int unw_unwind (struct unw_frame_info *info);
1317f30491cSTony Luck 
1327f30491cSTony Luck /*
1337f30491cSTony Luck  * Unwind until the return pointer is in user-land (or until an error
1347f30491cSTony Luck  * occurs).  Returns 0 if successful, negative number in case of
1357f30491cSTony Luck  * error.
1367f30491cSTony Luck  */
1377f30491cSTony Luck extern int unw_unwind_to_user (struct unw_frame_info *info);
1387f30491cSTony Luck 
1397f30491cSTony Luck #define unw_is_intr_frame(info)	(((info)->flags & UNW_FLAG_INTERRUPT_FRAME) != 0)
1407f30491cSTony Luck 
1417f30491cSTony Luck static inline int
unw_get_ip(struct unw_frame_info * info,unsigned long * valp)1427f30491cSTony Luck unw_get_ip (struct unw_frame_info *info, unsigned long *valp)
1437f30491cSTony Luck {
1447f30491cSTony Luck 	*valp = (info)->ip;
1457f30491cSTony Luck 	return 0;
1467f30491cSTony Luck }
1477f30491cSTony Luck 
1487f30491cSTony Luck static inline int
unw_get_sp(struct unw_frame_info * info,unsigned long * valp)1497f30491cSTony Luck unw_get_sp (struct unw_frame_info *info, unsigned long *valp)
1507f30491cSTony Luck {
1517f30491cSTony Luck 	*valp = (info)->sp;
1527f30491cSTony Luck 	return 0;
1537f30491cSTony Luck }
1547f30491cSTony Luck 
1557f30491cSTony Luck static inline int
unw_get_psp(struct unw_frame_info * info,unsigned long * valp)1567f30491cSTony Luck unw_get_psp (struct unw_frame_info *info, unsigned long *valp)
1577f30491cSTony Luck {
1587f30491cSTony Luck 	*valp = (info)->psp;
1597f30491cSTony Luck 	return 0;
1607f30491cSTony Luck }
1617f30491cSTony Luck 
1627f30491cSTony Luck static inline int
unw_get_bsp(struct unw_frame_info * info,unsigned long * valp)1637f30491cSTony Luck unw_get_bsp (struct unw_frame_info *info, unsigned long *valp)
1647f30491cSTony Luck {
1657f30491cSTony Luck 	*valp = (info)->bsp;
1667f30491cSTony Luck 	return 0;
1677f30491cSTony Luck }
1687f30491cSTony Luck 
1697f30491cSTony Luck static inline int
unw_get_cfm(struct unw_frame_info * info,unsigned long * valp)1707f30491cSTony Luck unw_get_cfm (struct unw_frame_info *info, unsigned long *valp)
1717f30491cSTony Luck {
1727f30491cSTony Luck 	*valp = *(info)->cfm_loc;
1737f30491cSTony Luck 	return 0;
1747f30491cSTony Luck }
1757f30491cSTony Luck 
1767f30491cSTony Luck static inline int
unw_set_cfm(struct unw_frame_info * info,unsigned long val)1777f30491cSTony Luck unw_set_cfm (struct unw_frame_info *info, unsigned long val)
1787f30491cSTony Luck {
1797f30491cSTony Luck 	*(info)->cfm_loc = val;
1807f30491cSTony Luck 	return 0;
1817f30491cSTony Luck }
1827f30491cSTony Luck 
1837f30491cSTony Luck static inline int
unw_get_rp(struct unw_frame_info * info,unsigned long * val)1847f30491cSTony Luck unw_get_rp (struct unw_frame_info *info, unsigned long *val)
1857f30491cSTony Luck {
1867f30491cSTony Luck 	if (!info->rp_loc)
1877f30491cSTony Luck 		return -1;
1887f30491cSTony Luck 	*val = *info->rp_loc;
1897f30491cSTony Luck 	return 0;
1907f30491cSTony Luck }
1917f30491cSTony Luck 
1927f30491cSTony Luck extern int unw_access_gr (struct unw_frame_info *, int, unsigned long *, char *, int);
1937f30491cSTony Luck extern int unw_access_br (struct unw_frame_info *, int, unsigned long *, int);
1947f30491cSTony Luck extern int unw_access_fr (struct unw_frame_info *, int, struct ia64_fpreg *, int);
1957f30491cSTony Luck extern int unw_access_ar (struct unw_frame_info *, int, unsigned long *, int);
1967f30491cSTony Luck extern int unw_access_pr (struct unw_frame_info *, unsigned long *, int);
1977f30491cSTony Luck 
1987f30491cSTony Luck static inline int
unw_set_gr(struct unw_frame_info * i,int n,unsigned long v,char nat)1997f30491cSTony Luck unw_set_gr (struct unw_frame_info *i, int n, unsigned long v, char nat)
2007f30491cSTony Luck {
2017f30491cSTony Luck 	return unw_access_gr(i, n, &v, &nat, 1);
2027f30491cSTony Luck }
2037f30491cSTony Luck 
2047f30491cSTony Luck static inline int
unw_set_br(struct unw_frame_info * i,int n,unsigned long v)2057f30491cSTony Luck unw_set_br (struct unw_frame_info *i, int n, unsigned long v)
2067f30491cSTony Luck {
2077f30491cSTony Luck 	return unw_access_br(i, n, &v, 1);
2087f30491cSTony Luck }
2097f30491cSTony Luck 
2107f30491cSTony Luck static inline int
unw_set_fr(struct unw_frame_info * i,int n,struct ia64_fpreg v)2117f30491cSTony Luck unw_set_fr (struct unw_frame_info *i, int n, struct ia64_fpreg v)
2127f30491cSTony Luck {
2137f30491cSTony Luck 	return unw_access_fr(i, n, &v, 1);
2147f30491cSTony Luck }
2157f30491cSTony Luck 
2167f30491cSTony Luck static inline int
unw_set_ar(struct unw_frame_info * i,int n,unsigned long v)2177f30491cSTony Luck unw_set_ar (struct unw_frame_info *i, int n, unsigned long v)
2187f30491cSTony Luck {
2197f30491cSTony Luck 	return unw_access_ar(i, n, &v, 1);
2207f30491cSTony Luck }
2217f30491cSTony Luck 
2227f30491cSTony Luck static inline int
unw_set_pr(struct unw_frame_info * i,unsigned long v)2237f30491cSTony Luck unw_set_pr (struct unw_frame_info *i, unsigned long v)
2247f30491cSTony Luck {
2257f30491cSTony Luck 	return unw_access_pr(i, &v, 1);
2267f30491cSTony Luck }
2277f30491cSTony Luck 
2287f30491cSTony Luck #define unw_get_gr(i,n,v,nat)	unw_access_gr(i,n,v,nat,0)
2297f30491cSTony Luck #define unw_get_br(i,n,v)	unw_access_br(i,n,v,0)
2307f30491cSTony Luck #define unw_get_fr(i,n,v)	unw_access_fr(i,n,v,0)
2317f30491cSTony Luck #define unw_get_ar(i,n,v)	unw_access_ar(i,n,v,0)
2327f30491cSTony Luck #define unw_get_pr(i,v)		unw_access_pr(i,v,0)
2337f30491cSTony Luck 
2347f30491cSTony Luck #endif /* _ASM_UNWIND_H */
235