0001
0002
0003
0004
0005
0006 #include <linux/efi.h>
0007 #include <linux/log2.h>
0008 #include <asm/efi.h>
0009
0010 #include "efistub.h"
0011
0012
0013
0014
0015
0016
0017 static unsigned long get_entry_num_slots(efi_memory_desc_t *md,
0018 unsigned long size,
0019 unsigned long align_shift)
0020 {
0021 unsigned long align = 1UL << align_shift;
0022 u64 first_slot, last_slot, region_end;
0023
0024 if (md->type != EFI_CONVENTIONAL_MEMORY)
0025 return 0;
0026
0027 if (efi_soft_reserve_enabled() &&
0028 (md->attribute & EFI_MEMORY_SP))
0029 return 0;
0030
0031 region_end = min(md->phys_addr + md->num_pages * EFI_PAGE_SIZE - 1,
0032 (u64)ULONG_MAX);
0033 if (region_end < size)
0034 return 0;
0035
0036 first_slot = round_up(md->phys_addr, align);
0037 last_slot = round_down(region_end - size + 1, align);
0038
0039 if (first_slot > last_slot)
0040 return 0;
0041
0042 return ((unsigned long)(last_slot - first_slot) >> align_shift) + 1;
0043 }
0044
0045
0046
0047
0048
0049
0050
0051 #define MD_NUM_SLOTS(md) ((md)->virt_addr)
0052
0053 efi_status_t efi_random_alloc(unsigned long size,
0054 unsigned long align,
0055 unsigned long *addr,
0056 unsigned long random_seed)
0057 {
0058 unsigned long map_size, desc_size, total_slots = 0, target_slot;
0059 unsigned long total_mirrored_slots = 0;
0060 unsigned long buff_size;
0061 efi_status_t status;
0062 efi_memory_desc_t *memory_map;
0063 int map_offset;
0064 struct efi_boot_memmap map;
0065
0066 map.map = &memory_map;
0067 map.map_size = &map_size;
0068 map.desc_size = &desc_size;
0069 map.desc_ver = NULL;
0070 map.key_ptr = NULL;
0071 map.buff_size = &buff_size;
0072
0073 status = efi_get_memory_map(&map);
0074 if (status != EFI_SUCCESS)
0075 return status;
0076
0077 if (align < EFI_ALLOC_ALIGN)
0078 align = EFI_ALLOC_ALIGN;
0079
0080 size = round_up(size, EFI_ALLOC_ALIGN);
0081
0082
0083 for (map_offset = 0; map_offset < map_size; map_offset += desc_size) {
0084 efi_memory_desc_t *md = (void *)memory_map + map_offset;
0085 unsigned long slots;
0086
0087 slots = get_entry_num_slots(md, size, ilog2(align));
0088 MD_NUM_SLOTS(md) = slots;
0089 total_slots += slots;
0090 if (md->attribute & EFI_MEMORY_MORE_RELIABLE)
0091 total_mirrored_slots += slots;
0092 }
0093
0094
0095 if (total_mirrored_slots > 0)
0096 total_slots = total_mirrored_slots;
0097
0098
0099 target_slot = (total_slots * (u64)(random_seed & U32_MAX)) >> 32;
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112 for (map_offset = 0; map_offset < map_size; map_offset += desc_size) {
0113 efi_memory_desc_t *md = (void *)memory_map + map_offset;
0114 efi_physical_addr_t target;
0115 unsigned long pages;
0116
0117 if (total_mirrored_slots > 0 &&
0118 !(md->attribute & EFI_MEMORY_MORE_RELIABLE))
0119 continue;
0120
0121 if (target_slot >= MD_NUM_SLOTS(md)) {
0122 target_slot -= MD_NUM_SLOTS(md);
0123 continue;
0124 }
0125
0126 target = round_up(md->phys_addr, align) + target_slot * align;
0127 pages = size / EFI_PAGE_SIZE;
0128
0129 status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS,
0130 EFI_LOADER_DATA, pages, &target);
0131 if (status == EFI_SUCCESS)
0132 *addr = target;
0133 break;
0134 }
0135
0136 efi_bs_call(free_pool, memory_map);
0137
0138 return status;
0139 }