提交 5fbe4c22 编写于 作者: L Linus Torvalds

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

Pull misc x86 fixes from Ingo Molnar:
 "This contains:

   - EFI fixes
   - a boot printout fix
   - ASLR/kASLR fixes
   - intel microcode driver fixes
   - other misc fixes

  Most of the linecount comes from an EFI revert"

* 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/mm/ASLR: Avoid PAGE_SIZE redefinition for UML subarch
  x86/microcode/intel: Handle truncated microcode images more robustly
  x86/microcode/intel: Guard against stack overflow in the loader
  x86, mm/ASLR: Fix stack randomization on 64-bit systems
  x86/mm/init: Fix incorrect page size in init_memory_mapping() printks
  x86/mm/ASLR: Propagate base load address calculation
  Documentation/x86: Fix path in zero-page.txt
  x86/apic: Fix the devicetree build in certain configs
  Revert "efi/libstub: Call get_memory_map() to obtain map and desc sizes"
  x86/efi: Avoid triple faults during EFI mixed mode calls
...@@ -3,7 +3,7 @@ protocol of kernel. These should be filled by bootloader or 16-bit ...@@ -3,7 +3,7 @@ protocol of kernel. These should be filled by bootloader or 16-bit
real-mode setup code of the kernel. References/settings to it mainly real-mode setup code of the kernel. References/settings to it mainly
are in: are in:
arch/x86/include/asm/bootparam.h arch/x86/include/uapi/asm/bootparam.h
Offset Proto Name Meaning Offset Proto Name Meaning
......
...@@ -51,6 +51,7 @@ $(obj)/eboot.o: KBUILD_CFLAGS += -fshort-wchar -mno-red-zone ...@@ -51,6 +51,7 @@ $(obj)/eboot.o: KBUILD_CFLAGS += -fshort-wchar -mno-red-zone
vmlinux-objs-$(CONFIG_EFI_STUB) += $(obj)/eboot.o $(obj)/efi_stub_$(BITS).o \ vmlinux-objs-$(CONFIG_EFI_STUB) += $(obj)/eboot.o $(obj)/efi_stub_$(BITS).o \
$(objtree)/drivers/firmware/efi/libstub/lib.a $(objtree)/drivers/firmware/efi/libstub/lib.a
vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_thunk_$(BITS).o
$(obj)/vmlinux: $(vmlinux-objs-y) FORCE $(obj)/vmlinux: $(vmlinux-objs-y) FORCE
$(call if_changed,ld) $(call if_changed,ld)
......
...@@ -14,6 +14,13 @@ ...@@ -14,6 +14,13 @@
static const char build_str[] = UTS_RELEASE " (" LINUX_COMPILE_BY "@" static const char build_str[] = UTS_RELEASE " (" LINUX_COMPILE_BY "@"
LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION; LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION;
struct kaslr_setup_data {
__u64 next;
__u32 type;
__u32 len;
__u8 data[1];
} kaslr_setup_data;
#define I8254_PORT_CONTROL 0x43 #define I8254_PORT_CONTROL 0x43
#define I8254_PORT_COUNTER0 0x40 #define I8254_PORT_COUNTER0 0x40
#define I8254_CMD_READBACK 0xC0 #define I8254_CMD_READBACK 0xC0
...@@ -295,7 +302,29 @@ static unsigned long find_random_addr(unsigned long minimum, ...@@ -295,7 +302,29 @@ static unsigned long find_random_addr(unsigned long minimum,
return slots_fetch_random(); return slots_fetch_random();
} }
unsigned char *choose_kernel_location(unsigned char *input, static void add_kaslr_setup_data(struct boot_params *params, __u8 enabled)
{
struct setup_data *data;
kaslr_setup_data.type = SETUP_KASLR;
kaslr_setup_data.len = 1;
kaslr_setup_data.next = 0;
kaslr_setup_data.data[0] = enabled;
data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
while (data && data->next)
data = (struct setup_data *)(unsigned long)data->next;
if (data)
data->next = (unsigned long)&kaslr_setup_data;
else
params->hdr.setup_data = (unsigned long)&kaslr_setup_data;
}
unsigned char *choose_kernel_location(struct boot_params *params,
unsigned char *input,
unsigned long input_size, unsigned long input_size,
unsigned char *output, unsigned char *output,
unsigned long output_size) unsigned long output_size)
...@@ -306,14 +335,17 @@ unsigned char *choose_kernel_location(unsigned char *input, ...@@ -306,14 +335,17 @@ unsigned char *choose_kernel_location(unsigned char *input,
#ifdef CONFIG_HIBERNATION #ifdef CONFIG_HIBERNATION
if (!cmdline_find_option_bool("kaslr")) { if (!cmdline_find_option_bool("kaslr")) {
debug_putstr("KASLR disabled by default...\n"); debug_putstr("KASLR disabled by default...\n");
add_kaslr_setup_data(params, 0);
goto out; goto out;
} }
#else #else
if (cmdline_find_option_bool("nokaslr")) { if (cmdline_find_option_bool("nokaslr")) {
debug_putstr("KASLR disabled by cmdline...\n"); debug_putstr("KASLR disabled by cmdline...\n");
add_kaslr_setup_data(params, 0);
goto out; goto out;
} }
#endif #endif
add_kaslr_setup_data(params, 1);
/* Record the various known unsafe memory ranges. */ /* Record the various known unsafe memory ranges. */
mem_avoid_init((unsigned long)input, input_size, mem_avoid_init((unsigned long)input, input_size,
......
...@@ -3,28 +3,3 @@ ...@@ -3,28 +3,3 @@
#include <asm/processor-flags.h> #include <asm/processor-flags.h>
#include "../../platform/efi/efi_stub_64.S" #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 */
/*
* Copyright (C) 2014, 2015 Intel Corporation; author Matt Fleming
*
* Early support for invoking 32-bit EFI services from a 64-bit kernel.
*
* Because this thunking occurs before ExitBootServices() we have to
* restore the firmware's 32-bit GDT before we make EFI serivce calls,
* since the firmware's 32-bit IDT is still currently installed and it
* needs to be able to service interrupts.
*
* On the plus side, we don't have to worry about mangling 64-bit
* addresses into 32-bits because we're executing with an identify
* mapped pagetable and haven't transitioned to 64-bit virtual addresses
* yet.
*/
#include <linux/linkage.h>
#include <asm/msr.h>
#include <asm/page_types.h>
#include <asm/processor-flags.h>
#include <asm/segment.h>
.code64
.text
ENTRY(efi64_thunk)
push %rbp
push %rbx
subq $8, %rsp
leaq efi_exit32(%rip), %rax
movl %eax, 4(%rsp)
leaq efi_gdt64(%rip), %rax
movl %eax, (%rsp)
movl %eax, 2(%rax) /* Fixup the gdt base address */
movl %ds, %eax
push %rax
movl %es, %eax
push %rax
movl %ss, %eax
push %rax
/*
* Convert x86-64 ABI params to i386 ABI
*/
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. This is the firmware GDT
* that was installed when the kernel started executing. This
* pointer was saved at the EFI stub entry point in head_64.S.
*/
leaq efi32_boot_gdt(%rip), %rax
lgdt (%rax)
pushq $__KERNEL_CS
leaq efi_enter32(%rip), %rax
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:
addq $8, %rsp
pop %rbx
pop %rbp
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 56(%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 60(%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:
...@@ -401,7 +401,8 @@ asmlinkage __visible void *decompress_kernel(void *rmode, memptr heap, ...@@ -401,7 +401,8 @@ asmlinkage __visible void *decompress_kernel(void *rmode, memptr heap,
* the entire decompressed kernel plus relocation table, or the * the entire decompressed kernel plus relocation table, or the
* entire decompressed kernel plus .bss and .brk sections. * entire decompressed kernel plus .bss and .brk sections.
*/ */
output = choose_kernel_location(input_data, input_len, output, output = choose_kernel_location(real_mode, input_data, input_len,
output,
output_len > run_size ? output_len output_len > run_size ? output_len
: run_size); : run_size);
......
...@@ -57,7 +57,8 @@ int cmdline_find_option_bool(const char *option); ...@@ -57,7 +57,8 @@ int cmdline_find_option_bool(const char *option);
#if CONFIG_RANDOMIZE_BASE #if CONFIG_RANDOMIZE_BASE
/* aslr.c */ /* aslr.c */
unsigned char *choose_kernel_location(unsigned char *input, unsigned char *choose_kernel_location(struct boot_params *params,
unsigned char *input,
unsigned long input_size, unsigned long input_size,
unsigned char *output, unsigned char *output,
unsigned long output_size); unsigned long output_size);
...@@ -65,7 +66,8 @@ unsigned char *choose_kernel_location(unsigned char *input, ...@@ -65,7 +66,8 @@ unsigned char *choose_kernel_location(unsigned char *input,
bool has_cpuflag(int flag); bool has_cpuflag(int flag);
#else #else
static inline static inline
unsigned char *choose_kernel_location(unsigned char *input, unsigned char *choose_kernel_location(struct boot_params *params,
unsigned char *input,
unsigned long input_size, unsigned long input_size,
unsigned char *output, unsigned char *output,
unsigned long output_size) unsigned long output_size)
......
...@@ -213,7 +213,15 @@ void register_lapic_address(unsigned long address); ...@@ -213,7 +213,15 @@ void register_lapic_address(unsigned long address);
extern void setup_boot_APIC_clock(void); extern void setup_boot_APIC_clock(void);
extern void setup_secondary_APIC_clock(void); extern void setup_secondary_APIC_clock(void);
extern int APIC_init_uniprocessor(void); extern int APIC_init_uniprocessor(void);
#ifdef CONFIG_X86_64
static inline int apic_force_enable(unsigned long addr)
{
return -1;
}
#else
extern int apic_force_enable(unsigned long addr); extern int apic_force_enable(unsigned long addr);
#endif
extern int apic_bsp_setup(bool upmode); extern int apic_bsp_setup(bool upmode);
extern void apic_ap_setup(void); extern void apic_ap_setup(void);
......
...@@ -51,6 +51,8 @@ extern int devmem_is_allowed(unsigned long pagenr); ...@@ -51,6 +51,8 @@ extern int devmem_is_allowed(unsigned long pagenr);
extern unsigned long max_low_pfn_mapped; extern unsigned long max_low_pfn_mapped;
extern unsigned long max_pfn_mapped; extern unsigned long max_pfn_mapped;
extern bool kaslr_enabled;
static inline phys_addr_t get_max_mapped(void) static inline phys_addr_t get_max_mapped(void)
{ {
return (phys_addr_t)max_pfn_mapped << PAGE_SHIFT; return (phys_addr_t)max_pfn_mapped << PAGE_SHIFT;
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#define SETUP_DTB 2 #define SETUP_DTB 2
#define SETUP_PCI 3 #define SETUP_PCI 3
#define SETUP_EFI 4 #define SETUP_EFI 4
#define SETUP_KASLR 5
/* ram_size flags */ /* ram_size flags */
#define RAMDISK_IMAGE_START_MASK 0x07FF #define RAMDISK_IMAGE_START_MASK 0x07FF
......
...@@ -196,6 +196,11 @@ static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size, ...@@ -196,6 +196,11 @@ static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size,
struct microcode_header_intel mc_header; struct microcode_header_intel mc_header;
unsigned int mc_size; unsigned int mc_size;
if (leftover < sizeof(mc_header)) {
pr_err("error! Truncated header in microcode data file\n");
break;
}
if (get_ucode_data(&mc_header, ucode_ptr, sizeof(mc_header))) if (get_ucode_data(&mc_header, ucode_ptr, sizeof(mc_header)))
break; break;
......
...@@ -321,7 +321,11 @@ get_matching_model_microcode(int cpu, unsigned long start, ...@@ -321,7 +321,11 @@ get_matching_model_microcode(int cpu, unsigned long start,
unsigned int mc_saved_count = mc_saved_data->mc_saved_count; unsigned int mc_saved_count = mc_saved_data->mc_saved_count;
int i; int i;
while (leftover) { while (leftover && mc_saved_count < ARRAY_SIZE(mc_saved_tmp)) {
if (leftover < sizeof(mc_header))
break;
mc_header = (struct microcode_header_intel *)ucode_ptr; mc_header = (struct microcode_header_intel *)ucode_ptr;
mc_size = get_totalsize(mc_header); mc_size = get_totalsize(mc_header);
......
...@@ -47,21 +47,13 @@ do { \ ...@@ -47,21 +47,13 @@ do { \
#ifdef CONFIG_RANDOMIZE_BASE #ifdef CONFIG_RANDOMIZE_BASE
static unsigned long module_load_offset; static unsigned long module_load_offset;
static int randomize_modules = 1;
/* Mutex protects the module_load_offset. */ /* Mutex protects the module_load_offset. */
static DEFINE_MUTEX(module_kaslr_mutex); static DEFINE_MUTEX(module_kaslr_mutex);
static int __init parse_nokaslr(char *p)
{
randomize_modules = 0;
return 0;
}
early_param("nokaslr", parse_nokaslr);
static unsigned long int get_module_load_offset(void) static unsigned long int get_module_load_offset(void)
{ {
if (randomize_modules) { if (kaslr_enabled) {
mutex_lock(&module_kaslr_mutex); mutex_lock(&module_kaslr_mutex);
/* /*
* Calculate the module_load_offset the first time this * Calculate the module_load_offset the first time this
......
...@@ -122,6 +122,8 @@ ...@@ -122,6 +122,8 @@
unsigned long max_low_pfn_mapped; unsigned long max_low_pfn_mapped;
unsigned long max_pfn_mapped; unsigned long max_pfn_mapped;
bool __read_mostly kaslr_enabled = false;
#ifdef CONFIG_DMI #ifdef CONFIG_DMI
RESERVE_BRK(dmi_alloc, 65536); RESERVE_BRK(dmi_alloc, 65536);
#endif #endif
...@@ -425,6 +427,11 @@ static void __init reserve_initrd(void) ...@@ -425,6 +427,11 @@ static void __init reserve_initrd(void)
} }
#endif /* CONFIG_BLK_DEV_INITRD */ #endif /* CONFIG_BLK_DEV_INITRD */
static void __init parse_kaslr_setup(u64 pa_data, u32 data_len)
{
kaslr_enabled = (bool)(pa_data + sizeof(struct setup_data));
}
static void __init parse_setup_data(void) static void __init parse_setup_data(void)
{ {
struct setup_data *data; struct setup_data *data;
...@@ -450,6 +457,9 @@ static void __init parse_setup_data(void) ...@@ -450,6 +457,9 @@ static void __init parse_setup_data(void)
case SETUP_EFI: case SETUP_EFI:
parse_efi_setup(pa_data, data_len); parse_efi_setup(pa_data, data_len);
break; break;
case SETUP_KASLR:
parse_kaslr_setup(pa_data, data_len);
break;
default: default:
break; break;
} }
...@@ -832,10 +842,14 @@ static void __init trim_low_memory_range(void) ...@@ -832,10 +842,14 @@ static void __init trim_low_memory_range(void)
static int static int
dump_kernel_offset(struct notifier_block *self, unsigned long v, void *p) dump_kernel_offset(struct notifier_block *self, unsigned long v, void *p)
{ {
pr_emerg("Kernel Offset: 0x%lx from 0x%lx " if (kaslr_enabled)
"(relocation range: 0x%lx-0x%lx)\n", pr_emerg("Kernel Offset: 0x%lx from 0x%lx (relocation range: 0x%lx-0x%lx)\n",
(unsigned long)&_text - __START_KERNEL, __START_KERNEL, (unsigned long)&_text - __START_KERNEL,
__START_KERNEL_map, MODULES_VADDR-1); __START_KERNEL,
__START_KERNEL_map,
MODULES_VADDR-1);
else
pr_emerg("Kernel Offset: disabled\n");
return 0; return 0;
} }
......
...@@ -238,6 +238,31 @@ static void __init_refok adjust_range_page_size_mask(struct map_range *mr, ...@@ -238,6 +238,31 @@ static void __init_refok adjust_range_page_size_mask(struct map_range *mr,
} }
} }
static const char *page_size_string(struct map_range *mr)
{
static const char str_1g[] = "1G";
static const char str_2m[] = "2M";
static const char str_4m[] = "4M";
static const char str_4k[] = "4k";
if (mr->page_size_mask & (1<<PG_LEVEL_1G))
return str_1g;
/*
* 32-bit without PAE has a 4M large page size.
* PG_LEVEL_2M is misnamed, but we can at least
* print out the right size in the string.
*/
if (IS_ENABLED(CONFIG_X86_32) &&
!IS_ENABLED(CONFIG_X86_PAE) &&
mr->page_size_mask & (1<<PG_LEVEL_2M))
return str_4m;
if (mr->page_size_mask & (1<<PG_LEVEL_2M))
return str_2m;
return str_4k;
}
static int __meminit split_mem_range(struct map_range *mr, int nr_range, static int __meminit split_mem_range(struct map_range *mr, int nr_range,
unsigned long start, unsigned long start,
unsigned long end) unsigned long end)
...@@ -333,8 +358,7 @@ static int __meminit split_mem_range(struct map_range *mr, int nr_range, ...@@ -333,8 +358,7 @@ static int __meminit split_mem_range(struct map_range *mr, int nr_range,
for (i = 0; i < nr_range; i++) for (i = 0; i < nr_range; i++)
printk(KERN_DEBUG " [mem %#010lx-%#010lx] page %s\n", printk(KERN_DEBUG " [mem %#010lx-%#010lx] page %s\n",
mr[i].start, mr[i].end - 1, mr[i].start, mr[i].end - 1,
(mr[i].page_size_mask & (1<<PG_LEVEL_1G))?"1G":( page_size_string(&mr[i]));
(mr[i].page_size_mask & (1<<PG_LEVEL_2M))?"2M":"4k"));
return nr_range; return nr_range;
} }
......
...@@ -35,12 +35,12 @@ struct va_alignment __read_mostly va_align = { ...@@ -35,12 +35,12 @@ struct va_alignment __read_mostly va_align = {
.flags = -1, .flags = -1,
}; };
static unsigned int stack_maxrandom_size(void) static unsigned long stack_maxrandom_size(void)
{ {
unsigned int max = 0; unsigned long max = 0;
if ((current->flags & PF_RANDOMIZE) && if ((current->flags & PF_RANDOMIZE) &&
!(current->personality & ADDR_NO_RANDOMIZE)) { !(current->personality & ADDR_NO_RANDOMIZE)) {
max = ((-1U) & STACK_RND_MASK) << PAGE_SHIFT; max = ((-1UL) & STACK_RND_MASK) << PAGE_SHIFT;
} }
return max; return max;
......
...@@ -91,167 +91,6 @@ ENTRY(efi_call) ...@@ -91,167 +91,6 @@ ENTRY(efi_call)
ret ret
ENDPROC(efi_call) ENDPROC(efi_call)
#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 .data
ENTRY(efi_scratch) ENTRY(efi_scratch)
.fill 3,8,0 .fill 3,8,0
......
/* /*
* Copyright (C) 2014 Intel Corporation; author Matt Fleming * Copyright (C) 2014 Intel Corporation; author Matt Fleming
*
* Support for invoking 32-bit EFI runtime services from a 64-bit
* kernel.
*
* The below thunking functions are only used after ExitBootServices()
* has been called. This simplifies things considerably as compared with
* the early EFI thunking because we can leave all the kernel state
* intact (GDT, IDT, etc) and simply invoke the the 32-bit EFI runtime
* services from __KERNEL32_CS. This means we can continue to service
* interrupts across an EFI mixed mode call.
*
* We do however, need to handle the fact that we're running in a full
* 64-bit virtual address space. Things like the stack and instruction
* addresses need to be accessible by the 32-bit firmware, so we rely on
* using the identity mappings in the EFI page table to access the stack
* and kernel text (see efi_setup_page_tables()).
*/ */
#include <linux/linkage.h> #include <linux/linkage.h>
#include <asm/page_types.h> #include <asm/page_types.h>
#include <asm/segment.h>
.text .text
.code64 .code64
...@@ -33,14 +50,6 @@ ENTRY(efi64_thunk) ...@@ -33,14 +50,6 @@ ENTRY(efi64_thunk)
leaq efi_exit32(%rip), %rbx leaq efi_exit32(%rip), %rbx
subq %rax, %rbx subq %rax, %rbx
movl %ebx, 8(%rsp) 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 leaq __efi64_thunk(%rip), %rbx
subq %rax, %rbx subq %rax, %rbx
...@@ -52,14 +61,92 @@ ENTRY(efi64_thunk) ...@@ -52,14 +61,92 @@ ENTRY(efi64_thunk)
retq retq
ENDPROC(efi64_thunk) ENDPROC(efi64_thunk)
.data /*
efi_gdt32: * We run this function from the 1:1 mapping.
.word efi_gdt32_end - efi_gdt32 *
.long 0 /* Filled out above */ * This function must be invoked with a 1:1 mapped stack.
.word 0 */
.quad 0x0000000000000000 /* NULL descriptor */ ENTRY(__efi64_thunk)
.quad 0x00cf9a000000ffff /* __KERNEL_CS */ movl %ds, %eax
.quad 0x00cf93000000ffff /* __KERNEL_DS */ push %rax
efi_gdt32_end: 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)
leaq 1f(%rip), %rbx
movq %rbx, func_rt_ptr(%rip)
/* Switch to 32-bit descriptor */
pushq $__KERNEL32_CS
leaq efi_enter32(%rip), %rax
pushq %rax
lretq
1: addq $32, %rsp
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
call *%edi
/* We must preserve return value */
movl %eax, %edi
movl 72(%esp), %eax
pushl $__KERNEL_CS
pushl %eax
lret
ENDPROC(efi_enter32)
.data
.balign 8
func_rt_ptr: .quad 0
efi_saved_sp: .quad 0 efi_saved_sp: .quad 0
...@@ -75,29 +75,25 @@ efi_status_t efi_get_memory_map(efi_system_table_t *sys_table_arg, ...@@ -75,29 +75,25 @@ efi_status_t efi_get_memory_map(efi_system_table_t *sys_table_arg,
unsigned long key; unsigned long key;
u32 desc_version; u32 desc_version;
*map_size = 0; *map_size = sizeof(*m) * 32;
*desc_size = 0; again:
key = 0;
status = efi_call_early(get_memory_map, map_size, NULL,
&key, desc_size, &desc_version);
if (status != EFI_BUFFER_TOO_SMALL)
return EFI_LOAD_ERROR;
/* /*
* Add an additional efi_memory_desc_t because we're doing an * Add an additional efi_memory_desc_t because we're doing an
* allocation which may be in a new descriptor region. * allocation which may be in a new descriptor region.
*/ */
*map_size += *desc_size; *map_size += sizeof(*m);
status = efi_call_early(allocate_pool, EFI_LOADER_DATA, status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
*map_size, (void **)&m); *map_size, (void **)&m);
if (status != EFI_SUCCESS) if (status != EFI_SUCCESS)
goto fail; goto fail;
*desc_size = 0;
key = 0;
status = efi_call_early(get_memory_map, map_size, m, status = efi_call_early(get_memory_map, map_size, m,
&key, desc_size, &desc_version); &key, desc_size, &desc_version);
if (status == EFI_BUFFER_TOO_SMALL) { if (status == EFI_BUFFER_TOO_SMALL) {
efi_call_early(free_pool, m); efi_call_early(free_pool, m);
return EFI_LOAD_ERROR; goto again;
} }
if (status != EFI_SUCCESS) if (status != EFI_SUCCESS)
......
...@@ -645,11 +645,12 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, ...@@ -645,11 +645,12 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
static unsigned long randomize_stack_top(unsigned long stack_top) static unsigned long randomize_stack_top(unsigned long stack_top)
{ {
unsigned int random_variable = 0; unsigned long random_variable = 0;
if ((current->flags & PF_RANDOMIZE) && if ((current->flags & PF_RANDOMIZE) &&
!(current->personality & ADDR_NO_RANDOMIZE)) { !(current->personality & ADDR_NO_RANDOMIZE)) {
random_variable = get_random_int() & STACK_RND_MASK; random_variable = (unsigned long) get_random_int();
random_variable &= STACK_RND_MASK;
random_variable <<= PAGE_SHIFT; random_variable <<= PAGE_SHIFT;
} }
#ifdef CONFIG_STACK_GROWSUP #ifdef CONFIG_STACK_GROWSUP
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册