Skip to content

Commit

Permalink
efi/x86: Remove GDT setup from efi_main
Browse files Browse the repository at this point in the history
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 <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Ard Biesheuvel <[email protected]>
  • Loading branch information
nivedita76 authored and ardbiesheuvel committed Feb 22, 2020
1 parent cae0e43 commit ef5a7b5
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 109 deletions.
103 changes: 0 additions & 103 deletions arch/x86/boot/compressed/eboot.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand All @@ -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");
Expand Down
40 changes: 34 additions & 6 deletions arch/x86/boot/compressed/head_32.S
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,6 @@
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
Expand All @@ -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
Expand Down Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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
*/
Expand Down

0 comments on commit ef5a7b5

Please sign in to comment.