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

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 */
#define EFI_LOADER_SIGNATURE "EL64"
extern u64 efi_call0(void *fp);
extern u64 efi_call1(void *fp, u64 arg1);
extern u64 efi_call2(void *fp, u64 arg1, u64 arg2);
......@@ -119,7 +119,6 @@ extern void __iomem *efi_ioremap(unsigned long addr, unsigned long size,
#endif /* CONFIG_X86_32 */
extern int add_efi_memmap;
extern unsigned long x86_efi_facility;
extern struct efi_scratch efi_scratch;
extern void efi_set_executable(efi_memory_desc_t *md, bool executable);
extern int efi_memblock_x86_reserve_range(void);
......@@ -130,10 +129,12 @@ extern void efi_memory_uc(u64 addr, unsigned long size);
extern void __init efi_map_region(efi_memory_desc_t *md);
extern void __init efi_map_region_fixed(efi_memory_desc_t *md);
extern void efi_sync_low_kernel_mappings(void);
extern void efi_setup_page_tables(void);
extern int efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages);
extern void efi_cleanup_page_tables(unsigned long pa_memmap, unsigned num_pages);
extern void __init old_map_region(efi_memory_desc_t *md);
extern void __init runtime_code_page_mkexec(void);
extern void __init efi_runtime_mkexec(void);
extern void __init efi_dump_pagetable(void);
extern void __init efi_apply_memmap_quirks(void);
struct efi_setup_data {
......@@ -153,8 +154,40 @@ static inline bool efi_is_native(void)
return IS_ENABLED(CONFIG_X86_64) == efi_enabled(EFI_64BIT);
}
static inline bool efi_runtime_supported(void)
{
if (efi_is_native())
return true;
if (IS_ENABLED(CONFIG_EFI_MIXED) && !efi_enabled(EFI_OLD_MEMMAP))
return true;
return false;
}
extern struct console early_efi_console;
extern void parse_efi_setup(u64 phys_addr, u32 data_len);
#ifdef CONFIG_EFI_MIXED
extern void efi_thunk_runtime_setup(void);
extern efi_status_t efi_thunk_set_virtual_address_map(
void *phys_set_virtual_address_map,
unsigned long memory_map_size,
unsigned long descriptor_size,
u32 descriptor_version,
efi_memory_desc_t *virtual_map);
#else
static inline void efi_thunk_runtime_setup(void) {}
static inline efi_status_t efi_thunk_set_virtual_address_map(
void *phys_set_virtual_address_map,
unsigned long memory_map_size,
unsigned long descriptor_size,
u32 descriptor_version,
efi_memory_desc_t *virtual_map)
{
return EFI_SUCCESS;
}
#endif /* CONFIG_EFI_MIXED */
#else
/*
* IF EFI is not configured, have the EFI calls return -ENOSYS.
......
......@@ -15,9 +15,10 @@
: (prot))
#ifndef __ASSEMBLY__
#include <asm/x86_init.h>
void ptdump_walk_pgd_level(struct seq_file *m, pgd_t *pgd);
/*
* ZERO_PAGE is a global shared page that is always zero: used
* for zero-mapped memory areas etc..
......
......@@ -382,9 +382,13 @@ static inline void update_page_count(int level, unsigned long pages) { }
* as a pte too.
*/
extern pte_t *lookup_address(unsigned long address, unsigned int *level);
extern pte_t *lookup_address_in_pgd(pgd_t *pgd, unsigned long address,
unsigned int *level);
extern phys_addr_t slow_virt_to_phys(void *__address);
extern int kernel_map_pages_in_pgd(pgd_t *pgd, u64 pfn, unsigned long address,
unsigned numpages, unsigned long page_flags);
void kernel_unmap_pages_in_pgd(pgd_t *root, unsigned long address,
unsigned numpages);
#endif /* !__ASSEMBLY__ */
#endif /* _ASM_X86_PGTABLE_DEFS_H */
......@@ -926,11 +926,11 @@ void __init setup_arch(char **cmdline_p)
#ifdef CONFIG_EFI
if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature,
"EL32", 4)) {
set_bit(EFI_BOOT, &x86_efi_facility);
set_bit(EFI_BOOT, &efi.flags);
} else if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature,
"EL64", 4)) {
set_bit(EFI_BOOT, &x86_efi_facility);
set_bit(EFI_64BIT, &x86_efi_facility);
set_bit(EFI_BOOT, &efi.flags);
set_bit(EFI_64BIT, &efi.flags);
}
if (efi_enabled(EFI_BOOT))
......
......@@ -30,6 +30,7 @@ struct pg_state {
unsigned long start_address;
unsigned long current_address;
const struct addr_marker *marker;
bool to_dmesg;
};
struct addr_marker {
......@@ -88,10 +89,28 @@ static struct addr_marker address_markers[] = {
#define PUD_LEVEL_MULT (PTRS_PER_PMD * PMD_LEVEL_MULT)
#define PGD_LEVEL_MULT (PTRS_PER_PUD * PUD_LEVEL_MULT)
#define pt_dump_seq_printf(m, to_dmesg, fmt, args...) \
({ \
if (to_dmesg) \
printk(KERN_INFO fmt, ##args); \
else \
if (m) \
seq_printf(m, fmt, ##args); \
})
#define pt_dump_cont_printf(m, to_dmesg, fmt, args...) \
({ \
if (to_dmesg) \
printk(KERN_CONT fmt, ##args); \
else \
if (m) \
seq_printf(m, fmt, ##args); \
})
/*
* Print a readable form of a pgprot_t to the seq_file
*/
static void printk_prot(struct seq_file *m, pgprot_t prot, int level)
static void printk_prot(struct seq_file *m, pgprot_t prot, int level, bool dmsg)
{
pgprotval_t pr = pgprot_val(prot);
static const char * const level_name[] =
......@@ -99,47 +118,47 @@ static void printk_prot(struct seq_file *m, pgprot_t prot, int level)
if (!pgprot_val(prot)) {
/* Not present */
seq_printf(m, " ");
pt_dump_cont_printf(m, dmsg, " ");
} else {
if (pr & _PAGE_USER)
seq_printf(m, "USR ");
pt_dump_cont_printf(m, dmsg, "USR ");
else
seq_printf(m, " ");
pt_dump_cont_printf(m, dmsg, " ");
if (pr & _PAGE_RW)
seq_printf(m, "RW ");
pt_dump_cont_printf(m, dmsg, "RW ");
else
seq_printf(m, "ro ");
pt_dump_cont_printf(m, dmsg, "ro ");
if (pr & _PAGE_PWT)
seq_printf(m, "PWT ");
pt_dump_cont_printf(m, dmsg, "PWT ");
else
seq_printf(m, " ");
pt_dump_cont_printf(m, dmsg, " ");
if (pr & _PAGE_PCD)
seq_printf(m, "PCD ");
pt_dump_cont_printf(m, dmsg, "PCD ");
else
seq_printf(m, " ");
pt_dump_cont_printf(m, dmsg, " ");
/* Bit 9 has a different meaning on level 3 vs 4 */
if (level <= 3) {
if (pr & _PAGE_PSE)
seq_printf(m, "PSE ");
pt_dump_cont_printf(m, dmsg, "PSE ");
else
seq_printf(m, " ");
pt_dump_cont_printf(m, dmsg, " ");
} else {
if (pr & _PAGE_PAT)
seq_printf(m, "pat ");
pt_dump_cont_printf(m, dmsg, "pat ");
else
seq_printf(m, " ");
pt_dump_cont_printf(m, dmsg, " ");
}
if (pr & _PAGE_GLOBAL)
seq_printf(m, "GLB ");
pt_dump_cont_printf(m, dmsg, "GLB ");
else
seq_printf(m, " ");
pt_dump_cont_printf(m, dmsg, " ");
if (pr & _PAGE_NX)
seq_printf(m, "NX ");
pt_dump_cont_printf(m, dmsg, "NX ");
else
seq_printf(m, "x ");
pt_dump_cont_printf(m, dmsg, "x ");
}
seq_printf(m, "%s\n", level_name[level]);
pt_dump_cont_printf(m, dmsg, "%s\n", level_name[level]);
}
/*
......@@ -178,7 +197,8 @@ static void note_page(struct seq_file *m, struct pg_state *st,
st->current_prot = new_prot;
st->level = level;
st->marker = address_markers;
seq_printf(m, "---[ %s ]---\n", st->marker->name);
pt_dump_seq_printf(m, st->to_dmesg, "---[ %s ]---\n",
st->marker->name);
} else if (prot != cur || level != st->level ||
st->current_address >= st->marker[1].start_address) {
const char *unit = units;
......@@ -188,17 +208,17 @@ static void note_page(struct seq_file *m, struct pg_state *st,
/*
* Now print the actual finished series
*/
seq_printf(m, "0x%0*lx-0x%0*lx ",
width, st->start_address,
width, st->current_address);
pt_dump_seq_printf(m, st->to_dmesg, "0x%0*lx-0x%0*lx ",
width, st->start_address,
width, st->current_address);
delta = (st->current_address - st->start_address) >> 10;
while (!(delta & 1023) && unit[1]) {
delta >>= 10;
unit++;
}
seq_printf(m, "%9lu%c ", delta, *unit);
printk_prot(m, st->current_prot, st->level);
pt_dump_cont_printf(m, st->to_dmesg, "%9lu%c ", delta, *unit);
printk_prot(m, st->current_prot, st->level, st->to_dmesg);
/*
* We print markers for special areas of address space,
......@@ -207,7 +227,8 @@ static void note_page(struct seq_file *m, struct pg_state *st,
*/
if (st->current_address >= st->marker[1].start_address) {
st->marker++;
seq_printf(m, "---[ %s ]---\n", st->marker->name);
pt_dump_seq_printf(m, st->to_dmesg, "---[ %s ]---\n",
st->marker->name);
}
st->start_address = st->current_address;
......@@ -296,7 +317,7 @@ static void walk_pud_level(struct seq_file *m, struct pg_state *st, pgd_t addr,
#define pgd_none(a) pud_none(__pud(pgd_val(a)))
#endif
static void walk_pgd_level(struct seq_file *m)
void ptdump_walk_pgd_level(struct seq_file *m, pgd_t *pgd)
{
#ifdef CONFIG_X86_64
pgd_t *start = (pgd_t *) &init_level4_pgt;
......@@ -304,9 +325,12 @@ static void walk_pgd_level(struct seq_file *m)
pgd_t *start = swapper_pg_dir;
#endif
int i;
struct pg_state st;
struct pg_state st = {};
memset(&st, 0, sizeof(st));
if (pgd) {
start = pgd;
st.to_dmesg = true;
}
for (i = 0; i < PTRS_PER_PGD; i++) {
st.current_address = normalize_addr(i * PGD_LEVEL_MULT);
......@@ -331,7 +355,7 @@ static void walk_pgd_level(struct seq_file *m)
static int ptdump_show(struct seq_file *m, void *v)
{
walk_pgd_level(m);
ptdump_walk_pgd_level(m, NULL);
return 0;
}
......
......@@ -584,8 +584,13 @@ show_fault_oops(struct pt_regs *regs, unsigned long error_code,
if (error_code & PF_INSTR) {
unsigned int level;
pgd_t *pgd;
pte_t *pte;
pte_t *pte = lookup_address(address, &level);
pgd = __va(read_cr3() & PHYSICAL_PAGE_MASK);
pgd += pgd_index(address);
pte = lookup_address_in_pgd(pgd, address, &level);
if (pte && pte_present(*pte) && !pte_exec(*pte))
printk(nx_warning, from_kuid(&init_user_ns, current_uid()));
......
......@@ -323,8 +323,12 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address,
return prot;
}
static pte_t *__lookup_address_in_pgd(pgd_t *pgd, unsigned long address,
unsigned int *level)
/*
* Lookup the page table entry for a virtual address in a specific pgd.
* Return a pointer to the entry and the level of the mapping.
*/
pte_t *lookup_address_in_pgd(pgd_t *pgd, unsigned long address,
unsigned int *level)
{
pud_t *pud;
pmd_t *pmd;
......@@ -365,7 +369,7 @@ static pte_t *__lookup_address_in_pgd(pgd_t *pgd, unsigned long address,
*/
pte_t *lookup_address(unsigned long address, unsigned int *level)
{
return __lookup_address_in_pgd(pgd_offset_k(address), address, level);
return lookup_address_in_pgd(pgd_offset_k(address), address, level);
}
EXPORT_SYMBOL_GPL(lookup_address);
......@@ -373,7 +377,7 @@ static pte_t *_lookup_address_cpa(struct cpa_data *cpa, unsigned long address,
unsigned int *level)
{
if (cpa->pgd)
return __lookup_address_in_pgd(cpa->pgd + pgd_index(address),
return lookup_address_in_pgd(cpa->pgd + pgd_index(address),
address, level);
return lookup_address(address, level);
......@@ -692,6 +696,18 @@ static bool try_to_free_pmd_page(pmd_t *pmd)
return true;
}
static bool try_to_free_pud_page(pud_t *pud)
{
int i;
for (i = 0; i < PTRS_PER_PUD; i++)
if (!pud_none(pud[i]))
return false;
free_page((unsigned long)pud);
return true;
}
static bool unmap_pte_range(pmd_t *pmd, unsigned long start, unsigned long end)
{
pte_t *pte = pte_offset_kernel(pmd, start);
......@@ -805,6 +821,16 @@ static void unmap_pud_range(pgd_t *pgd, unsigned long start, unsigned long end)
*/
}
static void unmap_pgd_range(pgd_t *root, unsigned long addr, unsigned long end)
{
pgd_t *pgd_entry = root + pgd_index(addr);
unmap_pud_range(pgd_entry, addr, end);
if (try_to_free_pud_page((pud_t *)pgd_page_vaddr(*pgd_entry)))
pgd_clear(pgd_entry);
}
static int alloc_pte_page(pmd_t *pmd)
{
pte_t *pte = (pte_t *)get_zeroed_page(GFP_KERNEL | __GFP_NOTRACK);
......@@ -999,9 +1025,8 @@ static int populate_pud(struct cpa_data *cpa, unsigned long start, pgd_t *pgd,
static int populate_pgd(struct cpa_data *cpa, unsigned long addr)
{
pgprot_t pgprot = __pgprot(_KERNPG_TABLE);
bool allocd_pgd = false;
pgd_t *pgd_entry;
pud_t *pud = NULL; /* shut up gcc */
pgd_t *pgd_entry;
int ret;
pgd_entry = cpa->pgd + pgd_index(addr);
......@@ -1015,7 +1040,6 @@ static int populate_pgd(struct cpa_data *cpa, unsigned long addr)
return -1;
set_pgd(pgd_entry, __pgd(__pa(pud) | _KERNPG_TABLE));
allocd_pgd = true;
}
pgprot_val(pgprot) &= ~pgprot_val(cpa->mask_clr);
......@@ -1023,19 +1047,11 @@ static int populate_pgd(struct cpa_data *cpa, unsigned long addr)
ret = populate_pud(cpa, addr, pgd_entry, pgprot);
if (ret < 0) {
unmap_pud_range(pgd_entry, addr,
unmap_pgd_range(cpa->pgd, addr,
addr + (cpa->numpages << PAGE_SHIFT));
if (allocd_pgd) {
/*
* If I allocated this PUD page, I can just as well
* free it in this error path.
*/
pgd_clear(pgd_entry);
free_page((unsigned long)pud);
}
return ret;
}
cpa->numpages = ret;
return 0;
}
......@@ -1861,6 +1877,12 @@ int kernel_map_pages_in_pgd(pgd_t *pgd, u64 pfn, unsigned long address,
return retval;
}
void kernel_unmap_pages_in_pgd(pgd_t *root, unsigned long address,
unsigned numpages)
{
unmap_pgd_range(root, address, address + (numpages << PAGE_SHIFT));
}
/*
* The testcases use internal knowledge of the implementation that shouldn't
* be exposed to the rest of the kernel. Include these directly here.
......
obj-$(CONFIG_EFI) += efi.o efi_$(BITS).o efi_stub_$(BITS).o
obj-$(CONFIG_ACPI_BGRT) += efi-bgrt.o
obj-$(CONFIG_EARLY_PRINTK_EFI) += early_printk.o
obj-$(CONFIG_EFI_MIXED) += efi_thunk_$(BITS).o
This diff is collapsed.
......@@ -40,7 +40,12 @@
static unsigned long efi_rt_eflags;
void efi_sync_low_kernel_mappings(void) {}
void efi_setup_page_tables(void) {}
void __init efi_dump_pagetable(void) {}
int efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages)
{
return 0;
}
void efi_cleanup_page_tables(unsigned long pa_memmap, unsigned num_pages) {}
void __init efi_map_region(efi_memory_desc_t *md)
{
......
This diff is collapsed.
......@@ -7,6 +7,10 @@
*/
#include <linux/linkage.h>
#include <asm/segment.h>
#include <asm/msr.h>
#include <asm/processor-flags.h>
#include <asm/page_types.h>
#define SAVE_XMM \
mov %rsp, %rax; \
......@@ -164,7 +168,169 @@ ENTRY(efi_call6)
ret
ENDPROC(efi_call6)
#ifdef CONFIG_EFI_MIXED
/*
* We run this function from the 1:1 mapping.
*
* This function must be invoked with a 1:1 mapped stack.
*/
ENTRY(__efi64_thunk)
movl %ds, %eax
push %rax
movl %es, %eax
push %rax
movl %ss, %eax
push %rax
subq $32, %rsp
movl %esi, 0x0(%rsp)
movl %edx, 0x4(%rsp)
movl %ecx, 0x8(%rsp)
movq %r8, %rsi
movl %esi, 0xc(%rsp)
movq %r9, %rsi
movl %esi, 0x10(%rsp)
sgdt save_gdt(%rip)
leaq 1f(%rip), %rbx
movq %rbx, func_rt_ptr(%rip)
/* Switch to gdt with 32-bit segments */
movl 64(%rsp), %eax
lgdt (%rax)
leaq efi_enter32(%rip), %rax
pushq $__KERNEL_CS
pushq %rax
lretq
1: addq $32, %rsp
lgdt save_gdt(%rip)
pop %rbx
movl %ebx, %ss
pop %rbx
movl %ebx, %es
pop %rbx
movl %ebx, %ds
/*
* Convert 32-bit status code into 64-bit.
*/
test %rax, %rax
jz 1f
movl %eax, %ecx
andl $0x0fffffff, %ecx
andl $0xf0000000, %eax
shl $32, %rax
or %rcx, %rax
1:
ret
ENDPROC(__efi64_thunk)
ENTRY(efi_exit32)
movq func_rt_ptr(%rip), %rax
push %rax
mov %rdi, %rax
ret
ENDPROC(efi_exit32)
.code32
/*
* EFI service pointer must be in %edi.
*
* The stack should represent the 32-bit calling convention.
*/
ENTRY(efi_enter32)
movl $__KERNEL_DS, %eax
movl %eax, %ds
movl %eax, %es
movl %eax, %ss
/* Reload pgtables */
movl %cr3, %eax
movl %eax, %cr3
/* Disable paging */
movl %cr0, %eax
btrl $X86_CR0_PG_BIT, %eax
movl %eax, %cr0
/* Disable long mode via EFER */
movl $MSR_EFER, %ecx
rdmsr
btrl $_EFER_LME, %eax
wrmsr
call *%edi
/* We must preserve return value */
movl %eax, %edi
/*
* Some firmware will return with interrupts enabled. Be sure to
* disable them before we switch GDTs.
*/
cli
movl 68(%esp), %eax
movl %eax, 2(%eax)
lgdtl (%eax)
movl %cr4, %eax
btsl $(X86_CR4_PAE_BIT), %eax
movl %eax, %cr4
movl %cr3, %eax
movl %eax, %cr3
movl $MSR_EFER, %ecx
rdmsr
btsl $_EFER_LME, %eax
wrmsr
xorl %eax, %eax
lldt %ax
movl 72(%esp), %eax
pushl $__KERNEL_CS
pushl %eax
/* Enable paging */
movl %cr0, %eax
btsl $X86_CR0_PG_BIT, %eax
movl %eax, %cr0
lret
ENDPROC(efi_enter32)
.data
.balign 8
.global efi32_boot_gdt
efi32_boot_gdt: .word 0
.quad 0
save_gdt: .word 0
.quad 0
func_rt_ptr: .quad 0
.global efi_gdt64
efi_gdt64:
.word efi_gdt64_end - efi_gdt64
.long 0 /* Filled out by user */
.word 0
.quad 0x0000000000000000 /* NULL descriptor */
.quad 0x00af9a000000ffff /* __KERNEL_CS */
.quad 0x00cf92000000ffff /* __KERNEL_DS */
.quad 0x0080890000000000 /* TS descriptor */
.quad 0x0000000000000000 /* TS continued */
efi_gdt64_end:
#endif /* CONFIG_EFI_MIXED */
.data
ENTRY(efi_scratch)
.fill 3,8,0
.byte 0
.quad 0
/*
* Copyright (C) 2014 Intel Corporation; author Matt Fleming
*/
#include <linux/linkage.h>
#include <asm/page_types.h>
.text
.code64
ENTRY(efi64_thunk)
push %rbp
push %rbx
/*
* Switch to 1:1 mapped 32-bit stack pointer.
*/
movq %rsp, efi_saved_sp(%rip)
movq efi_scratch+25(%rip), %rsp
/*
* Calculate the physical address of the kernel text.
*/
movq $__START_KERNEL_map, %rax
subq phys_base(%rip), %rax
/*
* Push some physical addresses onto the stack. This is easier
* to do now in a code64 section while the assembler can address
* 64-bit values. Note that all the addresses on the stack are
* 32-bit.
*/
subq $16, %rsp
leaq efi_exit32(%rip), %rbx
subq %rax, %rbx
movl %ebx, 8(%rsp)
leaq efi_gdt64(%rip), %rbx
subq %rax, %rbx
movl %ebx, 2(%ebx)
movl %ebx, 4(%rsp)
leaq efi_gdt32(%rip), %rbx
subq %rax, %rbx
movl %ebx, 2(%ebx)
movl %ebx, (%rsp)
leaq __efi64_thunk(%rip), %rbx
subq %rax, %rbx
call *%rbx
movq efi_saved_sp(%rip), %rsp
pop %rbx
pop %rbp
retq
ENDPROC(efi64_thunk)
.data
efi_gdt32:
.word efi_gdt32_end - efi_gdt32
.long 0 /* Filled out above */
.word 0
.quad 0x0000000000000000 /* NULL descriptor */
.quad 0x00cf9a000000ffff /* __KERNEL_CS */
.quad 0x00cf93000000ffff /* __KERNEL_DS */
efi_gdt32_end:
efi_saved_sp: .quad 0
......@@ -16,18 +16,6 @@ struct file_info {
u64 size;
};
static void efi_char16_printk(efi_system_table_t *sys_table_arg,
efi_char16_t *str)
{
struct efi_simple_text_output_protocol *out;
out = (struct efi_simple_text_output_protocol *)sys_table_arg->con_out;
efi_call_phys2(out->output_string, out, str);
}
static void efi_printk(efi_system_table_t *sys_table_arg, char *str)
{
char *s8;
......@@ -65,20 +53,23 @@ static efi_status_t efi_get_memory_map(efi_system_table_t *sys_table_arg,
* allocation which may be in a new descriptor region.
*/
*map_size += sizeof(*m);
status = efi_call_phys3(sys_table_arg->boottime->allocate_pool,
EFI_LOADER_DATA, *map_size, (void **)&m);
status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
*map_size, (void **)&m);
if (status != EFI_SUCCESS)
goto fail;
status = efi_call_phys5(sys_table_arg->boottime->get_memory_map,
map_size, m, &key, desc_size, &desc_version);
*desc_size = 0;
key = 0;
status = efi_call_early(get_memory_map, map_size, m,
&key, desc_size, &desc_version);
if (status == EFI_BUFFER_TOO_SMALL) {
efi_call_phys1(sys_table_arg->boottime->free_pool, m);
efi_call_early(free_pool, m);
goto again;
}
if (status != EFI_SUCCESS)
efi_call_phys1(sys_table_arg->boottime->free_pool, m);
efi_call_early(free_pool, m);
if (key_ptr && status == EFI_SUCCESS)
*key_ptr = key;
if (desc_ver && status == EFI_SUCCESS)
......@@ -158,7 +149,7 @@ static efi_status_t efi_high_alloc(efi_system_table_t *sys_table_arg,
if (!max_addr)
status = EFI_NOT_FOUND;
else {
status = efi_call_phys4(sys_table_arg->boottime->allocate_pages,
status = efi_call_early(allocate_pages,
EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
nr_pages, &max_addr);
if (status != EFI_SUCCESS) {
......@@ -170,8 +161,7 @@ static efi_status_t efi_high_alloc(efi_system_table_t *sys_table_arg,
*addr = max_addr;
}
efi_call_phys1(sys_table_arg->boottime->free_pool, map);
efi_call_early(free_pool, map);
fail:
return status;
}
......@@ -231,7 +221,7 @@ static efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg,
if ((start + size) > end)
continue;
status = efi_call_phys4(sys_table_arg->boottime->allocate_pages,
status = efi_call_early(allocate_pages,
EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
nr_pages, &start);
if (status == EFI_SUCCESS) {
......@@ -243,7 +233,7 @@ static efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg,
if (i == map_size / desc_size)
status = EFI_NOT_FOUND;
efi_call_phys1(sys_table_arg->boottime->free_pool, map);
efi_call_early(free_pool, map);
fail:
return status;
}
......@@ -257,7 +247,7 @@ static void efi_free(efi_system_table_t *sys_table_arg, unsigned long size,
return;
nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
efi_call_phys2(sys_table_arg->boottime->free_pages, addr, nr_pages);
efi_call_early(free_pages, addr, nr_pages);
}
......@@ -276,9 +266,7 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
{
struct file_info *files;
unsigned long file_addr;
efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
u64 file_size_total;
efi_file_io_interface_t *io;
efi_file_handle_t *fh;
efi_status_t status;
int nr_files;
......@@ -319,10 +307,8 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
if (!nr_files)
return EFI_SUCCESS;
status = efi_call_phys3(sys_table_arg->boottime->allocate_pool,
EFI_LOADER_DATA,
nr_files * sizeof(*files),
(void **)&files);
status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
nr_files * sizeof(*files), (void **)&files);
if (status != EFI_SUCCESS) {
efi_printk(sys_table_arg, "Failed to alloc mem for file handle list\n");
goto fail;
......@@ -331,13 +317,8 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
str = cmd_line;
for (i = 0; i < nr_files; i++) {
struct file_info *file;
efi_file_handle_t *h;
efi_file_info_t *info;
efi_char16_t filename_16[256];
unsigned long info_sz;
efi_guid_t info_guid = EFI_FILE_INFO_ID;
efi_char16_t *p;
u64 file_sz;
str = strstr(str, option_string);
if (!str)
......@@ -368,71 +349,18 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
/* Only open the volume once. */
if (!i) {
efi_boot_services_t *boottime;
boottime = sys_table_arg->boottime;
status = efi_call_phys3(boottime->handle_protocol,
image->device_handle, &fs_proto,
(void **)&io);
if (status != EFI_SUCCESS) {
efi_printk(sys_table_arg, "Failed to handle fs_proto\n");
goto free_files;
}
status = efi_call_phys2(io->open_volume, io, &fh);
if (status != EFI_SUCCESS) {
efi_printk(sys_table_arg, "Failed to open volume\n");
status = efi_open_volume(sys_table_arg, image,
(void **)&fh);
if (status != EFI_SUCCESS)
goto free_files;
}
}
status = efi_call_phys5(fh->open, fh, &h, filename_16,
EFI_FILE_MODE_READ, (u64)0);
if (status != EFI_SUCCESS) {
efi_printk(sys_table_arg, "Failed to open file: ");
efi_char16_printk(sys_table_arg, filename_16);
efi_printk(sys_table_arg, "\n");
status = efi_file_size(sys_table_arg, fh, filename_16,
(void **)&file->handle, &file->size);
if (status != EFI_SUCCESS)
goto close_handles;
}
file->handle = h;
info_sz = 0;
status = efi_call_phys4(h->get_info, h, &info_guid,
&info_sz, NULL);
if (status != EFI_BUFFER_TOO_SMALL) {
efi_printk(sys_table_arg, "Failed to get file info size\n");
goto close_handles;
}
grow:
status = efi_call_phys3(sys_table_arg->boottime->allocate_pool,
EFI_LOADER_DATA, info_sz,
(void **)&info);
if (status != EFI_SUCCESS) {
efi_printk(sys_table_arg, "Failed to alloc mem for file info\n");
goto close_handles;
}
status = efi_call_phys4(h->get_info, h, &info_guid,
&info_sz, info);
if (status == EFI_BUFFER_TOO_SMALL) {
efi_call_phys1(sys_table_arg->boottime->free_pool,
info);
goto grow;
}
file_sz = info->file_size;
efi_call_phys1(sys_table_arg->boottime->free_pool, info);
if (status != EFI_SUCCESS) {
efi_printk(sys_table_arg, "Failed to get file info\n");
goto close_handles;
}
file->size = file_sz;
file_size_total += file_sz;
file_size_total += file->size;
}
if (file_size_total) {
......@@ -468,10 +396,10 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
chunksize = EFI_READ_CHUNK_SIZE;
else
chunksize = size;
status = efi_call_phys3(fh->read,
files[j].handle,
&chunksize,
(void *)addr);
status = efi_file_read(fh, files[j].handle,
&chunksize,
(void *)addr);
if (status != EFI_SUCCESS) {
efi_printk(sys_table_arg, "Failed to read file\n");
goto free_file_total;
......@@ -480,12 +408,12 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
size -= chunksize;
}
efi_call_phys1(fh->close, files[j].handle);
efi_file_close(fh, files[j].handle);
}
}
efi_call_phys1(sys_table_arg->boottime->free_pool, files);
efi_call_early(free_pool, files);
*load_addr = file_addr;
*load_size = file_size_total;
......@@ -497,9 +425,9 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
close_handles:
for (k = j; k < i; k++)
efi_call_phys1(fh->close, files[k].handle);
efi_file_close(fh, files[k].handle);
free_files:
efi_call_phys1(sys_table_arg->boottime->free_pool, files);
efi_call_early(free_pool, files);
fail:
*load_addr = 0;
*load_size = 0;
......@@ -545,7 +473,7 @@ static efi_status_t efi_relocate_kernel(efi_system_table_t *sys_table_arg,
* as possible while respecting the required alignment.
*/
nr_pages = round_up(alloc_size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
status = efi_call_phys4(sys_table_arg->boottime->allocate_pages,
status = efi_call_early(allocate_pages,
EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
nr_pages, &efi_addr);
new_addr = efi_addr;
......
......@@ -233,7 +233,7 @@ static __initdata efi_config_table_type_t common_tables[] = {
{SAL_SYSTEM_TABLE_GUID, "SALsystab", &efi.sal_systab},
{SMBIOS_TABLE_GUID, "SMBIOS", &efi.smbios},
{UGA_IO_PROTOCOL_GUID, "UGA", &efi.uga},
{NULL_GUID, NULL, 0},
{NULL_GUID, NULL, NULL},
};
static __init int match_config_table(efi_guid_t *guid,
......@@ -313,5 +313,8 @@ int __init efi_config_init(efi_config_table_type_t *arch_tables)
}
pr_cont("\n");
early_iounmap(config_tables, efi.systab->nr_tables * sz);
set_bit(EFI_CONFIG_TABLES, &efi.flags);
return 0;
}
......@@ -227,7 +227,7 @@ efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count)
memcpy(&entry->var, new_var, count);
err = efivar_entry_set(entry, new_var->Attributes,
new_var->DataSize, new_var->Data, false);
new_var->DataSize, new_var->Data, NULL);
if (err) {
printk(KERN_WARNING "efivars: set_variable() failed: status=%d\n", err);
return -EIO;
......
......@@ -21,7 +21,7 @@ static ssize_t efivarfs_file_write(struct file *file,
u32 attributes;
struct inode *inode = file->f_mapping->host;
unsigned long datasize = count - sizeof(attributes);
ssize_t bytes = 0;
ssize_t bytes;
bool set = false;
if (count < sizeof(attributes))
......@@ -33,14 +33,9 @@ static ssize_t efivarfs_file_write(struct file *file,
if (attributes & ~(EFI_VARIABLE_MASK))
return -EINVAL;
data = kmalloc(datasize, GFP_KERNEL);
if (!data)
return -ENOMEM;
if (copy_from_user(data, userbuf + sizeof(attributes), datasize)) {
bytes = -EFAULT;
goto out;
}
data = memdup_user(userbuf + sizeof(attributes), datasize);
if (IS_ERR(data))
return PTR_ERR(data);
bytes = efivar_entry_set_get_size(var, attributes, &datasize,
data, &set);
......
......@@ -153,6 +153,102 @@ typedef struct {
u8 sets_to_zero;
} efi_time_cap_t;
typedef struct {
efi_table_hdr_t hdr;
u32 raise_tpl;
u32 restore_tpl;
u32 allocate_pages;
u32 free_pages;
u32 get_memory_map;
u32 allocate_pool;
u32 free_pool;
u32 create_event;
u32 set_timer;
u32 wait_for_event;
u32 signal_event;
u32 close_event;
u32 check_event;
u32 install_protocol_interface;
u32 reinstall_protocol_interface;
u32 uninstall_protocol_interface;
u32 handle_protocol;
u32 __reserved;
u32 register_protocol_notify;
u32 locate_handle;
u32 locate_device_path;
u32 install_configuration_table;
u32 load_image;
u32 start_image;
u32 exit;
u32 unload_image;
u32 exit_boot_services;
u32 get_next_monotonic_count;
u32 stall;
u32 set_watchdog_timer;
u32 connect_controller;
u32 disconnect_controller;
u32 open_protocol;
u32 close_protocol;
u32 open_protocol_information;
u32 protocols_per_handle;
u32 locate_handle_buffer;
u32 locate_protocol;
u32 install_multiple_protocol_interfaces;
u32 uninstall_multiple_protocol_interfaces;
u32 calculate_crc32;
u32 copy_mem;
u32 set_mem;
u32 create_event_ex;
} __packed efi_boot_services_32_t;
typedef struct {
efi_table_hdr_t hdr;
u64 raise_tpl;
u64 restore_tpl;
u64 allocate_pages;
u64 free_pages;
u64 get_memory_map;
u64 allocate_pool;
u64 free_pool;
u64 create_event;
u64 set_timer;
u64 wait_for_event;
u64 signal_event;
u64 close_event;
u64 check_event;
u64 install_protocol_interface;
u64 reinstall_protocol_interface;
u64 uninstall_protocol_interface;
u64 handle_protocol;
u64 __reserved;
u64 register_protocol_notify;
u64 locate_handle;
u64 locate_device_path;
u64 install_configuration_table;
u64 load_image;
u64 start_image;
u64 exit;
u64 unload_image;
u64 exit_boot_services;
u64 get_next_monotonic_count;
u64 stall;
u64 set_watchdog_timer;
u64 connect_controller;
u64 disconnect_controller;
u64 open_protocol;
u64 close_protocol;
u64 open_protocol_information;
u64 protocols_per_handle;
u64 locate_handle_buffer;
u64 locate_protocol;
u64 install_multiple_protocol_interfaces;
u64 uninstall_multiple_protocol_interfaces;
u64 calculate_crc32;
u64 copy_mem;
u64 set_mem;
u64 create_event_ex;
} __packed efi_boot_services_64_t;
/*
* EFI Boot Services table
*/
......@@ -231,12 +327,61 @@ typedef enum {
EfiPciIoAttributeOperationMaximum
} EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION;
typedef struct {
u32 read;
u32 write;
} efi_pci_io_protocol_access_32_t;
typedef struct {
u64 read;
u64 write;
} efi_pci_io_protocol_access_64_t;
typedef struct {
void *read;
void *write;
} efi_pci_io_protocol_access_t;
typedef struct {
u32 poll_mem;
u32 poll_io;
efi_pci_io_protocol_access_32_t mem;
efi_pci_io_protocol_access_32_t io;
efi_pci_io_protocol_access_32_t pci;
u32 copy_mem;
u32 map;
u32 unmap;
u32 allocate_buffer;
u32 free_buffer;
u32 flush;
u32 get_location;
u32 attributes;
u32 get_bar_attributes;
u32 set_bar_attributes;
uint64_t romsize;
void *romimage;
} efi_pci_io_protocol_32;
typedef struct {
u64 poll_mem;
u64 poll_io;
efi_pci_io_protocol_access_64_t mem;
efi_pci_io_protocol_access_64_t io;
efi_pci_io_protocol_access_64_t pci;
u64 copy_mem;
u64 map;
u64 unmap;
u64 allocate_buffer;
u64 free_buffer;
u64 flush;
u64 get_location;
u64 attributes;
u64 get_bar_attributes;
u64 set_bar_attributes;
uint64_t romsize;
void *romimage;
} efi_pci_io_protocol_64;
typedef struct {
void *poll_mem;
void *poll_io;
......@@ -290,6 +435,42 @@ typedef struct {
#define EFI_RUNTIME_SERVICES_SIGNATURE ((u64)0x5652453544e5552ULL)
#define EFI_RUNTIME_SERVICES_REVISION 0x00010000
typedef struct {
efi_table_hdr_t hdr;
u32 get_time;
u32 set_time;
u32 get_wakeup_time;
u32 set_wakeup_time;
u32 set_virtual_address_map;
u32 convert_pointer;
u32 get_variable;
u32 get_next_variable;
u32 set_variable;
u32 get_next_high_mono_count;
u32 reset_system;
u32 update_capsule;
u32 query_capsule_caps;
u32 query_variable_info;
} efi_runtime_services_32_t;
typedef struct {
efi_table_hdr_t hdr;
u64 get_time;
u64 set_time;
u64 get_wakeup_time;
u64 set_wakeup_time;
u64 set_virtual_address_map;
u64 convert_pointer;
u64 get_variable;
u64 get_next_variable;
u64 set_variable;
u64 get_next_high_mono_count;
u64 reset_system;
u64 update_capsule;
u64 query_capsule_caps;
u64 query_variable_info;
} efi_runtime_services_64_t;
typedef struct {
efi_table_hdr_t hdr;
void *get_time;
......@@ -483,6 +664,38 @@ struct efi_memory_map {
unsigned long desc_size;
};
typedef struct {
u32 revision;
u32 parent_handle;
u32 system_table;
u32 device_handle;
u32 file_path;
u32 reserved;
u32 load_options_size;
u32 load_options;
u32 image_base;
__aligned_u64 image_size;
unsigned int image_code_type;
unsigned int image_data_type;
unsigned long unload;
} efi_loaded_image_32_t;
typedef struct {
u32 revision;
u64 parent_handle;
u64 system_table;
u64 device_handle;
u64 file_path;
u64 reserved;
u32 load_options_size;
u64 load_options;
u64 image_base;
__aligned_u64 image_size;
unsigned int image_code_type;
unsigned int image_data_type;
unsigned long unload;
} efi_loaded_image_64_t;
typedef struct {
u32 revision;
void *parent_handle;
......@@ -511,6 +724,34 @@ typedef struct {
efi_char16_t filename[1];
} efi_file_info_t;
typedef struct {
u64 revision;
u32 open;
u32 close;
u32 delete;
u32 read;
u32 write;
u32 get_position;
u32 set_position;
u32 get_info;
u32 set_info;
u32 flush;
} efi_file_handle_32_t;
typedef struct {
u64 revision;
u64 open;
u64 close;
u64 delete;
u64 read;
u64 write;
u64 get_position;
u64 set_position;
u64 get_info;
u64 set_info;
u64 flush;
} efi_file_handle_64_t;
typedef struct _efi_file_handle {
u64 revision;
efi_status_t (*open)(struct _efi_file_handle *,
......@@ -573,6 +814,7 @@ extern struct efi {
efi_reset_system_t *reset_system;
efi_set_virtual_address_map_t *set_virtual_address_map;
struct efi_memory_map *memmap;
unsigned long flags;
} efi;
static inline int
......@@ -659,18 +901,17 @@ extern int __init efi_setup_pcdp_console(char *);
#define EFI_ARCH_1 6 /* First arch-specific bit */
#ifdef CONFIG_EFI
# ifdef CONFIG_X86
extern int efi_enabled(int facility);
# else
static inline int efi_enabled(int facility)
/*
* Test whether the above EFI_* bits are enabled.
*/
static inline bool efi_enabled(int feature)
{
return 1;
return test_bit(feature, &efi.flags) != 0;
}
# endif
#else
static inline int efi_enabled(int facility)
static inline bool efi_enabled(int feature)
{
return 0;
return false;
}
#endif
......@@ -809,6 +1050,17 @@ struct efivar_entry {
bool deleting;
};
struct efi_simple_text_output_protocol_32 {
u32 reset;
u32 output_string;
u32 test_string;
};
struct efi_simple_text_output_protocol_64 {
u64 reset;
u64 output_string;
u64 test_string;
};
struct efi_simple_text_output_protocol {
void *reset;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment