1 /* BPDT version 1.7 support */
2 /* SPDX-License-Identifier: GPL-2.0-only */
6 #include "cse_serger.h"
9 BPDT_FLAGS_REDUNDANCY_SUPPORTED
= 1 << 0,
13 uint32_t signature
; /* BPDT_SIGNATURE */
14 uint16_t descriptor_count
;
15 uint8_t version
; /* Layout 1.7 = 2 */
16 uint8_t flags
; /* See enum bpdt_flags */
18 uint32_t ifwi_version
;
28 uint8_t rom_bypass
[16];
44 uint32_t temp_base_addr
;
45 uint32_t temp_base_size
;
50 static bool match_version(const struct buffer
*buff
)
52 const uint8_t *data
= buffer_get(buff
);
53 const uint32_t sig
= read_le32(data
);
54 const uint8_t version
= read_at_le8(data
, offsetof(struct bpdt_header
, version
));
56 if (sig
!= BPDT_SIGNATURE
) {
57 ERROR("Invalid BPDT signature(0x%x)!\n", sig
);
61 return version
== BPDT_VERSION_1_7
;
64 static bpdt_hdr_ptr
create_bpdt_hdr(void)
66 struct bpdt_header
*h
= calloc(1, sizeof(*h
));
71 h
->signature
= BPDT_SIGNATURE
;
72 h
->descriptor_count
= 0;
73 h
->version
= BPDT_VERSION_1_7
;
77 h
->fit_tool_version
.major
= 0;
78 h
->fit_tool_version
.minor
= 0;
79 h
->fit_tool_version
.build
= 0;
80 h
->fit_tool_version
.hotfix
= 0;
85 static void print_bpdt_hdr(const bpdt_hdr_ptr ptr
)
87 struct bpdt_header
*h
= ptr
;
89 printf(" * BPDT header\n");
90 printf("%-25s 0x%-23.8x\n", "Signature", h
->signature
);
91 printf("%-25s %-25d\n", "Descriptor count", h
->descriptor_count
);
92 printf("%-25s %d (Layout 1.7)\n", "BPDT Version", h
->version
);
93 printf("%-25s 0x%-23x\n", "Flags", h
->flags
);
94 printf("%-25s 0x%-23x\n", "Checksum", h
->checksum
);
95 printf("%-25s 0x%-23x\n", "IFWI Version", h
->ifwi_version
);
96 printf("%-25s %d.%d.%d.%d(%.2x.%.2x.%.2x.%.2x)\n", "FIT Tool Version",
97 h
->fit_tool_version
.major
, h
->fit_tool_version
.minor
,
98 h
->fit_tool_version
.build
, h
->fit_tool_version
.hotfix
,
99 h
->fit_tool_version
.major
, h
->fit_tool_version
.minor
,
100 h
->fit_tool_version
.build
, h
->fit_tool_version
.hotfix
);
103 static bpdt_hdr_ptr
read_bpdt_hdr(struct buffer
*buff
)
105 struct bpdt_header
*h
= calloc(1, sizeof(*h
));
110 READ_MEMBER(buff
, h
->signature
);
111 READ_MEMBER(buff
, h
->descriptor_count
);
112 READ_MEMBER(buff
, h
->version
);
113 READ_MEMBER(buff
, h
->flags
);
114 READ_MEMBER(buff
, h
->checksum
);
115 READ_MEMBER(buff
, h
->ifwi_version
);
116 READ_MEMBER(buff
, h
->fit_tool_version
);
121 static int write_bpdt_hdr(struct buffer
*buff
, const bpdt_hdr_ptr ptr
)
123 struct bpdt_header
*h
= ptr
;
125 if (buffer_size(buff
) < sizeof(struct bpdt_header
)) {
126 ERROR("Not enough size in buffer for BPDT header!\n");
130 WRITE_MEMBER(buff
, h
->signature
);
131 WRITE_MEMBER(buff
, h
->descriptor_count
);
132 WRITE_MEMBER(buff
, h
->version
);
133 WRITE_MEMBER(buff
, h
->flags
);
134 WRITE_MEMBER(buff
, h
->checksum
);
135 WRITE_MEMBER(buff
, h
->ifwi_version
);
136 WRITE_MEMBER(buff
, h
->fit_tool_version
);
141 static size_t get_bpdt_entry_count(const bpdt_hdr_ptr ptr
)
143 return ((const struct bpdt_header
*)ptr
)->descriptor_count
;
146 static void inc_bpdt_entry_count(bpdt_hdr_ptr ptr
)
148 struct bpdt_header
*h
= ptr
;
149 h
->descriptor_count
++;
152 static uint32_t crc32(uint32_t seed
, const uint8_t *data
, size_t len
)
156 for (size_t i
= 0; i
< len
; i
++) {
159 for (size_t b
= 0; b
< 8; b
++) {
161 crc
= (crc
>> 1) ^ 0xedb88320;
171 * Calculate checksum by:
172 * a. stashing l->checksum in curr_checksum and setting l->checksum to 0
173 * b. calculating checksum
174 * c. restoring l->checksum and return calculated checksum value.
176 static uint32_t calculate_layout_checksum(struct cse_layout
*l
)
178 uint32_t curr_checksum
= l
->checksum
;
179 uint32_t calc_checksum
;
182 calc_checksum
= ~crc32(0xffffffff, (void *)&l
->size
, l
->size
);
183 l
->checksum
= curr_checksum
;
185 return calc_checksum
;
188 static cse_layout_ptr
create_cse_layout(const struct region
*r
)
190 struct cse_layout
*l
= calloc(1, sizeof(*l
));
195 memset(l
->rom_bypass
, 0xff, sizeof(l
->rom_bypass
));
196 l
->size
= sizeof(struct cse_layout
) - sizeof(l
->rom_bypass
);
199 l
->data_offset
= region_offset(&r
[DP
]);
200 l
->data_size
= region_sz(&r
[DP
]);
201 l
->bp1_offset
= region_offset(&r
[BP1
]);
202 l
->bp1_size
= region_sz(&r
[BP1
]);
203 l
->bp2_offset
= region_offset(&r
[BP2
]);
204 l
->bp2_size
= region_sz(&r
[BP2
]);
205 l
->bp3_offset
= region_offset(&r
[BP3
]);
206 l
->bp3_size
= region_sz(&r
[BP3
]);
207 l
->bp4_offset
= region_offset(&r
[BP4
]);
208 l
->bp4_size
= region_sz(&r
[BP4
]);
211 l
->temp_base_addr
= 0;
212 l
->temp_base_size
= 0;
216 l
->checksum
= calculate_layout_checksum(l
);
221 static void print_cse_layout(const cse_layout_ptr ptr
)
223 struct cse_layout
*l
= ptr
;
225 printf(" * CSE Layout\n\n");
226 printf("ROM Bypass: ");
227 for (size_t i
= 0; i
< sizeof(l
->rom_bypass
); i
++)
228 printf("0x%x ", l
->rom_bypass
[i
]);
230 printf("Size: 0x%x\n", l
->size
);
231 printf("Redundancy: 0x%x\n", l
->redundancy
);
232 printf("Checksum: 0x%x\n", l
->checksum
);
233 printf("Data partition offset: 0x%x\n", l
->data_offset
);
234 printf("Data partition size: 0x%x\n", l
->data_size
);
235 printf("BP1 offset: 0x%x\n", l
->bp1_offset
);
236 printf("BP1 size: 0x%x\n", l
->bp1_size
);
237 printf("BP2 offset: 0x%x\n", l
->bp2_offset
);
238 printf("BP2 size: 0x%x\n", l
->bp2_size
);
239 printf("BP3 offset: 0x%x\n", l
->bp3_offset
);
240 printf("BP3 size: 0x%x\n", l
->bp3_size
);
241 printf("BP4 offset: 0x%x\n", l
->bp4_offset
);
242 printf("BP4 size: 0x%x\n", l
->bp4_size
);
243 printf("BP5 offset: 0x%x\n", l
->bp5_offset
);
244 printf("BP5 size: 0x%x\n", l
->bp5_size
);
245 printf("Temp base addr: 0x%x\n", l
->temp_base_addr
);
246 printf("Temp base size: 0x%x\n", l
->temp_base_size
);
247 printf("FLOG offset: 0x%x\n", l
->flog_offset
);
248 printf("FLOG size: 0x%x\n", l
->flog_size
);
251 static cse_layout_ptr
read_cse_layout(struct buffer
*buff
)
253 struct cse_layout
*l
= calloc(1, sizeof(*l
));
258 READ_MEMBER(buff
, l
->rom_bypass
);
259 READ_MEMBER(buff
, l
->size
);
260 READ_MEMBER(buff
, l
->redundancy
);
261 READ_MEMBER(buff
, l
->checksum
);
262 READ_MEMBER(buff
, l
->data_offset
);
263 READ_MEMBER(buff
, l
->data_size
);
264 READ_MEMBER(buff
, l
->bp1_offset
);
265 READ_MEMBER(buff
, l
->bp1_size
);
266 READ_MEMBER(buff
, l
->bp2_offset
);
267 READ_MEMBER(buff
, l
->bp2_size
);
268 READ_MEMBER(buff
, l
->bp3_offset
);
269 READ_MEMBER(buff
, l
->bp3_size
);
270 READ_MEMBER(buff
, l
->bp4_offset
);
271 READ_MEMBER(buff
, l
->bp4_size
);
272 READ_MEMBER(buff
, l
->bp5_offset
);
273 READ_MEMBER(buff
, l
->bp5_size
);
274 READ_MEMBER(buff
, l
->temp_base_addr
);
275 READ_MEMBER(buff
, l
->temp_base_size
);
276 READ_MEMBER(buff
, l
->flog_offset
);
277 READ_MEMBER(buff
, l
->flog_size
);
282 static int write_cse_layout(struct buffer
*buff
, const cse_layout_ptr ptr
)
284 struct cse_layout
*l
= ptr
;
286 if (buffer_size(buff
) < sizeof(struct cse_layout
)) {
287 ERROR("Not enough size in buffer for CSE layout!\n");
291 WRITE_MEMBER(buff
, l
->rom_bypass
);
292 WRITE_MEMBER(buff
, l
->size
);
293 WRITE_MEMBER(buff
, l
->redundancy
);
294 WRITE_MEMBER(buff
, l
->checksum
);
295 WRITE_MEMBER(buff
, l
->data_offset
);
296 WRITE_MEMBER(buff
, l
->data_size
);
297 WRITE_MEMBER(buff
, l
->bp1_offset
);
298 WRITE_MEMBER(buff
, l
->bp1_size
);
299 WRITE_MEMBER(buff
, l
->bp2_offset
);
300 WRITE_MEMBER(buff
, l
->bp2_size
);
301 WRITE_MEMBER(buff
, l
->bp3_offset
);
302 WRITE_MEMBER(buff
, l
->bp3_size
);
303 WRITE_MEMBER(buff
, l
->bp4_offset
);
304 WRITE_MEMBER(buff
, l
->bp4_size
);
305 WRITE_MEMBER(buff
, l
->bp5_offset
);
306 WRITE_MEMBER(buff
, l
->bp5_size
);
307 WRITE_MEMBER(buff
, l
->temp_base_addr
);
308 WRITE_MEMBER(buff
, l
->temp_base_size
);
309 WRITE_MEMBER(buff
, l
->flog_offset
);
310 WRITE_MEMBER(buff
, l
->flog_size
);
315 static uint32_t calculate_bpdt_checksum(struct bpdt_header
*h
, struct bpdt_entry
*e
)
317 uint32_t calc_checksum
;
318 uint32_t curr_checksum
= h
->checksum
;
322 calc_checksum
= crc32(0xffffffff, (void *)&h
->descriptor_count
,
323 sizeof(*h
) - sizeof(h
->signature
));
325 if (e
&& h
->descriptor_count
)
326 calc_checksum
= crc32(calc_checksum
, (void *)e
,
327 h
->descriptor_count
* sizeof(struct bpdt_entry
));
329 h
->checksum
= curr_checksum
;
331 return ~calc_checksum
;
334 static void update_checksum(bpdt_hdr_ptr ptr
, struct bpdt_entry
*e
)
336 struct bpdt_header
*h
= ptr
;
337 h
->checksum
= calculate_bpdt_checksum(h
, e
);
340 static bool validate_checksum(bpdt_hdr_ptr ptr
, struct bpdt_entry
*e
)
342 struct bpdt_header
*h
= ptr
;
343 return calculate_bpdt_checksum(h
, e
) == h
->checksum
;
346 const struct bpdt_ops bpdt_1_7_ops
= {
347 .match_version
= match_version
,
349 .create_hdr
= create_bpdt_hdr
,
350 .print_hdr
= print_bpdt_hdr
,
351 .read_hdr
= read_bpdt_hdr
,
352 .write_hdr
= write_bpdt_hdr
,
354 .get_entry_count
= get_bpdt_entry_count
,
355 .inc_entry_count
= inc_bpdt_entry_count
,
357 .create_layout
= create_cse_layout
,
358 .print_layout
= print_cse_layout
,
359 .read_layout
= read_cse_layout
,
360 .write_layout
= write_cse_layout
,
362 .update_checksum
= update_checksum
,
363 .validate_checksum
= validate_checksum
,
365 .subpart_hdr_version
= SUBPART_HDR_VERSION_2
,
366 .subpart_entry_version
= SUBPART_ENTRY_VERSION_1
,