162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci#ifndef _ASM_X86_FRAME_H 362306a36Sopenharmony_ci#define _ASM_X86_FRAME_H 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include <asm/asm.h> 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci/* 862306a36Sopenharmony_ci * These are stack frame creation macros. They should be used by every 962306a36Sopenharmony_ci * callable non-leaf asm function to make kernel stack traces more reliable. 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#ifdef CONFIG_FRAME_POINTER 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#ifdef __ASSEMBLY__ 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci.macro FRAME_BEGIN 1762306a36Sopenharmony_ci push %_ASM_BP 1862306a36Sopenharmony_ci _ASM_MOV %_ASM_SP, %_ASM_BP 1962306a36Sopenharmony_ci.endm 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci.macro FRAME_END 2262306a36Sopenharmony_ci pop %_ASM_BP 2362306a36Sopenharmony_ci.endm 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#ifdef CONFIG_X86_64 2662306a36Sopenharmony_ci/* 2762306a36Sopenharmony_ci * This is a sneaky trick to help the unwinder find pt_regs on the stack. The 2862306a36Sopenharmony_ci * frame pointer is replaced with an encoded pointer to pt_regs. The encoding 2962306a36Sopenharmony_ci * is just setting the LSB, which makes it an invalid stack address and is also 3062306a36Sopenharmony_ci * a signal to the unwinder that it's a pt_regs pointer in disguise. 3162306a36Sopenharmony_ci * 3262306a36Sopenharmony_ci * NOTE: This macro must be used *after* PUSH_AND_CLEAR_REGS because it corrupts 3362306a36Sopenharmony_ci * the original rbp. 3462306a36Sopenharmony_ci */ 3562306a36Sopenharmony_ci.macro ENCODE_FRAME_POINTER ptregs_offset=0 3662306a36Sopenharmony_ci leaq 1+\ptregs_offset(%rsp), %rbp 3762306a36Sopenharmony_ci.endm 3862306a36Sopenharmony_ci#else /* !CONFIG_X86_64 */ 3962306a36Sopenharmony_ci/* 4062306a36Sopenharmony_ci * This is a sneaky trick to help the unwinder find pt_regs on the stack. The 4162306a36Sopenharmony_ci * frame pointer is replaced with an encoded pointer to pt_regs. The encoding 4262306a36Sopenharmony_ci * is just clearing the MSB, which makes it an invalid stack address and is also 4362306a36Sopenharmony_ci * a signal to the unwinder that it's a pt_regs pointer in disguise. 4462306a36Sopenharmony_ci * 4562306a36Sopenharmony_ci * NOTE: This macro must be used *after* SAVE_ALL because it corrupts the 4662306a36Sopenharmony_ci * original ebp. 4762306a36Sopenharmony_ci */ 4862306a36Sopenharmony_ci.macro ENCODE_FRAME_POINTER 4962306a36Sopenharmony_ci mov %esp, %ebp 5062306a36Sopenharmony_ci andl $0x7fffffff, %ebp 5162306a36Sopenharmony_ci.endm 5262306a36Sopenharmony_ci#endif /* CONFIG_X86_64 */ 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci#else /* !__ASSEMBLY__ */ 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#define FRAME_BEGIN \ 5762306a36Sopenharmony_ci "push %" _ASM_BP "\n" \ 5862306a36Sopenharmony_ci _ASM_MOV "%" _ASM_SP ", %" _ASM_BP "\n" 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#define FRAME_END "pop %" _ASM_BP "\n" 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci#ifdef CONFIG_X86_64 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci#define ENCODE_FRAME_POINTER \ 6562306a36Sopenharmony_ci "lea 1(%rsp), %rbp\n\t" 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic inline unsigned long encode_frame_pointer(struct pt_regs *regs) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci return (unsigned long)regs + 1; 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci#else /* !CONFIG_X86_64 */ 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci#define ENCODE_FRAME_POINTER \ 7562306a36Sopenharmony_ci "movl %esp, %ebp\n\t" \ 7662306a36Sopenharmony_ci "andl $0x7fffffff, %ebp\n\t" 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistatic inline unsigned long encode_frame_pointer(struct pt_regs *regs) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci return (unsigned long)regs & 0x7fffffff; 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci#endif /* CONFIG_X86_64 */ 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci#endif /* __ASSEMBLY__ */ 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci#define FRAME_OFFSET __ASM_SEL(4, 8) 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci#else /* !CONFIG_FRAME_POINTER */ 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci#ifdef __ASSEMBLY__ 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci.macro ENCODE_FRAME_POINTER ptregs_offset=0 9462306a36Sopenharmony_ci.endm 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci#else /* !__ASSEMBLY */ 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci#define ENCODE_FRAME_POINTER 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistatic inline unsigned long encode_frame_pointer(struct pt_regs *regs) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci return 0; 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci#endif 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci#define FRAME_BEGIN 10862306a36Sopenharmony_ci#define FRAME_END 10962306a36Sopenharmony_ci#define FRAME_OFFSET 0 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci#endif /* CONFIG_FRAME_POINTER */ 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci#endif /* _ASM_X86_FRAME_H */ 114