From: Simon Glass <simon.glass@canonical.com> By default, U-Boot on 32-bit x86 uses -mregparm=3 to pass the first three function arguments in registers (EAX, EDX, ECX) rather than on the stack. This is more efficient but makes it harder to link U-Boot against libraries which expect the standard calling convention, e.g. using ulib from Rust. Add a Kconfig option X86_NO_REGPARM to disable regparm and use the standard i386 calling convention where all arguments are passed on the stack. Adjust the assembly-based startup code to support both options. For qemu-x86 this increases code size by about 42K, i.e. 4.1% growth. Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com> Signed-off-by: Simon Glass <simon.glass@canonical.com> --- arch/x86/Kconfig | 14 ++++++++++++++ arch/x86/config.mk | 2 ++ arch/x86/cpu/i386/interrupt.c | 10 ++++++++-- arch/x86/cpu/start.S | 23 +++++++++++++++++++++-- arch/x86/cpu/start_from_spl.S | 21 ++++++++++++++++++++- arch/x86/cpu/start_from_tpl.S | 19 ++++++++++++++++++- 6 files changed, 83 insertions(+), 6 deletions(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 835cf2d8025..a7d616a401d 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -750,6 +750,20 @@ config X86_HARDFP start-up code for 64-bit mode and changes the compiler options for 64-bit to enable SSE. +config X86_NO_REGPARM + bool "Disable register parameters (regparm=3)" + depends on !X86_64 + help + By default, U-Boot on 32-bit x86 uses -mregparm=3 to pass the first + three function arguments in registers (EAX, EDX, ECX) rather than on + the stack. This is more efficient but can cause issues with debugging + tools or when interfacing with code that expects the standard calling + convention. + + Select this option to disable regparm and use the standard i386 + calling convention where all arguments are passed on the stack. This + may be useful for debugging or for running in certain emulators. + config HAVE_ITSS bool "Enable ITSS" help diff --git a/arch/x86/config.mk b/arch/x86/config.mk index 0deea05c15f..51f5026fb2c 100644 --- a/arch/x86/config.mk +++ b/arch/x86/config.mk @@ -83,8 +83,10 @@ LDSCRIPT := $(LDSCRIPT_EFI) else ifeq ($(IS_32BIT),y) +ifndef CONFIG_X86_NO_REGPARM PLATFORM_CPPFLAGS += -mregparm=3 endif +endif KBUILD_LDFLAGS += --emit-relocs LDFLAGS_FINAL += --gc-sections $(if $(CONFIG_XPL_BUILD),,-pie) diff --git a/arch/x86/cpu/i386/interrupt.c b/arch/x86/cpu/i386/interrupt.c index 6f78b072cde..22241005948 100644 --- a/arch/x86/cpu/i386/interrupt.c +++ b/arch/x86/cpu/i386/interrupt.c @@ -354,9 +354,15 @@ asm(".globl irq_common_entry\n" \ "pushl %esi\n" \ "pushl %edx\n" \ "pushl %ecx\n" \ - "pushl %ebx\n" \ - "mov %esp, %eax\n" \ + "pushl %ebx\n" +#ifdef CONFIG_X86_NO_REGPARM + "pushl %esp\n" \ "call irq_llsr\n" \ + "addl $4, %esp\n" +#else + "mov %esp, %eax\n" \ + "call irq_llsr\n" +#endif "popl %ebx\n" \ "popl %ecx\n" \ "popl %edx\n" \ diff --git a/arch/x86/cpu/start.S b/arch/x86/cpu/start.S index 385a691265e..a9f034d8c7e 100644 --- a/arch/x86/cpu/start.S +++ b/arch/x86/cpu/start.S @@ -134,10 +134,20 @@ car_init_ret: */ #endif /* Set up global data */ +#ifdef CONFIG_X86_NO_REGPARM + push %esp + call board_init_f_alloc_reserve + add $4, %esp + mov %eax, %esp + push %eax + call board_init_f_init_reserve + add $4, %esp +#else mov %esp, %eax call board_init_f_alloc_reserve mov %eax, %esp call board_init_f_init_reserve +#endif #ifdef CONFIG_DEBUG_UART call debug_uart_init @@ -171,10 +181,16 @@ skip_hob: /* Set parameter to board_init_f() to boot flags */ post_code(POST_START_DONE) - xorl %eax, %eax /* Enter, U-Boot! */ +#ifdef CONFIG_X86_NO_REGPARM + push $0 call board_init_f + add $4, %esp +#else + xorl %eax, %eax + call board_init_f +#endif /* indicate (lack of) progress */ movw $0x85, %ax @@ -188,10 +204,13 @@ board_init_f_r_trampoline: * RAM, BSS has been cleared and relocation adjustments have been * made. It is now time to jump into the in-RAM copy of U-Boot * - * %eax = Address of top of new stack + * %eax = Address of top of new stack (or 4(%esp) without regparm) */ /* Stack grows down from top of SDRAM */ +#ifdef CONFIG_X86_NO_REGPARM + movl 4(%esp), %eax +#endif movl %eax, %esp /* See if we need to disable CAR */ diff --git a/arch/x86/cpu/start_from_spl.S b/arch/x86/cpu/start_from_spl.S index abfd4abb623..1d6777c2160 100644 --- a/arch/x86/cpu/start_from_spl.S +++ b/arch/x86/cpu/start_from_spl.S @@ -38,18 +38,34 @@ _start: use_existing_stack: mov %esp, %eax 2: +#ifdef CONFIG_X86_NO_REGPARM + push %eax + call board_init_f_alloc_reserve + add $4, %esp + mov %eax, %esp + push %eax + call board_init_f_init_reserve + add $4, %esp +#else call board_init_f_alloc_reserve mov %eax, %esp call board_init_f_init_reserve +#endif #ifdef CONFIG_DEBUG_UART call debug_uart_init #endif call x86_cpu_reinit_f +#ifdef CONFIG_X86_NO_REGPARM + push $0 + call board_init_f + add $4, %esp +#else xorl %eax, %eax call board_init_f +#endif call board_init_f_r /* Should not return here */ @@ -64,10 +80,13 @@ board_init_f_r_trampoline: * adjustments have been made. It is now time to jump into the in-RAM * copy of U-Boot * - * %eax = Address of top of new stack + * %eax = Address of top of new stack (or 4(%esp) without regparm) */ /* Stack grows down from top of SDRAM */ +#ifdef CONFIG_X86_NO_REGPARM + movl 4(%esp), %eax +#endif movl %eax, %esp /* Re-enter U-Boot by calling board_init_f_r() */ diff --git a/arch/x86/cpu/start_from_tpl.S b/arch/x86/cpu/start_from_tpl.S index 9a4974a5f1b..ca6613217d2 100644 --- a/arch/x86/cpu/start_from_tpl.S +++ b/arch/x86/cpu/start_from_tpl.S @@ -15,6 +15,19 @@ .type _start, @function _start: /* Set up memory using the existing stack */ +#ifdef CONFIG_X86_NO_REGPARM + push %esp + call board_init_f_alloc_reserve + add $4, %esp + mov %eax, %esp + push %eax + call board_init_f_init_reserve + add $4, %esp + + push $0 + call board_init_f + add $4, %esp +#else mov %esp, %eax call board_init_f_alloc_reserve mov %eax, %esp @@ -23,6 +36,7 @@ _start: xorl %eax, %eax call board_init_f +#endif call board_init_f_r /* Should not return here */ @@ -35,10 +49,13 @@ board_init_f_r_trampoline: * TPL has been executed: SDRAM has been initialised, BSS has been * cleared. * - * %eax = Address of top of new stack + * %eax = Address of top of new stack (or 4(%esp) without regparm) */ /* Stack grows down from top of SDRAM */ +#ifdef CONFIG_X86_NO_REGPARM + movl 4(%esp), %eax +#endif movl %eax, %esp /* Re-enter SPL by calling board_init_f_r() */ -- 2.43.0