1 /*
2 * Copyright (c) 2021, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 #include "uefi_capsule_parser.h"
9 #include "fwu_agent.h"
10 #include <string.h>
11
12 /*
13 Update Capsule Structure (UEFI spec 2.9 1004)
14 EFI_CAPSULE_HEADER
15 ...
16 ...
17 ...
18 CAPSULE_BODY
19 efi_firmware_management_capsule_header
20 Optional Driver 1 (item_offset[0])
21 Optional Driver 2 (item_offset[1])
22 Payload 1 (item_offset[2])
23 efi_firmware_management_capsule_iamge_header
24 Binary Update image (Image_length == update_image_size)
25 Vendor Code bytes (Data lenght == update_vendorcode_size)
26 Payload 2 (item_offset[3])
27 ...
28 ...
29 Payload n (item_offset[embedded_driver_count + payload_item_count -1])
30 */
31
32 typedef struct {
33 struct efi_guid capsule_guid;
34 uint32_t header_size;
35 uint32_t flags;
36 uint32_t capsule_image_size;
37 } efi_capsule_header_t;
38
39 typedef struct {
40 uint32_t version;
41 uint16_t embedded_driver_count;
42 uint16_t payload_item_count;
43 uint64_t item_offset_list[];
44 } efi_firmware_management_capsule_header_t;
45
46 typedef struct {
47 uint32_t version;
48 struct efi_guid update_image_type_id;
49 uint8_t update_image_index;
50 uint8_t reserved_bytes[3];
51 uint32_t update_image_size;
52 uint32_t update_vendorcode_size;
53 uint64_t update_hardware_instance; //introduced in v2
54 uint64_t image_capsule_support; //introduced in v3
55 } efi_firmware_management_capsule_image_header_t;
56
57 typedef struct {
58 uint32_t signature;
59 uint32_t header_size;
60 uint32_t fw_version;
61 uint32_t lowest_supported_version;
62 } fmp_payload_header_t;
63
64 #define ANYSIZE_ARRAY 0
65
66 typedef struct {
67 uint32_t dwLength;
68 uint16_t wRevision;
69 uint16_t wCertificateType;
70 uint8_t bCertificate[ANYSIZE_ARRAY];
71 } WIN_CERTIFICATE;
72
73 typedef struct {
74 WIN_CERTIFICATE hdr;
75 struct efi_guid cert_type;
76 uint8_t cert_data[ANYSIZE_ARRAY];
77 } win_certificate_uefi_guid_t;
78
79 typedef struct {
80 uint64_t monotonic_count;
81 win_certificate_uefi_guid_t auth_info;
82 } efi_firmware_image_authentication_t;
83
84
uefi_capsule_retrieve_images(void * capsule_ptr,capsule_image_info_t * images_info)85 enum uefi_capsule_error_t uefi_capsule_retrieve_images(void* capsule_ptr,
86 capsule_image_info_t* images_info)
87 {
88 char *ptr = (char*)capsule_ptr;
89 efi_capsule_header_t* capsule_header;
90 efi_firmware_management_capsule_header_t* fmp_capsule_header;
91 efi_firmware_management_capsule_image_header_t* image_header;
92 efi_firmware_image_authentication_t* image_auth;
93 fmp_payload_header_t *fmp_payload_header;
94 uint32_t total_size;
95 uint32_t image_count;
96 uint32_t auth_size;
97
98 FWU_LOG_MSG("%s: enter, capsule ptr = 0x%p\n\r", __func__, capsule_ptr);
99
100 if (!capsule_ptr) {
101 return UEFI_CAPSULE_PARSER_ERROR;
102 }
103
104 capsule_header = (efi_capsule_header_t*)ptr;
105 ptr += sizeof(efi_capsule_header_t);
106 fmp_capsule_header = (efi_firmware_management_capsule_header_t*)ptr;
107
108 total_size = capsule_header->capsule_image_size;
109 image_count = fmp_capsule_header->payload_item_count;
110 images_info->nr_image = image_count;
111
112 FWU_LOG_MSG("%s: capsule size = %u, image count = %u\n\r", __func__,
113 total_size, image_count);
114
115 if ((image_count == 0) || (image_count > NR_OF_IMAGES_IN_FW_BANK)) {
116 return UEFI_CAPSULE_PARSER_ERROR;
117 }
118
119 for (int i = 0; i < image_count; i++) {
120 image_header = (efi_firmware_management_capsule_image_header_t*)(ptr +
121 fmp_capsule_header->item_offset_list[i]);
122
123 images_info->size[i] = image_header->update_image_size;
124
125 #ifdef AUTHENTICATED_CAPSULE
126 image_auth = (efi_firmware_image_authentication_t*)(
127 (char*)image_header +
128 sizeof (efi_firmware_management_capsule_image_header_t)
129 );
130 auth_size = sizeof(uint64_t) /* monotonic_count */ +
131 image_auth->auth_info.hdr.dwLength/* WIN_CERTIFICATE + cert_data + cert_type */;
132
133 fmp_payload_header = (fmp_payload_header_t*)((char*)image_auth + auth_size);
134
135 FWU_LOG_MSG("%s: auth size = %u\n\r", __func__, auth_size);
136
137 images_info->size[i] -= auth_size;
138
139 images_info->image[i] = (
140 (char*)image_header +
141 sizeof(efi_firmware_management_capsule_image_header_t) +
142 auth_size +
143 sizeof(*fmp_payload_header));
144 #else
145 images_info->image[i] = (
146 (char*)image_header +
147 sizeof(efi_firmware_management_capsule_image_header_t) +
148 sizeof(*fmp_payload_header));
149
150 fmp_payload_header = (fmp_payload_header_t*)((char*)image_header +
151 sizeof(efi_firmware_management_capsule_image_header_t));
152
153 #endif
154 memcpy(&images_info->guid[i], &(image_header->update_image_type_id),
155 sizeof(struct efi_guid));
156
157 images_info->version[i] = fmp_payload_header->fw_version;
158 FWU_LOG_MSG("%s: image %i version = %d\n\r", __func__, i,
159 images_info->version[i]);
160
161 FWU_LOG_MSG("%s: image %d at %p, size=%u\n\r", __func__, i,
162 images_info->image[i], images_info->size[i]);
163
164 if ((fmp_capsule_header->item_offset_list[i] +
165 sizeof(efi_firmware_management_capsule_image_header_t) +
166 image_header->update_image_size) > total_size)
167 {
168 return UEFI_CAPSULE_PARSER_ERROR;
169 }
170
171 }
172
173 FWU_LOG_MSG("%s: exit\n\r", __func__);
174 return UEFI_CAPSULE_PARSER_SUCCESS;
175 }
176