Merge remote-tracking branch 'tip/x86/efi-mixed' into efi-for-mingo
Conflicts: arch/x86/kernel/setup.c arch/x86/platform/efi/efi.c arch/x86/platform/efi/efi_64.c
This commit is contained in:
Коммит
994448f1af
|
@ -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"
|
||||
|
|
|
@ -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) > $@
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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 */
|
||||
|
|
|
@ -1 +1,30 @@
|
|||
#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,13 @@ relocated:
|
|||
xorl %ebx, %ebx
|
||||
jmp *%eax
|
||||
|
||||
.data
|
||||
efi32_config:
|
||||
.fill 11,8,0
|
||||
.long efi_call_phys
|
||||
.long 0
|
||||
.byte 0
|
||||
|
||||
/*
|
||||
* 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,22 @@ gdt:
|
|||
.quad 0x0000000000000000 /* TS continued */
|
||||
gdt_end:
|
||||
|
||||
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
|
||||
/*
|
||||
* 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,51 @@ 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) {}
|
||||
static inline void update_pecoff_text(unsigned int, unsigned int) {}
|
||||
static inline void efi_stub_defaults(void) {}
|
||||
static inline void efi_stup_entry_update(void) {}
|
||||
|
||||
static inline int reserve_pecoff_reloc_section(int c)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_EFI_STUB */
|
||||
|
||||
|
||||
|
@ -250,7 +296,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 +318,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 +341,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 +350,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 +375,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);
|
||||
|
@ -154,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.
|
||||
|
|
|
@ -382,6 +382,8 @@ 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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
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
|
||||
|
|
|
@ -453,9 +453,6 @@ void __init efi_free_boot_services(void)
|
|||
{
|
||||
void *p;
|
||||
|
||||
if (!efi_is_native())
|
||||
return;
|
||||
|
||||
for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
|
||||
efi_memory_desc_t *md = p;
|
||||
unsigned long long start = md->phys_addr;
|
||||
|
@ -579,9 +576,71 @@ static int __init efi_systab_init(void *phys)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __init efi_runtime_init32(void)
|
||||
{
|
||||
efi_runtime_services_32_t *runtime;
|
||||
|
||||
runtime = early_ioremap((unsigned long)efi.systab->runtime,
|
||||
sizeof(efi_runtime_services_32_t));
|
||||
if (!runtime) {
|
||||
pr_err("Could not map the runtime service table!\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/*
|
||||
* We will only need *early* access to the following two
|
||||
* EFI runtime services before set_virtual_address_map
|
||||
* is invoked.
|
||||
*/
|
||||
efi_phys.get_time = (efi_get_time_t *)
|
||||
(unsigned long)runtime->get_time;
|
||||
efi_phys.set_virtual_address_map =
|
||||
(efi_set_virtual_address_map_t *)
|
||||
(unsigned long)runtime->set_virtual_address_map;
|
||||
/*
|
||||
* Make efi_get_time can be called before entering
|
||||
* virtual mode.
|
||||
*/
|
||||
efi.get_time = phys_efi_get_time;
|
||||
early_iounmap(runtime, sizeof(efi_runtime_services_32_t));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init efi_runtime_init64(void)
|
||||
{
|
||||
efi_runtime_services_64_t *runtime;
|
||||
|
||||
runtime = early_ioremap((unsigned long)efi.systab->runtime,
|
||||
sizeof(efi_runtime_services_64_t));
|
||||
if (!runtime) {
|
||||
pr_err("Could not map the runtime service table!\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/*
|
||||
* We will only need *early* access to the following two
|
||||
* EFI runtime services before set_virtual_address_map
|
||||
* is invoked.
|
||||
*/
|
||||
efi_phys.get_time = (efi_get_time_t *)
|
||||
(unsigned long)runtime->get_time;
|
||||
efi_phys.set_virtual_address_map =
|
||||
(efi_set_virtual_address_map_t *)
|
||||
(unsigned long)runtime->set_virtual_address_map;
|
||||
/*
|
||||
* Make efi_get_time can be called before entering
|
||||
* virtual mode.
|
||||
*/
|
||||
efi.get_time = phys_efi_get_time;
|
||||
early_iounmap(runtime, sizeof(efi_runtime_services_64_t));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init efi_runtime_init(void)
|
||||
{
|
||||
efi_runtime_services_t *runtime;
|
||||
int rv;
|
||||
|
||||
/*
|
||||
* Check out the runtime services table. We need to map
|
||||
|
@ -589,27 +648,13 @@ static int __init efi_runtime_init(void)
|
|||
* address of several of the EFI runtime functions, needed to
|
||||
* set the firmware into virtual mode.
|
||||
*/
|
||||
runtime = early_ioremap((unsigned long)efi.systab->runtime,
|
||||
sizeof(efi_runtime_services_t));
|
||||
if (!runtime) {
|
||||
pr_err("Could not map the runtime service table!\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
/*
|
||||
* We will only need *early* access to the following
|
||||
* two EFI runtime services before set_virtual_address_map
|
||||
* is invoked.
|
||||
*/
|
||||
efi_phys.get_time = (efi_get_time_t *)runtime->get_time;
|
||||
efi_phys.set_virtual_address_map =
|
||||
(efi_set_virtual_address_map_t *)
|
||||
runtime->set_virtual_address_map;
|
||||
/*
|
||||
* Make efi_get_time can be called before entering
|
||||
* virtual mode.
|
||||
*/
|
||||
efi.get_time = phys_efi_get_time;
|
||||
early_iounmap(runtime, sizeof(efi_runtime_services_t));
|
||||
if (efi_enabled(EFI_64BIT))
|
||||
rv = efi_runtime_init64();
|
||||
else
|
||||
rv = efi_runtime_init32();
|
||||
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
|
||||
|
||||
|
@ -747,7 +792,7 @@ void __init efi_init(void)
|
|||
* that doesn't match the kernel 32/64-bit mode.
|
||||
*/
|
||||
|
||||
if (!efi_is_native())
|
||||
if (!efi_runtime_supported())
|
||||
pr_info("No EFI runtime due to 32/64-bit mismatch with kernel\n");
|
||||
else {
|
||||
if (disable_runtime || efi_runtime_init())
|
||||
|
@ -833,6 +878,22 @@ void __init old_map_region(efi_memory_desc_t *md)
|
|||
(unsigned long long)md->phys_addr);
|
||||
}
|
||||
|
||||
static void native_runtime_setup(void)
|
||||
{
|
||||
efi.get_time = virt_efi_get_time;
|
||||
efi.set_time = virt_efi_set_time;
|
||||
efi.get_wakeup_time = virt_efi_get_wakeup_time;
|
||||
efi.set_wakeup_time = virt_efi_set_wakeup_time;
|
||||
efi.get_variable = virt_efi_get_variable;
|
||||
efi.get_next_variable = virt_efi_get_next_variable;
|
||||
efi.set_variable = virt_efi_set_variable;
|
||||
efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count;
|
||||
efi.reset_system = virt_efi_reset_system;
|
||||
efi.query_variable_info = virt_efi_query_variable_info;
|
||||
efi.update_capsule = virt_efi_update_capsule;
|
||||
efi.query_capsule_caps = virt_efi_query_capsule_caps;
|
||||
}
|
||||
|
||||
/* Merge contiguous regions of the same type and attribute */
|
||||
static void __init efi_merge_regions(void)
|
||||
{
|
||||
|
@ -1015,19 +1076,10 @@ static void __init kexec_enter_virtual_mode(void)
|
|||
* Call EFI services through wrapper functions.
|
||||
*/
|
||||
efi.runtime_version = efi_systab.hdr.revision;
|
||||
efi.get_time = virt_efi_get_time;
|
||||
efi.set_time = virt_efi_set_time;
|
||||
efi.get_wakeup_time = virt_efi_get_wakeup_time;
|
||||
efi.set_wakeup_time = virt_efi_set_wakeup_time;
|
||||
efi.get_variable = virt_efi_get_variable;
|
||||
efi.get_next_variable = virt_efi_get_next_variable;
|
||||
efi.set_variable = virt_efi_set_variable;
|
||||
efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count;
|
||||
efi.reset_system = virt_efi_reset_system;
|
||||
|
||||
native_runtime_setup();
|
||||
|
||||
efi.set_virtual_address_map = NULL;
|
||||
efi.query_variable_info = virt_efi_query_variable_info;
|
||||
efi.update_capsule = virt_efi_update_capsule;
|
||||
efi.query_capsule_caps = virt_efi_query_capsule_caps;
|
||||
|
||||
if (efi_enabled(EFI_OLD_MEMMAP) && (__supported_pte_mask & _PAGE_NX))
|
||||
runtime_code_page_mkexec();
|
||||
|
@ -1071,15 +1123,6 @@ static void __init __efi_enter_virtual_mode(void)
|
|||
|
||||
efi.systab = NULL;
|
||||
|
||||
/*
|
||||
* We don't do virtual mode, since we don't do runtime services, on
|
||||
* non-native EFI
|
||||
*/
|
||||
if (!efi_is_native()) {
|
||||
efi_unmap_memmap();
|
||||
return;
|
||||
}
|
||||
|
||||
efi_merge_regions();
|
||||
new_memmap = efi_map_regions(&count, &pg_shift);
|
||||
if (!new_memmap) {
|
||||
|
@ -1097,11 +1140,20 @@ static void __init __efi_enter_virtual_mode(void)
|
|||
efi_sync_low_kernel_mappings();
|
||||
efi_dump_pagetable();
|
||||
|
||||
status = phys_efi_set_virtual_address_map(
|
||||
memmap.desc_size * count,
|
||||
memmap.desc_size,
|
||||
memmap.desc_version,
|
||||
(efi_memory_desc_t *)__pa(new_memmap));
|
||||
if (efi_is_native()) {
|
||||
status = phys_efi_set_virtual_address_map(
|
||||
memmap.desc_size * count,
|
||||
memmap.desc_size,
|
||||
memmap.desc_version,
|
||||
(efi_memory_desc_t *)__pa(new_memmap));
|
||||
} else {
|
||||
status = efi_thunk_set_virtual_address_map(
|
||||
efi_phys.set_virtual_address_map,
|
||||
memmap.desc_size * count,
|
||||
memmap.desc_size,
|
||||
memmap.desc_version,
|
||||
(efi_memory_desc_t *)__pa(new_memmap));
|
||||
}
|
||||
|
||||
if (status != EFI_SUCCESS) {
|
||||
pr_alert("Unable to switch EFI into virtual mode (status=%lx)!\n",
|
||||
|
@ -1116,19 +1168,13 @@ static void __init __efi_enter_virtual_mode(void)
|
|||
* Call EFI services through wrapper functions.
|
||||
*/
|
||||
efi.runtime_version = efi_systab.hdr.revision;
|
||||
efi.get_time = virt_efi_get_time;
|
||||
efi.set_time = virt_efi_set_time;
|
||||
efi.get_wakeup_time = virt_efi_get_wakeup_time;
|
||||
efi.set_wakeup_time = virt_efi_set_wakeup_time;
|
||||
efi.get_variable = virt_efi_get_variable;
|
||||
efi.get_next_variable = virt_efi_get_next_variable;
|
||||
efi.set_variable = virt_efi_set_variable;
|
||||
efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count;
|
||||
efi.reset_system = virt_efi_reset_system;
|
||||
|
||||
if (efi_is_native())
|
||||
native_runtime_setup();
|
||||
else
|
||||
efi_thunk_runtime_setup();
|
||||
|
||||
efi.set_virtual_address_map = NULL;
|
||||
efi.query_variable_info = virt_efi_query_variable_info;
|
||||
efi.update_capsule = virt_efi_update_capsule;
|
||||
efi.query_capsule_caps = virt_efi_query_capsule_caps;
|
||||
|
||||
efi_runtime_mkexec();
|
||||
|
||||
|
@ -1311,7 +1357,7 @@ void __init efi_apply_memmap_quirks(void)
|
|||
* firmware/kernel architectures since there is no support for runtime
|
||||
* services.
|
||||
*/
|
||||
if (!efi_is_native()) {
|
||||
if (!efi_runtime_supported()) {
|
||||
pr_info("efi: Setup done, disabling due to 32/64-bit mismatch\n");
|
||||
efi_unmap_memmap();
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include <asm/cacheflush.h>
|
||||
#include <asm/fixmap.h>
|
||||
#include <asm/realmode.h>
|
||||
#include <asm/time.h>
|
||||
|
||||
static pgd_t *save_pgd __initdata;
|
||||
static unsigned long efi_flags __initdata;
|
||||
|
@ -58,7 +59,8 @@ struct efi_scratch {
|
|||
u64 prev_cr3;
|
||||
pgd_t *efi_pgt;
|
||||
bool use_pgd;
|
||||
};
|
||||
u64 phys_stack;
|
||||
} __packed;
|
||||
|
||||
static void __init early_code_mapping_set_exec(int executable)
|
||||
{
|
||||
|
@ -139,6 +141,9 @@ void efi_sync_low_kernel_mappings(void)
|
|||
|
||||
int efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages)
|
||||
{
|
||||
unsigned long text;
|
||||
struct page *page;
|
||||
unsigned npages;
|
||||
pgd_t *pgd;
|
||||
|
||||
if (efi_enabled(EFI_OLD_MEMMAP))
|
||||
|
@ -160,6 +165,29 @@ int efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages)
|
|||
|
||||
efi_scratch.use_pgd = true;
|
||||
|
||||
/*
|
||||
* When making calls to the firmware everything needs to be 1:1
|
||||
* mapped and addressable with 32-bit pointers. Map the kernel
|
||||
* text and allocate a new stack because we can't rely on the
|
||||
* stack pointer being < 4GB.
|
||||
*/
|
||||
if (!IS_ENABLED(CONFIG_EFI_MIXED))
|
||||
return 0;
|
||||
|
||||
page = alloc_page(GFP_KERNEL|__GFP_DMA32);
|
||||
if (!page)
|
||||
panic("Unable to allocate EFI runtime stack < 4GB\n");
|
||||
|
||||
efi_scratch.phys_stack = virt_to_phys(page_address(page));
|
||||
efi_scratch.phys_stack += PAGE_SIZE; /* stack grows down */
|
||||
|
||||
npages = (_end - _text) >> PAGE_SHIFT;
|
||||
text = __pa(_text);
|
||||
|
||||
if (kernel_map_pages_in_pgd(pgd, text >> PAGE_SHIFT, text, npages, 0)) {
|
||||
pr_err("Failed to map kernel text 1:1\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -199,6 +227,16 @@ void __init efi_map_region(efi_memory_desc_t *md)
|
|||
*/
|
||||
__map_region(md, md->phys_addr);
|
||||
|
||||
/*
|
||||
* Enforce the 1:1 mapping as the default virtual address when
|
||||
* booting in EFI mixed mode, because even though we may be
|
||||
* running a 64-bit kernel, the firmware may only be 32-bit.
|
||||
*/
|
||||
if (!efi_is_native () && IS_ENABLED(CONFIG_EFI_MIXED)) {
|
||||
md->virt_addr = md->phys_addr;
|
||||
return;
|
||||
}
|
||||
|
||||
efi_va -= size;
|
||||
|
||||
/* Is PA 2M-aligned? */
|
||||
|
@ -277,3 +315,290 @@ void __init efi_dump_pagetable(void)
|
|||
ptdump_walk_pgd_level(NULL, pgd);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_EFI_MIXED
|
||||
extern efi_status_t efi64_thunk(u32, ...);
|
||||
|
||||
#define runtime_service32(func) \
|
||||
({ \
|
||||
u32 table = (u32)(unsigned long)efi.systab; \
|
||||
u32 *rt, *___f; \
|
||||
\
|
||||
rt = (u32 *)(table + offsetof(efi_system_table_32_t, runtime)); \
|
||||
___f = (u32 *)(*rt + offsetof(efi_runtime_services_32_t, func)); \
|
||||
*___f; \
|
||||
})
|
||||
|
||||
/*
|
||||
* Switch to the EFI page tables early so that we can access the 1:1
|
||||
* runtime services mappings which are not mapped in any other page
|
||||
* tables. This function must be called before runtime_service32().
|
||||
*
|
||||
* Also, disable interrupts because the IDT points to 64-bit handlers,
|
||||
* which aren't going to function correctly when we switch to 32-bit.
|
||||
*/
|
||||
#define efi_thunk(f, ...) \
|
||||
({ \
|
||||
efi_status_t __s; \
|
||||
unsigned long flags; \
|
||||
u32 func; \
|
||||
\
|
||||
efi_sync_low_kernel_mappings(); \
|
||||
local_irq_save(flags); \
|
||||
\
|
||||
efi_scratch.prev_cr3 = read_cr3(); \
|
||||
write_cr3((unsigned long)efi_scratch.efi_pgt); \
|
||||
__flush_tlb_all(); \
|
||||
\
|
||||
func = runtime_service32(f); \
|
||||
__s = efi64_thunk(func, __VA_ARGS__); \
|
||||
\
|
||||
write_cr3(efi_scratch.prev_cr3); \
|
||||
__flush_tlb_all(); \
|
||||
local_irq_restore(flags); \
|
||||
\
|
||||
__s; \
|
||||
})
|
||||
|
||||
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)
|
||||
{
|
||||
efi_status_t status;
|
||||
unsigned long flags;
|
||||
u32 func;
|
||||
|
||||
efi_sync_low_kernel_mappings();
|
||||
local_irq_save(flags);
|
||||
|
||||
efi_scratch.prev_cr3 = read_cr3();
|
||||
write_cr3((unsigned long)efi_scratch.efi_pgt);
|
||||
__flush_tlb_all();
|
||||
|
||||
func = (u32)(unsigned long)phys_set_virtual_address_map;
|
||||
status = efi64_thunk(func, memory_map_size, descriptor_size,
|
||||
descriptor_version, virtual_map);
|
||||
|
||||
write_cr3(efi_scratch.prev_cr3);
|
||||
__flush_tlb_all();
|
||||
local_irq_restore(flags);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static efi_status_t efi_thunk_get_time(efi_time_t *tm, efi_time_cap_t *tc)
|
||||
{
|
||||
efi_status_t status;
|
||||
u32 phys_tm, phys_tc;
|
||||
|
||||
spin_lock(&rtc_lock);
|
||||
|
||||
phys_tm = virt_to_phys(tm);
|
||||
phys_tc = virt_to_phys(tc);
|
||||
|
||||
status = efi_thunk(get_time, phys_tm, phys_tc);
|
||||
|
||||
spin_unlock(&rtc_lock);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static efi_status_t efi_thunk_set_time(efi_time_t *tm)
|
||||
{
|
||||
efi_status_t status;
|
||||
u32 phys_tm;
|
||||
|
||||
spin_lock(&rtc_lock);
|
||||
|
||||
phys_tm = virt_to_phys(tm);
|
||||
|
||||
status = efi_thunk(set_time, phys_tm);
|
||||
|
||||
spin_unlock(&rtc_lock);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static efi_status_t
|
||||
efi_thunk_get_wakeup_time(efi_bool_t *enabled, efi_bool_t *pending,
|
||||
efi_time_t *tm)
|
||||
{
|
||||
efi_status_t status;
|
||||
u32 phys_enabled, phys_pending, phys_tm;
|
||||
|
||||
spin_lock(&rtc_lock);
|
||||
|
||||
phys_enabled = virt_to_phys(enabled);
|
||||
phys_pending = virt_to_phys(pending);
|
||||
phys_tm = virt_to_phys(tm);
|
||||
|
||||
status = efi_thunk(get_wakeup_time, phys_enabled,
|
||||
phys_pending, phys_tm);
|
||||
|
||||
spin_unlock(&rtc_lock);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static efi_status_t
|
||||
efi_thunk_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
|
||||
{
|
||||
efi_status_t status;
|
||||
u32 phys_tm;
|
||||
|
||||
spin_lock(&rtc_lock);
|
||||
|
||||
phys_tm = virt_to_phys(tm);
|
||||
|
||||
status = efi_thunk(set_wakeup_time, enabled, phys_tm);
|
||||
|
||||
spin_unlock(&rtc_lock);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static efi_status_t
|
||||
efi_thunk_get_variable(efi_char16_t *name, efi_guid_t *vendor,
|
||||
u32 *attr, unsigned long *data_size, void *data)
|
||||
{
|
||||
efi_status_t status;
|
||||
u32 phys_name, phys_vendor, phys_attr;
|
||||
u32 phys_data_size, phys_data;
|
||||
|
||||
phys_data_size = virt_to_phys(data_size);
|
||||
phys_vendor = virt_to_phys(vendor);
|
||||
phys_name = virt_to_phys(name);
|
||||
phys_attr = virt_to_phys(attr);
|
||||
phys_data = virt_to_phys(data);
|
||||
|
||||
status = efi_thunk(get_variable, phys_name, phys_vendor,
|
||||
phys_attr, phys_data_size, phys_data);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static efi_status_t
|
||||
efi_thunk_set_variable(efi_char16_t *name, efi_guid_t *vendor,
|
||||
u32 attr, unsigned long data_size, void *data)
|
||||
{
|
||||
u32 phys_name, phys_vendor, phys_data;
|
||||
efi_status_t status;
|
||||
|
||||
phys_name = virt_to_phys(name);
|
||||
phys_vendor = virt_to_phys(vendor);
|
||||
phys_data = virt_to_phys(data);
|
||||
|
||||
/* If data_size is > sizeof(u32) we've got problems */
|
||||
status = efi_thunk(set_variable, phys_name, phys_vendor,
|
||||
attr, data_size, phys_data);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static efi_status_t
|
||||
efi_thunk_get_next_variable(unsigned long *name_size,
|
||||
efi_char16_t *name,
|
||||
efi_guid_t *vendor)
|
||||
{
|
||||
efi_status_t status;
|
||||
u32 phys_name_size, phys_name, phys_vendor;
|
||||
|
||||
phys_name_size = virt_to_phys(name_size);
|
||||
phys_vendor = virt_to_phys(vendor);
|
||||
phys_name = virt_to_phys(name);
|
||||
|
||||
status = efi_thunk(get_next_variable, phys_name_size,
|
||||
phys_name, phys_vendor);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static efi_status_t
|
||||
efi_thunk_get_next_high_mono_count(u32 *count)
|
||||
{
|
||||
efi_status_t status;
|
||||
u32 phys_count;
|
||||
|
||||
phys_count = virt_to_phys(count);
|
||||
status = efi_thunk(get_next_high_mono_count, phys_count);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void
|
||||
efi_thunk_reset_system(int reset_type, efi_status_t status,
|
||||
unsigned long data_size, efi_char16_t *data)
|
||||
{
|
||||
u32 phys_data;
|
||||
|
||||
phys_data = virt_to_phys(data);
|
||||
|
||||
efi_thunk(reset_system, reset_type, status, data_size, phys_data);
|
||||
}
|
||||
|
||||
static efi_status_t
|
||||
efi_thunk_update_capsule(efi_capsule_header_t **capsules,
|
||||
unsigned long count, unsigned long sg_list)
|
||||
{
|
||||
/*
|
||||
* To properly support this function we would need to repackage
|
||||
* 'capsules' because the firmware doesn't understand 64-bit
|
||||
* pointers.
|
||||
*/
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
static efi_status_t
|
||||
efi_thunk_query_variable_info(u32 attr, u64 *storage_space,
|
||||
u64 *remaining_space,
|
||||
u64 *max_variable_size)
|
||||
{
|
||||
efi_status_t status;
|
||||
u32 phys_storage, phys_remaining, phys_max;
|
||||
|
||||
if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
|
||||
return EFI_UNSUPPORTED;
|
||||
|
||||
phys_storage = virt_to_phys(storage_space);
|
||||
phys_remaining = virt_to_phys(remaining_space);
|
||||
phys_max = virt_to_phys(max_variable_size);
|
||||
|
||||
status = efi_thunk(query_variable_info, phys_storage,
|
||||
phys_remaining, phys_max);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static efi_status_t
|
||||
efi_thunk_query_capsule_caps(efi_capsule_header_t **capsules,
|
||||
unsigned long count, u64 *max_size,
|
||||
int *reset_type)
|
||||
{
|
||||
/*
|
||||
* To properly support this function we would need to repackage
|
||||
* 'capsules' because the firmware doesn't understand 64-bit
|
||||
* pointers.
|
||||
*/
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
void efi_thunk_runtime_setup(void)
|
||||
{
|
||||
efi.get_time = efi_thunk_get_time;
|
||||
efi.set_time = efi_thunk_set_time;
|
||||
efi.get_wakeup_time = efi_thunk_get_wakeup_time;
|
||||
efi.set_wakeup_time = efi_thunk_set_wakeup_time;
|
||||
efi.get_variable = efi_thunk_get_variable;
|
||||
efi.get_next_variable = efi_thunk_get_next_variable;
|
||||
efi.set_variable = efi_thunk_set_variable;
|
||||
efi.get_next_high_mono_count = efi_thunk_get_next_high_mono_count;
|
||||
efi.reset_system = efi_thunk_reset_system;
|
||||
efi.query_variable_info = efi_thunk_query_variable_info;
|
||||
efi.update_capsule = efi_thunk_update_capsule;
|
||||
efi.query_capsule_caps = efi_thunk_query_capsule_caps;
|
||||
}
|
||||
#endif /* CONFIG_EFI_MIXED */
|
||||
|
|
|
@ -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,160 @@ 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)
|
||||
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 40(%rsp), %eax
|
||||
lgdt (%rax)
|
||||
|
||||
leaq efi_enter32(%rip), %rax
|
||||
pushq $__KERNEL_CS
|
||||
pushq %rax
|
||||
lretq
|
||||
|
||||
1: addq $32, %rsp
|
||||
|
||||
lgdt save_gdt(%rip)
|
||||
|
||||
/*
|
||||
* 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)
|
||||
xorq %rax, %rax
|
||||
movl %eax, %ds
|
||||
movl %eax, %es
|
||||
movl %eax, %ss
|
||||
|
||||
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 44(%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 48(%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
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* 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 @@ again:
|
|||
* 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_early->call(efi_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_early->call(efi_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_early->call(efi_early->free_pool, m);
|
||||
goto again;
|
||||
}
|
||||
|
||||
if (status != EFI_SUCCESS)
|
||||
efi_call_phys1(sys_table_arg->boottime->free_pool, m);
|
||||
efi_early->call(efi_early->free_pool, m);
|
||||
|
||||
if (key_ptr && status == EFI_SUCCESS)
|
||||
*key_ptr = key;
|
||||
if (desc_ver && status == EFI_SUCCESS)
|
||||
|
@ -158,9 +149,9 @@ again:
|
|||
if (!max_addr)
|
||||
status = EFI_NOT_FOUND;
|
||||
else {
|
||||
status = efi_call_phys4(sys_table_arg->boottime->allocate_pages,
|
||||
EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
|
||||
nr_pages, &max_addr);
|
||||
status = efi_early->call(efi_early->allocate_pages,
|
||||
EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
|
||||
nr_pages, &max_addr);
|
||||
if (status != EFI_SUCCESS) {
|
||||
max = max_addr;
|
||||
max_addr = 0;
|
||||
|
@ -170,8 +161,7 @@ again:
|
|||
*addr = max_addr;
|
||||
}
|
||||
|
||||
efi_call_phys1(sys_table_arg->boottime->free_pool, map);
|
||||
|
||||
efi_early->call(efi_early->free_pool, map);
|
||||
fail:
|
||||
return status;
|
||||
}
|
||||
|
@ -231,9 +221,9 @@ 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,
|
||||
EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
|
||||
nr_pages, &start);
|
||||
status = efi_early->call(efi_early->allocate_pages,
|
||||
EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
|
||||
nr_pages, &start);
|
||||
if (status == EFI_SUCCESS) {
|
||||
*addr = start;
|
||||
break;
|
||||
|
@ -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_early->call(efi_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_early->call(efi_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_early->call(efi_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");
|
||||
status = efi_open_volume(sys_table_arg, image,
|
||||
(void **)&fh);
|
||||
if (status != EFI_SUCCESS)
|
||||
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");
|
||||
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 @@ grow:
|
|||
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 @@ grow:
|
|||
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_early->call(efi_early->free_pool, files);
|
||||
|
||||
*load_addr = file_addr;
|
||||
*load_size = file_size_total;
|
||||
|
@ -497,9 +425,9 @@ free_file_total:
|
|||
|
||||
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_early->call(efi_early->free_pool, files);
|
||||
fail:
|
||||
*load_addr = 0;
|
||||
*load_size = 0;
|
||||
|
@ -545,9 +473,9 @@ 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,
|
||||
EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
|
||||
nr_pages, &efi_addr);
|
||||
status = efi_early->call(efi_early->allocate_pages,
|
||||
EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
|
||||
nr_pages, &efi_addr);
|
||||
new_addr = efi_addr;
|
||||
/*
|
||||
* If preferred address allocation failed allocate as low as
|
||||
|
|
|
@ -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 *,
|
||||
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче