mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2025-01-18 12:46:11 +07:00
Merge branch 'efi-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull EFI updates from Thomas Gleixner: "The EFI pile: - Make mixed mode UEFI runtime service invocations mutually exclusive, as mandated by the UEFI spec - Perform UEFI runtime services calls from a work queue so the calls into the firmware occur from a kernel thread - Honor the UEFI memory map attributes for live memory regions configured by UEFI as a framebuffer. This works around a coherency problem with KVM guests running on ARM. - Cleanups, improvements and fixes all over the place" * 'efi-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: efivars: Call guid_parse() against guid_t type of variable efi/cper: Use consistent types for UUIDs efi/x86: Replace references to efi_early->is64 with efi_is_64bit() efi: Deduplicate efi_open_volume() efi/x86: Add missing NULL initialization in UGA draw protocol discovery efi/x86: Merge 32-bit and 64-bit UGA draw protocol setup routines efi/x86: Align efi_uga_draw_protocol typedef names to convention efi/x86: Merge the setup_efi_pci32() and setup_efi_pci64() routines efi/x86: Prevent reentrant firmware calls in mixed mode efi/esrt: Only call efi_mem_reserve() for boot services memory fbdev/efifb: Honour UEFI memory map attributes when mapping the FB efi: Drop type and attribute checks in efi_mem_desc_lookup() efi/libstub/arm: Add opt-in Kconfig option for the DTB loader efi: Remove the declaration of efi_late_init() as the function is unused efi/cper: Avoid using get_seconds() efi: Use a work queue to invoke EFI Runtime Services efi/x86: Use non-blocking SetVariable() for efi_delete_dummy_variable() efi/x86: Clean up the eboot code
This commit is contained in:
commit
400439275d
@ -58,6 +58,9 @@ void efi_virtmap_unload(void);
|
|||||||
#define efi_call_runtime(f, ...) sys_table_arg->runtime->f(__VA_ARGS__)
|
#define efi_call_runtime(f, ...) sys_table_arg->runtime->f(__VA_ARGS__)
|
||||||
#define efi_is_64bit() (false)
|
#define efi_is_64bit() (false)
|
||||||
|
|
||||||
|
#define efi_table_attr(table, attr, instance) \
|
||||||
|
((table##_t *)instance)->attr
|
||||||
|
|
||||||
#define efi_call_proto(protocol, f, instance, ...) \
|
#define efi_call_proto(protocol, f, instance, ...) \
|
||||||
((protocol##_t *)instance)->f(instance, ##__VA_ARGS__)
|
((protocol##_t *)instance)->f(instance, ##__VA_ARGS__)
|
||||||
|
|
||||||
|
@ -87,6 +87,9 @@ static inline unsigned long efi_get_max_initrd_addr(unsigned long dram_base,
|
|||||||
#define efi_call_runtime(f, ...) sys_table_arg->runtime->f(__VA_ARGS__)
|
#define efi_call_runtime(f, ...) sys_table_arg->runtime->f(__VA_ARGS__)
|
||||||
#define efi_is_64bit() (true)
|
#define efi_is_64bit() (true)
|
||||||
|
|
||||||
|
#define efi_table_attr(table, attr, instance) \
|
||||||
|
((table##_t *)instance)->attr
|
||||||
|
|
||||||
#define efi_call_proto(protocol, f, instance, ...) \
|
#define efi_call_proto(protocol, f, instance, ...) \
|
||||||
((protocol##_t *)instance)->f(instance, ##__VA_ARGS__)
|
((protocol##_t *)instance)->f(instance, ##__VA_ARGS__)
|
||||||
|
|
||||||
|
@ -34,74 +34,13 @@ static void setup_boot_services##bits(struct efi_config *c) \
|
|||||||
\
|
\
|
||||||
table = (typeof(table))sys_table; \
|
table = (typeof(table))sys_table; \
|
||||||
\
|
\
|
||||||
c->runtime_services = table->runtime; \
|
c->runtime_services = table->runtime; \
|
||||||
c->boot_services = table->boottime; \
|
c->boot_services = table->boottime; \
|
||||||
c->text_output = table->con_out; \
|
c->text_output = table->con_out; \
|
||||||
}
|
}
|
||||||
BOOT_SERVICES(32);
|
BOOT_SERVICES(32);
|
||||||
BOOT_SERVICES(64);
|
BOOT_SERVICES(64);
|
||||||
|
|
||||||
static inline efi_status_t __open_volume32(void *__image, void **__fh)
|
|
||||||
{
|
|
||||||
efi_file_io_interface_t *io;
|
|
||||||
efi_loaded_image_32_t *image = __image;
|
|
||||||
efi_file_handle_32_t *fh;
|
|
||||||
efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
|
|
||||||
efi_status_t status;
|
|
||||||
void *handle = (void *)(unsigned long)image->device_handle;
|
|
||||||
unsigned long func;
|
|
||||||
|
|
||||||
status = efi_call_early(handle_protocol, handle,
|
|
||||||
&fs_proto, (void **)&io);
|
|
||||||
if (status != EFI_SUCCESS) {
|
|
||||||
efi_printk(sys_table, "Failed to handle fs_proto\n");
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
func = (unsigned long)io->open_volume;
|
|
||||||
status = efi_early->call(func, io, &fh);
|
|
||||||
if (status != EFI_SUCCESS)
|
|
||||||
efi_printk(sys_table, "Failed to open volume\n");
|
|
||||||
|
|
||||||
*__fh = fh;
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline efi_status_t __open_volume64(void *__image, void **__fh)
|
|
||||||
{
|
|
||||||
efi_file_io_interface_t *io;
|
|
||||||
efi_loaded_image_64_t *image = __image;
|
|
||||||
efi_file_handle_64_t *fh;
|
|
||||||
efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
|
|
||||||
efi_status_t status;
|
|
||||||
void *handle = (void *)(unsigned long)image->device_handle;
|
|
||||||
unsigned long func;
|
|
||||||
|
|
||||||
status = efi_call_early(handle_protocol, handle,
|
|
||||||
&fs_proto, (void **)&io);
|
|
||||||
if (status != EFI_SUCCESS) {
|
|
||||||
efi_printk(sys_table, "Failed to handle fs_proto\n");
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
func = (unsigned long)io->open_volume;
|
|
||||||
status = efi_early->call(func, io, &fh);
|
|
||||||
if (status != EFI_SUCCESS)
|
|
||||||
efi_printk(sys_table, "Failed to open volume\n");
|
|
||||||
|
|
||||||
*__fh = fh;
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
efi_status_t
|
|
||||||
efi_open_volume(efi_system_table_t *sys_table, void *__image, void **__fh)
|
|
||||||
{
|
|
||||||
if (efi_early->is64)
|
|
||||||
return __open_volume64(__image, __fh);
|
|
||||||
|
|
||||||
return __open_volume32(__image, __fh);
|
|
||||||
}
|
|
||||||
|
|
||||||
void efi_char16_printk(efi_system_table_t *table, efi_char16_t *str)
|
void efi_char16_printk(efi_system_table_t *table, efi_char16_t *str)
|
||||||
{
|
{
|
||||||
efi_call_proto(efi_simple_text_output_protocol, output_string,
|
efi_call_proto(efi_simple_text_output_protocol, output_string,
|
||||||
@ -109,7 +48,7 @@ void efi_char16_printk(efi_system_table_t *table, efi_char16_t *str)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static efi_status_t
|
static efi_status_t
|
||||||
__setup_efi_pci(efi_pci_io_protocol_t *pci, struct pci_setup_rom **__rom)
|
preserve_pci_rom_image(efi_pci_io_protocol_t *pci, struct pci_setup_rom **__rom)
|
||||||
{
|
{
|
||||||
struct pci_setup_rom *rom = NULL;
|
struct pci_setup_rom *rom = NULL;
|
||||||
efi_status_t status;
|
efi_status_t status;
|
||||||
@ -134,16 +73,16 @@ __setup_efi_pci(efi_pci_io_protocol_t *pci, struct pci_setup_rom **__rom)
|
|||||||
|
|
||||||
status = efi_call_early(allocate_pool, EFI_LOADER_DATA, size, &rom);
|
status = efi_call_early(allocate_pool, EFI_LOADER_DATA, size, &rom);
|
||||||
if (status != EFI_SUCCESS) {
|
if (status != EFI_SUCCESS) {
|
||||||
efi_printk(sys_table, "Failed to alloc mem for rom\n");
|
efi_printk(sys_table, "Failed to allocate memory for 'rom'\n");
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(rom, 0, sizeof(*rom));
|
memset(rom, 0, sizeof(*rom));
|
||||||
|
|
||||||
rom->data.type = SETUP_PCI;
|
rom->data.type = SETUP_PCI;
|
||||||
rom->data.len = size - sizeof(struct setup_data);
|
rom->data.len = size - sizeof(struct setup_data);
|
||||||
rom->data.next = 0;
|
rom->data.next = 0;
|
||||||
rom->pcilen = pci->romsize;
|
rom->pcilen = pci->romsize;
|
||||||
*__rom = rom;
|
*__rom = rom;
|
||||||
|
|
||||||
status = efi_call_proto(efi_pci_io_protocol, pci.read, pci,
|
status = efi_call_proto(efi_pci_io_protocol, pci.read, pci,
|
||||||
@ -179,96 +118,6 @@ __setup_efi_pci(efi_pci_io_protocol_t *pci, struct pci_setup_rom **__rom)
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
setup_efi_pci32(struct boot_params *params, void **pci_handle,
|
|
||||||
unsigned long size)
|
|
||||||
{
|
|
||||||
efi_pci_io_protocol_t *pci = NULL;
|
|
||||||
efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
|
|
||||||
u32 *handles = (u32 *)(unsigned long)pci_handle;
|
|
||||||
efi_status_t status;
|
|
||||||
unsigned long nr_pci;
|
|
||||||
struct setup_data *data;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
|
|
||||||
|
|
||||||
while (data && data->next)
|
|
||||||
data = (struct setup_data *)(unsigned long)data->next;
|
|
||||||
|
|
||||||
nr_pci = size / sizeof(u32);
|
|
||||||
for (i = 0; i < nr_pci; i++) {
|
|
||||||
struct pci_setup_rom *rom = NULL;
|
|
||||||
u32 h = handles[i];
|
|
||||||
|
|
||||||
status = efi_call_early(handle_protocol, h,
|
|
||||||
&pci_proto, (void **)&pci);
|
|
||||||
|
|
||||||
if (status != EFI_SUCCESS)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!pci)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
status = __setup_efi_pci(pci, &rom);
|
|
||||||
if (status != EFI_SUCCESS)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (data)
|
|
||||||
data->next = (unsigned long)rom;
|
|
||||||
else
|
|
||||||
params->hdr.setup_data = (unsigned long)rom;
|
|
||||||
|
|
||||||
data = (struct setup_data *)rom;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
setup_efi_pci64(struct boot_params *params, void **pci_handle,
|
|
||||||
unsigned long size)
|
|
||||||
{
|
|
||||||
efi_pci_io_protocol_t *pci = NULL;
|
|
||||||
efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
|
|
||||||
u64 *handles = (u64 *)(unsigned long)pci_handle;
|
|
||||||
efi_status_t status;
|
|
||||||
unsigned long nr_pci;
|
|
||||||
struct setup_data *data;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
|
|
||||||
|
|
||||||
while (data && data->next)
|
|
||||||
data = (struct setup_data *)(unsigned long)data->next;
|
|
||||||
|
|
||||||
nr_pci = size / sizeof(u64);
|
|
||||||
for (i = 0; i < nr_pci; i++) {
|
|
||||||
struct pci_setup_rom *rom = NULL;
|
|
||||||
u64 h = handles[i];
|
|
||||||
|
|
||||||
status = efi_call_early(handle_protocol, h,
|
|
||||||
&pci_proto, (void **)&pci);
|
|
||||||
|
|
||||||
if (status != EFI_SUCCESS)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!pci)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
status = __setup_efi_pci(pci, &rom);
|
|
||||||
if (status != EFI_SUCCESS)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (data)
|
|
||||||
data->next = (unsigned long)rom;
|
|
||||||
else
|
|
||||||
params->hdr.setup_data = (unsigned long)rom;
|
|
||||||
|
|
||||||
data = (struct setup_data *)rom;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* There's no way to return an informative status from this function,
|
* There's no way to return an informative status from this function,
|
||||||
* because any analysis (and printing of error messages) needs to be
|
* because any analysis (and printing of error messages) needs to be
|
||||||
@ -284,6 +133,9 @@ static void setup_efi_pci(struct boot_params *params)
|
|||||||
void **pci_handle = NULL;
|
void **pci_handle = NULL;
|
||||||
efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
|
efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
|
||||||
unsigned long size = 0;
|
unsigned long size = 0;
|
||||||
|
unsigned long nr_pci;
|
||||||
|
struct setup_data *data;
|
||||||
|
int i;
|
||||||
|
|
||||||
status = efi_call_early(locate_handle,
|
status = efi_call_early(locate_handle,
|
||||||
EFI_LOCATE_BY_PROTOCOL,
|
EFI_LOCATE_BY_PROTOCOL,
|
||||||
@ -295,7 +147,7 @@ static void setup_efi_pci(struct boot_params *params)
|
|||||||
size, (void **)&pci_handle);
|
size, (void **)&pci_handle);
|
||||||
|
|
||||||
if (status != EFI_SUCCESS) {
|
if (status != EFI_SUCCESS) {
|
||||||
efi_printk(sys_table, "Failed to alloc mem for pci_handle\n");
|
efi_printk(sys_table, "Failed to allocate memory for 'pci_handle'\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -307,10 +159,34 @@ static void setup_efi_pci(struct boot_params *params)
|
|||||||
if (status != EFI_SUCCESS)
|
if (status != EFI_SUCCESS)
|
||||||
goto free_handle;
|
goto free_handle;
|
||||||
|
|
||||||
if (efi_early->is64)
|
data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
|
||||||
setup_efi_pci64(params, pci_handle, size);
|
|
||||||
else
|
while (data && data->next)
|
||||||
setup_efi_pci32(params, pci_handle, size);
|
data = (struct setup_data *)(unsigned long)data->next;
|
||||||
|
|
||||||
|
nr_pci = size / (efi_is_64bit() ? sizeof(u64) : sizeof(u32));
|
||||||
|
for (i = 0; i < nr_pci; i++) {
|
||||||
|
efi_pci_io_protocol_t *pci = NULL;
|
||||||
|
struct pci_setup_rom *rom;
|
||||||
|
|
||||||
|
status = efi_call_early(handle_protocol,
|
||||||
|
efi_is_64bit() ? ((u64 *)pci_handle)[i]
|
||||||
|
: ((u32 *)pci_handle)[i],
|
||||||
|
&pci_proto, (void **)&pci);
|
||||||
|
if (status != EFI_SUCCESS || !pci)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
status = preserve_pci_rom_image(pci, &rom);
|
||||||
|
if (status != EFI_SUCCESS)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (data)
|
||||||
|
data->next = (unsigned long)rom;
|
||||||
|
else
|
||||||
|
params->hdr.setup_data = (unsigned long)rom;
|
||||||
|
|
||||||
|
data = (struct setup_data *)rom;
|
||||||
|
}
|
||||||
|
|
||||||
free_handle:
|
free_handle:
|
||||||
efi_call_early(free_pool, pci_handle);
|
efi_call_early(free_pool, pci_handle);
|
||||||
@ -341,8 +217,7 @@ static void retrieve_apple_device_properties(struct boot_params *boot_params)
|
|||||||
status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
|
status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
|
||||||
size + sizeof(struct setup_data), &new);
|
size + sizeof(struct setup_data), &new);
|
||||||
if (status != EFI_SUCCESS) {
|
if (status != EFI_SUCCESS) {
|
||||||
efi_printk(sys_table,
|
efi_printk(sys_table, "Failed to allocate memory for 'properties'\n");
|
||||||
"Failed to alloc mem for properties\n");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -358,9 +233,9 @@ static void retrieve_apple_device_properties(struct boot_params *boot_params)
|
|||||||
new->next = 0;
|
new->next = 0;
|
||||||
|
|
||||||
data = (struct setup_data *)(unsigned long)boot_params->hdr.setup_data;
|
data = (struct setup_data *)(unsigned long)boot_params->hdr.setup_data;
|
||||||
if (!data)
|
if (!data) {
|
||||||
boot_params->hdr.setup_data = (unsigned long)new;
|
boot_params->hdr.setup_data = (unsigned long)new;
|
||||||
else {
|
} else {
|
||||||
while (data->next)
|
while (data->next)
|
||||||
data = (struct setup_data *)(unsigned long)data->next;
|
data = (struct setup_data *)(unsigned long)data->next;
|
||||||
data->next = (unsigned long)new;
|
data->next = (unsigned long)new;
|
||||||
@ -380,105 +255,18 @@ static void setup_quirks(struct boot_params *boot_params)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static efi_status_t
|
|
||||||
setup_uga32(void **uga_handle, unsigned long size, u32 *width, u32 *height)
|
|
||||||
{
|
|
||||||
struct efi_uga_draw_protocol *uga = NULL, *first_uga;
|
|
||||||
efi_guid_t uga_proto = EFI_UGA_PROTOCOL_GUID;
|
|
||||||
unsigned long nr_ugas;
|
|
||||||
u32 *handles = (u32 *)uga_handle;
|
|
||||||
efi_status_t status = EFI_INVALID_PARAMETER;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
first_uga = NULL;
|
|
||||||
nr_ugas = size / sizeof(u32);
|
|
||||||
for (i = 0; i < nr_ugas; i++) {
|
|
||||||
efi_guid_t pciio_proto = EFI_PCI_IO_PROTOCOL_GUID;
|
|
||||||
u32 w, h, depth, refresh;
|
|
||||||
void *pciio;
|
|
||||||
u32 handle = handles[i];
|
|
||||||
|
|
||||||
status = efi_call_early(handle_protocol, handle,
|
|
||||||
&uga_proto, (void **)&uga);
|
|
||||||
if (status != EFI_SUCCESS)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
efi_call_early(handle_protocol, handle, &pciio_proto, &pciio);
|
|
||||||
|
|
||||||
status = efi_early->call((unsigned long)uga->get_mode, uga,
|
|
||||||
&w, &h, &depth, &refresh);
|
|
||||||
if (status == EFI_SUCCESS && (!first_uga || pciio)) {
|
|
||||||
*width = w;
|
|
||||||
*height = h;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Once we've found a UGA supporting PCIIO,
|
|
||||||
* don't bother looking any further.
|
|
||||||
*/
|
|
||||||
if (pciio)
|
|
||||||
break;
|
|
||||||
|
|
||||||
first_uga = uga;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
static efi_status_t
|
|
||||||
setup_uga64(void **uga_handle, unsigned long size, u32 *width, u32 *height)
|
|
||||||
{
|
|
||||||
struct efi_uga_draw_protocol *uga = NULL, *first_uga;
|
|
||||||
efi_guid_t uga_proto = EFI_UGA_PROTOCOL_GUID;
|
|
||||||
unsigned long nr_ugas;
|
|
||||||
u64 *handles = (u64 *)uga_handle;
|
|
||||||
efi_status_t status = EFI_INVALID_PARAMETER;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
first_uga = NULL;
|
|
||||||
nr_ugas = size / sizeof(u64);
|
|
||||||
for (i = 0; i < nr_ugas; i++) {
|
|
||||||
efi_guid_t pciio_proto = EFI_PCI_IO_PROTOCOL_GUID;
|
|
||||||
u32 w, h, depth, refresh;
|
|
||||||
void *pciio;
|
|
||||||
u64 handle = handles[i];
|
|
||||||
|
|
||||||
status = efi_call_early(handle_protocol, handle,
|
|
||||||
&uga_proto, (void **)&uga);
|
|
||||||
if (status != EFI_SUCCESS)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
efi_call_early(handle_protocol, handle, &pciio_proto, &pciio);
|
|
||||||
|
|
||||||
status = efi_early->call((unsigned long)uga->get_mode, uga,
|
|
||||||
&w, &h, &depth, &refresh);
|
|
||||||
if (status == EFI_SUCCESS && (!first_uga || pciio)) {
|
|
||||||
*width = w;
|
|
||||||
*height = h;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Once we've found a UGA supporting PCIIO,
|
|
||||||
* don't bother looking any further.
|
|
||||||
*/
|
|
||||||
if (pciio)
|
|
||||||
break;
|
|
||||||
|
|
||||||
first_uga = uga;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* See if we have Universal Graphics Adapter (UGA) protocol
|
* See if we have Universal Graphics Adapter (UGA) protocol
|
||||||
*/
|
*/
|
||||||
static efi_status_t setup_uga(struct screen_info *si, efi_guid_t *uga_proto,
|
static efi_status_t
|
||||||
unsigned long size)
|
setup_uga(struct screen_info *si, efi_guid_t *uga_proto, unsigned long size)
|
||||||
{
|
{
|
||||||
efi_status_t status;
|
efi_status_t status;
|
||||||
u32 width, height;
|
u32 width, height;
|
||||||
void **uga_handle = NULL;
|
void **uga_handle = NULL;
|
||||||
|
efi_uga_draw_protocol_t *uga = NULL, *first_uga;
|
||||||
|
unsigned long nr_ugas;
|
||||||
|
int i;
|
||||||
|
|
||||||
status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
|
status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
|
||||||
size, (void **)&uga_handle);
|
size, (void **)&uga_handle);
|
||||||
@ -494,32 +282,62 @@ static efi_status_t setup_uga(struct screen_info *si, efi_guid_t *uga_proto,
|
|||||||
height = 0;
|
height = 0;
|
||||||
width = 0;
|
width = 0;
|
||||||
|
|
||||||
if (efi_early->is64)
|
first_uga = NULL;
|
||||||
status = setup_uga64(uga_handle, size, &width, &height);
|
nr_ugas = size / (efi_is_64bit() ? sizeof(u64) : sizeof(u32));
|
||||||
else
|
for (i = 0; i < nr_ugas; i++) {
|
||||||
status = setup_uga32(uga_handle, size, &width, &height);
|
efi_guid_t pciio_proto = EFI_PCI_IO_PROTOCOL_GUID;
|
||||||
|
u32 w, h, depth, refresh;
|
||||||
|
void *pciio;
|
||||||
|
unsigned long handle = efi_is_64bit() ? ((u64 *)uga_handle)[i]
|
||||||
|
: ((u32 *)uga_handle)[i];
|
||||||
|
|
||||||
|
status = efi_call_early(handle_protocol, handle,
|
||||||
|
uga_proto, (void **)&uga);
|
||||||
|
if (status != EFI_SUCCESS)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
pciio = NULL;
|
||||||
|
efi_call_early(handle_protocol, handle, &pciio_proto, &pciio);
|
||||||
|
|
||||||
|
status = efi_call_proto(efi_uga_draw_protocol, get_mode, uga,
|
||||||
|
&w, &h, &depth, &refresh);
|
||||||
|
if (status == EFI_SUCCESS && (!first_uga || pciio)) {
|
||||||
|
width = w;
|
||||||
|
height = h;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Once we've found a UGA supporting PCIIO,
|
||||||
|
* don't bother looking any further.
|
||||||
|
*/
|
||||||
|
if (pciio)
|
||||||
|
break;
|
||||||
|
|
||||||
|
first_uga = uga;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!width && !height)
|
if (!width && !height)
|
||||||
goto free_handle;
|
goto free_handle;
|
||||||
|
|
||||||
/* EFI framebuffer */
|
/* EFI framebuffer */
|
||||||
si->orig_video_isVGA = VIDEO_TYPE_EFI;
|
si->orig_video_isVGA = VIDEO_TYPE_EFI;
|
||||||
|
|
||||||
si->lfb_depth = 32;
|
si->lfb_depth = 32;
|
||||||
si->lfb_width = width;
|
si->lfb_width = width;
|
||||||
si->lfb_height = height;
|
si->lfb_height = height;
|
||||||
|
|
||||||
si->red_size = 8;
|
si->red_size = 8;
|
||||||
si->red_pos = 16;
|
si->red_pos = 16;
|
||||||
si->green_size = 8;
|
si->green_size = 8;
|
||||||
si->green_pos = 8;
|
si->green_pos = 8;
|
||||||
si->blue_size = 8;
|
si->blue_size = 8;
|
||||||
si->blue_pos = 0;
|
si->blue_pos = 0;
|
||||||
si->rsvd_size = 8;
|
si->rsvd_size = 8;
|
||||||
si->rsvd_pos = 24;
|
si->rsvd_pos = 24;
|
||||||
|
|
||||||
free_handle:
|
free_handle:
|
||||||
efi_call_early(free_pool, uga_handle);
|
efi_call_early(free_pool, uga_handle);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -586,7 +404,7 @@ struct boot_params *make_boot_params(struct efi_config *c)
|
|||||||
if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
|
if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (efi_early->is64)
|
if (efi_is_64bit())
|
||||||
setup_boot_services64(efi_early);
|
setup_boot_services64(efi_early);
|
||||||
else
|
else
|
||||||
setup_boot_services32(efi_early);
|
setup_boot_services32(efi_early);
|
||||||
@ -601,7 +419,7 @@ struct boot_params *make_boot_params(struct efi_config *c)
|
|||||||
status = efi_low_alloc(sys_table, 0x4000, 1,
|
status = efi_low_alloc(sys_table, 0x4000, 1,
|
||||||
(unsigned long *)&boot_params);
|
(unsigned long *)&boot_params);
|
||||||
if (status != EFI_SUCCESS) {
|
if (status != EFI_SUCCESS) {
|
||||||
efi_printk(sys_table, "Failed to alloc lowmem for boot params\n");
|
efi_printk(sys_table, "Failed to allocate lowmem for boot params\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -617,9 +435,9 @@ struct boot_params *make_boot_params(struct efi_config *c)
|
|||||||
* Fill out some of the header fields ourselves because the
|
* Fill out some of the header fields ourselves because the
|
||||||
* EFI firmware loader doesn't load the first sector.
|
* EFI firmware loader doesn't load the first sector.
|
||||||
*/
|
*/
|
||||||
hdr->root_flags = 1;
|
hdr->root_flags = 1;
|
||||||
hdr->vid_mode = 0xffff;
|
hdr->vid_mode = 0xffff;
|
||||||
hdr->boot_flag = 0xAA55;
|
hdr->boot_flag = 0xAA55;
|
||||||
|
|
||||||
hdr->type_of_loader = 0x21;
|
hdr->type_of_loader = 0x21;
|
||||||
|
|
||||||
@ -627,6 +445,7 @@ struct boot_params *make_boot_params(struct efi_config *c)
|
|||||||
cmdline_ptr = efi_convert_cmdline(sys_table, image, &options_size);
|
cmdline_ptr = efi_convert_cmdline(sys_table, image, &options_size);
|
||||||
if (!cmdline_ptr)
|
if (!cmdline_ptr)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
hdr->cmd_line_ptr = (unsigned long)cmdline_ptr;
|
hdr->cmd_line_ptr = (unsigned long)cmdline_ptr;
|
||||||
/* Fill in upper bits of command line address, NOP on 32 bit */
|
/* Fill in upper bits of command line address, NOP on 32 bit */
|
||||||
boot_params->ext_cmd_line_ptr = (u64)(unsigned long)cmdline_ptr >> 32;
|
boot_params->ext_cmd_line_ptr = (u64)(unsigned long)cmdline_ptr >> 32;
|
||||||
@ -663,10 +482,12 @@ struct boot_params *make_boot_params(struct efi_config *c)
|
|||||||
boot_params->ext_ramdisk_size = (u64)ramdisk_size >> 32;
|
boot_params->ext_ramdisk_size = (u64)ramdisk_size >> 32;
|
||||||
|
|
||||||
return boot_params;
|
return boot_params;
|
||||||
|
|
||||||
fail2:
|
fail2:
|
||||||
efi_free(sys_table, options_size, hdr->cmd_line_ptr);
|
efi_free(sys_table, options_size, hdr->cmd_line_ptr);
|
||||||
fail:
|
fail:
|
||||||
efi_free(sys_table, 0x4000, (unsigned long)boot_params);
|
efi_free(sys_table, 0x4000, (unsigned long)boot_params);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -678,7 +499,7 @@ static void add_e820ext(struct boot_params *params,
|
|||||||
unsigned long size;
|
unsigned long size;
|
||||||
|
|
||||||
e820ext->type = SETUP_E820_EXT;
|
e820ext->type = SETUP_E820_EXT;
|
||||||
e820ext->len = nr_entries * sizeof(struct boot_e820_entry);
|
e820ext->len = nr_entries * sizeof(struct boot_e820_entry);
|
||||||
e820ext->next = 0;
|
e820ext->next = 0;
|
||||||
|
|
||||||
data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
|
data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
|
||||||
@ -692,8 +513,8 @@ static void add_e820ext(struct boot_params *params,
|
|||||||
params->hdr.setup_data = (unsigned long)e820ext;
|
params->hdr.setup_data = (unsigned long)e820ext;
|
||||||
}
|
}
|
||||||
|
|
||||||
static efi_status_t setup_e820(struct boot_params *params,
|
static efi_status_t
|
||||||
struct setup_data *e820ext, u32 e820ext_size)
|
setup_e820(struct boot_params *params, struct setup_data *e820ext, u32 e820ext_size)
|
||||||
{
|
{
|
||||||
struct boot_e820_entry *entry = params->e820_table;
|
struct boot_e820_entry *entry = params->e820_table;
|
||||||
struct efi_info *efi = ¶ms->efi_info;
|
struct efi_info *efi = ¶ms->efi_info;
|
||||||
@ -814,11 +635,10 @@ static efi_status_t alloc_e820ext(u32 nr_desc, struct setup_data **e820ext,
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct exit_boot_struct {
|
struct exit_boot_struct {
|
||||||
struct boot_params *boot_params;
|
struct boot_params *boot_params;
|
||||||
struct efi_info *efi;
|
struct efi_info *efi;
|
||||||
struct setup_data *e820ext;
|
struct setup_data *e820ext;
|
||||||
__u32 e820ext_size;
|
__u32 e820ext_size;
|
||||||
bool is64;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static efi_status_t exit_boot_func(efi_system_table_t *sys_table_arg,
|
static efi_status_t exit_boot_func(efi_system_table_t *sys_table_arg,
|
||||||
@ -845,25 +665,25 @@ static efi_status_t exit_boot_func(efi_system_table_t *sys_table_arg,
|
|||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
signature = p->is64 ? EFI64_LOADER_SIGNATURE : EFI32_LOADER_SIGNATURE;
|
signature = efi_is_64bit() ? EFI64_LOADER_SIGNATURE
|
||||||
|
: EFI32_LOADER_SIGNATURE;
|
||||||
memcpy(&p->efi->efi_loader_signature, signature, sizeof(__u32));
|
memcpy(&p->efi->efi_loader_signature, signature, sizeof(__u32));
|
||||||
|
|
||||||
p->efi->efi_systab = (unsigned long)sys_table_arg;
|
p->efi->efi_systab = (unsigned long)sys_table_arg;
|
||||||
p->efi->efi_memdesc_size = *map->desc_size;
|
p->efi->efi_memdesc_size = *map->desc_size;
|
||||||
p->efi->efi_memdesc_version = *map->desc_ver;
|
p->efi->efi_memdesc_version = *map->desc_ver;
|
||||||
p->efi->efi_memmap = (unsigned long)*map->map;
|
p->efi->efi_memmap = (unsigned long)*map->map;
|
||||||
p->efi->efi_memmap_size = *map->map_size;
|
p->efi->efi_memmap_size = *map->map_size;
|
||||||
|
|
||||||
#ifdef CONFIG_X86_64
|
#ifdef CONFIG_X86_64
|
||||||
p->efi->efi_systab_hi = (unsigned long)sys_table_arg >> 32;
|
p->efi->efi_systab_hi = (unsigned long)sys_table_arg >> 32;
|
||||||
p->efi->efi_memmap_hi = (unsigned long)*map->map >> 32;
|
p->efi->efi_memmap_hi = (unsigned long)*map->map >> 32;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static efi_status_t exit_boot(struct boot_params *boot_params,
|
static efi_status_t exit_boot(struct boot_params *boot_params, void *handle)
|
||||||
void *handle, bool is64)
|
|
||||||
{
|
{
|
||||||
unsigned long map_sz, key, desc_size, buff_size;
|
unsigned long map_sz, key, desc_size, buff_size;
|
||||||
efi_memory_desc_t *mem_map;
|
efi_memory_desc_t *mem_map;
|
||||||
@ -874,17 +694,16 @@ static efi_status_t exit_boot(struct boot_params *boot_params,
|
|||||||
struct efi_boot_memmap map;
|
struct efi_boot_memmap map;
|
||||||
struct exit_boot_struct priv;
|
struct exit_boot_struct priv;
|
||||||
|
|
||||||
map.map = &mem_map;
|
map.map = &mem_map;
|
||||||
map.map_size = &map_sz;
|
map.map_size = &map_sz;
|
||||||
map.desc_size = &desc_size;
|
map.desc_size = &desc_size;
|
||||||
map.desc_ver = &desc_version;
|
map.desc_ver = &desc_version;
|
||||||
map.key_ptr = &key;
|
map.key_ptr = &key;
|
||||||
map.buff_size = &buff_size;
|
map.buff_size = &buff_size;
|
||||||
priv.boot_params = boot_params;
|
priv.boot_params = boot_params;
|
||||||
priv.efi = &boot_params->efi_info;
|
priv.efi = &boot_params->efi_info;
|
||||||
priv.e820ext = NULL;
|
priv.e820ext = NULL;
|
||||||
priv.e820ext_size = 0;
|
priv.e820ext_size = 0;
|
||||||
priv.is64 = is64;
|
|
||||||
|
|
||||||
/* Might as well exit boot services now */
|
/* Might as well exit boot services now */
|
||||||
status = efi_exit_boot_services(sys_table, handle, &map, &priv,
|
status = efi_exit_boot_services(sys_table, handle, &map, &priv,
|
||||||
@ -892,10 +711,11 @@ static efi_status_t exit_boot(struct boot_params *boot_params,
|
|||||||
if (status != EFI_SUCCESS)
|
if (status != EFI_SUCCESS)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
e820ext = priv.e820ext;
|
e820ext = priv.e820ext;
|
||||||
e820ext_size = priv.e820ext_size;
|
e820ext_size = priv.e820ext_size;
|
||||||
|
|
||||||
/* Historic? */
|
/* Historic? */
|
||||||
boot_params->alt_mem_k = 32 * 1024;
|
boot_params->alt_mem_k = 32 * 1024;
|
||||||
|
|
||||||
status = setup_e820(boot_params, e820ext, e820ext_size);
|
status = setup_e820(boot_params, e820ext, e820ext_size);
|
||||||
if (status != EFI_SUCCESS)
|
if (status != EFI_SUCCESS)
|
||||||
@ -908,8 +728,8 @@ static efi_status_t exit_boot(struct boot_params *boot_params,
|
|||||||
* On success we return a pointer to a boot_params structure, and NULL
|
* On success we return a pointer to a boot_params structure, and NULL
|
||||||
* on failure.
|
* on failure.
|
||||||
*/
|
*/
|
||||||
struct boot_params *efi_main(struct efi_config *c,
|
struct boot_params *
|
||||||
struct boot_params *boot_params)
|
efi_main(struct efi_config *c, struct boot_params *boot_params)
|
||||||
{
|
{
|
||||||
struct desc_ptr *gdt = NULL;
|
struct desc_ptr *gdt = NULL;
|
||||||
efi_loaded_image_t *image;
|
efi_loaded_image_t *image;
|
||||||
@ -918,13 +738,11 @@ struct boot_params *efi_main(struct efi_config *c,
|
|||||||
struct desc_struct *desc;
|
struct desc_struct *desc;
|
||||||
void *handle;
|
void *handle;
|
||||||
efi_system_table_t *_table;
|
efi_system_table_t *_table;
|
||||||
bool is64;
|
|
||||||
|
|
||||||
efi_early = c;
|
efi_early = c;
|
||||||
|
|
||||||
_table = (efi_system_table_t *)(unsigned long)efi_early->table;
|
_table = (efi_system_table_t *)(unsigned long)efi_early->table;
|
||||||
handle = (void *)(unsigned long)efi_early->image_handle;
|
handle = (void *)(unsigned long)efi_early->image_handle;
|
||||||
is64 = efi_early->is64;
|
|
||||||
|
|
||||||
sys_table = _table;
|
sys_table = _table;
|
||||||
|
|
||||||
@ -932,7 +750,7 @@ struct boot_params *efi_main(struct efi_config *c,
|
|||||||
if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
|
if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (is64)
|
if (efi_is_64bit())
|
||||||
setup_boot_services64(efi_early);
|
setup_boot_services64(efi_early);
|
||||||
else
|
else
|
||||||
setup_boot_services32(efi_early);
|
setup_boot_services32(efi_early);
|
||||||
@ -957,7 +775,7 @@ struct boot_params *efi_main(struct efi_config *c,
|
|||||||
status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
|
status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
|
||||||
sizeof(*gdt), (void **)&gdt);
|
sizeof(*gdt), (void **)&gdt);
|
||||||
if (status != EFI_SUCCESS) {
|
if (status != EFI_SUCCESS) {
|
||||||
efi_printk(sys_table, "Failed to alloc mem for gdt structure\n");
|
efi_printk(sys_table, "Failed to allocate memory for 'gdt' structure\n");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -965,7 +783,7 @@ struct boot_params *efi_main(struct efi_config *c,
|
|||||||
status = efi_low_alloc(sys_table, gdt->size, 8,
|
status = efi_low_alloc(sys_table, gdt->size, 8,
|
||||||
(unsigned long *)&gdt->address);
|
(unsigned long *)&gdt->address);
|
||||||
if (status != EFI_SUCCESS) {
|
if (status != EFI_SUCCESS) {
|
||||||
efi_printk(sys_table, "Failed to alloc mem for gdt\n");
|
efi_printk(sys_table, "Failed to allocate memory for 'gdt'\n");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -988,7 +806,7 @@ struct boot_params *efi_main(struct efi_config *c,
|
|||||||
hdr->code32_start = bzimage_addr;
|
hdr->code32_start = bzimage_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = exit_boot(boot_params, handle, is64);
|
status = exit_boot(boot_params, handle);
|
||||||
if (status != EFI_SUCCESS) {
|
if (status != EFI_SUCCESS) {
|
||||||
efi_printk(sys_table, "exit_boot() failed!\n");
|
efi_printk(sys_table, "exit_boot() failed!\n");
|
||||||
goto fail;
|
goto fail;
|
||||||
@ -1002,19 +820,20 @@ struct boot_params *efi_main(struct efi_config *c,
|
|||||||
|
|
||||||
if (IS_ENABLED(CONFIG_X86_64)) {
|
if (IS_ENABLED(CONFIG_X86_64)) {
|
||||||
/* __KERNEL32_CS */
|
/* __KERNEL32_CS */
|
||||||
desc->limit0 = 0xffff;
|
desc->limit0 = 0xffff;
|
||||||
desc->base0 = 0x0000;
|
desc->base0 = 0x0000;
|
||||||
desc->base1 = 0x0000;
|
desc->base1 = 0x0000;
|
||||||
desc->type = SEG_TYPE_CODE | SEG_TYPE_EXEC_READ;
|
desc->type = SEG_TYPE_CODE | SEG_TYPE_EXEC_READ;
|
||||||
desc->s = DESC_TYPE_CODE_DATA;
|
desc->s = DESC_TYPE_CODE_DATA;
|
||||||
desc->dpl = 0;
|
desc->dpl = 0;
|
||||||
desc->p = 1;
|
desc->p = 1;
|
||||||
desc->limit1 = 0xf;
|
desc->limit1 = 0xf;
|
||||||
desc->avl = 0;
|
desc->avl = 0;
|
||||||
desc->l = 0;
|
desc->l = 0;
|
||||||
desc->d = SEG_OP_SIZE_32BIT;
|
desc->d = SEG_OP_SIZE_32BIT;
|
||||||
desc->g = SEG_GRANULARITY_4KB;
|
desc->g = SEG_GRANULARITY_4KB;
|
||||||
desc->base2 = 0x00;
|
desc->base2 = 0x00;
|
||||||
|
|
||||||
desc++;
|
desc++;
|
||||||
} else {
|
} else {
|
||||||
/* Second entry is unused on 32-bit */
|
/* Second entry is unused on 32-bit */
|
||||||
@ -1022,15 +841,16 @@ struct boot_params *efi_main(struct efi_config *c,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* __KERNEL_CS */
|
/* __KERNEL_CS */
|
||||||
desc->limit0 = 0xffff;
|
desc->limit0 = 0xffff;
|
||||||
desc->base0 = 0x0000;
|
desc->base0 = 0x0000;
|
||||||
desc->base1 = 0x0000;
|
desc->base1 = 0x0000;
|
||||||
desc->type = SEG_TYPE_CODE | SEG_TYPE_EXEC_READ;
|
desc->type = SEG_TYPE_CODE | SEG_TYPE_EXEC_READ;
|
||||||
desc->s = DESC_TYPE_CODE_DATA;
|
desc->s = DESC_TYPE_CODE_DATA;
|
||||||
desc->dpl = 0;
|
desc->dpl = 0;
|
||||||
desc->p = 1;
|
desc->p = 1;
|
||||||
desc->limit1 = 0xf;
|
desc->limit1 = 0xf;
|
||||||
desc->avl = 0;
|
desc->avl = 0;
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_X86_64)) {
|
if (IS_ENABLED(CONFIG_X86_64)) {
|
||||||
desc->l = 1;
|
desc->l = 1;
|
||||||
desc->d = 0;
|
desc->d = 0;
|
||||||
@ -1038,41 +858,41 @@ struct boot_params *efi_main(struct efi_config *c,
|
|||||||
desc->l = 0;
|
desc->l = 0;
|
||||||
desc->d = SEG_OP_SIZE_32BIT;
|
desc->d = SEG_OP_SIZE_32BIT;
|
||||||
}
|
}
|
||||||
desc->g = SEG_GRANULARITY_4KB;
|
desc->g = SEG_GRANULARITY_4KB;
|
||||||
desc->base2 = 0x00;
|
desc->base2 = 0x00;
|
||||||
desc++;
|
desc++;
|
||||||
|
|
||||||
/* __KERNEL_DS */
|
/* __KERNEL_DS */
|
||||||
desc->limit0 = 0xffff;
|
desc->limit0 = 0xffff;
|
||||||
desc->base0 = 0x0000;
|
desc->base0 = 0x0000;
|
||||||
desc->base1 = 0x0000;
|
desc->base1 = 0x0000;
|
||||||
desc->type = SEG_TYPE_DATA | SEG_TYPE_READ_WRITE;
|
desc->type = SEG_TYPE_DATA | SEG_TYPE_READ_WRITE;
|
||||||
desc->s = DESC_TYPE_CODE_DATA;
|
desc->s = DESC_TYPE_CODE_DATA;
|
||||||
desc->dpl = 0;
|
desc->dpl = 0;
|
||||||
desc->p = 1;
|
desc->p = 1;
|
||||||
desc->limit1 = 0xf;
|
desc->limit1 = 0xf;
|
||||||
desc->avl = 0;
|
desc->avl = 0;
|
||||||
desc->l = 0;
|
desc->l = 0;
|
||||||
desc->d = SEG_OP_SIZE_32BIT;
|
desc->d = SEG_OP_SIZE_32BIT;
|
||||||
desc->g = SEG_GRANULARITY_4KB;
|
desc->g = SEG_GRANULARITY_4KB;
|
||||||
desc->base2 = 0x00;
|
desc->base2 = 0x00;
|
||||||
desc++;
|
desc++;
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_X86_64)) {
|
if (IS_ENABLED(CONFIG_X86_64)) {
|
||||||
/* Task segment value */
|
/* Task segment value */
|
||||||
desc->limit0 = 0x0000;
|
desc->limit0 = 0x0000;
|
||||||
desc->base0 = 0x0000;
|
desc->base0 = 0x0000;
|
||||||
desc->base1 = 0x0000;
|
desc->base1 = 0x0000;
|
||||||
desc->type = SEG_TYPE_TSS;
|
desc->type = SEG_TYPE_TSS;
|
||||||
desc->s = 0;
|
desc->s = 0;
|
||||||
desc->dpl = 0;
|
desc->dpl = 0;
|
||||||
desc->p = 1;
|
desc->p = 1;
|
||||||
desc->limit1 = 0x0;
|
desc->limit1 = 0x0;
|
||||||
desc->avl = 0;
|
desc->avl = 0;
|
||||||
desc->l = 0;
|
desc->l = 0;
|
||||||
desc->d = 0;
|
desc->d = 0;
|
||||||
desc->g = SEG_GRANULARITY_4KB;
|
desc->g = SEG_GRANULARITY_4KB;
|
||||||
desc->base2 = 0x00;
|
desc->base2 = 0x00;
|
||||||
desc++;
|
desc++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1082,5 +902,6 @@ struct boot_params *efi_main(struct efi_config *c,
|
|||||||
return boot_params;
|
return boot_params;
|
||||||
fail:
|
fail:
|
||||||
efi_printk(sys_table, "efi_main() failed!\n");
|
efi_printk(sys_table, "efi_main() failed!\n");
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -12,22 +12,22 @@
|
|||||||
|
|
||||||
#define DESC_TYPE_CODE_DATA (1 << 0)
|
#define DESC_TYPE_CODE_DATA (1 << 0)
|
||||||
|
|
||||||
struct efi_uga_draw_protocol_32 {
|
typedef struct {
|
||||||
u32 get_mode;
|
u32 get_mode;
|
||||||
u32 set_mode;
|
u32 set_mode;
|
||||||
u32 blt;
|
u32 blt;
|
||||||
};
|
} efi_uga_draw_protocol_32_t;
|
||||||
|
|
||||||
struct efi_uga_draw_protocol_64 {
|
typedef struct {
|
||||||
u64 get_mode;
|
u64 get_mode;
|
||||||
u64 set_mode;
|
u64 set_mode;
|
||||||
u64 blt;
|
u64 blt;
|
||||||
};
|
} efi_uga_draw_protocol_64_t;
|
||||||
|
|
||||||
struct efi_uga_draw_protocol {
|
typedef struct {
|
||||||
void *get_mode;
|
void *get_mode;
|
||||||
void *set_mode;
|
void *set_mode;
|
||||||
void *blt;
|
void *blt;
|
||||||
};
|
} efi_uga_draw_protocol_t;
|
||||||
|
|
||||||
#endif /* BOOT_COMPRESSED_EBOOT_H */
|
#endif /* BOOT_COMPRESSED_EBOOT_H */
|
||||||
|
@ -636,6 +636,8 @@ void efi_switch_mm(struct mm_struct *mm)
|
|||||||
#ifdef CONFIG_EFI_MIXED
|
#ifdef CONFIG_EFI_MIXED
|
||||||
extern efi_status_t efi64_thunk(u32, ...);
|
extern efi_status_t efi64_thunk(u32, ...);
|
||||||
|
|
||||||
|
static DEFINE_SPINLOCK(efi_runtime_lock);
|
||||||
|
|
||||||
#define runtime_service32(func) \
|
#define runtime_service32(func) \
|
||||||
({ \
|
({ \
|
||||||
u32 table = (u32)(unsigned long)efi.systab; \
|
u32 table = (u32)(unsigned long)efi.systab; \
|
||||||
@ -657,17 +659,14 @@ extern efi_status_t efi64_thunk(u32, ...);
|
|||||||
#define efi_thunk(f, ...) \
|
#define efi_thunk(f, ...) \
|
||||||
({ \
|
({ \
|
||||||
efi_status_t __s; \
|
efi_status_t __s; \
|
||||||
unsigned long __flags; \
|
|
||||||
u32 __func; \
|
u32 __func; \
|
||||||
\
|
\
|
||||||
local_irq_save(__flags); \
|
|
||||||
arch_efi_call_virt_setup(); \
|
arch_efi_call_virt_setup(); \
|
||||||
\
|
\
|
||||||
__func = runtime_service32(f); \
|
__func = runtime_service32(f); \
|
||||||
__s = efi64_thunk(__func, __VA_ARGS__); \
|
__s = efi64_thunk(__func, __VA_ARGS__); \
|
||||||
\
|
\
|
||||||
arch_efi_call_virt_teardown(); \
|
arch_efi_call_virt_teardown(); \
|
||||||
local_irq_restore(__flags); \
|
|
||||||
\
|
\
|
||||||
__s; \
|
__s; \
|
||||||
})
|
})
|
||||||
@ -702,14 +701,17 @@ static efi_status_t efi_thunk_get_time(efi_time_t *tm, efi_time_cap_t *tc)
|
|||||||
{
|
{
|
||||||
efi_status_t status;
|
efi_status_t status;
|
||||||
u32 phys_tm, phys_tc;
|
u32 phys_tm, phys_tc;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock(&rtc_lock);
|
spin_lock(&rtc_lock);
|
||||||
|
spin_lock_irqsave(&efi_runtime_lock, flags);
|
||||||
|
|
||||||
phys_tm = virt_to_phys_or_null(tm);
|
phys_tm = virt_to_phys_or_null(tm);
|
||||||
phys_tc = virt_to_phys_or_null(tc);
|
phys_tc = virt_to_phys_or_null(tc);
|
||||||
|
|
||||||
status = efi_thunk(get_time, phys_tm, phys_tc);
|
status = efi_thunk(get_time, phys_tm, phys_tc);
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&efi_runtime_lock, flags);
|
||||||
spin_unlock(&rtc_lock);
|
spin_unlock(&rtc_lock);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
@ -719,13 +721,16 @@ static efi_status_t efi_thunk_set_time(efi_time_t *tm)
|
|||||||
{
|
{
|
||||||
efi_status_t status;
|
efi_status_t status;
|
||||||
u32 phys_tm;
|
u32 phys_tm;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock(&rtc_lock);
|
spin_lock(&rtc_lock);
|
||||||
|
spin_lock_irqsave(&efi_runtime_lock, flags);
|
||||||
|
|
||||||
phys_tm = virt_to_phys_or_null(tm);
|
phys_tm = virt_to_phys_or_null(tm);
|
||||||
|
|
||||||
status = efi_thunk(set_time, phys_tm);
|
status = efi_thunk(set_time, phys_tm);
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&efi_runtime_lock, flags);
|
||||||
spin_unlock(&rtc_lock);
|
spin_unlock(&rtc_lock);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
@ -737,8 +742,10 @@ efi_thunk_get_wakeup_time(efi_bool_t *enabled, efi_bool_t *pending,
|
|||||||
{
|
{
|
||||||
efi_status_t status;
|
efi_status_t status;
|
||||||
u32 phys_enabled, phys_pending, phys_tm;
|
u32 phys_enabled, phys_pending, phys_tm;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock(&rtc_lock);
|
spin_lock(&rtc_lock);
|
||||||
|
spin_lock_irqsave(&efi_runtime_lock, flags);
|
||||||
|
|
||||||
phys_enabled = virt_to_phys_or_null(enabled);
|
phys_enabled = virt_to_phys_or_null(enabled);
|
||||||
phys_pending = virt_to_phys_or_null(pending);
|
phys_pending = virt_to_phys_or_null(pending);
|
||||||
@ -747,6 +754,7 @@ efi_thunk_get_wakeup_time(efi_bool_t *enabled, efi_bool_t *pending,
|
|||||||
status = efi_thunk(get_wakeup_time, phys_enabled,
|
status = efi_thunk(get_wakeup_time, phys_enabled,
|
||||||
phys_pending, phys_tm);
|
phys_pending, phys_tm);
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&efi_runtime_lock, flags);
|
||||||
spin_unlock(&rtc_lock);
|
spin_unlock(&rtc_lock);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
@ -757,13 +765,16 @@ efi_thunk_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
|
|||||||
{
|
{
|
||||||
efi_status_t status;
|
efi_status_t status;
|
||||||
u32 phys_tm;
|
u32 phys_tm;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock(&rtc_lock);
|
spin_lock(&rtc_lock);
|
||||||
|
spin_lock_irqsave(&efi_runtime_lock, flags);
|
||||||
|
|
||||||
phys_tm = virt_to_phys_or_null(tm);
|
phys_tm = virt_to_phys_or_null(tm);
|
||||||
|
|
||||||
status = efi_thunk(set_wakeup_time, enabled, phys_tm);
|
status = efi_thunk(set_wakeup_time, enabled, phys_tm);
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&efi_runtime_lock, flags);
|
||||||
spin_unlock(&rtc_lock);
|
spin_unlock(&rtc_lock);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
@ -781,6 +792,9 @@ efi_thunk_get_variable(efi_char16_t *name, efi_guid_t *vendor,
|
|||||||
efi_status_t status;
|
efi_status_t status;
|
||||||
u32 phys_name, phys_vendor, phys_attr;
|
u32 phys_name, phys_vendor, phys_attr;
|
||||||
u32 phys_data_size, phys_data;
|
u32 phys_data_size, phys_data;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&efi_runtime_lock, flags);
|
||||||
|
|
||||||
phys_data_size = virt_to_phys_or_null(data_size);
|
phys_data_size = virt_to_phys_or_null(data_size);
|
||||||
phys_vendor = virt_to_phys_or_null(vendor);
|
phys_vendor = virt_to_phys_or_null(vendor);
|
||||||
@ -791,6 +805,8 @@ efi_thunk_get_variable(efi_char16_t *name, efi_guid_t *vendor,
|
|||||||
status = efi_thunk(get_variable, phys_name, phys_vendor,
|
status = efi_thunk(get_variable, phys_name, phys_vendor,
|
||||||
phys_attr, phys_data_size, phys_data);
|
phys_attr, phys_data_size, phys_data);
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&efi_runtime_lock, flags);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -800,6 +816,9 @@ efi_thunk_set_variable(efi_char16_t *name, efi_guid_t *vendor,
|
|||||||
{
|
{
|
||||||
u32 phys_name, phys_vendor, phys_data;
|
u32 phys_name, phys_vendor, phys_data;
|
||||||
efi_status_t status;
|
efi_status_t status;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&efi_runtime_lock, flags);
|
||||||
|
|
||||||
phys_name = virt_to_phys_or_null_size(name, efi_name_size(name));
|
phys_name = virt_to_phys_or_null_size(name, efi_name_size(name));
|
||||||
phys_vendor = virt_to_phys_or_null(vendor);
|
phys_vendor = virt_to_phys_or_null(vendor);
|
||||||
@ -809,6 +828,33 @@ efi_thunk_set_variable(efi_char16_t *name, efi_guid_t *vendor,
|
|||||||
status = efi_thunk(set_variable, phys_name, phys_vendor,
|
status = efi_thunk(set_variable, phys_name, phys_vendor,
|
||||||
attr, data_size, phys_data);
|
attr, data_size, phys_data);
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&efi_runtime_lock, flags);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static efi_status_t
|
||||||
|
efi_thunk_set_variable_nonblocking(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;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
if (!spin_trylock_irqsave(&efi_runtime_lock, flags))
|
||||||
|
return EFI_NOT_READY;
|
||||||
|
|
||||||
|
phys_name = virt_to_phys_or_null_size(name, efi_name_size(name));
|
||||||
|
phys_vendor = virt_to_phys_or_null(vendor);
|
||||||
|
phys_data = virt_to_phys_or_null_size(data, data_size);
|
||||||
|
|
||||||
|
/* If data_size is > sizeof(u32) we've got problems */
|
||||||
|
status = efi_thunk(set_variable, phys_name, phys_vendor,
|
||||||
|
attr, data_size, phys_data);
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&efi_runtime_lock, flags);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -819,6 +865,9 @@ efi_thunk_get_next_variable(unsigned long *name_size,
|
|||||||
{
|
{
|
||||||
efi_status_t status;
|
efi_status_t status;
|
||||||
u32 phys_name_size, phys_name, phys_vendor;
|
u32 phys_name_size, phys_name, phys_vendor;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&efi_runtime_lock, flags);
|
||||||
|
|
||||||
phys_name_size = virt_to_phys_or_null(name_size);
|
phys_name_size = virt_to_phys_or_null(name_size);
|
||||||
phys_vendor = virt_to_phys_or_null(vendor);
|
phys_vendor = virt_to_phys_or_null(vendor);
|
||||||
@ -827,6 +876,8 @@ efi_thunk_get_next_variable(unsigned long *name_size,
|
|||||||
status = efi_thunk(get_next_variable, phys_name_size,
|
status = efi_thunk(get_next_variable, phys_name_size,
|
||||||
phys_name, phys_vendor);
|
phys_name, phys_vendor);
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&efi_runtime_lock, flags);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -835,10 +886,15 @@ efi_thunk_get_next_high_mono_count(u32 *count)
|
|||||||
{
|
{
|
||||||
efi_status_t status;
|
efi_status_t status;
|
||||||
u32 phys_count;
|
u32 phys_count;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&efi_runtime_lock, flags);
|
||||||
|
|
||||||
phys_count = virt_to_phys_or_null(count);
|
phys_count = virt_to_phys_or_null(count);
|
||||||
status = efi_thunk(get_next_high_mono_count, phys_count);
|
status = efi_thunk(get_next_high_mono_count, phys_count);
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&efi_runtime_lock, flags);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -847,10 +903,15 @@ efi_thunk_reset_system(int reset_type, efi_status_t status,
|
|||||||
unsigned long data_size, efi_char16_t *data)
|
unsigned long data_size, efi_char16_t *data)
|
||||||
{
|
{
|
||||||
u32 phys_data;
|
u32 phys_data;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&efi_runtime_lock, flags);
|
||||||
|
|
||||||
phys_data = virt_to_phys_or_null_size(data, data_size);
|
phys_data = virt_to_phys_or_null_size(data, data_size);
|
||||||
|
|
||||||
efi_thunk(reset_system, reset_type, status, data_size, phys_data);
|
efi_thunk(reset_system, reset_type, status, data_size, phys_data);
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&efi_runtime_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static efi_status_t
|
static efi_status_t
|
||||||
@ -872,10 +933,13 @@ efi_thunk_query_variable_info(u32 attr, u64 *storage_space,
|
|||||||
{
|
{
|
||||||
efi_status_t status;
|
efi_status_t status;
|
||||||
u32 phys_storage, phys_remaining, phys_max;
|
u32 phys_storage, phys_remaining, phys_max;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
|
if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
|
||||||
return EFI_UNSUPPORTED;
|
return EFI_UNSUPPORTED;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&efi_runtime_lock, flags);
|
||||||
|
|
||||||
phys_storage = virt_to_phys_or_null(storage_space);
|
phys_storage = virt_to_phys_or_null(storage_space);
|
||||||
phys_remaining = virt_to_phys_or_null(remaining_space);
|
phys_remaining = virt_to_phys_or_null(remaining_space);
|
||||||
phys_max = virt_to_phys_or_null(max_variable_size);
|
phys_max = virt_to_phys_or_null(max_variable_size);
|
||||||
@ -883,6 +947,35 @@ efi_thunk_query_variable_info(u32 attr, u64 *storage_space,
|
|||||||
status = efi_thunk(query_variable_info, attr, phys_storage,
|
status = efi_thunk(query_variable_info, attr, phys_storage,
|
||||||
phys_remaining, phys_max);
|
phys_remaining, phys_max);
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&efi_runtime_lock, flags);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static efi_status_t
|
||||||
|
efi_thunk_query_variable_info_nonblocking(u32 attr, u64 *storage_space,
|
||||||
|
u64 *remaining_space,
|
||||||
|
u64 *max_variable_size)
|
||||||
|
{
|
||||||
|
efi_status_t status;
|
||||||
|
u32 phys_storage, phys_remaining, phys_max;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
|
||||||
|
return EFI_UNSUPPORTED;
|
||||||
|
|
||||||
|
if (!spin_trylock_irqsave(&efi_runtime_lock, flags))
|
||||||
|
return EFI_NOT_READY;
|
||||||
|
|
||||||
|
phys_storage = virt_to_phys_or_null(storage_space);
|
||||||
|
phys_remaining = virt_to_phys_or_null(remaining_space);
|
||||||
|
phys_max = virt_to_phys_or_null(max_variable_size);
|
||||||
|
|
||||||
|
status = efi_thunk(query_variable_info, attr, phys_storage,
|
||||||
|
phys_remaining, phys_max);
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&efi_runtime_lock, flags);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -908,9 +1001,11 @@ void efi_thunk_runtime_setup(void)
|
|||||||
efi.get_variable = efi_thunk_get_variable;
|
efi.get_variable = efi_thunk_get_variable;
|
||||||
efi.get_next_variable = efi_thunk_get_next_variable;
|
efi.get_next_variable = efi_thunk_get_next_variable;
|
||||||
efi.set_variable = efi_thunk_set_variable;
|
efi.set_variable = efi_thunk_set_variable;
|
||||||
|
efi.set_variable_nonblocking = efi_thunk_set_variable_nonblocking;
|
||||||
efi.get_next_high_mono_count = efi_thunk_get_next_high_mono_count;
|
efi.get_next_high_mono_count = efi_thunk_get_next_high_mono_count;
|
||||||
efi.reset_system = efi_thunk_reset_system;
|
efi.reset_system = efi_thunk_reset_system;
|
||||||
efi.query_variable_info = efi_thunk_query_variable_info;
|
efi.query_variable_info = efi_thunk_query_variable_info;
|
||||||
|
efi.query_variable_info_nonblocking = efi_thunk_query_variable_info_nonblocking;
|
||||||
efi.update_capsule = efi_thunk_update_capsule;
|
efi.update_capsule = efi_thunk_update_capsule;
|
||||||
efi.query_capsule_caps = efi_thunk_query_capsule_caps;
|
efi.query_capsule_caps = efi_thunk_query_capsule_caps;
|
||||||
}
|
}
|
||||||
|
@ -105,12 +105,11 @@ early_param("efi_no_storage_paranoia", setup_storage_paranoia);
|
|||||||
*/
|
*/
|
||||||
void efi_delete_dummy_variable(void)
|
void efi_delete_dummy_variable(void)
|
||||||
{
|
{
|
||||||
efi.set_variable((efi_char16_t *)efi_dummy_name,
|
efi.set_variable_nonblocking((efi_char16_t *)efi_dummy_name,
|
||||||
&EFI_DUMMY_GUID,
|
&EFI_DUMMY_GUID,
|
||||||
EFI_VARIABLE_NON_VOLATILE |
|
EFI_VARIABLE_NON_VOLATILE |
|
||||||
EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
||||||
EFI_VARIABLE_RUNTIME_ACCESS,
|
EFI_VARIABLE_RUNTIME_ACCESS, 0, NULL);
|
||||||
0, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -249,7 +248,8 @@ void __init efi_arch_mem_reserve(phys_addr_t addr, u64 size)
|
|||||||
int num_entries;
|
int num_entries;
|
||||||
void *new;
|
void *new;
|
||||||
|
|
||||||
if (efi_mem_desc_lookup(addr, &md)) {
|
if (efi_mem_desc_lookup(addr, &md) ||
|
||||||
|
md.type != EFI_BOOT_SERVICES_DATA) {
|
||||||
pr_err("Failed to lookup EFI memory descriptor for %pa\n", &addr);
|
pr_err("Failed to lookup EFI memory descriptor for %pa\n", &addr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -87,6 +87,18 @@ config EFI_RUNTIME_WRAPPERS
|
|||||||
config EFI_ARMSTUB
|
config EFI_ARMSTUB
|
||||||
bool
|
bool
|
||||||
|
|
||||||
|
config EFI_ARMSTUB_DTB_LOADER
|
||||||
|
bool "Enable the DTB loader"
|
||||||
|
depends on EFI_ARMSTUB
|
||||||
|
help
|
||||||
|
Select this config option to add support for the dtb= command
|
||||||
|
line parameter, allowing a device tree blob to be loaded into
|
||||||
|
memory from the EFI System Partition by the stub.
|
||||||
|
|
||||||
|
The device tree is typically provided by the platform or by
|
||||||
|
the bootloader, so this option is mostly for development
|
||||||
|
purposes only.
|
||||||
|
|
||||||
config EFI_BOOTLOADER_CONTROL
|
config EFI_BOOTLOADER_CONTROL
|
||||||
tristate "EFI Bootloader Control"
|
tristate "EFI Bootloader Control"
|
||||||
depends on EFI_VARS
|
depends on EFI_VARS
|
||||||
|
@ -48,8 +48,21 @@ u64 cper_next_record_id(void)
|
|||||||
{
|
{
|
||||||
static atomic64_t seq;
|
static atomic64_t seq;
|
||||||
|
|
||||||
if (!atomic64_read(&seq))
|
if (!atomic64_read(&seq)) {
|
||||||
atomic64_set(&seq, ((u64)get_seconds()) << 32);
|
time64_t time = ktime_get_real_seconds();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code is unlikely to still be needed in year 2106,
|
||||||
|
* but just in case, let's use a few more bits for timestamps
|
||||||
|
* after y2038 to be sure they keep increasing monotonically
|
||||||
|
* for the next few hundred years...
|
||||||
|
*/
|
||||||
|
if (time < 0x80000000)
|
||||||
|
atomic64_set(&seq, (ktime_get_real_seconds()) << 32);
|
||||||
|
else
|
||||||
|
atomic64_set(&seq, 0x8000000000000000ull |
|
||||||
|
ktime_get_real_seconds() << 24);
|
||||||
|
}
|
||||||
|
|
||||||
return atomic64_inc_return(&seq);
|
return atomic64_inc_return(&seq);
|
||||||
}
|
}
|
||||||
@ -459,7 +472,7 @@ cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata
|
|||||||
else
|
else
|
||||||
goto err_section_too_small;
|
goto err_section_too_small;
|
||||||
#if defined(CONFIG_ARM64) || defined(CONFIG_ARM)
|
#if defined(CONFIG_ARM64) || defined(CONFIG_ARM)
|
||||||
} else if (!uuid_le_cmp(*sec_type, CPER_SEC_PROC_ARM)) {
|
} else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) {
|
||||||
struct cper_sec_proc_arm *arm_err = acpi_hest_get_payload(gdata);
|
struct cper_sec_proc_arm *arm_err = acpi_hest_get_payload(gdata);
|
||||||
|
|
||||||
printk("%ssection_type: ARM processor error\n", newpfx);
|
printk("%ssection_type: ARM processor error\n", newpfx);
|
||||||
|
@ -84,6 +84,8 @@ struct mm_struct efi_mm = {
|
|||||||
.mmlist = LIST_HEAD_INIT(efi_mm.mmlist),
|
.mmlist = LIST_HEAD_INIT(efi_mm.mmlist),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct workqueue_struct *efi_rts_wq;
|
||||||
|
|
||||||
static bool disable_runtime;
|
static bool disable_runtime;
|
||||||
static int __init setup_noefi(char *arg)
|
static int __init setup_noefi(char *arg)
|
||||||
{
|
{
|
||||||
@ -337,6 +339,18 @@ static int __init efisubsys_init(void)
|
|||||||
if (!efi_enabled(EFI_BOOT))
|
if (!efi_enabled(EFI_BOOT))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Since we process only one efi_runtime_service() at a time, an
|
||||||
|
* ordered workqueue (which creates only one execution context)
|
||||||
|
* should suffice all our needs.
|
||||||
|
*/
|
||||||
|
efi_rts_wq = alloc_ordered_workqueue("efi_rts_wq", 0);
|
||||||
|
if (!efi_rts_wq) {
|
||||||
|
pr_err("Creating efi_rts_wq failed, EFI runtime services disabled.\n");
|
||||||
|
clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* We register the efi directory at /sys/firmware/efi */
|
/* We register the efi directory at /sys/firmware/efi */
|
||||||
efi_kobj = kobject_create_and_add("efi", firmware_kobj);
|
efi_kobj = kobject_create_and_add("efi", firmware_kobj);
|
||||||
if (!efi_kobj) {
|
if (!efi_kobj) {
|
||||||
@ -388,7 +402,7 @@ subsys_initcall(efisubsys_init);
|
|||||||
* and if so, populate the supplied memory descriptor with the appropriate
|
* and if so, populate the supplied memory descriptor with the appropriate
|
||||||
* data.
|
* data.
|
||||||
*/
|
*/
|
||||||
int __init efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md)
|
int efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md)
|
||||||
{
|
{
|
||||||
efi_memory_desc_t *md;
|
efi_memory_desc_t *md;
|
||||||
|
|
||||||
@ -406,12 +420,6 @@ int __init efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md)
|
|||||||
u64 size;
|
u64 size;
|
||||||
u64 end;
|
u64 end;
|
||||||
|
|
||||||
if (!(md->attribute & EFI_MEMORY_RUNTIME) &&
|
|
||||||
md->type != EFI_BOOT_SERVICES_DATA &&
|
|
||||||
md->type != EFI_RUNTIME_SERVICES_DATA) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
size = md->num_pages << EFI_PAGE_SHIFT;
|
size = md->num_pages << EFI_PAGE_SHIFT;
|
||||||
end = md->phys_addr + size;
|
end = md->phys_addr + size;
|
||||||
if (phys_addr >= md->phys_addr && phys_addr < end) {
|
if (phys_addr >= md->phys_addr && phys_addr < end) {
|
||||||
|
@ -250,7 +250,10 @@ void __init efi_esrt_init(void)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
rc = efi_mem_desc_lookup(efi.esrt, &md);
|
rc = efi_mem_desc_lookup(efi.esrt, &md);
|
||||||
if (rc < 0) {
|
if (rc < 0 ||
|
||||||
|
(!(md.attribute & EFI_MEMORY_RUNTIME) &&
|
||||||
|
md.type != EFI_BOOT_SERVICES_DATA &&
|
||||||
|
md.type != EFI_RUNTIME_SERVICES_DATA)) {
|
||||||
pr_warn("ESRT header is not in the memory map.\n");
|
pr_warn("ESRT header is not in the memory map.\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -326,7 +329,8 @@ void __init efi_esrt_init(void)
|
|||||||
|
|
||||||
end = esrt_data + size;
|
end = esrt_data + size;
|
||||||
pr_info("Reserving ESRT space from %pa to %pa.\n", &esrt_data, &end);
|
pr_info("Reserving ESRT space from %pa to %pa.\n", &esrt_data, &end);
|
||||||
efi_mem_reserve(esrt_data, esrt_data_size);
|
if (md.type == EFI_BOOT_SERVICES_DATA)
|
||||||
|
efi_mem_reserve(esrt_data, esrt_data_size);
|
||||||
|
|
||||||
pr_debug("esrt-init: loaded.\n");
|
pr_debug("esrt-init: loaded.\n");
|
||||||
}
|
}
|
||||||
|
@ -40,31 +40,6 @@
|
|||||||
|
|
||||||
static u64 virtmap_base = EFI_RT_VIRTUAL_BASE;
|
static u64 virtmap_base = EFI_RT_VIRTUAL_BASE;
|
||||||
|
|
||||||
efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg,
|
|
||||||
void *__image, void **__fh)
|
|
||||||
{
|
|
||||||
efi_file_io_interface_t *io;
|
|
||||||
efi_loaded_image_t *image = __image;
|
|
||||||
efi_file_handle_t *fh;
|
|
||||||
efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
|
|
||||||
efi_status_t status;
|
|
||||||
void *handle = (void *)(unsigned long)image->device_handle;
|
|
||||||
|
|
||||||
status = sys_table_arg->boottime->handle_protocol(handle,
|
|
||||||
&fs_proto, (void **)&io);
|
|
||||||
if (status != EFI_SUCCESS) {
|
|
||||||
efi_printk(sys_table_arg, "Failed to handle fs_proto\n");
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = io->open_volume(io, &fh);
|
|
||||||
if (status != EFI_SUCCESS)
|
|
||||||
efi_printk(sys_table_arg, "Failed to open volume\n");
|
|
||||||
|
|
||||||
*__fh = fh;
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
void efi_char16_printk(efi_system_table_t *sys_table_arg,
|
void efi_char16_printk(efi_system_table_t *sys_table_arg,
|
||||||
efi_char16_t *str)
|
efi_char16_t *str)
|
||||||
{
|
{
|
||||||
@ -202,9 +177,10 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table,
|
|||||||
* 'dtb=' unless UEFI Secure Boot is disabled. We assume that secure
|
* 'dtb=' unless UEFI Secure Boot is disabled. We assume that secure
|
||||||
* boot is enabled if we can't determine its state.
|
* boot is enabled if we can't determine its state.
|
||||||
*/
|
*/
|
||||||
if (secure_boot != efi_secureboot_mode_disabled &&
|
if (!IS_ENABLED(CONFIG_EFI_ARMSTUB_DTB_LOADER) ||
|
||||||
strstr(cmdline_ptr, "dtb=")) {
|
secure_boot != efi_secureboot_mode_disabled) {
|
||||||
pr_efi(sys_table, "Ignoring DTB from command line.\n");
|
if (strstr(cmdline_ptr, "dtb="))
|
||||||
|
pr_efi(sys_table, "Ignoring DTB from command line.\n");
|
||||||
} else {
|
} else {
|
||||||
status = handle_cmdline_files(sys_table, image, cmdline_ptr,
|
status = handle_cmdline_files(sys_table, image, cmdline_ptr,
|
||||||
"dtb=",
|
"dtb=",
|
||||||
|
@ -413,6 +413,34 @@ static efi_status_t efi_file_close(void *handle)
|
|||||||
return efi_call_proto(efi_file_handle, close, handle);
|
return efi_call_proto(efi_file_handle, close, handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg,
|
||||||
|
efi_loaded_image_t *image,
|
||||||
|
efi_file_handle_t **__fh)
|
||||||
|
{
|
||||||
|
efi_file_io_interface_t *io;
|
||||||
|
efi_file_handle_t *fh;
|
||||||
|
efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
|
||||||
|
efi_status_t status;
|
||||||
|
void *handle = (void *)(unsigned long)efi_table_attr(efi_loaded_image,
|
||||||
|
device_handle,
|
||||||
|
image);
|
||||||
|
|
||||||
|
status = efi_call_early(handle_protocol, handle,
|
||||||
|
&fs_proto, (void **)&io);
|
||||||
|
if (status != EFI_SUCCESS) {
|
||||||
|
efi_printk(sys_table_arg, "Failed to handle fs_proto\n");
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = efi_call_proto(efi_file_io_interface, open_volume, io, &fh);
|
||||||
|
if (status != EFI_SUCCESS)
|
||||||
|
efi_printk(sys_table_arg, "Failed to open volume\n");
|
||||||
|
else
|
||||||
|
*__fh = fh;
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse the ASCII string 'cmdline' for EFI options, denoted by the efi=
|
* Parse the ASCII string 'cmdline' for EFI options, denoted by the efi=
|
||||||
* option, e.g. efi=nochunk.
|
* option, e.g. efi=nochunk.
|
||||||
@ -563,8 +591,7 @@ efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
|
|||||||
|
|
||||||
/* Only open the volume once. */
|
/* Only open the volume once. */
|
||||||
if (!i) {
|
if (!i) {
|
||||||
status = efi_open_volume(sys_table_arg, image,
|
status = efi_open_volume(sys_table_arg, image, &fh);
|
||||||
(void **)&fh);
|
|
||||||
if (status != EFI_SUCCESS)
|
if (status != EFI_SUCCESS)
|
||||||
goto free_files;
|
goto free_files;
|
||||||
}
|
}
|
||||||
|
@ -36,9 +36,6 @@ extern int __pure is_quiet(void);
|
|||||||
|
|
||||||
void efi_char16_printk(efi_system_table_t *, efi_char16_t *);
|
void efi_char16_printk(efi_system_table_t *, efi_char16_t *);
|
||||||
|
|
||||||
efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg, void *__image,
|
|
||||||
void **__fh);
|
|
||||||
|
|
||||||
unsigned long get_dram_base(efi_system_table_t *sys_table_arg);
|
unsigned long get_dram_base(efi_system_table_t *sys_table_arg);
|
||||||
|
|
||||||
efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
|
efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
|
||||||
|
@ -1,6 +1,15 @@
|
|||||||
/*
|
/*
|
||||||
* runtime-wrappers.c - Runtime Services function call wrappers
|
* runtime-wrappers.c - Runtime Services function call wrappers
|
||||||
*
|
*
|
||||||
|
* Implementation summary:
|
||||||
|
* -----------------------
|
||||||
|
* 1. When user/kernel thread requests to execute efi_runtime_service(),
|
||||||
|
* enqueue work to efi_rts_wq.
|
||||||
|
* 2. Caller thread waits for completion until the work is finished
|
||||||
|
* because it's dependent on the return status and execution of
|
||||||
|
* efi_runtime_service().
|
||||||
|
* For instance, get_variable() and get_next_variable().
|
||||||
|
*
|
||||||
* Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org>
|
* Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org>
|
||||||
*
|
*
|
||||||
* Split off from arch/x86/platform/efi/efi.c
|
* Split off from arch/x86/platform/efi/efi.c
|
||||||
@ -22,6 +31,9 @@
|
|||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
#include <linux/semaphore.h>
|
#include <linux/semaphore.h>
|
||||||
#include <linux/stringify.h>
|
#include <linux/stringify.h>
|
||||||
|
#include <linux/workqueue.h>
|
||||||
|
#include <linux/completion.h>
|
||||||
|
|
||||||
#include <asm/efi.h>
|
#include <asm/efi.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -33,6 +45,76 @@
|
|||||||
#define __efi_call_virt(f, args...) \
|
#define __efi_call_virt(f, args...) \
|
||||||
__efi_call_virt_pointer(efi.systab->runtime, f, args)
|
__efi_call_virt_pointer(efi.systab->runtime, f, args)
|
||||||
|
|
||||||
|
/* efi_runtime_service() function identifiers */
|
||||||
|
enum efi_rts_ids {
|
||||||
|
GET_TIME,
|
||||||
|
SET_TIME,
|
||||||
|
GET_WAKEUP_TIME,
|
||||||
|
SET_WAKEUP_TIME,
|
||||||
|
GET_VARIABLE,
|
||||||
|
GET_NEXT_VARIABLE,
|
||||||
|
SET_VARIABLE,
|
||||||
|
QUERY_VARIABLE_INFO,
|
||||||
|
GET_NEXT_HIGH_MONO_COUNT,
|
||||||
|
UPDATE_CAPSULE,
|
||||||
|
QUERY_CAPSULE_CAPS,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* efi_runtime_work: Details of EFI Runtime Service work
|
||||||
|
* @arg<1-5>: EFI Runtime Service function arguments
|
||||||
|
* @status: Status of executing EFI Runtime Service
|
||||||
|
* @efi_rts_id: EFI Runtime Service function identifier
|
||||||
|
* @efi_rts_comp: Struct used for handling completions
|
||||||
|
*/
|
||||||
|
struct efi_runtime_work {
|
||||||
|
void *arg1;
|
||||||
|
void *arg2;
|
||||||
|
void *arg3;
|
||||||
|
void *arg4;
|
||||||
|
void *arg5;
|
||||||
|
efi_status_t status;
|
||||||
|
struct work_struct work;
|
||||||
|
enum efi_rts_ids efi_rts_id;
|
||||||
|
struct completion efi_rts_comp;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* efi_queue_work: Queue efi_runtime_service() and wait until it's done
|
||||||
|
* @rts: efi_runtime_service() function identifier
|
||||||
|
* @rts_arg<1-5>: efi_runtime_service() function arguments
|
||||||
|
*
|
||||||
|
* Accesses to efi_runtime_services() are serialized by a binary
|
||||||
|
* semaphore (efi_runtime_lock) and caller waits until the work is
|
||||||
|
* finished, hence _only_ one work is queued at a time and the caller
|
||||||
|
* thread waits for completion.
|
||||||
|
*/
|
||||||
|
#define efi_queue_work(_rts, _arg1, _arg2, _arg3, _arg4, _arg5) \
|
||||||
|
({ \
|
||||||
|
struct efi_runtime_work efi_rts_work; \
|
||||||
|
efi_rts_work.status = EFI_ABORTED; \
|
||||||
|
\
|
||||||
|
init_completion(&efi_rts_work.efi_rts_comp); \
|
||||||
|
INIT_WORK_ONSTACK(&efi_rts_work.work, efi_call_rts); \
|
||||||
|
efi_rts_work.arg1 = _arg1; \
|
||||||
|
efi_rts_work.arg2 = _arg2; \
|
||||||
|
efi_rts_work.arg3 = _arg3; \
|
||||||
|
efi_rts_work.arg4 = _arg4; \
|
||||||
|
efi_rts_work.arg5 = _arg5; \
|
||||||
|
efi_rts_work.efi_rts_id = _rts; \
|
||||||
|
\
|
||||||
|
/* \
|
||||||
|
* queue_work() returns 0 if work was already on queue, \
|
||||||
|
* _ideally_ this should never happen. \
|
||||||
|
*/ \
|
||||||
|
if (queue_work(efi_rts_wq, &efi_rts_work.work)) \
|
||||||
|
wait_for_completion(&efi_rts_work.efi_rts_comp); \
|
||||||
|
else \
|
||||||
|
pr_err("Failed to queue work to efi_rts_wq.\n"); \
|
||||||
|
\
|
||||||
|
efi_rts_work.status; \
|
||||||
|
})
|
||||||
|
|
||||||
void efi_call_virt_check_flags(unsigned long flags, const char *call)
|
void efi_call_virt_check_flags(unsigned long flags, const char *call)
|
||||||
{
|
{
|
||||||
unsigned long cur_flags, mismatch;
|
unsigned long cur_flags, mismatch;
|
||||||
@ -90,13 +172,98 @@ void efi_call_virt_check_flags(unsigned long flags, const char *call)
|
|||||||
*/
|
*/
|
||||||
static DEFINE_SEMAPHORE(efi_runtime_lock);
|
static DEFINE_SEMAPHORE(efi_runtime_lock);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calls the appropriate efi_runtime_service() with the appropriate
|
||||||
|
* arguments.
|
||||||
|
*
|
||||||
|
* Semantics followed by efi_call_rts() to understand efi_runtime_work:
|
||||||
|
* 1. If argument was a pointer, recast it from void pointer to original
|
||||||
|
* pointer type.
|
||||||
|
* 2. If argument was a value, recast it from void pointer to original
|
||||||
|
* pointer type and dereference it.
|
||||||
|
*/
|
||||||
|
static void efi_call_rts(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct efi_runtime_work *efi_rts_work;
|
||||||
|
void *arg1, *arg2, *arg3, *arg4, *arg5;
|
||||||
|
efi_status_t status = EFI_NOT_FOUND;
|
||||||
|
|
||||||
|
efi_rts_work = container_of(work, struct efi_runtime_work, work);
|
||||||
|
arg1 = efi_rts_work->arg1;
|
||||||
|
arg2 = efi_rts_work->arg2;
|
||||||
|
arg3 = efi_rts_work->arg3;
|
||||||
|
arg4 = efi_rts_work->arg4;
|
||||||
|
arg5 = efi_rts_work->arg5;
|
||||||
|
|
||||||
|
switch (efi_rts_work->efi_rts_id) {
|
||||||
|
case GET_TIME:
|
||||||
|
status = efi_call_virt(get_time, (efi_time_t *)arg1,
|
||||||
|
(efi_time_cap_t *)arg2);
|
||||||
|
break;
|
||||||
|
case SET_TIME:
|
||||||
|
status = efi_call_virt(set_time, (efi_time_t *)arg1);
|
||||||
|
break;
|
||||||
|
case GET_WAKEUP_TIME:
|
||||||
|
status = efi_call_virt(get_wakeup_time, (efi_bool_t *)arg1,
|
||||||
|
(efi_bool_t *)arg2, (efi_time_t *)arg3);
|
||||||
|
break;
|
||||||
|
case SET_WAKEUP_TIME:
|
||||||
|
status = efi_call_virt(set_wakeup_time, *(efi_bool_t *)arg1,
|
||||||
|
(efi_time_t *)arg2);
|
||||||
|
break;
|
||||||
|
case GET_VARIABLE:
|
||||||
|
status = efi_call_virt(get_variable, (efi_char16_t *)arg1,
|
||||||
|
(efi_guid_t *)arg2, (u32 *)arg3,
|
||||||
|
(unsigned long *)arg4, (void *)arg5);
|
||||||
|
break;
|
||||||
|
case GET_NEXT_VARIABLE:
|
||||||
|
status = efi_call_virt(get_next_variable, (unsigned long *)arg1,
|
||||||
|
(efi_char16_t *)arg2,
|
||||||
|
(efi_guid_t *)arg3);
|
||||||
|
break;
|
||||||
|
case SET_VARIABLE:
|
||||||
|
status = efi_call_virt(set_variable, (efi_char16_t *)arg1,
|
||||||
|
(efi_guid_t *)arg2, *(u32 *)arg3,
|
||||||
|
*(unsigned long *)arg4, (void *)arg5);
|
||||||
|
break;
|
||||||
|
case QUERY_VARIABLE_INFO:
|
||||||
|
status = efi_call_virt(query_variable_info, *(u32 *)arg1,
|
||||||
|
(u64 *)arg2, (u64 *)arg3, (u64 *)arg4);
|
||||||
|
break;
|
||||||
|
case GET_NEXT_HIGH_MONO_COUNT:
|
||||||
|
status = efi_call_virt(get_next_high_mono_count, (u32 *)arg1);
|
||||||
|
break;
|
||||||
|
case UPDATE_CAPSULE:
|
||||||
|
status = efi_call_virt(update_capsule,
|
||||||
|
(efi_capsule_header_t **)arg1,
|
||||||
|
*(unsigned long *)arg2,
|
||||||
|
*(unsigned long *)arg3);
|
||||||
|
break;
|
||||||
|
case QUERY_CAPSULE_CAPS:
|
||||||
|
status = efi_call_virt(query_capsule_caps,
|
||||||
|
(efi_capsule_header_t **)arg1,
|
||||||
|
*(unsigned long *)arg2, (u64 *)arg3,
|
||||||
|
(int *)arg4);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/*
|
||||||
|
* Ideally, we should never reach here because a caller of this
|
||||||
|
* function should have put the right efi_runtime_service()
|
||||||
|
* function identifier into efi_rts_work->efi_rts_id
|
||||||
|
*/
|
||||||
|
pr_err("Requested executing invalid EFI Runtime Service.\n");
|
||||||
|
}
|
||||||
|
efi_rts_work->status = status;
|
||||||
|
complete(&efi_rts_work->efi_rts_comp);
|
||||||
|
}
|
||||||
|
|
||||||
static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
|
static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
|
||||||
{
|
{
|
||||||
efi_status_t status;
|
efi_status_t status;
|
||||||
|
|
||||||
if (down_interruptible(&efi_runtime_lock))
|
if (down_interruptible(&efi_runtime_lock))
|
||||||
return EFI_ABORTED;
|
return EFI_ABORTED;
|
||||||
status = efi_call_virt(get_time, tm, tc);
|
status = efi_queue_work(GET_TIME, tm, tc, NULL, NULL, NULL);
|
||||||
up(&efi_runtime_lock);
|
up(&efi_runtime_lock);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@ -107,7 +274,7 @@ static efi_status_t virt_efi_set_time(efi_time_t *tm)
|
|||||||
|
|
||||||
if (down_interruptible(&efi_runtime_lock))
|
if (down_interruptible(&efi_runtime_lock))
|
||||||
return EFI_ABORTED;
|
return EFI_ABORTED;
|
||||||
status = efi_call_virt(set_time, tm);
|
status = efi_queue_work(SET_TIME, tm, NULL, NULL, NULL, NULL);
|
||||||
up(&efi_runtime_lock);
|
up(&efi_runtime_lock);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@ -120,7 +287,8 @@ static efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled,
|
|||||||
|
|
||||||
if (down_interruptible(&efi_runtime_lock))
|
if (down_interruptible(&efi_runtime_lock))
|
||||||
return EFI_ABORTED;
|
return EFI_ABORTED;
|
||||||
status = efi_call_virt(get_wakeup_time, enabled, pending, tm);
|
status = efi_queue_work(GET_WAKEUP_TIME, enabled, pending, tm, NULL,
|
||||||
|
NULL);
|
||||||
up(&efi_runtime_lock);
|
up(&efi_runtime_lock);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@ -131,7 +299,8 @@ static efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
|
|||||||
|
|
||||||
if (down_interruptible(&efi_runtime_lock))
|
if (down_interruptible(&efi_runtime_lock))
|
||||||
return EFI_ABORTED;
|
return EFI_ABORTED;
|
||||||
status = efi_call_virt(set_wakeup_time, enabled, tm);
|
status = efi_queue_work(SET_WAKEUP_TIME, &enabled, tm, NULL, NULL,
|
||||||
|
NULL);
|
||||||
up(&efi_runtime_lock);
|
up(&efi_runtime_lock);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@ -146,8 +315,8 @@ static efi_status_t virt_efi_get_variable(efi_char16_t *name,
|
|||||||
|
|
||||||
if (down_interruptible(&efi_runtime_lock))
|
if (down_interruptible(&efi_runtime_lock))
|
||||||
return EFI_ABORTED;
|
return EFI_ABORTED;
|
||||||
status = efi_call_virt(get_variable, name, vendor, attr, data_size,
|
status = efi_queue_work(GET_VARIABLE, name, vendor, attr, data_size,
|
||||||
data);
|
data);
|
||||||
up(&efi_runtime_lock);
|
up(&efi_runtime_lock);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@ -160,7 +329,8 @@ static efi_status_t virt_efi_get_next_variable(unsigned long *name_size,
|
|||||||
|
|
||||||
if (down_interruptible(&efi_runtime_lock))
|
if (down_interruptible(&efi_runtime_lock))
|
||||||
return EFI_ABORTED;
|
return EFI_ABORTED;
|
||||||
status = efi_call_virt(get_next_variable, name_size, name, vendor);
|
status = efi_queue_work(GET_NEXT_VARIABLE, name_size, name, vendor,
|
||||||
|
NULL, NULL);
|
||||||
up(&efi_runtime_lock);
|
up(&efi_runtime_lock);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@ -175,8 +345,8 @@ static efi_status_t virt_efi_set_variable(efi_char16_t *name,
|
|||||||
|
|
||||||
if (down_interruptible(&efi_runtime_lock))
|
if (down_interruptible(&efi_runtime_lock))
|
||||||
return EFI_ABORTED;
|
return EFI_ABORTED;
|
||||||
status = efi_call_virt(set_variable, name, vendor, attr, data_size,
|
status = efi_queue_work(SET_VARIABLE, name, vendor, &attr, &data_size,
|
||||||
data);
|
data);
|
||||||
up(&efi_runtime_lock);
|
up(&efi_runtime_lock);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@ -210,8 +380,8 @@ static efi_status_t virt_efi_query_variable_info(u32 attr,
|
|||||||
|
|
||||||
if (down_interruptible(&efi_runtime_lock))
|
if (down_interruptible(&efi_runtime_lock))
|
||||||
return EFI_ABORTED;
|
return EFI_ABORTED;
|
||||||
status = efi_call_virt(query_variable_info, attr, storage_space,
|
status = efi_queue_work(QUERY_VARIABLE_INFO, &attr, storage_space,
|
||||||
remaining_space, max_variable_size);
|
remaining_space, max_variable_size, NULL);
|
||||||
up(&efi_runtime_lock);
|
up(&efi_runtime_lock);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@ -242,7 +412,8 @@ static efi_status_t virt_efi_get_next_high_mono_count(u32 *count)
|
|||||||
|
|
||||||
if (down_interruptible(&efi_runtime_lock))
|
if (down_interruptible(&efi_runtime_lock))
|
||||||
return EFI_ABORTED;
|
return EFI_ABORTED;
|
||||||
status = efi_call_virt(get_next_high_mono_count, count);
|
status = efi_queue_work(GET_NEXT_HIGH_MONO_COUNT, count, NULL, NULL,
|
||||||
|
NULL, NULL);
|
||||||
up(&efi_runtime_lock);
|
up(&efi_runtime_lock);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@ -272,7 +443,8 @@ static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules,
|
|||||||
|
|
||||||
if (down_interruptible(&efi_runtime_lock))
|
if (down_interruptible(&efi_runtime_lock))
|
||||||
return EFI_ABORTED;
|
return EFI_ABORTED;
|
||||||
status = efi_call_virt(update_capsule, capsules, count, sg_list);
|
status = efi_queue_work(UPDATE_CAPSULE, capsules, &count, &sg_list,
|
||||||
|
NULL, NULL);
|
||||||
up(&efi_runtime_lock);
|
up(&efi_runtime_lock);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@ -289,8 +461,8 @@ static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules,
|
|||||||
|
|
||||||
if (down_interruptible(&efi_runtime_lock))
|
if (down_interruptible(&efi_runtime_lock))
|
||||||
return EFI_ABORTED;
|
return EFI_ABORTED;
|
||||||
status = efi_call_virt(query_capsule_caps, capsules, count, max_size,
|
status = efi_queue_work(QUERY_CAPSULE_CAPS, capsules, &count,
|
||||||
reset_type);
|
max_size, reset_type, NULL);
|
||||||
up(&efi_runtime_lock);
|
up(&efi_runtime_lock);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
#include <drm/drm_connector.h> /* For DRM_MODE_PANEL_ORIENTATION_* */
|
#include <drm/drm_connector.h> /* For DRM_MODE_PANEL_ORIENTATION_* */
|
||||||
|
|
||||||
static bool request_mem_succeeded = false;
|
static bool request_mem_succeeded = false;
|
||||||
static bool nowc = false;
|
static u64 mem_flags = EFI_MEMORY_WC | EFI_MEMORY_UC;
|
||||||
|
|
||||||
static struct fb_var_screeninfo efifb_defined = {
|
static struct fb_var_screeninfo efifb_defined = {
|
||||||
.activate = FB_ACTIVATE_NOW,
|
.activate = FB_ACTIVATE_NOW,
|
||||||
@ -68,8 +68,12 @@ static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green,
|
|||||||
|
|
||||||
static void efifb_destroy(struct fb_info *info)
|
static void efifb_destroy(struct fb_info *info)
|
||||||
{
|
{
|
||||||
if (info->screen_base)
|
if (info->screen_base) {
|
||||||
iounmap(info->screen_base);
|
if (mem_flags & (EFI_MEMORY_UC | EFI_MEMORY_WC))
|
||||||
|
iounmap(info->screen_base);
|
||||||
|
else
|
||||||
|
memunmap(info->screen_base);
|
||||||
|
}
|
||||||
if (request_mem_succeeded)
|
if (request_mem_succeeded)
|
||||||
release_mem_region(info->apertures->ranges[0].base,
|
release_mem_region(info->apertures->ranges[0].base,
|
||||||
info->apertures->ranges[0].size);
|
info->apertures->ranges[0].size);
|
||||||
@ -104,7 +108,7 @@ static int efifb_setup(char *options)
|
|||||||
else if (!strncmp(this_opt, "width:", 6))
|
else if (!strncmp(this_opt, "width:", 6))
|
||||||
screen_info.lfb_width = simple_strtoul(this_opt+6, NULL, 0);
|
screen_info.lfb_width = simple_strtoul(this_opt+6, NULL, 0);
|
||||||
else if (!strcmp(this_opt, "nowc"))
|
else if (!strcmp(this_opt, "nowc"))
|
||||||
nowc = true;
|
mem_flags &= ~EFI_MEMORY_WC;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,6 +168,7 @@ static int efifb_probe(struct platform_device *dev)
|
|||||||
unsigned int size_remap;
|
unsigned int size_remap;
|
||||||
unsigned int size_total;
|
unsigned int size_total;
|
||||||
char *option = NULL;
|
char *option = NULL;
|
||||||
|
efi_memory_desc_t md;
|
||||||
|
|
||||||
if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI || pci_dev_disabled)
|
if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI || pci_dev_disabled)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
@ -272,12 +277,35 @@ static int efifb_probe(struct platform_device *dev)
|
|||||||
info->apertures->ranges[0].base = efifb_fix.smem_start;
|
info->apertures->ranges[0].base = efifb_fix.smem_start;
|
||||||
info->apertures->ranges[0].size = size_remap;
|
info->apertures->ranges[0].size = size_remap;
|
||||||
|
|
||||||
if (nowc)
|
if (!efi_mem_desc_lookup(efifb_fix.smem_start, &md)) {
|
||||||
info->screen_base = ioremap(efifb_fix.smem_start, efifb_fix.smem_len);
|
if ((efifb_fix.smem_start + efifb_fix.smem_len) >
|
||||||
else
|
(md.phys_addr + (md.num_pages << EFI_PAGE_SHIFT))) {
|
||||||
info->screen_base = ioremap_wc(efifb_fix.smem_start, efifb_fix.smem_len);
|
pr_err("efifb: video memory @ 0x%lx spans multiple EFI memory regions\n",
|
||||||
|
efifb_fix.smem_start);
|
||||||
|
err = -EIO;
|
||||||
|
goto err_release_fb;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* If the UEFI memory map covers the efifb region, we may only
|
||||||
|
* remap it using the attributes the memory map prescribes.
|
||||||
|
*/
|
||||||
|
mem_flags |= EFI_MEMORY_WT | EFI_MEMORY_WB;
|
||||||
|
mem_flags &= md.attribute;
|
||||||
|
}
|
||||||
|
if (mem_flags & EFI_MEMORY_WC)
|
||||||
|
info->screen_base = ioremap_wc(efifb_fix.smem_start,
|
||||||
|
efifb_fix.smem_len);
|
||||||
|
else if (mem_flags & EFI_MEMORY_UC)
|
||||||
|
info->screen_base = ioremap(efifb_fix.smem_start,
|
||||||
|
efifb_fix.smem_len);
|
||||||
|
else if (mem_flags & EFI_MEMORY_WT)
|
||||||
|
info->screen_base = memremap(efifb_fix.smem_start,
|
||||||
|
efifb_fix.smem_len, MEMREMAP_WT);
|
||||||
|
else if (mem_flags & EFI_MEMORY_WB)
|
||||||
|
info->screen_base = memremap(efifb_fix.smem_start,
|
||||||
|
efifb_fix.smem_len, MEMREMAP_WB);
|
||||||
if (!info->screen_base) {
|
if (!info->screen_base) {
|
||||||
pr_err("efifb: abort, cannot ioremap video memory 0x%x @ 0x%lx\n",
|
pr_err("efifb: abort, cannot remap video memory 0x%x @ 0x%lx\n",
|
||||||
efifb_fix.smem_len, efifb_fix.smem_start);
|
efifb_fix.smem_len, efifb_fix.smem_start);
|
||||||
err = -EIO;
|
err = -EIO;
|
||||||
goto err_release_fb;
|
goto err_release_fb;
|
||||||
@ -371,7 +399,10 @@ static int efifb_probe(struct platform_device *dev)
|
|||||||
err_groups:
|
err_groups:
|
||||||
sysfs_remove_groups(&dev->dev.kobj, efifb_groups);
|
sysfs_remove_groups(&dev->dev.kobj, efifb_groups);
|
||||||
err_unmap:
|
err_unmap:
|
||||||
iounmap(info->screen_base);
|
if (mem_flags & (EFI_MEMORY_UC | EFI_MEMORY_WC))
|
||||||
|
iounmap(info->screen_base);
|
||||||
|
else
|
||||||
|
memunmap(info->screen_base);
|
||||||
err_release_fb:
|
err_release_fb:
|
||||||
framebuffer_release(info);
|
framebuffer_release(info);
|
||||||
err_release_mem:
|
err_release_mem:
|
||||||
|
@ -86,7 +86,9 @@ static int efivarfs_create(struct inode *dir, struct dentry *dentry,
|
|||||||
/* length of the variable name itself: remove GUID and separator */
|
/* length of the variable name itself: remove GUID and separator */
|
||||||
namelen = dentry->d_name.len - EFI_VARIABLE_GUID_LEN - 1;
|
namelen = dentry->d_name.len - EFI_VARIABLE_GUID_LEN - 1;
|
||||||
|
|
||||||
uuid_le_to_bin(dentry->d_name.name + namelen + 1, &var->var.VendorGuid);
|
err = guid_parse(dentry->d_name.name + namelen + 1, &var->var.VendorGuid);
|
||||||
|
if (err)
|
||||||
|
goto out;
|
||||||
|
|
||||||
if (efivar_variable_is_removable(var->var.VendorGuid,
|
if (efivar_variable_is_removable(var->var.VendorGuid,
|
||||||
dentry->d_name.name, namelen))
|
dentry->d_name.name, namelen))
|
||||||
|
@ -894,6 +894,16 @@ typedef struct _efi_file_handle {
|
|||||||
void *flush;
|
void *flush;
|
||||||
} efi_file_handle_t;
|
} efi_file_handle_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
u64 revision;
|
||||||
|
u32 open_volume;
|
||||||
|
} efi_file_io_interface_32_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
u64 revision;
|
||||||
|
u64 open_volume;
|
||||||
|
} efi_file_io_interface_64_t;
|
||||||
|
|
||||||
typedef struct _efi_file_io_interface {
|
typedef struct _efi_file_io_interface {
|
||||||
u64 revision;
|
u64 revision;
|
||||||
int (*open_volume)(struct _efi_file_io_interface *,
|
int (*open_volume)(struct _efi_file_io_interface *,
|
||||||
@ -988,14 +998,12 @@ extern void efi_memmap_walk (efi_freemem_callback_t callback, void *arg);
|
|||||||
extern void efi_gettimeofday (struct timespec64 *ts);
|
extern void efi_gettimeofday (struct timespec64 *ts);
|
||||||
extern void efi_enter_virtual_mode (void); /* switch EFI to virtual mode, if possible */
|
extern void efi_enter_virtual_mode (void); /* switch EFI to virtual mode, if possible */
|
||||||
#ifdef CONFIG_X86
|
#ifdef CONFIG_X86
|
||||||
extern void efi_late_init(void);
|
|
||||||
extern void efi_free_boot_services(void);
|
extern void efi_free_boot_services(void);
|
||||||
extern efi_status_t efi_query_variable_store(u32 attributes,
|
extern efi_status_t efi_query_variable_store(u32 attributes,
|
||||||
unsigned long size,
|
unsigned long size,
|
||||||
bool nonblocking);
|
bool nonblocking);
|
||||||
extern void efi_find_mirror(void);
|
extern void efi_find_mirror(void);
|
||||||
#else
|
#else
|
||||||
static inline void efi_late_init(void) {}
|
|
||||||
static inline void efi_free_boot_services(void) {}
|
static inline void efi_free_boot_services(void) {}
|
||||||
|
|
||||||
static inline efi_status_t efi_query_variable_store(u32 attributes,
|
static inline efi_status_t efi_query_variable_store(u32 attributes,
|
||||||
@ -1651,4 +1659,7 @@ struct linux_efi_tpm_eventlog {
|
|||||||
|
|
||||||
extern int efi_tpm_eventlog_init(void);
|
extern int efi_tpm_eventlog_init(void);
|
||||||
|
|
||||||
|
/* Workqueue to queue EFI Runtime Services */
|
||||||
|
extern struct workqueue_struct *efi_rts_wq;
|
||||||
|
|
||||||
#endif /* _LINUX_EFI_H */
|
#endif /* _LINUX_EFI_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user