1
2
3
4
5
6
7
8#include <common.h>
9#include <efi_loader.h>
10#include <log.h>
11#include <efi_api.h>
12#include <malloc.h>
13
14const efi_guid_t efi_esrt_guid = EFI_SYSTEM_RESOURCE_TABLE_GUID;
15
16static struct efi_system_resource_table *esrt;
17
18#define EFI_ESRT_VERSION 1
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36static efi_status_t
37efi_esrt_image_info_to_entry(struct efi_firmware_image_descriptor *img_info,
38 struct efi_system_resource_entry *entry,
39 u32 desc_version, u32 image_type, u32 flags)
40{
41 if (guidcmp(&entry->fw_class, &img_info->image_type_id)) {
42 EFI_PRINT("ESRT entry %pUL mismatches img_type_id %pUL\n",
43 &entry->fw_class, &img_info->image_type_id);
44 return EFI_INVALID_PARAMETER;
45 }
46
47 entry->fw_version = img_info->version;
48
49 entry->fw_type = image_type;
50 entry->capsule_flags = flags;
51
52
53
54
55
56
57 if (desc_version >= 2)
58 entry->lowest_supported_fw_version =
59 img_info->lowest_supported_image_version;
60 else
61 entry->lowest_supported_fw_version = 0;
62
63
64
65
66
67
68
69 if (desc_version >= 3) {
70 entry->last_attempt_version =
71 img_info->last_attempt_version;
72
73 entry->last_attempt_status =
74 img_info->last_attempt_status;
75 } else {
76 entry->last_attempt_version = 0;
77 entry->last_attempt_status = LAST_ATTEMPT_STATUS_SUCCESS;
78 }
79
80 return EFI_SUCCESS;
81}
82
83
84
85
86
87
88
89
90
91static
92inline u32 efi_esrt_entries_to_size(u32 num_entries)
93{
94 u32 esrt_size = sizeof(struct efi_system_resource_table) +
95 num_entries * sizeof(struct efi_system_resource_entry);
96
97 return esrt_size;
98}
99
100
101
102
103
104
105
106
107
108
109
110static
111efi_status_t efi_esrt_allocate_install(u32 num_entries)
112{
113 efi_status_t ret;
114 struct efi_system_resource_table *new_esrt;
115 u32 size = efi_esrt_entries_to_size(num_entries);
116 efi_guid_t esrt_guid = efi_esrt_guid;
117
118
119 ret = efi_allocate_pool(EFI_BOOT_SERVICES_DATA, size,
120 (void **)&new_esrt);
121
122 if (ret != EFI_SUCCESS) {
123 EFI_PRINT("ESRT cannot allocate memory for %u entries (%u bytes)\n",
124 num_entries, size);
125
126 return ret;
127 }
128
129 new_esrt->fw_resource_count_max = num_entries;
130 new_esrt->fw_resource_count = 0;
131 new_esrt->fw_resource_version = EFI_ESRT_VERSION;
132
133
134 ret = efi_install_configuration_table(&esrt_guid, (void *)new_esrt);
135 if (ret != EFI_SUCCESS) {
136 EFI_PRINT("ESRT failed to install the ESRT in the system table\n");
137 return ret;
138 }
139
140
141 if (esrt)
142 ret = efi_free_pool(esrt);
143
144 esrt = new_esrt;
145
146 return EFI_SUCCESS;
147}
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165static
166struct efi_system_resource_entry *esrt_find_entry(efi_guid_t *img_fw_class)
167{
168 u32 filled_entries;
169 u32 max_entries;
170 struct efi_system_resource_entry *entry;
171
172 if (!esrt) {
173 EFI_PRINT("ESRT access before initialized\n");
174 return NULL;
175 }
176
177 filled_entries = esrt->fw_resource_count;
178 entry = esrt->entries;
179
180
181 for (u32 idx = 0; idx < filled_entries; idx++) {
182 if (!guidcmp(&entry[idx].fw_class, img_fw_class)) {
183 EFI_PRINT("ESRT found entry for image %pUl at index %u\n",
184 img_fw_class, idx);
185 return &entry[idx];
186 }
187 }
188
189 max_entries = esrt->fw_resource_count_max;
190
191
192
193
194 if (filled_entries == max_entries) {
195 EFI_PRINT("ESRT full, this should not happen\n");
196 return NULL;
197 }
198
199
200
201
202
203 esrt->fw_resource_count++;
204 entry[filled_entries].fw_class = *img_fw_class;
205 EFI_PRINT("ESRT allocated new entry for image %pUl at index %u\n",
206 img_fw_class, filled_entries);
207
208 return &entry[filled_entries];
209}
210
211
212
213
214
215
216
217
218
219
220
221static
222efi_status_t efi_esrt_add_from_fmp(struct efi_firmware_management_protocol *fmp)
223{
224 struct efi_system_resource_entry *entry = NULL;
225 size_t info_size = 0;
226 struct efi_firmware_image_descriptor *img_info = NULL;
227 u32 desc_version;
228 u8 desc_count;
229 size_t desc_size;
230 u32 package_version;
231 u16 *package_version_name;
232 efi_status_t ret = EFI_SUCCESS;
233
234
235
236
237
238 u32 image_type = ESRT_FW_TYPE_UNKNOWN;
239
240
241 u32 flags = 0;
242
243 ret = EFI_CALL(fmp->get_image_info(fmp, &info_size, img_info,
244 &desc_version, &desc_count,
245 &desc_size, NULL, NULL));
246
247 if (ret != EFI_BUFFER_TOO_SMALL) {
248
249
250
251
252 EFI_PRINT("Erroneous FMP implementation\n");
253 return EFI_INVALID_PARAMETER;
254 }
255
256 ret = efi_allocate_pool(EFI_BOOT_SERVICES_DATA, info_size,
257 (void **)&img_info);
258 if (ret != EFI_SUCCESS) {
259 EFI_PRINT("ESRT failed to allocate memory for image info.\n");
260 return ret;
261 }
262
263 ret = EFI_CALL(fmp->get_image_info(fmp, &info_size, img_info,
264 &desc_version, &desc_count,
265 &desc_size, &package_version,
266 &package_version_name));
267 if (ret != EFI_SUCCESS) {
268 EFI_PRINT("ESRT failed to obtain the FMP image info\n");
269 goto out;
270 }
271
272
273
274
275 for (u32 desc_idx = 0; desc_idx < desc_count; desc_idx++) {
276 struct efi_firmware_image_descriptor *cur_img_info =
277 (struct efi_firmware_image_descriptor *)
278 ((uintptr_t)img_info + desc_idx * desc_size);
279
280
281
282
283
284 entry = esrt_find_entry(&cur_img_info->image_type_id);
285
286 if (entry) {
287 ret = efi_esrt_image_info_to_entry(cur_img_info, entry,
288 desc_version,
289 image_type, flags);
290 if (ret != EFI_SUCCESS)
291 EFI_PRINT("ESRT entry mismatches image_type\n");
292
293 } else {
294 EFI_PRINT("ESRT failed to add entry for %pUl\n",
295 &cur_img_info->image_type_id);
296 continue;
297 }
298 }
299
300out:
301 efi_free_pool(img_info);
302 return EFI_SUCCESS;
303}
304
305
306
307
308
309
310
311
312
313
314
315efi_status_t efi_esrt_populate(void)
316{
317 efi_handle_t *base_handle = NULL;
318 efi_handle_t *it_handle;
319 efi_uintn_t no_handles = 0;
320 struct efi_firmware_management_protocol *fmp;
321 efi_status_t ret;
322 u32 num_entries = 0;
323 struct efi_handler *handler;
324
325
326
327
328 ret = EFI_CALL(efi_locate_handle_buffer(BY_PROTOCOL,
329 &efi_guid_firmware_management_protocol,
330 NULL, &no_handles,
331 (efi_handle_t **)&base_handle));
332
333 if (ret != EFI_SUCCESS) {
334 EFI_PRINT("ESRT There are no FMP instances\n");
335
336 ret = efi_esrt_allocate_install(0);
337 if (ret != EFI_SUCCESS) {
338 EFI_PRINT("ESRT failed to create table with 0 entries\n");
339 return ret;
340 }
341 return EFI_SUCCESS;
342 }
343
344 EFI_PRINT("ESRT populate esrt from (%zd) available FMP handles\n",
345 no_handles);
346
347
348
349
350
351 it_handle = base_handle;
352 for (u32 idx = 0; idx < no_handles; idx++, it_handle++) {
353 struct efi_firmware_image_descriptor *img_info = NULL;
354 size_t info_size = 0;
355 u32 desc_version = 0;
356 u8 desc_count = 0;
357 size_t desc_size = 0;
358 u32 package_version;
359 u16 *package_version_name;
360
361 ret = efi_search_protocol(*it_handle,
362 &efi_guid_firmware_management_protocol,
363 &handler);
364
365 if (ret != EFI_SUCCESS) {
366 EFI_PRINT("ESRT Unable to find FMP handle (%u)\n",
367 idx);
368 goto out;
369 }
370 fmp = handler->protocol_interface;
371
372 ret = EFI_CALL(fmp->get_image_info(fmp, &info_size, NULL,
373 &desc_version, &desc_count,
374 &desc_size, &package_version,
375 &package_version_name));
376
377 if (ret != EFI_BUFFER_TOO_SMALL) {
378
379
380
381
382 EFI_PRINT("ESRT erroneous FMP implementation\n");
383 ret = EFI_INVALID_PARAMETER;
384 goto out;
385 }
386
387 ret = efi_allocate_pool(EFI_BOOT_SERVICES_DATA, info_size,
388 (void **)&img_info);
389 if (ret != EFI_SUCCESS) {
390 EFI_PRINT("ESRT failed to allocate memory for image info\n");
391 goto out;
392 }
393
394
395
396
397
398
399
400
401 ret = EFI_CALL(fmp->get_image_info(fmp, &info_size, img_info,
402 &desc_version, &desc_count,
403 &desc_size, &package_version,
404 &package_version_name));
405
406 if (ret != EFI_SUCCESS) {
407 EFI_PRINT("ESRT failed to obtain image info from FMP\n");
408 efi_free_pool(img_info);
409 goto out;
410 }
411
412 num_entries += desc_count;
413
414 efi_free_pool(img_info);
415 }
416
417 EFI_PRINT("ESRT create table with %u entries\n", num_entries);
418
419
420
421
422 ret = efi_esrt_allocate_install(num_entries);
423 if (ret != EFI_SUCCESS) {
424 EFI_PRINT("ESRT failed to initialize table\n");
425 goto out;
426 }
427
428
429
430
431 it_handle = base_handle;
432 for (u32 idx = 0; idx < no_handles; idx++, it_handle++) {
433 ret = efi_search_protocol(*it_handle,
434 &efi_guid_firmware_management_protocol,
435 &handler);
436
437 if (ret != EFI_SUCCESS) {
438 EFI_PRINT("ESRT unable to find FMP handle (%u)\n",
439 idx);
440 break;
441 }
442 fmp = handler->protocol_interface;
443
444 ret = efi_esrt_add_from_fmp(fmp);
445 if (ret != EFI_SUCCESS)
446 EFI_PRINT("ESRT failed to add FMP to the table\n");
447 }
448
449out:
450
451 efi_free_pool(base_handle);
452
453 return ret;
454}
455
456
457
458
459
460static void EFIAPI efi_esrt_new_fmp_notify(struct efi_event *event,
461 void *context)
462{
463 efi_status_t ret;
464
465 EFI_ENTRY();
466
467 ret = efi_esrt_populate();
468 if (ret != EFI_SUCCESS)
469 EFI_PRINT("ESRT failed to populate ESRT entry\n");
470
471 EFI_EXIT(ret);
472}
473
474
475
476
477
478
479efi_status_t efi_esrt_register(void)
480{
481 struct efi_event *ev = NULL;
482 void *registration;
483 efi_status_t ret;
484
485 EFI_PRINT("ESRT creation start\n");
486
487 ret = efi_esrt_populate();
488 if (ret != EFI_SUCCESS) {
489 EFI_PRINT("ESRT failed to initiate the table\n");
490 return ret;
491 }
492
493 ret = efi_create_event(EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
494 efi_esrt_new_fmp_notify, NULL, NULL, &ev);
495 if (ret != EFI_SUCCESS) {
496 EFI_PRINT("ESRT failed to create event\n");
497 return ret;
498 }
499
500 ret = EFI_CALL(efi_register_protocol_notify(&efi_guid_firmware_management_protocol,
501 ev, ®istration));
502 if (ret != EFI_SUCCESS) {
503 EFI_PRINT("ESRT failed to register FMP callback\n");
504 return ret;
505 }
506
507 EFI_PRINT("ESRT table created\n");
508
509 return ret;
510}
511