History

efi/libstub: Allocate headspace in efi_get_memory_map()

efi_get_memory_map() allocates a buffer to store the memory map that it retrieves. This buffer may need to be reused by the client after ExitBootServices() is called, at which point allocations are not longer permitted. To support this usecase, provide the allocated buffer size back to the client, and allocate some additional headroom to account for any reasonable growth in the map that is likely to happen between the call to efi_get_memory_map() and the client reusing the buffer.

Jeffrey Hugo committed 10 years ago

Commit dadb57a1 parent 4af9ed55 files · +111 −49Browse files

Unified · Split

5 files
  1. arch/x86/boot/compressed/eboot.c +13 −7
  2. drivers/firmware/efi/libstub/efi-stub-helper.c +66 −30
  3. drivers/firmware/efi/libstub/fdt.c +12 −5
  4. drivers/firmware/efi/libstub/random.c +10 −2
  5. include/linux/efi.h +10 −5
arch/x86/boot/compressed/eboot.c+13−7
@@ -1008,7 +1008,7 @@ static efi_status_t exit_boot(struct boot_params *boot_params, · 1007 unmodified lines
1008 void *handle, bool is64)1008 void *handle, bool is64)
1009{1009{
1010 struct efi_info *efi = &boot_params->efi_info;1010 struct efi_info *efi = &boot_params->efi_info;
1011 unsigned long map_sz, key, desc_size;1011 unsigned long map_sz, key, desc_size, buff_size;
1012 efi_memory_desc_t *mem_map;1012 efi_memory_desc_t *mem_map;
1013 struct setup_data *e820ext;1013 struct setup_data *e820ext;
1014 const char *signature;1014 const char *signature;
@@ -1019,14 +1019,20 @@ static efi_status_t exit_boot(struct boot_params *boot_params, · 4 unmodified lines
1019 bool called_exit = false;1019 bool called_exit = false;
1020 u8 nr_entries;1020 u8 nr_entries;
1021 int i;1021 int i;
1022 1022 struct efi_boot_memmap map;
1023 nr_desc = 0;1023
1024 e820ext = NULL;1024 nr_desc = 0;
1025 e820ext_size = 0;1025 e820ext = NULL;
1026 e820ext_size = 0;
1027 map.map = &mem_map;
1028 map.map_size = &map_sz;
1029 map.desc_size = &desc_size;
1030 map.desc_ver = &desc_version;
1031 map.key_ptr = &key;
1032 map.buff_size = &buff_size;
1026 1033
1027get_map:1034get_map:
1028 status = efi_get_memory_map(sys_table, &mem_map, &map_sz, &desc_size,1035 status = efi_get_memory_map(sys_table, &map);
1029 &desc_version, &key);
1030 1036
1031 if (status != EFI_SUCCESS)1037 if (status != EFI_SUCCESS)
1032 return status;1038 return status;
drivers/firmware/efi/libstub/efi-stub-helper.c+66−30
@@ -41,6 +41,8 @@ static unsigned long __chunk_size = EFI_READ_CHUNK_SIZE; · 40 unmodified lines
41#define EFI_ALLOC_ALIGN EFI_PAGE_SIZE41#define EFI_ALLOC_ALIGN EFI_PAGE_SIZE
42#endif42#endif
43 43
44#define EFI_MMAP_NR_SLACK_SLOTS 8
45
44struct file_info {46struct file_info {
45 efi_file_handle_t *handle;47 efi_file_handle_t *handle;
46 u64 size;48 u64 size;
@@ -63,49 +65,62 @@ void efi_printk(efi_system_table_t *sys_table_arg, char *str) · 16 unmodified lines
63 }65 }
64}66}
65 67
68static inline bool mmap_has_headroom(unsigned long buff_size,
69 unsigned long map_size,
70 unsigned long desc_size)
71{
72 unsigned long slack = buff_size - map_size;
73
74 return slack / desc_size >= EFI_MMAP_NR_SLACK_SLOTS;
75}
76
66efi_status_t efi_get_memory_map(efi_system_table_t *sys_table_arg,77efi_status_t efi_get_memory_map(efi_system_table_t *sys_table_arg,
67 efi_memory_desc_t **map,78 struct efi_boot_memmap *map)
68 unsigned long *map_size,
69 unsigned long *desc_size,
70 u32 *desc_ver,
71 unsigned long *key_ptr)
72{79{
73 efi_memory_desc_t *m = NULL;80 efi_memory_desc_t *m = NULL;
74 efi_status_t status;81 efi_status_t status;
75 unsigned long key;82 unsigned long key;
76 u32 desc_version;83 u32 desc_version;
77 84
78 *map_size = sizeof(*m) * 32;85 *map->desc_size = sizeof(*m);
86 *map->map_size = *map->desc_size * 32;
87 *map->buff_size = *map->map_size;
79again:88again:
80 /*
81 * Add an additional efi_memory_desc_t because we're doing an
82 * allocation which may be in a new descriptor region.
83 */
84 *map_size += sizeof(*m);
85 status = efi_call_early(allocate_pool, EFI_LOADER_DATA,89 status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
86 *map_size, (void **)&m);90 *map->map_size, (void **)&m);
87 if (status != EFI_SUCCESS)91 if (status != EFI_SUCCESS)
88 goto fail;92 goto fail;
89 93
90 *desc_size = 0;94 *map->desc_size = 0;
91 key = 0;95 key = 0;
92 status = efi_call_early(get_memory_map, map_size, m,96 status = efi_call_early(get_memory_map, map->map_size, m,
93 &key, desc_size, &desc_version);97 &key, map->desc_size, &desc_version);
94 if (status == EFI_BUFFER_TOO_SMALL) {98 if (status == EFI_BUFFER_TOO_SMALL ||
99 !mmap_has_headroom(*map->buff_size, *map->map_size,
100 *map->desc_size)) {
95 efi_call_early(free_pool, m);101 efi_call_early(free_pool, m);
102 /*
103 * Make sure there is some entries of headroom so that the
104 * buffer can be reused for a new map after allocations are
105 * no longer permitted. Its unlikely that the map will grow to
106 * exceed this headroom once we are ready to trigger
107 * ExitBootServices()
108 */
109 *map->map_size += *map->desc_size * EFI_MMAP_NR_SLACK_SLOTS;
110 *map->buff_size = *map->map_size;
96 goto again;111 goto again;
97 }112 }
98 113
99 if (status != EFI_SUCCESS)114 if (status != EFI_SUCCESS)
100 efi_call_early(free_pool, m);115 efi_call_early(free_pool, m);
101 116
102 if (key_ptr && status == EFI_SUCCESS)117 if (map->key_ptr && status == EFI_SUCCESS)
103 *key_ptr = key;118 *map->key_ptr = key;
104 if (desc_ver && status == EFI_SUCCESS)119 if (map->desc_ver && status == EFI_SUCCESS)
105 *desc_ver = desc_version;120 *map->desc_ver = desc_version;
106 121
107fail:122fail:
108 *map = m;123 *map->map = m;
109 return status;124 return status;
110}125}
111 126
@@ -113,13 +128,20 @@ fail: · 1 unmodified line
113unsigned long get_dram_base(efi_system_table_t *sys_table_arg)128unsigned long get_dram_base(efi_system_table_t *sys_table_arg)
114{129{
115 efi_status_t status;130 efi_status_t status;
116 unsigned long map_size;131 unsigned long map_size, buff_size;
117 unsigned long membase = EFI_ERROR;132 unsigned long membase = EFI_ERROR;
118 struct efi_memory_map map;133 struct efi_memory_map map;
119 efi_memory_desc_t *md;134 efi_memory_desc_t *md;
135 struct efi_boot_memmap boot_map;
120 136
121 status = efi_get_memory_map(sys_table_arg, (efi_memory_desc_t **)&map.map,137 boot_map.map = (efi_memory_desc_t **)&map.map;
122 &map_size, &map.desc_size, NULL, NULL);138 boot_map.map_size = &map_size;
139 boot_map.desc_size = &map.desc_size;
140 boot_map.desc_ver = NULL;
141 boot_map.key_ptr = NULL;
142 boot_map.buff_size = &buff_size;
143
144 status = efi_get_memory_map(sys_table_arg, &boot_map);
123 if (status != EFI_SUCCESS)145 if (status != EFI_SUCCESS)
124 return membase;146 return membase;
125 147
@@ -144,15 +166,22 @@ efi_status_t efi_high_alloc(efi_system_table_t *sys_table_arg, · 18 unmodified lines
144 unsigned long size, unsigned long align,166 unsigned long size, unsigned long align,
145 unsigned long *addr, unsigned long max)167 unsigned long *addr, unsigned long max)
146{168{
147 unsigned long map_size, desc_size;169 unsigned long map_size, desc_size, buff_size;
148 efi_memory_desc_t *map;170 efi_memory_desc_t *map;
149 efi_status_t status;171 efi_status_t status;
150 unsigned long nr_pages;172 unsigned long nr_pages;
151 u64 max_addr = 0;173 u64 max_addr = 0;
152 int i;174 int i;
175 struct efi_boot_memmap boot_map;
176
177 boot_map.map = ↦
178 boot_map.map_size = &map_size;
179 boot_map.desc_size = &desc_size;
180 boot_map.desc_ver = NULL;
181 boot_map.key_ptr = NULL;
182 boot_map.buff_size = &buff_size;
153 183
154 status = efi_get_memory_map(sys_table_arg, &map, &map_size, &desc_size,184 status = efi_get_memory_map(sys_table_arg, &boot_map);
155 NULL, NULL);
156 if (status != EFI_SUCCESS)185 if (status != EFI_SUCCESS)
157 goto fail;186 goto fail;
158 187
@@ -230,14 +259,21 @@ efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg, · 71 unmodified lines
230 unsigned long size, unsigned long align,259 unsigned long size, unsigned long align,
231 unsigned long *addr)260 unsigned long *addr)
232{261{
233 unsigned long map_size, desc_size;262 unsigned long map_size, desc_size, buff_size;
234 efi_memory_desc_t *map;263 efi_memory_desc_t *map;
235 efi_status_t status;264 efi_status_t status;
236 unsigned long nr_pages;265 unsigned long nr_pages;
237 int i;266 int i;
267 struct efi_boot_memmap boot_map;
268
269 boot_map.map = ↦
270 boot_map.map_size = &map_size;
271 boot_map.desc_size = &desc_size;
272 boot_map.desc_ver = NULL;
273 boot_map.key_ptr = NULL;
274 boot_map.buff_size = &buff_size;
238 275
239 status = efi_get_memory_map(sys_table_arg, &map, &map_size, &desc_size,276 status = efi_get_memory_map(sys_table_arg, &boot_map);
240 NULL, NULL);
241 if (status != EFI_SUCCESS)277 if (status != EFI_SUCCESS)
242 goto fail;278 goto fail;
243 279
drivers/firmware/efi/libstub/fdt.c+12−5
@@ -175,13 +175,21 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table, · 174 unmodified lines
175 unsigned long fdt_addr,175 unsigned long fdt_addr,
176 unsigned long fdt_size)176 unsigned long fdt_size)
177{177{
178 unsigned long map_size, desc_size;178 unsigned long map_size, desc_size, buff_size;
179 u32 desc_ver;179 u32 desc_ver;
180 unsigned long mmap_key;180 unsigned long mmap_key;
181 efi_memory_desc_t *memory_map, *runtime_map;181 efi_memory_desc_t *memory_map, *runtime_map;
182 unsigned long new_fdt_size;182 unsigned long new_fdt_size;
183 efi_status_t status;183 efi_status_t status;
184 int runtime_entry_count = 0;184 int runtime_entry_count = 0;
185 struct efi_boot_memmap map;
186
187 map.map = &runtime_map;
188 map.map_size = &map_size;
189 map.desc_size = &desc_size;
190 map.desc_ver = &desc_ver;
191 map.key_ptr = &mmap_key;
192 map.buff_size = &buff_size;
185 193
186 /*194 /*
187 * Get a copy of the current memory map that we will use to prepare195 * Get a copy of the current memory map that we will use to prepare
@@ -189,8 +197,7 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table, · 1 unmodified line
189 * subsequent allocations adding entries, since they could not affect197 * subsequent allocations adding entries, since they could not affect
190 * the number of EFI_MEMORY_RUNTIME regions.198 * the number of EFI_MEMORY_RUNTIME regions.
191 */199 */
192 status = efi_get_memory_map(sys_table, &runtime_map, &map_size,200 status = efi_get_memory_map(sys_table, &map);
193 &desc_size, &desc_ver, &mmap_key);
194 if (status != EFI_SUCCESS) {201 if (status != EFI_SUCCESS) {
195 pr_efi_err(sys_table, "Unable to retrieve UEFI memory map.\n");202 pr_efi_err(sys_table, "Unable to retrieve UEFI memory map.\n");
196 return status;203 return status;
@@ -199,6 +206,7 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table, · 2 unmodified lines
199 pr_efi(sys_table,206 pr_efi(sys_table,
200 "Exiting boot services and installing virtual address map...\n");207 "Exiting boot services and installing virtual address map...\n");
201 208
209 map.map = &memory_map;
202 /*210 /*
203 * Estimate size of new FDT, and allocate memory for it. We211 * Estimate size of new FDT, and allocate memory for it. We
204 * will allocate a bigger buffer if this ends up being too212 * will allocate a bigger buffer if this ends up being too
@@ -218,8 +226,7 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table, · 13 unmodified lines
218 * we can get the memory map key needed for226 * we can get the memory map key needed for
219 * exit_boot_services().227 * exit_boot_services().
220 */228 */
221 status = efi_get_memory_map(sys_table, &memory_map, &map_size,229 status = efi_get_memory_map(sys_table, &map);
222 &desc_size, &desc_ver, &mmap_key);
223 if (status != EFI_SUCCESS)230 if (status != EFI_SUCCESS)
224 goto fail_free_new_fdt;231 goto fail_free_new_fdt;
225 232
drivers/firmware/efi/libstub/random.c+10−2
@@ -73,12 +73,20 @@ efi_status_t efi_random_alloc(efi_system_table_t *sys_table_arg, · 72 unmodified lines
73 unsigned long random_seed)73 unsigned long random_seed)
74{74{
75 unsigned long map_size, desc_size, total_slots = 0, target_slot;75 unsigned long map_size, desc_size, total_slots = 0, target_slot;
76 unsigned long buff_size;
76 efi_status_t status;77 efi_status_t status;
77 efi_memory_desc_t *memory_map;78 efi_memory_desc_t *memory_map;
78 int map_offset;79 int map_offset;
80 struct efi_boot_memmap map;
79 81
80 status = efi_get_memory_map(sys_table_arg, &memory_map, &map_size,82 map.map = &memory_map;
81 &desc_size, NULL, NULL);83 map.map_size = &map_size;
84 map.desc_size = &desc_size;
85 map.desc_ver = NULL;
86 map.key_ptr = NULL;
87 map.buff_size = &buff_size;
88
89 status = efi_get_memory_map(sys_table_arg, &map);
82 if (status != EFI_SUCCESS)90 if (status != EFI_SUCCESS)
83 return status;91 return status;
84 92
include/linux/efi.h+10−5
@@ -118,6 +118,15 @@ typedef struct { · 117 unmodified lines
118 u32 imagesize;118 u32 imagesize;
119} efi_capsule_header_t;119} efi_capsule_header_t;
120 120
121struct efi_boot_memmap {
122 efi_memory_desc_t **map;
123 unsigned long *map_size;
124 unsigned long *desc_size;
125 u32 *desc_ver;
126 unsigned long *key_ptr;
127 unsigned long *buff_size;
128};
129
121/*130/*
122 * EFI capsule flags131 * EFI capsule flags
123 */132 */
@@ -1371,11 +1380,7 @@ char *efi_convert_cmdline(efi_system_table_t *sys_table_arg, · 1247 unmodified lines
1371 efi_loaded_image_t *image, int *cmd_line_len);1380 efi_loaded_image_t *image, int *cmd_line_len);
1372 1381
1373efi_status_t efi_get_memory_map(efi_system_table_t *sys_table_arg,1382efi_status_t efi_get_memory_map(efi_system_table_t *sys_table_arg,
1374 efi_memory_desc_t **map,1383 struct efi_boot_memmap *map);
1375 unsigned long *map_size,
1376 unsigned long *desc_size,
1377 u32 *desc_ver,
1378 unsigned long *key_ptr);
1379 1384
1380efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg,1385efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg,
1381 unsigned long size, unsigned long align,1386 unsigned long size, unsigned long align,