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