[U-Boot] [PATCH v2 2/3] x86: fsp: Load GDT before calling FspInitEntry
Bin Meng
bmeng.cn at gmail.com
Fri Jun 5 17:59:49 CEST 2015
Hi Simon,
On Fri, Jun 5, 2015 at 11:34 PM, Simon Glass <sjg at chromium.org> wrote:
> Hi Bin,
>
> On 4 June 2015 at 04:28, Bin Meng <bmeng.cn at gmail.com> wrote:
>> Currently the FSP execution environment GDT is setup by U-Boot in
>> arch/x86/cpu/start16.S, which works pretty well. But if we try to
>> move the FspInitEntry call a little bit later to better fit into
>> U-Boot's initialization sequence, FSP will fail to bring up the AP
>> due to #GP fault as AP's GDT is duplicated from BSP whose GDT is
>> now moved into CAR, and unfortunately FSP calls AP initialization
>> after it disables the CAR. So basically the BSP's GDT still refers
>> to the one in the CAR, whose content is no longer available, so
>> when AP starts up and loads its segment register, it blows up.
>>
>> To resolve this, we load GDT before calling into FspInitEntry.
>> The GDT is the same one used in arch/x86/cpu/start16.S, which is
>> in the ROM and exists forever.
>>
>> Signed-off-by: Bin Meng <bmeng.cn at gmail.com>
>
> Tested on Minnowboard MAX:
> Tested-by: Simon Glass <sjg at chromium.org>
>
>>
>> ---
>>
>> Changes in v2:
>> - Use CONFIG_RESET_SEG_START to avoid duplication
>>
>> arch/x86/cpu/cpu.c | 20 ++++++++++++++++++++
>> arch/x86/cpu/start16.S | 1 +
>> arch/x86/include/asm/u-boot-x86.h | 3 +++
>> arch/x86/lib/fsp/fsp_support.c | 3 +++
>> 4 files changed, 27 insertions(+)
>>
>> diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c
>> index bb4a110..f4ebc97 100644
>> --- a/arch/x86/cpu/cpu.c
>> +++ b/arch/x86/cpu/cpu.c
>> @@ -164,6 +164,26 @@ void setup_gdt(gd_t *id, u64 *gdt_addr)
>> load_fs(X86_GDT_ENTRY_32BIT_FS);
>> }
>>
>> +#ifdef CONFIG_HAVE_FSP
>> +/*
>> + * Setup FSP execution environment GDT
>> + *
>> + * Per Intel FSP external architecture specification, before calling any FSP
>> + * APIs, we need make sure the system is in flat 32-bit mode and both the code
>> + * and data selectors should have full 4GB access range. Here we reuse the one
>> + * we used in arch/x86/cpu/start16.S, and reload the segement registers.
>> + */
>> +void setup_fsp_gdt(void)
>> +{
>> + load_gdt((const u64 *)((u32)&gdt + CONFIG_RESET_SEG_START), 4);
>> + load_ds(X86_GDT_ENTRY_32BIT_DS);
>> + load_ss(X86_GDT_ENTRY_32BIT_DS);
>> + load_es(X86_GDT_ENTRY_32BIT_DS);
>> + load_fs(X86_GDT_ENTRY_32BIT_DS);
>> + load_gs(X86_GDT_ENTRY_32BIT_DS);
>> +}
>> +#endif
>> +
>> int __weak x86_cleanup_before_linux(void)
>> {
>> #ifdef CONFIG_BOOTSTAGE_STASH
>> diff --git a/arch/x86/cpu/start16.S b/arch/x86/cpu/start16.S
>> index 826e2b4..a3e7ab4 100644
>> --- a/arch/x86/cpu/start16.S
>> +++ b/arch/x86/cpu/start16.S
>> @@ -75,6 +75,7 @@ gdt_ptr:
>>
>> /* Some CPUs are picky about GDT alignment... */
>> .align 16
>> +.globl gdt
>> gdt:
>
> Could we rename this to gdt_initial or something like that? To me, gdt
> is a bit vague for an exported symbol. We need to use a name that
> indicates it is only used at the start.
Agreed. How about gdt_rom?
>> /*
>> * The GDT table ...
>> diff --git a/arch/x86/include/asm/u-boot-x86.h b/arch/x86/include/asm/u-boot-x86.h
>> index d1d21ed..67c0098 100644
>> --- a/arch/x86/include/asm/u-boot-x86.h
>> +++ b/arch/x86/include/asm/u-boot-x86.h
>> @@ -8,12 +8,15 @@
>> #ifndef _U_BOOT_I386_H_
>> #define _U_BOOT_I386_H_ 1
>>
>> +extern u32 gdt;
>
> Perhaps this should be declared as char gdt[] so you don't need to
> take its address later? See asm/linkage.h for how they do it.
Good idea!
>> +
>> /* cpu/.../cpu.c */
>> int arch_cpu_init(void);
>> int x86_cpu_init_f(void);
>> int cpu_init_f(void);
>> void init_gd(gd_t *id, u64 *gdt_addr);
>> void setup_gdt(gd_t *id, u64 *gdt_addr);
>> +void setup_fsp_gdt(void);
>
> Please add function comment.
Sure.
>> int init_cache(void);
>> int cleanup_before_linux(void);
>>
>> diff --git a/arch/x86/lib/fsp/fsp_support.c b/arch/x86/lib/fsp/fsp_support.c
>> index 5809235..4585166 100644
>> --- a/arch/x86/lib/fsp/fsp_support.c
>> +++ b/arch/x86/lib/fsp/fsp_support.c
>> @@ -173,6 +173,9 @@ void fsp_init(u32 stack_top, u32 boot_mode, void *nvs_buf)
>>
>> post_code(POST_PRE_MRC);
>>
>> + /* Load GDT for FSP */
>> + setup_fsp_gdt();
>> +
>> /*
>> * Use ASM code to ensure the register value in EAX & ECX
>> * will be passed into BlContinuationFunc
>> --
Regards,
Bin
More information about the U-Boot
mailing list