[U-Boot] [PATCH] x86: Add 64-bit setjmp/longjmp implementation
Ivan Gorinov
ivan.gorinov at intel.com
Tue Jun 5 17:56:38 UTC 2018
On Sun, Jun 03, 2018 at 02:06:47PM +0200, Alexander Graf wrote:
> On 02.06.18 20:44, Heinrich Schuchardt wrote:
> > On 05/31/2018 12:50 AM, Ivan Gorinov wrote:
> >> Add setjmp/longjmp functions for x86_64,
> >> based on existing 32-bit implementation.
> >
> > Thank you for your patch. This addresses a gap that really should be closed.
> >
> > Please, add a line to the commit message indicating the calling
> > conventions that are supported. This is important because we use
> > different calling conventions in different places.
> >
> > One function where we need setjmp() is efi_start_image(). The function
> > is defined as EFIAPI. So we need an implementation supporting the ms_abi
> > calling convention.
>
> I don't quite follow. The calling convention is declared in the C header
> (omitted means sysv, EFIAPI means ms). The compiler will adapt the call
> to the respective convention automatically. So if you call a sysv
> function from an EFIAPI function, gcc will push all registers that are
> potentially getting clobbered on the stack.
I can confirm that gcc does save %rsi and %rdi in EFIAPI functions before
using those two registers for setjmp() parameters. The other callee-saved
registers in ms_abi are also callee-saved in sysv and correctly handled by
the proposed implementation.
static efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,
unsigned long *exit_data_size,
s16 **exit_data)
{
5f03ce56: 57 push %rdi
5f03ce57: 56 push %rsi
...
/* call the image! */
if (setjmp(&info->exit_jmp)) {
5f03cecd: 48 8b 84 24 f0 00 00 mov 0xf0(%rsp),%rax
5f03ced4: 00
5f03ced5: 48 8d 78 78 lea 0x78(%rax),%rdi
5f03ced9: e8 82 32 fc ff callq 5f000160 <setjmp>
5f03cede: 85 c0 test %eax,%eax
5f03cee0: 74 1b je 5f03cefd <efi_start_image+0xa7>
...
> So IIUC we really only need the sysv variant - which this patch
> implements, right? This also shouldn't need any mentioning, as it's the
> default throughout the code base, unless the function is annotated with
> the EFIAPI tag.
> > Another function where we use setjmp() is do_bootefi_exec() but this
> > function is defined as sysv_abi.
> >
> > I guess the patch relates to the sysv_abi calling convention:
> >
> > "System V Application Binary Interface: AMD64 Architecture Processor
> > Supplement (With LP64 and ILP32 Programming Models)"
> > https://software.intel.com/sites/default/files/article/402129/mpx-linux64-abi.pdf
> >
> > This document contains the following sentence:
> >
> > The control bits of the MXCSR register are callee-saved (preserved
> > across calls), while the status bits are caller-saved (not preserved).
> > I cannot see that this is reflected in the patch.
Thank you for the link! I will add MXCSR to the callee-saved register set.
> > See also https://msdn.microsoft.com/en-us/library/36d3b75w.aspx
> >
> > Your setjmp implemantion is not usable for the ms_abi that we need in
> > for efi_start_image(). Here you would have to save registers RBX, RBP,
> > RDI, RSI, RSP, R12, R13, R14, and R15.
> >
> > As reference have a look at this implementation:
> > https://github.com/freebsd/freebsd/blob/master/lib/libc/amd64/gen/setjmp.S
> >
> >>
> >> Signed-off-by: Ivan Gorinov <ivan.gorinov at intel.com>
> >
> >
> >
> >> ---
> >> arch/x86/cpu/x86_64/setjmp.S | 56 +++++++++++++++++++++++++++++++++++++++++++
> >> arch/x86/cpu/x86_64/setjmp.c | 19 ---------------
> >> arch/x86/include/asm/setjmp.h | 17 +++++++++++++
> >> 3 files changed, 73 insertions(+), 19 deletions(-)
> >> create mode 100644 arch/x86/cpu/x86_64/setjmp.S
> >> delete mode 100644 arch/x86/cpu/x86_64/setjmp.c
> >>
> >> diff --git a/arch/x86/cpu/x86_64/setjmp.S b/arch/x86/cpu/x86_64/setjmp.S
> >> new file mode 100644
> >> index 0000000..e10ee49
> >> --- /dev/null
> >> +++ b/arch/x86/cpu/x86_64/setjmp.S
> >> @@ -0,0 +1,56 @@
> >> +/*
> >> + * Based on arch/x86/cpu/i386/setjmp.S by H. Peter Anvin <hpa at zytor.com>
> >> + *
> >> + * SPDX-License-Identifier: GPL-2.0
> >> + */
> >> +
> >> +/*
> >> + * The jmp_buf is assumed to contain the following, in order:
> >> + * <return address>
> >> + * %rsp
> >> + * %rbp
> >> + * %rbx
> >> + * %r12
> >> + * %r13
> >> + * %r14
> >> + * %r15
> >> + */
> >> +
> >> +.text
> >> +.align 8
> >> +.globl setjmp
> >> +.type setjmp, @function
> >> +
> >> +setjmp:
>
> We have macros for asm provided functions (see arch/arm/lib/setjmp.S) to
> ensure that linker based section elimination works. Please make sure you
> use those.
OK. Shall I also add .pushsection/.popsection?
Can't find any example in arch/x86/
> >> + pop %rcx
> >> + movq %rcx, (%rdi) /* Return address */
> >> + movq %rsp, 8 (%rdi) /* Post-return %rsp! */
> >> + movq %rbp, 16 (%rdi)
> >> + movq %rbx, 24 (%rdi)
> >> + movq %r12, 32 (%rdi)
> >> + movq %r13, 40 (%rdi)
> >> + movq %r14, 48 (%rdi)
> >> + movq %r15, 56 (%rdi)
> >> + xorq %rax, %rax /* Return value */
> >> + jmpq *%rcx
> >> +
> >> +/* Provide function size if needed */
> >> +.size setjmp, .-setjmp
> >> +
> >> +.align 8
> >> +.globl longjmp
> >> +.type longjmp, @function
> >> +
> >> +longjmp:
> >> + movq 32 (%rdi), %r12
> >> + movq 40 (%rdi), %r13
> >> + movq 48 (%rdi), %r14
> >> + movq 56 (%rdi), %r15
> >> + movq 16 (%rdi), %rbp
> >> + movq 24 (%rdi), %rbx
> >> + movq 8 (%rdi), %rsp
> >> + movq (%rdi), %rcx
> >> + movq %rsi, %rdi
> >> + jmpq *%rcx
> >> +
> >> + .size longjmp, .-longjmp
> >> diff --git a/arch/x86/cpu/x86_64/setjmp.c b/arch/x86/cpu/x86_64/setjmp.c
> >> deleted file mode 100644
> >> index 5d4a74a..0000000
> >> --- a/arch/x86/cpu/x86_64/setjmp.c
> >> +++ /dev/null
> >> @@ -1,19 +0,0 @@
> >> -// SPDX-License-Identifier: GPL-2.0+
> >> -/*
> >> - * Copyright (c) 2016 Google, Inc
> >> - */
> >> -
> >> -#include <common.h>
> >> -#include <asm/setjmp.h>
> >> -
> >> -int setjmp(struct jmp_buf_data *jmp_buf)
> >> -{
> >> - printf("WARNING: setjmp() is not supported\n");
> >> -
> >> - return 0;
> >> -}
> >> -
> >> -void longjmp(struct jmp_buf_data *jmp_buf, int val)
> >> -{
> >> - printf("WARNING: longjmp() is not supported\n");
> >> -}
> >> diff --git a/arch/x86/include/asm/setjmp.h b/arch/x86/include/asm/setjmp.h
> >> index f25975f..49c36c1 100644
> >> --- a/arch/x86/include/asm/setjmp.h
> >> +++ b/arch/x86/include/asm/setjmp.h
> >> @@ -8,6 +8,21 @@
> >> #ifndef __setjmp_h
> >> #define __setjmp_h
> >>
> >> +#ifdef CONFIG_X86_64
> >> +
> >> +struct jmp_buf_data {
> >> + unsigned long __rip;
> >> + unsigned long __rsp;
> >> + unsigned long __rbp;
> >> + unsigned long __rbx;
> >> + unsigned long __r12;
> >> + unsigned long __r13;
> >> + unsigned long __r14;
> >> + unsigned long __r15;
> >> +};
> >> +
> >> +#else
> >> +
> >> struct jmp_buf_data {
> >> unsigned int __ebx;
> >> unsigned int __esp;
> >> @@ -17,6 +32,8 @@ struct jmp_buf_data {
> >> unsigned int __eip;
> >> };
> >>
> >> +#endif
> >> +
> >> int setjmp(struct jmp_buf_data *jmp_buf);
> >> void longjmp(struct jmp_buf_data *jmp_buf, int val);
> >>
> >>
> >
More information about the U-Boot
mailing list