On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass <[email protected]> wrote: > The procedure to drop from 64-bit mode to 32-bit is a bit messy. Add a > function to take care of it. It requires identity-mapped pages and that > the calling code is running below 4GB. > > Signed-off-by: Simon Glass <[email protected]> > --- > > Changes in v2: > - Add a comment about the REX prefix > - Drop the REX prefix in 32-bit mode > > arch/x86/cpu/Makefile | 6 +++++ > arch/x86/cpu/call32.S | 64 > ++++++++++++++++++++++++++++++++++++++++++++++ > arch/x86/include/asm/cpu.h | 9 +++++++ > 3 files changed, 79 insertions(+) > create mode 100644 arch/x86/cpu/call32.S > > diff --git a/arch/x86/cpu/Makefile b/arch/x86/cpu/Makefile > index 5e058c0..e797925 100644 > --- a/arch/x86/cpu/Makefile > +++ b/arch/x86/cpu/Makefile > @@ -12,6 +12,12 @@ extra-y = start.o > obj-$(CONFIG_X86_RESET_VECTOR) += resetvec.o start16.o > obj-y += interrupts.o cpu.o cpu_x86.o call64.o > > +AFLAGS_REMOVE_call32.o := -mregparm=3 \ > + $(if $(CONFIG_EFI_STUB_64BIT),-march=i386 -m32) > +AFLAGS_call32.o := -fpic -fshort-wchar > + > +extra-y += call32.o > + > obj-$(CONFIG_INTEL_BAYTRAIL) += baytrail/ > obj-$(CONFIG_SYS_COREBOOT) += coreboot/ > obj-$(CONFIG_EFI_APP) += efi/ > diff --git a/arch/x86/cpu/call32.S b/arch/x86/cpu/call32.S > new file mode 100644 > index 0000000..c517e4a > --- /dev/null > +++ b/arch/x86/cpu/call32.S > @@ -0,0 +1,64 @@ > +/* > + * (C) Copyright 2015 Google, Inc > + * Written by Simon Glass <[email protected]> > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > + > +#include <asm/global_data.h> > +#include <asm/msr-index.h> > +#include <asm/processor-flags.h> > + > + /* > + * rdi - 32-bit code segment selector > + * rsi - target address > + * rdx - table address (0 if none) > + */ > +.code64 > +.globl cpu_call32 > +cpu_call32: > + cli > + > + /* Save table pointer */ > + mov %edx, %ebx > + > + /* > + * Debugging option, this outputs characters to the console UART > + * mov $0x3f8,%edx > + * mov $'a',%al > + * out %al,(%dx) > + */ > + > + pushf > + push %rdi /* 32-bit code segment */ > + lea compat(%rip), %rax > + push %rax > + .byte 0x48 /* REX prefix to force 64-bit far return */ > + retf > +.code32 > +compat: > + /* > + * We are now in compatibility mode with a default operand size of > + * 32 bits. First disable paging. > + */ > + movl %cr0, %eax > + andl $~X86_CR0_PG, %eax > + movl %eax, %cr0 > + > + /* Invalidate TLB */ > + xorl %eax, %eax > + movl %eax, %cr3 > + > + /* Disable Long mode in EFER (Extended Feature Enable Register) */ > + movl $MSR_EFER, %ecx > + rdmsr > + btr $_EFER_LME, %eax > + wrmsr > + > + /* Set up table pointer for _x86boot_start */ > + mov %ebx, %ecx > + > + /* Jump to the required target */ > + pushl %edi /* 32-bit code segment */ > + pushl %esi /* 32-bit target address */ > + retf > diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h > index 5b89139..c70183c 100644 > --- a/arch/x86/include/asm/cpu.h > +++ b/arch/x86/include/asm/cpu.h > @@ -230,6 +230,15 @@ char *cpu_get_name(char *name); > void cpu_call64(ulong pgtable, ulong setup_base, ulong target); > > /** > + * cpu_call32() - Jump to a 32-bit entry point > + * > + * @code_seg32: 32-bit code segment to use (GDT offset, e.g. 0x20) > + * @target: Pointer to the start of the 32-bit U-Boot image/entry point > + * @table: Pointer to start of info table to pass to U-Boot > + */ > +void cpu_call32(ulong code_seg32, ulong target, ulong table); > + > +/** > * cpu_jump_to_64bit() - Jump to a 64-bit Linux kernel > * > * The kernel is uncompressed and the 64-bit entry point is expected to be > --
Reviewed-by: Bin Meng <[email protected]> _______________________________________________ U-Boot mailing list [email protected] http://lists.denx.de/mailman/listinfo/u-boot

