lkml.org 
[lkml]   [2020]   [Jul]   [24]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v5 29/75] x86/head/64: Install startup GDT
    Date
    From: Joerg Roedel <jroedel@suse.de>

    Handling exceptions during boot requires a working GDT. The kernel GDT
    can't be used on the direct mapping, so load a startup GDT and setup
    segments.

    Signed-off-by: Joerg Roedel <jroedel@suse.de>
    ---
    arch/x86/include/asm/setup.h | 1 +
    arch/x86/kernel/head64.c | 33 +++++++++++++++++++++++++++++++++
    arch/x86/kernel/head_64.S | 14 ++++++++++++++
    3 files changed, 48 insertions(+)

    diff --git a/arch/x86/include/asm/setup.h b/arch/x86/include/asm/setup.h
    index 84b645cc8bc9..5c2fd05bd52c 100644
    --- a/arch/x86/include/asm/setup.h
    +++ b/arch/x86/include/asm/setup.h
    @@ -48,6 +48,7 @@ extern void reserve_standard_io_resources(void);
    extern void i386_reserve_resources(void);
    extern unsigned long __startup_64(unsigned long physaddr, struct boot_params *bp);
    extern unsigned long __startup_secondary_64(void);
    +extern void startup_64_setup_env(unsigned long physbase);
    extern int early_make_pgtable(unsigned long address);

    #ifdef CONFIG_X86_INTEL_MID
    diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c
    index cbb71c1b574f..8c82be44be94 100644
    --- a/arch/x86/kernel/head64.c
    +++ b/arch/x86/kernel/head64.c
    @@ -61,6 +61,24 @@ unsigned long vmemmap_base __ro_after_init = __VMEMMAP_BASE_L4;
    EXPORT_SYMBOL(vmemmap_base);
    #endif

    +/*
    + * GDT used on the boot CPU before switching to virtual addresses.
    + */
    +static struct desc_struct startup_gdt[GDT_ENTRIES] = {
    + [GDT_ENTRY_KERNEL32_CS] = GDT_ENTRY_INIT(0xc09b, 0, 0xfffff),
    + [GDT_ENTRY_KERNEL_CS] = GDT_ENTRY_INIT(0xa09b, 0, 0xfffff),
    + [GDT_ENTRY_KERNEL_DS] = GDT_ENTRY_INIT(0xc093, 0, 0xfffff),
    +};
    +
    +/*
    + * Address needs to be set at runtime because it references the startup_gdt
    + * while the kernel still uses a direct mapping.
    + */
    +static struct desc_ptr startup_gdt_descr = {
    + .size = sizeof(startup_gdt),
    + .address = 0,
    +};
    +
    #define __head __section(.head.text)

    static void __head *fixup_pointer(void *ptr, unsigned long physaddr)
    @@ -489,3 +507,18 @@ void __init x86_64_start_reservations(char *real_mode_data)

    start_kernel();
    }
    +
    +/*
    + * Setup boot CPU state needed before kernel switches to virtual addresses.
    + */
    +void __head startup_64_setup_env(unsigned long physbase)
    +{
    + /* Load GDT */
    + startup_gdt_descr.address = (unsigned long)fixup_pointer(startup_gdt, physbase);
    + native_load_gdt(&startup_gdt_descr);
    +
    + /* New GDT is live - reload data segment registers */
    + asm volatile("movl %%eax, %%ds\n"
    + "movl %%eax, %%ss\n"
    + "movl %%eax, %%es\n" : : "a"(__KERNEL_DS) : "memory");
    +}
    diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S
    index 16da4ac01597..2b2e91627221 100644
    --- a/arch/x86/kernel/head_64.S
    +++ b/arch/x86/kernel/head_64.S
    @@ -73,6 +73,20 @@ SYM_CODE_START_NOALIGN(startup_64)
    /* Set up the stack for verify_cpu(), similar to initial_stack below */
    leaq (__end_init_task - SIZEOF_PTREGS)(%rip), %rsp

    + leaq _text(%rip), %rdi
    + pushq %rsi
    + call startup_64_setup_env
    + popq %rsi
    +
    + /* Now switch to __KERNEL_CS so IRET works reliably */
    + pushq $__KERNEL_CS
    + leaq .Lon_kernel_cs(%rip), %rax
    + pushq %rax
    + lretq
    +
    +.Lon_kernel_cs:
    + UNWIND_HINT_EMPTY
    +
    /* Sanitize CPU configuration */
    call verify_cpu

    --
    2.27.0
    \
     
     \ /
      Last update: 2020-07-24 18:10    [W:6.598 / U:0.128 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site