Commit 7cc3afdf authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'x86-efi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86 EFI changes from Ingo Molnar:
 "The main changes:

  - Add debug code to the dump EFI pagetable - Borislav Petkov

  - Make 1:1 runtime mapping robust when booting on machines with lots
    of memory - Borislav Petkov

  - Move the EFI facilities bits out of 'x86_efi_facility' and into
    efi.flags which is the standard architecture independent place to
    keep EFI state, by Matt Fleming.

  - Add 'EFI mixed mode' support: this allows 64-bit kernels to be
    booted from 32-bit firmware.  This needs a bootloader that supports
    the 'EFI handover protocol'.  By Matt Fleming"

* 'x86-efi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (31 commits)
  x86, efi: Abstract x86 efi_early calls
  x86/efi: Restore 'attr' argument to query_variable_info()
  x86/efi: Rip out phys_efi_get_time()
  x86/efi: Preserve segment registers in mixed mode
  x86/boot: Fix non-EFI build
  x86, tools: Fix up compiler warnings
  x86/efi: Re-disable interrupts after calling firmware services
  x86/boot: Don't overwrite cr4 when enabling PAE
  x86/efi: Wire up CONFIG_EFI_MIXED
  x86/efi: Add mixed runtime services support
  x86/efi: Firmware agnostic handover entry points
  x86/efi: Split the boot stub into 32/64 code paths
  x86/efi: Add early thunk code to go from 64-bit to 32-bit
  x86/efi: Build our own EFI services pointer table
  efi: Add separate 32-bit/64-bit definitions
  x86/efi: Delete dead code when checking for non-native
  x86/mm/pageattr: Always dump the right page table in an oops
  x86, tools: Consolidate #ifdef code
  x86/boot: Cleanup header.S by removing some #ifdefs
  efi: Use NULL instead of 0 for pointer
  ...
parents ad8946fb 204b0a1a
......@@ -477,6 +477,9 @@ efi_init (void)
char *cp, vendor[100] = "unknown";
int i;
set_bit(EFI_BOOT, &efi.flags);
set_bit(EFI_64BIT, &efi.flags);
/*
* It's too early to be able to use the standard kernel command line
* support...
......@@ -529,6 +532,8 @@ efi_init (void)
efi.systab->hdr.revision >> 16,
efi.systab->hdr.revision & 0xffff, vendor);
set_bit(EFI_SYSTEM_TABLES, &efi.flags);
palo_phys = EFI_INVALID_TABLE_ADDR;
if (efi_config_init(arch_tables) != 0)
......@@ -657,6 +662,8 @@ efi_enter_virtual_mode (void)
return;
}
set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
/*
* Now that EFI is in virtual mode, we call the EFI functions more
* efficiently:
......
......@@ -1585,6 +1585,20 @@ config EFI_STUB
See Documentation/efi-stub.txt for more information.
config EFI_MIXED
bool "EFI mixed-mode support"
depends on EFI_STUB && X86_64
---help---
Enabling this feature allows a 64-bit kernel to be booted
on a 32-bit firmware, provided that your CPU supports 64-bit
mode.
Note that it is not possible to boot a mixed-mode enabled
kernel via the EFI boot stub - a bootloader that supports
the EFI handover protocol must be used.
If unsure, say N.
config SECCOMP
def_bool y
prompt "Enable seccomp to safely compute untrusted bytecode"
......
......@@ -81,6 +81,15 @@ config X86_PTDUMP
kernel.
If in doubt, say "N"
config EFI_PGT_DUMP
bool "Dump the EFI pagetable"
depends on EFI && X86_PTDUMP
---help---
Enable this if you want to dump the EFI page table before
enabling virtual mode. This can be used to debug miscellaneous
issues with the mapping of the EFI runtime regions into that
table.
config DEBUG_RODATA
bool "Write protect kernel read-only data structures"
default y
......
......@@ -80,7 +80,7 @@ targets += voffset.h
$(obj)/voffset.h: vmlinux FORCE
$(call if_changed,voffset)
sed-zoffset := -e 's/^\([0-9a-fA-F]*\) . \(startup_32\|startup_64\|efi_pe_entry\|efi_stub_entry\|input_data\|_end\|z_.*\)$$/\#define ZO_\2 0x\1/p'
sed-zoffset := -e 's/^\([0-9a-fA-F]*\) . \(startup_32\|startup_64\|efi32_stub_entry\|efi64_stub_entry\|efi_pe_entry\|input_data\|_end\|z_.*\)$$/\#define ZO_\2 0x\1/p'
quiet_cmd_zoffset = ZOFFSET $@
cmd_zoffset = $(NM) $< | sed -n $(sed-zoffset) > $@
......
This diff is collapsed.
......@@ -37,6 +37,24 @@ struct efi_graphics_output_mode_info {
u32 pixels_per_scan_line;
} __packed;
struct efi_graphics_output_protocol_mode_32 {
u32 max_mode;
u32 mode;
u32 info;
u32 size_of_info;
u64 frame_buffer_base;
u32 frame_buffer_size;
} __packed;
struct efi_graphics_output_protocol_mode_64 {
u32 max_mode;
u32 mode;
u64 info;
u64 size_of_info;
u64 frame_buffer_base;
u64 frame_buffer_size;
} __packed;
struct efi_graphics_output_protocol_mode {
u32 max_mode;
u32 mode;
......@@ -46,6 +64,20 @@ struct efi_graphics_output_protocol_mode {
unsigned long frame_buffer_size;
} __packed;
struct efi_graphics_output_protocol_32 {
u32 query_mode;
u32 set_mode;
u32 blt;
u32 mode;
};
struct efi_graphics_output_protocol_64 {
u64 query_mode;
u64 set_mode;
u64 blt;
u64 mode;
};
struct efi_graphics_output_protocol {
void *query_mode;
unsigned long set_mode;
......@@ -53,10 +85,38 @@ struct efi_graphics_output_protocol {
struct efi_graphics_output_protocol_mode *mode;
};
struct efi_uga_draw_protocol_32 {
u32 get_mode;
u32 set_mode;
u32 blt;
};
struct efi_uga_draw_protocol_64 {
u64 get_mode;
u64 set_mode;
u64 blt;
};
struct efi_uga_draw_protocol {
void *get_mode;
void *set_mode;
void *blt;
};
struct efi_config {
u64 image_handle;
u64 table;
u64 allocate_pool;
u64 allocate_pages;
u64 get_memory_map;
u64 free_pool;
u64 free_pages;
u64 locate_handle;
u64 handle_protocol;
u64 exit_boot_services;
u64 text_output;
efi_status_t (*call)(unsigned long, ...);
bool is64;
} __packed;
#endif /* BOOT_COMPRESSED_EBOOT_H */
#include <asm/segment.h>
#include <asm/msr.h>
#include <asm/processor-flags.h>
#include "../../platform/efi/efi_stub_64.S"
#ifdef CONFIG_EFI_MIXED
.code64
.text
ENTRY(efi64_thunk)
push %rbp
push %rbx
subq $16, %rsp
leaq efi_exit32(%rip), %rax
movl %eax, 8(%rsp)
leaq efi_gdt64(%rip), %rax
movl %eax, 4(%rsp)
movl %eax, 2(%rax) /* Fixup the gdt base address */
leaq efi32_boot_gdt(%rip), %rax
movl %eax, (%rsp)
call __efi64_thunk
addq $16, %rsp
pop %rbx
pop %rbp
ret
ENDPROC(efi64_thunk)
#endif /* CONFIG_EFI_MIXED */
......@@ -42,26 +42,53 @@ ENTRY(startup_32)
ENTRY(efi_pe_entry)
add $0x4, %esp
call 1f
1: popl %esi
subl $1b, %esi
popl %ecx
movl %ecx, efi32_config(%esi) /* Handle */
popl %ecx
movl %ecx, efi32_config+8(%esi) /* EFI System table pointer */
/* Relocate efi_config->call() */
leal efi32_config(%esi), %eax
add %esi, 88(%eax)
pushl %eax
call make_boot_params
cmpl $0, %eax
je 1f
movl 0x4(%esp), %esi
movl (%esp), %ecx
je fail
popl %ecx
pushl %eax
pushl %esi
pushl %ecx
sub $0x4, %esp
jmp 2f /* Skip efi_config initialization */
ENTRY(efi_stub_entry)
ENTRY(efi32_stub_entry)
add $0x4, %esp
popl %ecx
popl %edx
call 1f
1: popl %esi
subl $1b, %esi
movl %ecx, efi32_config(%esi) /* Handle */
movl %edx, efi32_config+8(%esi) /* EFI System table pointer */
/* Relocate efi_config->call() */
leal efi32_config(%esi), %eax
add %esi, 88(%eax)
pushl %eax
2:
call efi_main
cmpl $0, %eax
movl %eax, %esi
jne 2f
1:
fail:
/* EFI init failed, so hang. */
hlt
jmp 1b
jmp fail
2:
call 3f
3:
......@@ -202,6 +229,15 @@ relocated:
xorl %ebx, %ebx
jmp *%eax
#ifdef CONFIG_EFI_STUB
.data
efi32_config:
.fill 11,8,0
.long efi_call_phys
.long 0
.byte 0
#endif
/*
* Stack and heap for uncompression
*/
......
......@@ -113,7 +113,8 @@ ENTRY(startup_32)
lgdt gdt(%ebp)
/* Enable PAE mode */
movl $(X86_CR4_PAE), %eax
movl %cr4, %eax
orl $X86_CR4_PAE, %eax
movl %eax, %cr4
/*
......@@ -178,6 +179,13 @@ ENTRY(startup_32)
*/
pushl $__KERNEL_CS
leal startup_64(%ebp), %eax
#ifdef CONFIG_EFI_MIXED
movl efi32_config(%ebp), %ebx
cmp $0, %ebx
jz 1f
leal handover_entry(%ebp), %eax
1:
#endif
pushl %eax
/* Enter paged protected Mode, activating Long Mode */
......@@ -188,6 +196,30 @@ ENTRY(startup_32)
lret
ENDPROC(startup_32)
#ifdef CONFIG_EFI_MIXED
.org 0x190
ENTRY(efi32_stub_entry)
add $0x4, %esp /* Discard return address */
popl %ecx
popl %edx
popl %esi
leal (BP_scratch+4)(%esi), %esp
call 1f
1: pop %ebp
subl $1b, %ebp
movl %ecx, efi32_config(%ebp)
movl %edx, efi32_config+8(%ebp)
sgdtl efi32_boot_gdt(%ebp)
leal efi32_config(%ebp), %eax
movl %eax, efi_config(%ebp)
jmp startup_32
ENDPROC(efi32_stub_entry)
#endif
.code64
.org 0x200
ENTRY(startup_64)
......@@ -209,26 +241,48 @@ ENTRY(startup_64)
jmp preferred_addr
ENTRY(efi_pe_entry)
mov %rcx, %rdi
mov %rdx, %rsi
pushq %rdi
pushq %rsi
movq %rcx, efi64_config(%rip) /* Handle */
movq %rdx, efi64_config+8(%rip) /* EFI System table pointer */
leaq efi64_config(%rip), %rax
movq %rax, efi_config(%rip)
call 1f
1: popq %rbp
subq $1b, %rbp
/*
* Relocate efi_config->call().
*/
addq %rbp, efi64_config+88(%rip)
movq %rax, %rdi
call make_boot_params
cmpq $0,%rax
je 1f
mov %rax, %rdx
popq %rsi
popq %rdi
je fail
mov %rax, %rsi
jmp 2f /* Skip the relocation */
ENTRY(efi_stub_entry)
handover_entry:
call 1f
1: popq %rbp
subq $1b, %rbp
/*
* Relocate efi_config->call().
*/
movq efi_config(%rip), %rax
addq %rbp, 88(%rax)
2:
movq efi_config(%rip), %rdi
call efi_main
movq %rax,%rsi
cmpq $0,%rax
jne 2f
1:
fail:
/* EFI init failed, so hang. */
hlt
jmp 1b
jmp fail
2:
call 3f
3:
......@@ -307,6 +361,20 @@ preferred_addr:
leaq relocated(%rbx), %rax
jmp *%rax
#ifdef CONFIG_EFI_STUB
.org 0x390
ENTRY(efi64_stub_entry)
movq %rdi, efi64_config(%rip) /* Handle */
movq %rsi, efi64_config+8(%rip) /* EFI System table pointer */
leaq efi64_config(%rip), %rax
movq %rax, efi_config(%rip)
movq %rdx, %rsi
jmp handover_entry
ENDPROC(efi64_stub_entry)
#endif
.text
relocated:
......@@ -372,6 +440,25 @@ gdt:
.quad 0x0000000000000000 /* TS continued */
gdt_end:
#ifdef CONFIG_EFI_STUB
efi_config:
.quad 0
#ifdef CONFIG_EFI_MIXED
.global efi32_config
efi32_config:
.fill 11,8,0
.quad efi64_thunk
.byte 0
#endif
.global efi64_config
efi64_config:
.fill 11,8,0
.quad efi_call6
.byte 1
#endif /* CONFIG_EFI_STUB */
/*
* Stack and heap for uncompression
*/
......
......@@ -283,7 +283,7 @@ _start:
# Part 2 of the header, from the old setup.S
.ascii "HdrS" # header signature
.word 0x020c # header version number (>= 0x0105)
.word 0x020d # header version number (>= 0x0105)
# or else old loadlin-1.5 will fail)
.globl realmode_swtch
realmode_swtch: .word 0, 0 # default_switch, SETUPSEG
......@@ -375,7 +375,8 @@ xloadflags:
# define XLF0 0
#endif
#if defined(CONFIG_RELOCATABLE) && defined(CONFIG_X86_64)
#if defined(CONFIG_RELOCATABLE) && defined(CONFIG_X86_64) && \
!defined(CONFIG_EFI_MIXED)
/* kernel/boot_param/ramdisk could be loaded above 4g */
# define XLF1 XLF_CAN_BE_LOADED_ABOVE_4G
#else
......@@ -383,10 +384,14 @@ xloadflags:
#endif
#ifdef CONFIG_EFI_STUB
# ifdef CONFIG_X86_64
# define XLF23 XLF_EFI_HANDOVER_64 /* 64-bit EFI handover ok */
# ifdef CONFIG_EFI_MIXED
# define XLF23 (XLF_EFI_HANDOVER_32|XLF_EFI_HANDOVER_64)
# else
# define XLF23 XLF_EFI_HANDOVER_32 /* 32-bit EFI handover ok */
# ifdef CONFIG_X86_64
# define XLF23 XLF_EFI_HANDOVER_64 /* 64-bit EFI handover ok */
# else
# define XLF23 XLF_EFI_HANDOVER_32 /* 32-bit EFI handover ok */
# endif
# endif
#else
# define XLF23 0
......@@ -426,13 +431,7 @@ pref_address: .quad LOAD_PHYSICAL_ADDR # preferred load addr
#define INIT_SIZE VO_INIT_SIZE
#endif
init_size: .long INIT_SIZE # kernel initialization size
handover_offset:
#ifdef CONFIG_EFI_STUB
.long 0x30 # offset to the handover
# protocol entry point
#else
.long 0
#endif
handover_offset: .long 0 # Filled in by build.c
# End of setup header #####################################################
......
......@@ -53,7 +53,8 @@ int is_big_kernel;
#define PECOFF_RELOC_RESERVE 0x20
unsigned long efi_stub_entry;
unsigned long efi32_stub_entry;
unsigned long efi64_stub_entry;
unsigned long efi_pe_entry;
unsigned long startup_64;
......@@ -219,6 +220,52 @@ static void update_pecoff_text(unsigned int text_start, unsigned int file_sz)
update_pecoff_section_header(".text", text_start, text_sz);
}
static int reserve_pecoff_reloc_section(int c)
{
/* Reserve 0x20 bytes for .reloc section */
memset(buf+c, 0, PECOFF_RELOC_RESERVE);
return PECOFF_RELOC_RESERVE;
}
static void efi_stub_defaults(void)
{
/* Defaults for old kernel */
#ifdef CONFIG_X86_32
efi_pe_entry = 0x10;
#else
efi_pe_entry = 0x210;
startup_64 = 0x200;
#endif
}
static void efi_stub_entry_update(void)
{
unsigned long addr = efi32_stub_entry;
#ifdef CONFIG_X86_64
/* Yes, this is really how we defined it :( */
addr = efi64_stub_entry - 0x200;
#endif
#ifdef CONFIG_EFI_MIXED
if (efi32_stub_entry != addr)
die("32-bit and 64-bit EFI entry points do not match\n");
#endif
put_unaligned_le32(addr, &buf[0x264]);
}
#else
static inline void update_pecoff_setup_and_reloc(unsigned int size) {}
static inline void update_pecoff_text(unsigned int text_start,
unsigned int file_sz) {}
static inline void efi_stub_defaults(void) {}
static inline void efi_stub_entry_update(void) {}
static inline int reserve_pecoff_reloc_section(int c)
{
return 0;
}
#endif /* CONFIG_EFI_STUB */
......@@ -250,7 +297,8 @@ static void parse_zoffset(char *fname)
p = (char *)buf;
while (p && *p) {
PARSE_ZOFS(p, efi_stub_entry);
PARSE_ZOFS(p, efi32_stub_entry);
PARSE_ZOFS(p, efi64_stub_entry);
PARSE_ZOFS(p, efi_pe_entry);
PARSE_ZOFS(p, startup_64);
......@@ -271,15 +319,7 @@ int main(int argc, char ** argv)
void *kernel;
u32 crc = 0xffffffffUL;
/* Defaults for old kernel */
#ifdef CONFIG_X86_32
efi_pe_entry = 0x10;
efi_stub_entry = 0x30;
#else
efi_pe_entry = 0x210;
efi_stub_entry = 0x230;
startup_64 = 0x200;
#endif
efi_stub_defaults();
if (argc != 5)
usage();
......@@ -302,11 +342,7 @@ int main(int argc, char ** argv)
die("Boot block hasn't got boot flag (0xAA55)");
fclose(file);
#ifdef CONFIG_EFI_STUB
/* Reserve 0x20 bytes for .reloc section */
memset(buf+c, 0, PECOFF_RELOC_RESERVE);
c += PECOFF_RELOC_RESERVE;
#endif
c += reserve_pecoff_reloc_section(c);
/* Pad unused space with zeros */
setup_sectors = (c + 511) / 512;
......@@ -315,9 +351,7 @@ int main(int argc, char ** argv)
i = setup_sectors*512;
memset(buf+c, 0, i-c);
#ifdef CONFIG_EFI_STUB
update_pecoff_setup_and_reloc(i);
#endif
/* Set the default root device */
put_unaligned_le16(DEFAULT_ROOT_DEV, &buf[508]);
......@@ -342,14 +376,9 @@ int main(int argc, char ** argv)
buf[0x1f1] = setup_sectors-1;
put_unaligned_le32(sys_size, &buf[0x1f4]);
#ifdef CONFIG_EFI_STUB
update_pecoff_text(setup_sectors * 512, sz + i + ((sys_size * 16) - sz));
#ifdef CONFIG_X86_64 /* Yes, this is really how we defined it :( */
efi_stub_entry -= 0x200;
#endif
put_unaligned_le32(efi_stub_entry, &buf[0x264]);
#endif
efi_stub_entry_update();
crc = partial_crc32(buf, i, crc);
if (fwrite(buf, 1, i, dest) != i)
......
......@@ -19,9 +19,11 @@
*/
#define EFI_OLD_MEMMAP EFI_ARCH_1
#define EFI32_LOADER_SIGNATURE "EL32"
#define EFI64_LOADER_SIGNATURE "EL64"
#ifdef CONFIG_X86_32
#define EFI_LOADER_SIGNATURE "EL32"
extern unsigned long asmlinkage efi_call_phys(void *, ...);
......@@ -57,8 +59,6 @@ extern unsigned long asmlinkage efi_call_phys(void *, ...);
#else /* !CONFIG_X86_32 */