18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci#ifndef _ASM_X86_FRAME_H
38c2ecf20Sopenharmony_ci#define _ASM_X86_FRAME_H
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci#include <asm/asm.h>
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci/*
88c2ecf20Sopenharmony_ci * These are stack frame creation macros.  They should be used by every
98c2ecf20Sopenharmony_ci * callable non-leaf asm function to make kernel stack traces more reliable.
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#ifdef CONFIG_FRAME_POINTER
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#ifdef __ASSEMBLY__
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci.macro FRAME_BEGIN
178c2ecf20Sopenharmony_ci	push %_ASM_BP
188c2ecf20Sopenharmony_ci	_ASM_MOV %_ASM_SP, %_ASM_BP
198c2ecf20Sopenharmony_ci.endm
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci.macro FRAME_END
228c2ecf20Sopenharmony_ci	pop %_ASM_BP
238c2ecf20Sopenharmony_ci.endm
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64
268c2ecf20Sopenharmony_ci/*
278c2ecf20Sopenharmony_ci * This is a sneaky trick to help the unwinder find pt_regs on the stack.  The
288c2ecf20Sopenharmony_ci * frame pointer is replaced with an encoded pointer to pt_regs.  The encoding
298c2ecf20Sopenharmony_ci * is just setting the LSB, which makes it an invalid stack address and is also
308c2ecf20Sopenharmony_ci * a signal to the unwinder that it's a pt_regs pointer in disguise.
318c2ecf20Sopenharmony_ci *
328c2ecf20Sopenharmony_ci * NOTE: This macro must be used *after* PUSH_AND_CLEAR_REGS because it corrupts
338c2ecf20Sopenharmony_ci * the original rbp.
348c2ecf20Sopenharmony_ci */
358c2ecf20Sopenharmony_ci.macro ENCODE_FRAME_POINTER ptregs_offset=0
368c2ecf20Sopenharmony_ci	leaq 1+\ptregs_offset(%rsp), %rbp
378c2ecf20Sopenharmony_ci.endm
388c2ecf20Sopenharmony_ci#else /* !CONFIG_X86_64 */
398c2ecf20Sopenharmony_ci/*
408c2ecf20Sopenharmony_ci * This is a sneaky trick to help the unwinder find pt_regs on the stack.  The
418c2ecf20Sopenharmony_ci * frame pointer is replaced with an encoded pointer to pt_regs.  The encoding
428c2ecf20Sopenharmony_ci * is just clearing the MSB, which makes it an invalid stack address and is also
438c2ecf20Sopenharmony_ci * a signal to the unwinder that it's a pt_regs pointer in disguise.
448c2ecf20Sopenharmony_ci *
458c2ecf20Sopenharmony_ci * NOTE: This macro must be used *after* SAVE_ALL because it corrupts the
468c2ecf20Sopenharmony_ci * original ebp.
478c2ecf20Sopenharmony_ci */
488c2ecf20Sopenharmony_ci.macro ENCODE_FRAME_POINTER
498c2ecf20Sopenharmony_ci	mov %esp, %ebp
508c2ecf20Sopenharmony_ci	andl $0x7fffffff, %ebp
518c2ecf20Sopenharmony_ci.endm
528c2ecf20Sopenharmony_ci#endif /* CONFIG_X86_64 */
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci#else /* !__ASSEMBLY__ */
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci#define FRAME_BEGIN				\
578c2ecf20Sopenharmony_ci	"push %" _ASM_BP "\n"			\
588c2ecf20Sopenharmony_ci	_ASM_MOV "%" _ASM_SP ", %" _ASM_BP "\n"
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci#define FRAME_END "pop %" _ASM_BP "\n"
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci#define ENCODE_FRAME_POINTER			\
658c2ecf20Sopenharmony_ci	"lea 1(%rsp), %rbp\n\t"
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistatic inline unsigned long encode_frame_pointer(struct pt_regs *regs)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	return (unsigned long)regs + 1;
708c2ecf20Sopenharmony_ci}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci#else /* !CONFIG_X86_64 */
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci#define ENCODE_FRAME_POINTER			\
758c2ecf20Sopenharmony_ci	"movl %esp, %ebp\n\t"			\
768c2ecf20Sopenharmony_ci	"andl $0x7fffffff, %ebp\n\t"
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_cistatic inline unsigned long encode_frame_pointer(struct pt_regs *regs)
798c2ecf20Sopenharmony_ci{
808c2ecf20Sopenharmony_ci	return (unsigned long)regs & 0x7fffffff;
818c2ecf20Sopenharmony_ci}
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci#endif /* CONFIG_X86_64 */
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci#endif /* __ASSEMBLY__ */
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci#define FRAME_OFFSET __ASM_SEL(4, 8)
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci#else /* !CONFIG_FRAME_POINTER */
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci#ifdef __ASSEMBLY__
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci.macro ENCODE_FRAME_POINTER ptregs_offset=0
948c2ecf20Sopenharmony_ci.endm
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci#else /* !__ASSEMBLY */
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci#define ENCODE_FRAME_POINTER
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_cistatic inline unsigned long encode_frame_pointer(struct pt_regs *regs)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	return 0;
1038c2ecf20Sopenharmony_ci}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci#endif
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci#define FRAME_BEGIN
1088c2ecf20Sopenharmony_ci#define FRAME_END
1098c2ecf20Sopenharmony_ci#define FRAME_OFFSET 0
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci#endif /* CONFIG_FRAME_POINTER */
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci#endif /* _ASM_X86_FRAME_H */
114