diff options
Diffstat (limited to 'drivers/firmware/efi/libstub')
-rw-r--r-- | drivers/firmware/efi/libstub/Makefile | 4 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/arm-stub.c | 2 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/efi-stub-helper.c | 33 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/efistub.h | 11 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/random.c | 67 |
5 files changed, 88 insertions, 29 deletions
diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index 5e23e2d305e7..6621b13c370f 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -36,11 +36,11 @@ arm-deps := fdt_rw.c fdt_ro.c fdt_wip.c fdt.c fdt_empty_tree.c fdt_sw.c sort.c $(obj)/lib-%.o: $(srctree)/lib/%.c FORCE $(call if_changed_rule,cc_o_c) -lib-$(CONFIG_EFI_ARMSTUB) += arm-stub.o fdt.o string.o \ +lib-$(CONFIG_EFI_ARMSTUB) += arm-stub.o fdt.o string.o random.o \ $(patsubst %.c,lib-%.o,$(arm-deps)) lib-$(CONFIG_ARM) += arm32-stub.o -lib-$(CONFIG_ARM64) += arm64-stub.o random.o +lib-$(CONFIG_ARM64) += arm64-stub.o CFLAGS_arm64-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET) # diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c index 993aa56755f6..b4f7d78f9e8b 100644 --- a/drivers/firmware/efi/libstub/arm-stub.c +++ b/drivers/firmware/efi/libstub/arm-stub.c @@ -340,6 +340,8 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, if (status != EFI_SUCCESS) pr_efi_err(sys_table, "Failed initrd from command line!\n"); + efi_random_get_seed(sys_table); + new_fdt_addr = fdt_addr; status = allocate_new_fdt_and_exit_boot(sys_table, handle, &new_fdt_addr, dram_base + MAX_FDT_OFFSET, diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c index aded10662020..757badc1debb 100644 --- a/drivers/firmware/efi/libstub/efi-stub-helper.c +++ b/drivers/firmware/efi/libstub/efi-stub-helper.c @@ -32,15 +32,6 @@ static unsigned long __chunk_size = EFI_READ_CHUNK_SIZE; -/* - * Allow the platform to override the allocation granularity: this allows - * systems that have the capability to run with a larger page size to deal - * with the allocations for initrd and fdt more efficiently. - */ -#ifndef EFI_ALLOC_ALIGN -#define EFI_ALLOC_ALIGN EFI_PAGE_SIZE -#endif - #define EFI_MMAP_NR_SLACK_SLOTS 8 struct file_info { @@ -186,14 +177,16 @@ efi_status_t efi_high_alloc(efi_system_table_t *sys_table_arg, goto fail; /* - * Enforce minimum alignment that EFI requires when requesting - * a specific address. We are doing page-based allocations, - * so we must be aligned to a page. + * Enforce minimum alignment that EFI or Linux requires when + * requesting a specific address. We are doing page-based (or + * larger) allocations, and both the address and size must meet + * alignment constraints. */ if (align < EFI_ALLOC_ALIGN) align = EFI_ALLOC_ALIGN; - nr_pages = round_up(size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE; + size = round_up(size, EFI_ALLOC_ALIGN); + nr_pages = size / EFI_PAGE_SIZE; again: for (i = 0; i < map_size / desc_size; i++) { efi_memory_desc_t *desc; @@ -208,7 +201,7 @@ again: continue; start = desc->phys_addr; - end = start + desc->num_pages * (1UL << EFI_PAGE_SHIFT); + end = start + desc->num_pages * EFI_PAGE_SIZE; if (end > max) end = max; @@ -278,14 +271,16 @@ efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg, goto fail; /* - * Enforce minimum alignment that EFI requires when requesting - * a specific address. We are doing page-based allocations, - * so we must be aligned to a page. + * Enforce minimum alignment that EFI or Linux requires when + * requesting a specific address. We are doing page-based (or + * larger) allocations, and both the address and size must meet + * alignment constraints. */ if (align < EFI_ALLOC_ALIGN) align = EFI_ALLOC_ALIGN; - nr_pages = round_up(size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE; + size = round_up(size, EFI_ALLOC_ALIGN); + nr_pages = size / EFI_PAGE_SIZE; for (i = 0; i < map_size / desc_size; i++) { efi_memory_desc_t *desc; unsigned long m = (unsigned long)map; @@ -300,7 +295,7 @@ efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg, continue; start = desc->phys_addr; - end = start + desc->num_pages * (1UL << EFI_PAGE_SHIFT); + end = start + desc->num_pages * EFI_PAGE_SIZE; /* * Don't allocate at 0x0. It will confuse code that diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h index ee49cd23ee63..b98824e3800a 100644 --- a/drivers/firmware/efi/libstub/efistub.h +++ b/drivers/firmware/efi/libstub/efistub.h @@ -15,6 +15,15 @@ */ #undef __init +/* + * Allow the platform to override the allocation granularity: this allows + * systems that have the capability to run with a larger page size to deal + * with the allocations for initrd and fdt more efficiently. + */ +#ifndef EFI_ALLOC_ALIGN +#define EFI_ALLOC_ALIGN EFI_PAGE_SIZE +#endif + 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, @@ -62,4 +71,6 @@ efi_status_t efi_random_alloc(efi_system_table_t *sys_table_arg, efi_status_t check_platform_features(efi_system_table_t *sys_table_arg); +efi_status_t efi_random_get_seed(efi_system_table_t *sys_table_arg); + #endif diff --git a/drivers/firmware/efi/libstub/random.c b/drivers/firmware/efi/libstub/random.c index 0c9f58c5ba50..7e72954d5860 100644 --- a/drivers/firmware/efi/libstub/random.c +++ b/drivers/firmware/efi/libstub/random.c @@ -8,6 +8,7 @@ */ #include <linux/efi.h> +#include <linux/log2.h> #include <asm/efi.h> #include "efistub.h" @@ -41,21 +42,23 @@ efi_status_t efi_get_random_bytes(efi_system_table_t *sys_table_arg, */ static unsigned long get_entry_num_slots(efi_memory_desc_t *md, unsigned long size, - unsigned long align) + unsigned long align_shift) { - u64 start, end; + unsigned long align = 1UL << align_shift; + u64 first_slot, last_slot, region_end; if (md->type != EFI_CONVENTIONAL_MEMORY) return 0; - start = round_up(md->phys_addr, align); - end = round_down(md->phys_addr + md->num_pages * EFI_PAGE_SIZE - size, - align); + region_end = min((u64)ULONG_MAX, md->phys_addr + md->num_pages*EFI_PAGE_SIZE - 1); - if (start > end) + first_slot = round_up(md->phys_addr, align); + last_slot = round_down(region_end - size + 1, align); + + if (first_slot > last_slot) return 0; - return (end - start + 1) / align; + return ((unsigned long)(last_slot - first_slot) >> align_shift) + 1; } /* @@ -98,7 +101,7 @@ efi_status_t efi_random_alloc(efi_system_table_t *sys_table_arg, efi_memory_desc_t *md = (void *)memory_map + map_offset; unsigned long slots; - slots = get_entry_num_slots(md, size, align); + slots = get_entry_num_slots(md, size, ilog2(align)); MD_NUM_SLOTS(md) = slots; total_slots += slots; } @@ -141,3 +144,51 @@ efi_status_t efi_random_alloc(efi_system_table_t *sys_table_arg, return status; } + +#define RANDOM_SEED_SIZE 32 + +efi_status_t efi_random_get_seed(efi_system_table_t *sys_table_arg) +{ + efi_guid_t rng_proto = EFI_RNG_PROTOCOL_GUID; + efi_guid_t rng_algo_raw = EFI_RNG_ALGORITHM_RAW; + efi_guid_t rng_table_guid = LINUX_EFI_RANDOM_SEED_TABLE_GUID; + struct efi_rng_protocol *rng; + struct linux_efi_random_seed *seed; + efi_status_t status; + + status = efi_call_early(locate_protocol, &rng_proto, NULL, + (void **)&rng); + if (status != EFI_SUCCESS) + return status; + + status = efi_call_early(allocate_pool, EFI_RUNTIME_SERVICES_DATA, + sizeof(*seed) + RANDOM_SEED_SIZE, + (void **)&seed); + if (status != EFI_SUCCESS) + return status; + + status = rng->get_rng(rng, &rng_algo_raw, RANDOM_SEED_SIZE, + seed->bits); + if (status == EFI_UNSUPPORTED) + /* + * Use whatever algorithm we have available if the raw algorithm + * is not implemented. + */ + status = rng->get_rng(rng, NULL, RANDOM_SEED_SIZE, + seed->bits); + + if (status != EFI_SUCCESS) + goto err_freepool; + + seed->size = RANDOM_SEED_SIZE; + status = efi_call_early(install_configuration_table, &rng_table_guid, + seed); + if (status != EFI_SUCCESS) + goto err_freepool; + + return EFI_SUCCESS; + +err_freepool: + efi_call_early(free_pool, seed); + return status; +} |