efi/x86: Remove GDT setup from efi_main
authorArvind Sankar <nivedita@alum.mit.edu>
Sun, 2 Feb 2020 17:13:51 +0000 (12:13 -0500)
committerArd Biesheuvel <ardb@kernel.org>
Sat, 22 Feb 2020 22:37:37 +0000 (23:37 +0100)
The 64-bit kernel will already load a GDT in startup_64, which is the
next function to execute after return from efi_main.

Add GDT setup code to the 32-bit kernel's startup_32 as well. Doing it
in the head code has the advantage that we can avoid potentially
corrupting the GDT during copy/decompression. This also removes
dependence on having a specific GDT layout setup by the bootloader.

Both startup_32 and startup_64 now clear interrupts on entry, so we can
remove that from efi_main as well.

Signed-off-by: Arvind Sankar <nivedita@alum.mit.edu>
Link: https://lore.kernel.org/r/20200202171353.3736319-6-nivedita@alum.mit.edu
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
arch/x86/boot/compressed/eboot.c
arch/x86/boot/compressed/head_32.S

index 287393d..c92fe0b 100644 (file)
@@ -712,10 +712,8 @@ struct boot_params *efi_main(efi_handle_t handle,
                             efi_system_table_t *sys_table_arg,
                             struct boot_params *boot_params)
 {
-       struct desc_ptr *gdt = NULL;
        struct setup_header *hdr = &boot_params->hdr;
        efi_status_t status;
-       struct desc_struct *desc;
        unsigned long cmdline_paddr;
 
        sys_table = sys_table_arg;
@@ -753,20 +751,6 @@ struct boot_params *efi_main(efi_handle_t handle,
 
        setup_quirks(boot_params);
 
-       status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, sizeof(*gdt),
-                            (void **)&gdt);
-       if (status != EFI_SUCCESS) {
-               efi_printk("Failed to allocate memory for 'gdt' structure\n");
-               goto fail;
-       }
-
-       gdt->size = 0x800;
-       status = efi_low_alloc(gdt->size, 8, (unsigned long *)&gdt->address);
-       if (status != EFI_SUCCESS) {
-               efi_printk("Failed to allocate memory for 'gdt'\n");
-               goto fail;
-       }
-
        /*
         * If the kernel isn't already loaded at the preferred load
         * address, relocate it.
@@ -793,93 +777,6 @@ struct boot_params *efi_main(efi_handle_t handle,
                goto fail;
        }
 
-       memset((char *)gdt->address, 0x0, gdt->size);
-       desc = (struct desc_struct *)gdt->address;
-
-       /* The first GDT is a dummy. */
-       desc++;
-
-       if (IS_ENABLED(CONFIG_X86_64)) {
-               /* __KERNEL32_CS */
-               desc->limit0    = 0xffff;
-               desc->base0     = 0x0000;
-               desc->base1     = 0x0000;
-               desc->type      = SEG_TYPE_CODE | SEG_TYPE_EXEC_READ;
-               desc->s         = DESC_TYPE_CODE_DATA;
-               desc->dpl       = 0;
-               desc->p         = 1;
-               desc->limit1    = 0xf;
-               desc->avl       = 0;
-               desc->l         = 0;
-               desc->d         = SEG_OP_SIZE_32BIT;
-               desc->g         = SEG_GRANULARITY_4KB;
-               desc->base2     = 0x00;
-
-               desc++;
-       } else {
-               /* Second entry is unused on 32-bit */
-               desc++;
-       }
-
-       /* __KERNEL_CS */
-       desc->limit0    = 0xffff;
-       desc->base0     = 0x0000;
-       desc->base1     = 0x0000;
-       desc->type      = SEG_TYPE_CODE | SEG_TYPE_EXEC_READ;
-       desc->s         = DESC_TYPE_CODE_DATA;
-       desc->dpl       = 0;
-       desc->p         = 1;
-       desc->limit1    = 0xf;
-       desc->avl       = 0;
-
-       if (IS_ENABLED(CONFIG_X86_64)) {
-               desc->l = 1;
-               desc->d = 0;
-       } else {
-               desc->l = 0;
-               desc->d = SEG_OP_SIZE_32BIT;
-       }
-       desc->g         = SEG_GRANULARITY_4KB;
-       desc->base2     = 0x00;
-       desc++;
-
-       /* __KERNEL_DS */
-       desc->limit0    = 0xffff;
-       desc->base0     = 0x0000;
-       desc->base1     = 0x0000;
-       desc->type      = SEG_TYPE_DATA | SEG_TYPE_READ_WRITE;
-       desc->s         = DESC_TYPE_CODE_DATA;
-       desc->dpl       = 0;
-       desc->p         = 1;
-       desc->limit1    = 0xf;
-       desc->avl       = 0;
-       desc->l         = 0;
-       desc->d         = SEG_OP_SIZE_32BIT;
-       desc->g         = SEG_GRANULARITY_4KB;
-       desc->base2     = 0x00;
-       desc++;
-
-       if (IS_ENABLED(CONFIG_X86_64)) {
-               /* Task segment value */
-               desc->limit0    = 0x0000;
-               desc->base0     = 0x0000;
-               desc->base1     = 0x0000;
-               desc->type      = SEG_TYPE_TSS;
-               desc->s         = 0;
-               desc->dpl       = 0;
-               desc->p         = 1;
-               desc->limit1    = 0x0;
-               desc->avl       = 0;
-               desc->l         = 0;
-               desc->d         = 0;
-               desc->g         = SEG_GRANULARITY_4KB;
-               desc->base2     = 0x00;
-               desc++;
-       }
-
-       asm volatile("cli");
-       asm volatile ("lgdt %0" : : "m" (*gdt));
-
        return boot_params;
 fail:
        efi_printk("efi_main() failed!\n");
index cb2cb91..356060c 100644 (file)
 SYM_FUNC_START(startup_32)
        cld
        cli
-       movl    $__BOOT_DS, %eax
-       movl    %eax, %ds
-       movl    %eax, %es
-       movl    %eax, %fs
-       movl    %eax, %gs
-       movl    %eax, %ss
 
 /*
  * Calculate the delta between where we were compiled to run
@@ -84,6 +78,19 @@ SYM_FUNC_START(startup_32)
 1:     popl    %ebp
        subl    $1b, %ebp
 
+       /* Load new GDT */
+       leal    gdt(%ebp), %eax
+       movl    %eax, 2(%eax)
+       lgdt    (%eax)
+
+       /* Load segment registers with our descriptors */
+       movl    $__BOOT_DS, %eax
+       movl    %eax, %ds
+       movl    %eax, %es
+       movl    %eax, %fs
+       movl    %eax, %gs
+       movl    %eax, %ss
+
 /*
  * %ebp contains the address we are loaded at by the boot loader and %ebx
  * contains the address where we should move the kernel image temporarily
@@ -129,6 +136,16 @@ SYM_FUNC_START(startup_32)
        cld
        popl    %esi
 
+       /*
+        * The GDT may get overwritten either during the copy we just did or
+        * during extract_kernel below. To avoid any issues, repoint the GDTR
+        * to the new copy of the GDT. EAX still contains the previously
+        * calculated relocation offset of init_size - _end.
+        */
+       leal    gdt(%ebx), %edx
+       addl    %eax, 2(%edx)
+       lgdt    (%edx)
+
 /*
  * Jump to the relocated address.
  */
@@ -201,6 +218,17 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)
        jmp     *%eax
 SYM_FUNC_END(.Lrelocated)
 
+       .data
+       .balign 8
+SYM_DATA_START_LOCAL(gdt)
+       .word   gdt_end - gdt - 1
+       .long   0
+       .word   0
+       .quad   0x0000000000000000      /* Reserved */
+       .quad   0x00cf9a000000ffff      /* __KERNEL_CS */
+       .quad   0x00cf92000000ffff      /* __KERNEL_DS */
+SYM_DATA_END_LABEL(gdt, SYM_L_LOCAL, gdt_end)
+
 /*
  * Stack and heap for uncompression
  */