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
This commit is contained in:
Коммит
5fbe4c224c
|
@ -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
|
||||
are in:
|
||||
|
||||
arch/x86/include/asm/bootparam.h
|
||||
arch/x86/include/uapi/asm/bootparam.h
|
||||
|
||||
|
||||
Offset Proto Name Meaning
|
||||
|
|
|
@ -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 \
|
||||
$(objtree)/drivers/firmware/efi/libstub/lib.a
|
||||
vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_thunk_$(BITS).o
|
||||
|
||||
$(obj)/vmlinux: $(vmlinux-objs-y) FORCE
|
||||
$(call if_changed,ld)
|
||||
|
|
|
@ -14,6 +14,13 @@
|
|||
static const char build_str[] = UTS_RELEASE " (" LINUX_COMPILE_BY "@"
|
||||
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_COUNTER0 0x40
|
||||
#define I8254_CMD_READBACK 0xC0
|
||||
|
@ -295,7 +302,29 @@ static unsigned long find_random_addr(unsigned long minimum,
|
|||
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 char *output,
|
||||
unsigned long output_size)
|
||||
|
@ -306,14 +335,17 @@ unsigned char *choose_kernel_location(unsigned char *input,
|
|||
#ifdef CONFIG_HIBERNATION
|
||||
if (!cmdline_find_option_bool("kaslr")) {
|
||||
debug_putstr("KASLR disabled by default...\n");
|
||||
add_kaslr_setup_data(params, 0);
|
||||
goto out;
|
||||
}
|
||||
#else
|
||||
if (cmdline_find_option_bool("nokaslr")) {
|
||||
debug_putstr("KASLR disabled by cmdline...\n");
|
||||
add_kaslr_setup_data(params, 0);
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
add_kaslr_setup_data(params, 1);
|
||||
|
||||
/* Record the various known unsafe memory ranges. */
|
||||
mem_avoid_init((unsigned long)input, input_size,
|
||||
|
|
|
@ -3,28 +3,3 @@
|
|||
#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 */
|
||||
|
|
|
@ -0,0 +1,196 @@
|
|||
/*
|
||||
* 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,
|
|||
* the entire decompressed kernel plus relocation table, or the
|
||||
* 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
|
||||
: run_size);
|
||||
|
||||
|
|
|
@ -57,7 +57,8 @@ int cmdline_find_option_bool(const char *option);
|
|||
|
||||
#if CONFIG_RANDOMIZE_BASE
|
||||
/* 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 char *output,
|
||||
unsigned long output_size);
|
||||
|
@ -65,7 +66,8 @@ unsigned char *choose_kernel_location(unsigned char *input,
|
|||
bool has_cpuflag(int flag);
|
||||
#else
|
||||
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 char *output,
|
||||
unsigned long output_size)
|
||||
|
|
|
@ -213,7 +213,15 @@ void register_lapic_address(unsigned long address);
|
|||
extern void setup_boot_APIC_clock(void);
|
||||
extern void setup_secondary_APIC_clock(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);
|
||||
#endif
|
||||
|
||||
extern int apic_bsp_setup(bool upmode);
|
||||
extern void apic_ap_setup(void);
|
||||
|
|
|
@ -51,6 +51,8 @@ extern int devmem_is_allowed(unsigned long pagenr);
|
|||
extern unsigned long max_low_pfn_mapped;
|
||||
extern unsigned long max_pfn_mapped;
|
||||
|
||||
extern bool kaslr_enabled;
|
||||
|
||||
static inline phys_addr_t get_max_mapped(void)
|
||||
{
|
||||
return (phys_addr_t)max_pfn_mapped << PAGE_SHIFT;
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#define SETUP_DTB 2
|
||||
#define SETUP_PCI 3
|
||||
#define SETUP_EFI 4
|
||||
#define SETUP_KASLR 5
|
||||
|
||||
/* ram_size flags */
|
||||
#define RAMDISK_IMAGE_START_MASK 0x07FF
|
||||
|
|
|
@ -196,6 +196,11 @@ static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size,
|
|||
struct microcode_header_intel mc_header;
|
||||
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)))
|
||||
break;
|
||||
|
||||
|
|
|
@ -321,7 +321,11 @@ get_matching_model_microcode(int cpu, unsigned long start,
|
|||
unsigned int mc_saved_count = mc_saved_data->mc_saved_count;
|
||||
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_size = get_totalsize(mc_header);
|
||||
|
|
|
@ -47,21 +47,13 @@ do { \
|
|||
|
||||
#ifdef CONFIG_RANDOMIZE_BASE
|
||||
static unsigned long module_load_offset;
|
||||
static int randomize_modules = 1;
|
||||
|
||||
/* Mutex protects the module_load_offset. */
|
||||
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)
|
||||
{
|
||||
if (randomize_modules) {
|
||||
if (kaslr_enabled) {
|
||||
mutex_lock(&module_kaslr_mutex);
|
||||
/*
|
||||
* Calculate the module_load_offset the first time this
|
||||
|
|
|
@ -122,6 +122,8 @@
|
|||
unsigned long max_low_pfn_mapped;
|
||||
unsigned long max_pfn_mapped;
|
||||
|
||||
bool __read_mostly kaslr_enabled = false;
|
||||
|
||||
#ifdef CONFIG_DMI
|
||||
RESERVE_BRK(dmi_alloc, 65536);
|
||||
#endif
|
||||
|
@ -425,6 +427,11 @@ static void __init reserve_initrd(void)
|
|||
}
|
||||
#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)
|
||||
{
|
||||
struct setup_data *data;
|
||||
|
@ -450,6 +457,9 @@ static void __init parse_setup_data(void)
|
|||
case SETUP_EFI:
|
||||
parse_efi_setup(pa_data, data_len);
|
||||
break;
|
||||
case SETUP_KASLR:
|
||||
parse_kaslr_setup(pa_data, data_len);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -832,10 +842,14 @@ static void __init trim_low_memory_range(void)
|
|||
static int
|
||||
dump_kernel_offset(struct notifier_block *self, unsigned long v, void *p)
|
||||
{
|
||||
pr_emerg("Kernel Offset: 0x%lx from 0x%lx "
|
||||
"(relocation range: 0x%lx-0x%lx)\n",
|
||||
(unsigned long)&_text - __START_KERNEL, __START_KERNEL,
|
||||
__START_KERNEL_map, MODULES_VADDR-1);
|
||||
if (kaslr_enabled)
|
||||
pr_emerg("Kernel Offset: 0x%lx from 0x%lx (relocation range: 0x%lx-0x%lx)\n",
|
||||
(unsigned long)&_text - __START_KERNEL,
|
||||
__START_KERNEL,
|
||||
__START_KERNEL_map,
|
||||
MODULES_VADDR-1);
|
||||
else
|
||||
pr_emerg("Kernel Offset: disabled\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
unsigned long start,
|
||||
unsigned long end)
|
||||
|
@ -333,8 +358,7 @@ static int __meminit split_mem_range(struct map_range *mr, int nr_range,
|
|||
for (i = 0; i < nr_range; i++)
|
||||
printk(KERN_DEBUG " [mem %#010lx-%#010lx] page %s\n",
|
||||
mr[i].start, mr[i].end - 1,
|
||||
(mr[i].page_size_mask & (1<<PG_LEVEL_1G))?"1G":(
|
||||
(mr[i].page_size_mask & (1<<PG_LEVEL_2M))?"2M":"4k"));
|
||||
page_size_string(&mr[i]));
|
||||
|
||||
return nr_range;
|
||||
}
|
||||
|
|
|
@ -35,12 +35,12 @@ struct va_alignment __read_mostly va_align = {
|
|||
.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) &&
|
||||
!(current->personality & ADDR_NO_RANDOMIZE)) {
|
||||
max = ((-1U) & STACK_RND_MASK) << PAGE_SHIFT;
|
||||
max = ((-1UL) & STACK_RND_MASK) << PAGE_SHIFT;
|
||||
}
|
||||
|
||||
return max;
|
||||
|
|
|
@ -91,167 +91,6 @@ ENTRY(efi_call)
|
|||
ret
|
||||
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
|
||||
ENTRY(efi_scratch)
|
||||
.fill 3,8,0
|
||||
|
|
|
@ -1,9 +1,26 @@
|
|||
/*
|
||||
* 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 <asm/page_types.h>
|
||||
#include <asm/segment.h>
|
||||
|
||||
.text
|
||||
.code64
|
||||
|
@ -33,14 +50,6 @@ ENTRY(efi64_thunk)
|
|||
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
|
||||
|
@ -52,14 +61,92 @@ ENTRY(efi64_thunk)
|
|||
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:
|
||||
/*
|
||||
* 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)
|
||||
|
||||
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
|
||||
|
|
|
@ -75,29 +75,25 @@ efi_status_t efi_get_memory_map(efi_system_table_t *sys_table_arg,
|
|||
unsigned long key;
|
||||
u32 desc_version;
|
||||
|
||||
*map_size = 0;
|
||||
*desc_size = 0;
|
||||
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;
|
||||
|
||||
*map_size = sizeof(*m) * 32;
|
||||
again:
|
||||
/*
|
||||
* Add an additional efi_memory_desc_t because we're doing an
|
||||
* 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,
|
||||
*map_size, (void **)&m);
|
||||
if (status != EFI_SUCCESS)
|
||||
goto fail;
|
||||
|
||||
*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_early(free_pool, m);
|
||||
return EFI_LOAD_ERROR;
|
||||
goto again;
|
||||
}
|
||||
|
||||
if (status != EFI_SUCCESS)
|
||||
|
|
|
@ -645,11 +645,12 @@ out:
|
|||
|
||||
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) &&
|
||||
!(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;
|
||||
}
|
||||
#ifdef CONFIG_STACK_GROWSUP
|
||||
|
|
Загрузка…
Ссылка в новой задаче