Message ID | 1437580180-6405-38-git-send-email-sjg@chromium.org |
---|---|
State | Superseded |
Delegated to: | Simon Glass |
Headers | show |
Hi Simon, On Wed, Jul 22, 2015 at 11:49 PM, Simon Glass <sjg@chromium.org> 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 <sjg@chromium.org> > --- > > arch/x86/cpu/Makefile | 6 +++++ > arch/x86/cpu/call32.S | 65 ++++++++++++++++++++++++++++++++++++++++++++++ > arch/x86/include/asm/cpu.h | 9 +++++++ > 3 files changed, 80 insertions(+) > create mode 100644 arch/x86/cpu/call32.S > > diff --git a/arch/x86/cpu/Makefile b/arch/x86/cpu/Makefile > index 9678976..eb993ec 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_ARCH_EFI) += efi/ > diff --git a/arch/x86/cpu/call32.S b/arch/x86/cpu/call32.S > new file mode 100644 > index 0000000..3fe010e > --- /dev/null > +++ b/arch/x86/cpu/call32.S > @@ -0,0 +1,65 @@ > +/* > + * (C) Copyright 2015 Google, Inc > + * Written by Simon Glass <sjg@chromium.org> > + * > + * 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 I think this is a REX prefix. Is there any compiler macro we can use? We can put some comments here for better understanding. BTW: is this a must? I believe retf will operate on 64-bit by operand in 64-bit by default? > + 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 */ > + .byte 0x48 > + retf > diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h > index b96513d..e977045 100644 > --- a/arch/x86/include/asm/cpu.h > +++ b/arch/x86/include/asm/cpu.h > @@ -222,6 +222,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 > -- Regards, Bin
Hi Bin, On 24 July 2015 at 01:25, Bin Meng <bmeng.cn@gmail.com> wrote: > Hi Simon, > > On Wed, Jul 22, 2015 at 11:49 PM, Simon Glass <sjg@chromium.org> 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 <sjg@chromium.org> >> --- >> >> arch/x86/cpu/Makefile | 6 +++++ >> arch/x86/cpu/call32.S | 65 ++++++++++++++++++++++++++++++++++++++++++++++ >> arch/x86/include/asm/cpu.h | 9 +++++++ >> 3 files changed, 80 insertions(+) >> create mode 100644 arch/x86/cpu/call32.S >> >> diff --git a/arch/x86/cpu/Makefile b/arch/x86/cpu/Makefile >> index 9678976..eb993ec 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_ARCH_EFI) += efi/ >> diff --git a/arch/x86/cpu/call32.S b/arch/x86/cpu/call32.S >> new file mode 100644 >> index 0000000..3fe010e >> --- /dev/null >> +++ b/arch/x86/cpu/call32.S >> @@ -0,0 +1,65 @@ >> +/* >> + * (C) Copyright 2015 Google, Inc >> + * Written by Simon Glass <sjg@chromium.org> >> + * >> + * 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 > > I think this is a REX prefix. Is there any compiler macro we can use? > We can put some comments here for better understanding. BTW: is this a > must? I believe retf will operate on 64-bit by operand in 64-bit by > default? I'll add a comment. In fact this problem took me ages to figure out as the documentation seems unclear. But neither qemu nor real hardware seem to work without this prefix. > >> + 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 */ >> + .byte 0x48 I'll drop this one though. >> + retf >> diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h >> index b96513d..e977045 100644 >> --- a/arch/x86/include/asm/cpu.h >> +++ b/arch/x86/include/asm/cpu.h >> @@ -222,6 +222,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 >> -- > > Regards, > Bin Regards, Simon
diff --git a/arch/x86/cpu/Makefile b/arch/x86/cpu/Makefile index 9678976..eb993ec 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_ARCH_EFI) += efi/ diff --git a/arch/x86/cpu/call32.S b/arch/x86/cpu/call32.S new file mode 100644 index 0000000..3fe010e --- /dev/null +++ b/arch/x86/cpu/call32.S @@ -0,0 +1,65 @@ +/* + * (C) Copyright 2015 Google, Inc + * Written by Simon Glass <sjg@chromium.org> + * + * 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 + 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 */ + .byte 0x48 + retf diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h index b96513d..e977045 100644 --- a/arch/x86/include/asm/cpu.h +++ b/arch/x86/include/asm/cpu.h @@ -222,6 +222,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
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 <sjg@chromium.org> --- arch/x86/cpu/Makefile | 6 +++++ arch/x86/cpu/call32.S | 65 ++++++++++++++++++++++++++++++++++++++++++++++ arch/x86/include/asm/cpu.h | 9 +++++++ 3 files changed, 80 insertions(+) create mode 100644 arch/x86/cpu/call32.S