162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#ifndef _ASM_IA64_UNWIND_H
362306a36Sopenharmony_ci#define _ASM_IA64_UNWIND_H
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci/*
662306a36Sopenharmony_ci * Copyright (C) 1999-2000, 2003 Hewlett-Packard Co
762306a36Sopenharmony_ci *	David Mosberger-Tang <davidm@hpl.hp.com>
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * A simple API for unwinding kernel stacks.  This is used for
1062306a36Sopenharmony_ci * debugging and error reporting purposes.  The kernel doesn't need
1162306a36Sopenharmony_ci * full-blown stack unwinding with all the bells and whitles, so there
1262306a36Sopenharmony_ci * is not much point in implementing the full IA-64 unwind API (though
1362306a36Sopenharmony_ci * it would of course be possible to implement the kernel API on top
1462306a36Sopenharmony_ci * of it).
1562306a36Sopenharmony_ci */
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_cistruct task_struct;	/* forward declaration */
1862306a36Sopenharmony_cistruct switch_stack;	/* forward declaration */
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cienum unw_application_register {
2162306a36Sopenharmony_ci	UNW_AR_BSP,
2262306a36Sopenharmony_ci	UNW_AR_BSPSTORE,
2362306a36Sopenharmony_ci	UNW_AR_PFS,
2462306a36Sopenharmony_ci	UNW_AR_RNAT,
2562306a36Sopenharmony_ci	UNW_AR_UNAT,
2662306a36Sopenharmony_ci	UNW_AR_LC,
2762306a36Sopenharmony_ci	UNW_AR_EC,
2862306a36Sopenharmony_ci	UNW_AR_FPSR,
2962306a36Sopenharmony_ci	UNW_AR_RSC,
3062306a36Sopenharmony_ci	UNW_AR_CCV,
3162306a36Sopenharmony_ci	UNW_AR_CSD,
3262306a36Sopenharmony_ci	UNW_AR_SSD
3362306a36Sopenharmony_ci};
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci/*
3662306a36Sopenharmony_ci * The following declarations are private to the unwind
3762306a36Sopenharmony_ci * implementation:
3862306a36Sopenharmony_ci */
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cistruct unw_stack {
4162306a36Sopenharmony_ci	unsigned long limit;
4262306a36Sopenharmony_ci	unsigned long top;
4362306a36Sopenharmony_ci};
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci#define UNW_FLAG_INTERRUPT_FRAME	(1UL << 0)
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci/*
4862306a36Sopenharmony_ci * No user of this module should every access this structure directly
4962306a36Sopenharmony_ci * as it is subject to change.  It is declared here solely so we can
5062306a36Sopenharmony_ci * use automatic variables.
5162306a36Sopenharmony_ci */
5262306a36Sopenharmony_cistruct unw_frame_info {
5362306a36Sopenharmony_ci	struct unw_stack regstk;
5462306a36Sopenharmony_ci	struct unw_stack memstk;
5562306a36Sopenharmony_ci	unsigned int flags;
5662306a36Sopenharmony_ci	short hint;
5762306a36Sopenharmony_ci	short prev_script;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	/* current frame info: */
6062306a36Sopenharmony_ci	unsigned long bsp;		/* backing store pointer value */
6162306a36Sopenharmony_ci	unsigned long sp;		/* stack pointer value */
6262306a36Sopenharmony_ci	unsigned long psp;		/* previous sp value */
6362306a36Sopenharmony_ci	unsigned long ip;		/* instruction pointer value */
6462306a36Sopenharmony_ci	unsigned long pr;		/* current predicate values */
6562306a36Sopenharmony_ci	unsigned long *cfm_loc;		/* cfm save location (or NULL) */
6662306a36Sopenharmony_ci	unsigned long pt;		/* struct pt_regs location */
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	struct task_struct *task;
6962306a36Sopenharmony_ci	struct switch_stack *sw;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	/* preserved state: */
7262306a36Sopenharmony_ci	unsigned long *bsp_loc;		/* previous bsp save location */
7362306a36Sopenharmony_ci	unsigned long *bspstore_loc;
7462306a36Sopenharmony_ci	unsigned long *pfs_loc;
7562306a36Sopenharmony_ci	unsigned long *rnat_loc;
7662306a36Sopenharmony_ci	unsigned long *rp_loc;
7762306a36Sopenharmony_ci	unsigned long *pri_unat_loc;
7862306a36Sopenharmony_ci	unsigned long *unat_loc;
7962306a36Sopenharmony_ci	unsigned long *pr_loc;
8062306a36Sopenharmony_ci	unsigned long *lc_loc;
8162306a36Sopenharmony_ci	unsigned long *fpsr_loc;
8262306a36Sopenharmony_ci	struct unw_ireg {
8362306a36Sopenharmony_ci		unsigned long *loc;
8462306a36Sopenharmony_ci		struct unw_ireg_nat {
8562306a36Sopenharmony_ci			unsigned long type : 3;		/* enum unw_nat_type */
8662306a36Sopenharmony_ci			signed long off : 61;		/* NaT word is at loc+nat.off */
8762306a36Sopenharmony_ci		} nat;
8862306a36Sopenharmony_ci	} r4, r5, r6, r7;
8962306a36Sopenharmony_ci	unsigned long *b1_loc, *b2_loc, *b3_loc, *b4_loc, *b5_loc;
9062306a36Sopenharmony_ci	struct ia64_fpreg *f2_loc, *f3_loc, *f4_loc, *f5_loc, *fr_loc[16];
9162306a36Sopenharmony_ci};
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci/*
9462306a36Sopenharmony_ci * The official API follows below:
9562306a36Sopenharmony_ci */
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistruct unw_table_entry {
9862306a36Sopenharmony_ci	u64 start_offset;
9962306a36Sopenharmony_ci	u64 end_offset;
10062306a36Sopenharmony_ci	u64 info_offset;
10162306a36Sopenharmony_ci};
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci/*
10462306a36Sopenharmony_ci * Initialize unwind support.
10562306a36Sopenharmony_ci */
10662306a36Sopenharmony_ciextern void unw_init (void);
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ciextern void *unw_add_unwind_table (const char *name, unsigned long segment_base, unsigned long gp,
10962306a36Sopenharmony_ci				   const void *table_start, const void *table_end);
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ciextern void unw_remove_unwind_table (void *handle);
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci/*
11462306a36Sopenharmony_ci * Prepare to unwind blocked task t.
11562306a36Sopenharmony_ci */
11662306a36Sopenharmony_ciextern void unw_init_from_blocked_task (struct unw_frame_info *info, struct task_struct *t);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ciextern void unw_init_frame_info (struct unw_frame_info *info, struct task_struct *t,
11962306a36Sopenharmony_ci				 struct switch_stack *sw);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci/*
12262306a36Sopenharmony_ci * Prepare to unwind the currently running thread.
12362306a36Sopenharmony_ci */
12462306a36Sopenharmony_ciextern void unw_init_running (void (*callback)(struct unw_frame_info *info, void *arg), void *arg);
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci/*
12762306a36Sopenharmony_ci * Unwind to previous to frame.  Returns 0 if successful, negative
12862306a36Sopenharmony_ci * number in case of an error.
12962306a36Sopenharmony_ci */
13062306a36Sopenharmony_ciextern int unw_unwind (struct unw_frame_info *info);
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci/*
13362306a36Sopenharmony_ci * Unwind until the return pointer is in user-land (or until an error
13462306a36Sopenharmony_ci * occurs).  Returns 0 if successful, negative number in case of
13562306a36Sopenharmony_ci * error.
13662306a36Sopenharmony_ci */
13762306a36Sopenharmony_ciextern int unw_unwind_to_user (struct unw_frame_info *info);
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci#define unw_is_intr_frame(info)	(((info)->flags & UNW_FLAG_INTERRUPT_FRAME) != 0)
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_cistatic inline int
14262306a36Sopenharmony_ciunw_get_ip (struct unw_frame_info *info, unsigned long *valp)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	*valp = (info)->ip;
14562306a36Sopenharmony_ci	return 0;
14662306a36Sopenharmony_ci}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_cistatic inline int
14962306a36Sopenharmony_ciunw_get_sp (struct unw_frame_info *info, unsigned long *valp)
15062306a36Sopenharmony_ci{
15162306a36Sopenharmony_ci	*valp = (info)->sp;
15262306a36Sopenharmony_ci	return 0;
15362306a36Sopenharmony_ci}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_cistatic inline int
15662306a36Sopenharmony_ciunw_get_psp (struct unw_frame_info *info, unsigned long *valp)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	*valp = (info)->psp;
15962306a36Sopenharmony_ci	return 0;
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_cistatic inline int
16362306a36Sopenharmony_ciunw_get_bsp (struct unw_frame_info *info, unsigned long *valp)
16462306a36Sopenharmony_ci{
16562306a36Sopenharmony_ci	*valp = (info)->bsp;
16662306a36Sopenharmony_ci	return 0;
16762306a36Sopenharmony_ci}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_cistatic inline int
17062306a36Sopenharmony_ciunw_get_cfm (struct unw_frame_info *info, unsigned long *valp)
17162306a36Sopenharmony_ci{
17262306a36Sopenharmony_ci	*valp = *(info)->cfm_loc;
17362306a36Sopenharmony_ci	return 0;
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_cistatic inline int
17762306a36Sopenharmony_ciunw_set_cfm (struct unw_frame_info *info, unsigned long val)
17862306a36Sopenharmony_ci{
17962306a36Sopenharmony_ci	*(info)->cfm_loc = val;
18062306a36Sopenharmony_ci	return 0;
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic inline int
18462306a36Sopenharmony_ciunw_get_rp (struct unw_frame_info *info, unsigned long *val)
18562306a36Sopenharmony_ci{
18662306a36Sopenharmony_ci	if (!info->rp_loc)
18762306a36Sopenharmony_ci		return -1;
18862306a36Sopenharmony_ci	*val = *info->rp_loc;
18962306a36Sopenharmony_ci	return 0;
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ciextern int unw_access_gr (struct unw_frame_info *, int, unsigned long *, char *, int);
19362306a36Sopenharmony_ciextern int unw_access_br (struct unw_frame_info *, int, unsigned long *, int);
19462306a36Sopenharmony_ciextern int unw_access_fr (struct unw_frame_info *, int, struct ia64_fpreg *, int);
19562306a36Sopenharmony_ciextern int unw_access_ar (struct unw_frame_info *, int, unsigned long *, int);
19662306a36Sopenharmony_ciextern int unw_access_pr (struct unw_frame_info *, unsigned long *, int);
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_cistatic inline int
19962306a36Sopenharmony_ciunw_set_gr (struct unw_frame_info *i, int n, unsigned long v, char nat)
20062306a36Sopenharmony_ci{
20162306a36Sopenharmony_ci	return unw_access_gr(i, n, &v, &nat, 1);
20262306a36Sopenharmony_ci}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_cistatic inline int
20562306a36Sopenharmony_ciunw_set_br (struct unw_frame_info *i, int n, unsigned long v)
20662306a36Sopenharmony_ci{
20762306a36Sopenharmony_ci	return unw_access_br(i, n, &v, 1);
20862306a36Sopenharmony_ci}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_cistatic inline int
21162306a36Sopenharmony_ciunw_set_fr (struct unw_frame_info *i, int n, struct ia64_fpreg v)
21262306a36Sopenharmony_ci{
21362306a36Sopenharmony_ci	return unw_access_fr(i, n, &v, 1);
21462306a36Sopenharmony_ci}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_cistatic inline int
21762306a36Sopenharmony_ciunw_set_ar (struct unw_frame_info *i, int n, unsigned long v)
21862306a36Sopenharmony_ci{
21962306a36Sopenharmony_ci	return unw_access_ar(i, n, &v, 1);
22062306a36Sopenharmony_ci}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_cistatic inline int
22362306a36Sopenharmony_ciunw_set_pr (struct unw_frame_info *i, unsigned long v)
22462306a36Sopenharmony_ci{
22562306a36Sopenharmony_ci	return unw_access_pr(i, &v, 1);
22662306a36Sopenharmony_ci}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci#define unw_get_gr(i,n,v,nat)	unw_access_gr(i,n,v,nat,0)
22962306a36Sopenharmony_ci#define unw_get_br(i,n,v)	unw_access_br(i,n,v,0)
23062306a36Sopenharmony_ci#define unw_get_fr(i,n,v)	unw_access_fr(i,n,v,0)
23162306a36Sopenharmony_ci#define unw_get_ar(i,n,v)	unw_access_ar(i,n,v,0)
23262306a36Sopenharmony_ci#define unw_get_pr(i,v)		unw_access_pr(i,v,0)
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci#endif /* _ASM_UNWIND_H */
235