File: | util/nvidia/cbootimage/src/data_layout.c |
Warning: | line 604, column 12 Potential leak of memory pointed to by 'hash_buffer' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | |||
2 | * Copyright (c) 2012-2014, NVIDIA CORPORATION. All rights reserved. | |||
3 | * | |||
4 | * This program is free software; you can redistribute it and/or modify it | |||
5 | * under the terms and conditions of the GNU General Public License, | |||
6 | * version 2, as published by the Free Software Foundation. | |||
7 | * | |||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | |||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |||
11 | * more details. | |||
12 | * | |||
13 | * You should have received a copy of the GNU General Public License | |||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
15 | * | |||
16 | * See file CREDITS for list of people who contributed to this | |||
17 | * project. | |||
18 | */ | |||
19 | ||||
20 | /* | |||
21 | * data_layout.c - Code to manage the layout of data in the boot device. | |||
22 | * | |||
23 | */ | |||
24 | ||||
25 | #include "data_layout.h" | |||
26 | #include "cbootimage.h" | |||
27 | #include "crypto.h" | |||
28 | #include "set.h" | |||
29 | #include "context.h" | |||
30 | #include "parse.h" | |||
31 | #include <sys/param.h> | |||
32 | ||||
33 | typedef struct blk_data_rec | |||
34 | { | |||
35 | uint32_t blk_number; | |||
36 | uint32_t pages_used; /* pages always used starting from 0. */ | |||
37 | uint8_t *data; | |||
38 | ||||
39 | /* Pointer to ECC errors? */ | |||
40 | ||||
41 | struct blk_data_rec *next; | |||
42 | } block_data; | |||
43 | ||||
44 | /* Function prototypes */ | |||
45 | static block_data | |||
46 | *new_block(uint32_t blk_number, uint32_t block_size); | |||
47 | static block_data | |||
48 | *find_block(uint32_t blk_number, block_data *block_list); | |||
49 | static block_data | |||
50 | *add_block(uint32_t blk_number, block_data **block_list, | |||
51 | uint32_t block_size); | |||
52 | static int | |||
53 | erase_block(build_image_context *context, uint32_t blk_number); | |||
54 | ||||
55 | static int | |||
56 | write_page(build_image_context *context, | |||
57 | uint32_t blk_number, | |||
58 | uint32_t page_number, | |||
59 | uint8_t *data); | |||
60 | ||||
61 | static void | |||
62 | insert_padding(uint8_t *data, uint32_t length); | |||
63 | ||||
64 | static void | |||
65 | write_padding(uint8_t *data, uint32_t length); | |||
66 | ||||
67 | static int write_bct(build_image_context *context, | |||
68 | uint32_t block, | |||
69 | uint32_t bct_slot); | |||
70 | ||||
71 | static void | |||
72 | set_bl_data(build_image_context *context, | |||
73 | uint32_t instance, | |||
74 | uint32_t start_blk, | |||
75 | uint32_t start_page, | |||
76 | uint32_t length); | |||
77 | ||||
78 | static int write_image(build_image_context *context, file_type image_type); | |||
79 | ||||
80 | static void find_new_bct_blk(build_image_context *context); | |||
81 | static int finish_update(build_image_context *context); | |||
82 | ||||
83 | uint32_t | |||
84 | iceil_log2(uint32_t a, uint32_t b) | |||
85 | { | |||
86 | return (a + (1 << b) - 1) >> b; | |||
87 | } | |||
88 | ||||
89 | /* Returns the smallest power of 2 >= a */ | |||
90 | uint32_t | |||
91 | ceil_log2(uint32_t a) | |||
92 | { | |||
93 | uint32_t result; | |||
94 | ||||
95 | result = log2(a); | |||
96 | if ((1UL << result) < a) | |||
97 | result++; | |||
98 | ||||
99 | return result; | |||
100 | } | |||
101 | ||||
102 | static block_data *new_block(uint32_t blk_number, uint32_t block_size) | |||
103 | { | |||
104 | block_data *new_block = malloc(sizeof(block_data)); | |||
105 | if (new_block == NULL((void*)0)) | |||
106 | return NULL((void*)0); | |||
107 | ||||
108 | new_block->blk_number = blk_number; | |||
109 | new_block->pages_used = 0; | |||
110 | new_block->data = malloc(block_size); | |||
111 | if (new_block->data == NULL((void*)0)) { | |||
112 | free(new_block); | |||
113 | return NULL((void*)0); | |||
114 | } | |||
115 | new_block->next = NULL((void*)0); | |||
116 | ||||
117 | memset(new_block->data, 0, block_size); | |||
118 | ||||
119 | return new_block; | |||
120 | } | |||
121 | ||||
122 | block_data *new_block_list(void) | |||
123 | { | |||
124 | return NULL((void*)0); | |||
125 | } | |||
126 | ||||
127 | void destroy_block_list(block_data *block_list) | |||
128 | { | |||
129 | block_data *next; | |||
130 | ||||
131 | while (block_list) { | |||
132 | next = block_list->next; | |||
133 | free(block_list->data); | |||
134 | free(block_list); | |||
135 | block_list = next; | |||
136 | } | |||
137 | } | |||
138 | ||||
139 | static block_data *find_block(uint32_t blk_number, block_data *block_list) | |||
140 | { | |||
141 | while (block_list) { | |||
142 | if (block_list->blk_number == blk_number) | |||
143 | return block_list; | |||
144 | ||||
145 | block_list = block_list->next; | |||
146 | } | |||
147 | ||||
148 | return NULL((void*)0); | |||
149 | } | |||
150 | ||||
151 | /* Returns pointer to block after adding it to block_list, if needed. */ | |||
152 | static block_data *add_block(uint32_t blk_number, | |||
153 | block_data **block_list, | |||
154 | uint32_t block_size) | |||
155 | { | |||
156 | block_data *block = find_block(blk_number,*block_list); | |||
157 | block_data *parent; | |||
158 | ||||
159 | if (block == NULL((void*)0)) { | |||
160 | block = new_block(blk_number, block_size); | |||
161 | if (block == NULL((void*)0)) | |||
162 | return block; | |||
163 | ||||
164 | /* Insert block into the list */ | |||
165 | if ((*block_list == NULL((void*)0)) || | |||
166 | (blk_number < (*block_list)->blk_number)) { | |||
167 | block->next = *block_list; | |||
168 | *block_list = block; | |||
169 | } else { | |||
170 | /* Search for the correct place to insert the block. */ | |||
171 | parent = *block_list; | |||
172 | while (parent->next != NULL((void*)0) && | |||
173 | parent->next->blk_number < blk_number) { | |||
174 | parent = parent->next; | |||
175 | } | |||
176 | ||||
177 | block->next = parent->next; | |||
178 | parent->next = block; | |||
179 | } | |||
180 | } | |||
181 | ||||
182 | return block; | |||
183 | } | |||
184 | ||||
185 | static int | |||
186 | erase_block(build_image_context *context, uint32_t blk_number) | |||
187 | { | |||
188 | block_data *block; | |||
189 | ||||
190 | assert(context != NULL)((context != ((void*)0)) ? (void) (0) : __assert_fail ("context != NULL" , "util/nvidia/cbootimage/src/data_layout.c", 190, __extension__ __PRETTY_FUNCTION__)); | |||
191 | ||||
192 | block = add_block(blk_number, &(context->memory), context->block_size); | |||
193 | ||||
194 | if (block == NULL((void*)0)) | |||
195 | return -ENOMEM12; | |||
196 | if (block->data == NULL((void*)0)) | |||
197 | return -ENOMEM12; | |||
198 | ||||
199 | memset(block->data, 0, context->block_size); | |||
200 | block->pages_used = 0; | |||
201 | return 0; | |||
202 | } | |||
203 | ||||
204 | static int | |||
205 | write_page(build_image_context *context, | |||
206 | uint32_t blk_number, | |||
207 | uint32_t page_number, | |||
208 | uint8_t *data) | |||
209 | { | |||
210 | block_data *block; | |||
211 | uint8_t *page_ptr; | |||
212 | ||||
213 | assert(context)((context) ? (void) (0) : __assert_fail ("context", "util/nvidia/cbootimage/src/data_layout.c" , 213, __extension__ __PRETTY_FUNCTION__)); | |||
214 | ||||
215 | block = add_block(blk_number, &(context->memory), context->block_size); | |||
216 | ||||
217 | if (block == NULL((void*)0)) | |||
218 | return -ENOMEM12; | |||
219 | if (block->data == NULL((void*)0)) | |||
220 | return -ENOMEM12; | |||
221 | if (((page_number + 1) * context->page_size) > context->block_size) { | |||
222 | printf("Page number outside block; likely config file error.\n"); | |||
223 | return -ENOMEM12; | |||
224 | } | |||
225 | ||||
226 | if (block->pages_used != page_number) { | |||
227 | printf("Warning: Writing page in block out of order.\n"); | |||
228 | printf(" block=%d page=%d\n", blk_number, page_number); | |||
229 | } | |||
230 | ||||
231 | page_ptr = block->data + (page_number * context->page_size); | |||
232 | memcpy(page_ptr, data, context->page_size); | |||
233 | if (block->pages_used < (page_number+1)) | |||
234 | block->pages_used = page_number+1; | |||
235 | return 0; | |||
236 | } | |||
237 | ||||
238 | static void | |||
239 | insert_padding(uint8_t *data, uint32_t length) | |||
240 | { | |||
241 | uint32_t aes_blks; | |||
242 | uint32_t remaining; | |||
243 | ||||
244 | aes_blks = iceil_log2(length, NVBOOT_AES_BLOCK_SIZE_LOG24); | |||
245 | remaining = (aes_blks << NVBOOT_AES_BLOCK_SIZE_LOG24) - length; | |||
246 | ||||
247 | write_padding(data + length, remaining); | |||
248 | } | |||
249 | ||||
250 | static void | |||
251 | write_padding(uint8_t *p, uint32_t remaining) | |||
252 | { | |||
253 | uint8_t value = 0x80; | |||
254 | ||||
255 | while (remaining) { | |||
256 | *p++ = value; | |||
257 | remaining--; | |||
258 | value = 0x00; | |||
259 | } | |||
260 | } | |||
261 | ||||
262 | static int | |||
263 | write_bct(build_image_context *context, | |||
264 | uint32_t block, | |||
265 | uint32_t bct_slot) | |||
266 | { | |||
267 | uint32_t pagesremaining; | |||
268 | uint32_t page; | |||
269 | uint32_t pages_per_bct; | |||
270 | uint8_t *buffer; | |||
271 | uint8_t *data; | |||
272 | int err = 0; | |||
273 | ||||
274 | assert(context)((context) ? (void) (0) : __assert_fail ("context", "util/nvidia/cbootimage/src/data_layout.c" , 274, __extension__ __PRETTY_FUNCTION__)); | |||
275 | ||||
276 | pages_per_bct = iceil_log2(context->bct_size, context->page_size_log2); | |||
277 | pagesremaining = pages_per_bct; | |||
278 | page = bct_slot * pages_per_bct; | |||
279 | ||||
280 | /* Create a local copy of the BCT data */ | |||
281 | buffer = malloc(pages_per_bct * context->page_size); | |||
282 | if (buffer == NULL((void*)0)) | |||
283 | return -ENOMEM12; | |||
284 | memset(buffer, 0, pages_per_bct * context->page_size); | |||
285 | ||||
286 | memcpy(buffer, context->bct, context->bct_size); | |||
287 | ||||
288 | insert_padding(buffer, context->bct_size); | |||
289 | ||||
290 | /* Encrypt and compute hash */ | |||
291 | err = sign_bct(context, buffer); | |||
292 | if (err != 0) | |||
293 | goto fail; | |||
294 | ||||
295 | /* Write the BCT data to the storage device, picking up ECC errors */ | |||
296 | data = buffer; | |||
297 | while (pagesremaining > 0) { | |||
298 | err = write_page(context, block, page, data); | |||
299 | if (err != 0) | |||
300 | goto fail; | |||
301 | page++; | |||
302 | pagesremaining--; | |||
303 | data += context->page_size; | |||
304 | } | |||
305 | fail: | |||
306 | /* Cleanup */ | |||
307 | free(buffer); | |||
308 | return err; | |||
309 | } | |||
310 | ||||
311 | #define SET_BL_FIELD(instance, field, value)do { g_soc_config->setbl_param(instance, token_bl_field, & (value), context->bct); } while (0); \ | |||
312 | do { \ | |||
313 | g_soc_config->setbl_param(instance, \ | |||
314 | token_bl_##field, \ | |||
315 | &(value), \ | |||
316 | context->bct); \ | |||
317 | } while (0); | |||
318 | ||||
319 | #define GET_BL_FIELD(instance, field, ptr)g_soc_config->getbl_param(instance, token_bl_field, ptr, context ->bct); \ | |||
320 | g_soc_config->getbl_param(instance, \ | |||
321 | token_bl_##field, \ | |||
322 | ptr, \ | |||
323 | context->bct); | |||
324 | ||||
325 | #define COPY_BL_FIELD(from, to, field)do { uint32_t v; g_soc_config->getbl_param(from, token_bl_field , &v, context->bct);; do { g_soc_config->setbl_param (to, token_bl_field, &(v), context->bct); } while (0); ; } while (0); \ | |||
326 | do { \ | |||
327 | uint32_t v; \ | |||
328 | GET_BL_FIELD(from, field, &v)g_soc_config->getbl_param(from, token_bl_field, &v, context ->bct);; \ | |||
329 | SET_BL_FIELD(to, field, v)do { g_soc_config->setbl_param(to, token_bl_field, &(v ), context->bct); } while (0);; \ | |||
330 | } while (0); | |||
331 | ||||
332 | #define SET_MTS_FIELD(instance, field, value)do { g_soc_config->set_mts_info(context, instance, token_mts_info_field , value); } while (0); \ | |||
333 | do { \ | |||
334 | g_soc_config->set_mts_info(context, \ | |||
335 | instance, \ | |||
336 | token_mts_info_##field, \ | |||
337 | value); \ | |||
338 | } while (0); | |||
339 | ||||
340 | #define GET_MTS_FIELD(instance, field, ptr)g_soc_config->get_mts_info(context, instance, token_mts_info_field , ptr); \ | |||
341 | g_soc_config->get_mts_info(context, \ | |||
342 | instance, \ | |||
343 | token_mts_info_##field, \ | |||
344 | ptr); | |||
345 | ||||
346 | #define COPY_MTS_FIELD(from, to, field)do { uint32_t v; g_soc_config->get_mts_info(context, from, token_mts_info_field, &v);; do { g_soc_config->set_mts_info (context, to, token_mts_info_field, v); } while (0);; } while (0); \ | |||
347 | do { \ | |||
348 | uint32_t v; \ | |||
349 | GET_MTS_FIELD(from, field, &v)g_soc_config->get_mts_info(context, from, token_mts_info_field , &v);; \ | |||
350 | SET_MTS_FIELD(to, field, v)do { g_soc_config->set_mts_info(context, to, token_mts_info_field , v); } while (0);; \ | |||
351 | } while (0); | |||
352 | ||||
353 | #define SET_FIELD(is_bl, instance, field, value)do { if (is_bl) { do { g_soc_config->setbl_param(instance, token_bl_field, &(value), context->bct); } while (0); ; } else { do { g_soc_config->set_mts_info(context, instance , token_mts_info_field, value); } while (0);; } } while (0);\ | |||
354 | do { \ | |||
355 | if (is_bl) { \ | |||
356 | SET_BL_FIELD(instance, field,value)do { g_soc_config->setbl_param(instance, token_bl_field, & (value), context->bct); } while (0);; \ | |||
357 | } \ | |||
358 | else { \ | |||
359 | SET_MTS_FIELD(instance, field, value)do { g_soc_config->set_mts_info(context, instance, token_mts_info_field , value); } while (0);; \ | |||
360 | } \ | |||
361 | } while (0); | |||
362 | ||||
363 | #define GET_FIELD(is_bl, instance, field, ptr)do { if (is_bl) { g_soc_config->getbl_param(instance, token_bl_field , ptr, context->bct);; } else { g_soc_config->get_mts_info (context, instance, token_mts_info_field, ptr);; } } while (0 ); \ | |||
364 | do { \ | |||
365 | if (is_bl) { \ | |||
366 | GET_BL_FIELD(instance, field, ptr)g_soc_config->getbl_param(instance, token_bl_field, ptr, context ->bct);; \ | |||
367 | } \ | |||
368 | else { \ | |||
369 | GET_MTS_FIELD(instance, field, ptr)g_soc_config->get_mts_info(context, instance, token_mts_info_field , ptr);; \ | |||
370 | } \ | |||
371 | } while (0); | |||
372 | ||||
373 | #define COPY_FIELD(is_bl, from, to, field)do { if (is_bl) { do { uint32_t v; g_soc_config->getbl_param (from, token_bl_field, &v, context->bct);; do { g_soc_config ->setbl_param(to, token_bl_field, &(v), context->bct ); } while (0);; } while (0);; } else { do { uint32_t v; g_soc_config ->get_mts_info(context, from, token_mts_info_field, &v );; do { g_soc_config->set_mts_info(context, to, token_mts_info_field , v); } while (0);; } while (0);; } } while (0); \ | |||
374 | do { \ | |||
375 | if (is_bl) { \ | |||
376 | COPY_BL_FIELD(from, to, field)do { uint32_t v; g_soc_config->getbl_param(from, token_bl_field , &v, context->bct);; do { g_soc_config->setbl_param (to, token_bl_field, &(v), context->bct); } while (0); ; } while (0);; \ | |||
377 | } \ | |||
378 | else { \ | |||
379 | COPY_MTS_FIELD(from, to, field)do { uint32_t v; g_soc_config->get_mts_info(context, from, token_mts_info_field, &v);; do { g_soc_config->set_mts_info (context, to, token_mts_info_field, v); } while (0);; } while (0);; \ | |||
380 | } \ | |||
381 | } while (0); | |||
382 | ||||
383 | static void | |||
384 | set_bl_data(build_image_context *context, | |||
385 | uint32_t instance, | |||
386 | uint32_t start_blk, | |||
387 | uint32_t start_page, | |||
388 | uint32_t length) | |||
389 | { | |||
390 | assert(context)((context) ? (void) (0) : __assert_fail ("context", "util/nvidia/cbootimage/src/data_layout.c" , 390, __extension__ __PRETTY_FUNCTION__)); | |||
391 | ||||
392 | SET_BL_FIELD(instance, version, context->version)do { g_soc_config->setbl_param(instance, token_bl_version, &(context->version), context->bct); } while (0);; | |||
393 | SET_BL_FIELD(instance, start_blk, start_blk)do { g_soc_config->setbl_param(instance, token_bl_start_blk , &(start_blk), context->bct); } while (0);; | |||
394 | SET_BL_FIELD(instance, start_page, start_page)do { g_soc_config->setbl_param(instance, token_bl_start_page , &(start_page), context->bct); } while (0);; | |||
395 | SET_BL_FIELD(instance, length, length)do { g_soc_config->setbl_param(instance, token_bl_length, & (length), context->bct); } while (0);; | |||
396 | SET_BL_FIELD(instance, load_addr, context->newbl_load_addr)do { g_soc_config->setbl_param(instance, token_bl_load_addr , &(context->newbl_load_addr), context->bct); } while (0);; | |||
397 | SET_BL_FIELD(instance, entry_point, context->newbl_entry_point)do { g_soc_config->setbl_param(instance, token_bl_entry_point , &(context->newbl_entry_point), context->bct); } while (0);; | |||
398 | SET_BL_FIELD(instance, attribute, context->newbl_attr)do { g_soc_config->setbl_param(instance, token_bl_attribute , &(context->newbl_attr), context->bct); } while (0 );; | |||
399 | } | |||
400 | ||||
401 | static void | |||
402 | set_mts_data(build_image_context *context, | |||
403 | uint32_t instance, | |||
404 | uint32_t start_blk, | |||
405 | uint32_t start_page, | |||
406 | uint32_t length) | |||
407 | { | |||
408 | assert(context)((context) ? (void) (0) : __assert_fail ("context", "util/nvidia/cbootimage/src/data_layout.c" , 408, __extension__ __PRETTY_FUNCTION__)); | |||
409 | ||||
410 | SET_MTS_FIELD(instance, version, context->version)do { g_soc_config->set_mts_info(context, instance, token_mts_info_version , context->version); } while (0);; | |||
411 | SET_MTS_FIELD(instance, start_blk, start_blk)do { g_soc_config->set_mts_info(context, instance, token_mts_info_start_blk , start_blk); } while (0);; | |||
412 | SET_MTS_FIELD(instance, start_page, start_page)do { g_soc_config->set_mts_info(context, instance, token_mts_info_start_page , start_page); } while (0);; | |||
413 | SET_MTS_FIELD(instance, length, length)do { g_soc_config->set_mts_info(context, instance, token_mts_info_length , length); } while (0);; | |||
414 | SET_MTS_FIELD(instance, load_addr, context->mts_load_addr)do { g_soc_config->set_mts_info(context, instance, token_mts_info_load_addr , context->mts_load_addr); } while (0);; | |||
415 | SET_MTS_FIELD(instance, entry_point, context->mts_entry_point)do { g_soc_config->set_mts_info(context, instance, token_mts_info_entry_point , context->mts_entry_point); } while (0);; | |||
416 | SET_MTS_FIELD(instance, attribute, context->mts_attr)do { g_soc_config->set_mts_info(context, instance, token_mts_info_attribute , context->mts_attr); } while (0);; | |||
417 | } | |||
418 | ||||
419 | #define SET_DATA(is_bl, context, instance, start_blk, start_page, length)do { if (is_bl) set_bl_data(context, instance, start_blk, start_page , length); else set_mts_data(context, instance, start_blk, start_page , length); } while (0); \ | |||
420 | do { \ | |||
421 | if (is_bl) \ | |||
422 | set_bl_data(context, instance, start_blk, start_page, length); \ | |||
423 | else \ | |||
424 | set_mts_data(context, instance, start_blk, start_page, length); \ | |||
425 | } while (0); | |||
426 | ||||
427 | /* | |||
428 | * Load the image then update it with the information from config file. | |||
429 | * In the interest of expediency, all image's allocated from bottom to top | |||
430 | * start at page 0 of a block, and all image's allocated from top to bottom | |||
431 | * end at the end of a block. | |||
432 | * | |||
433 | * @param context The main context pointer | |||
434 | * @param image_type The image type. Can be file_type_bl or file_type_mts | |||
435 | * only right now | |||
436 | * @return 0 for success | |||
437 | */ | |||
438 | static int | |||
439 | write_image(build_image_context *context, file_type image_type) | |||
440 | { | |||
441 | uint32_t i, j; | |||
442 | uint32_t image_instance; | |||
443 | uint32_t image_move_count = 0; | |||
444 | uint32_t image_move_remaining; | |||
445 | uint32_t current_blk; | |||
446 | uint32_t current_page; | |||
447 | uint32_t pages_in_image; | |||
448 | uint32_t image_used; | |||
449 | uint8_t *image_storage; /* Holds the image after reading */ | |||
450 | uint8_t *buffer; /* Holds the image for writing */ | |||
451 | uint8_t *src; /* Scans through the image during writing */ | |||
452 | uint32_t image_actual_size; /* In bytes */ | |||
453 | uint32_t pagesremaining; | |||
454 | uint32_t virtual_blk; | |||
455 | uint32_t pages_per_blk; | |||
456 | uint32_t image_version; | |||
457 | uint8_t *hash_buffer; | |||
458 | uint32_t hash_size; | |||
459 | uint32_t image_max; | |||
460 | parse_token token; | |||
461 | int err = 0, is_bl; | |||
462 | ||||
463 | assert(context)((context) ? (void) (0) : __assert_fail ("context", "util/nvidia/cbootimage/src/data_layout.c" , 463, __extension__ __PRETTY_FUNCTION__)); | |||
| ||||
464 | ||||
465 | /* Only support bootloader and mts image right now */ | |||
466 | if (image_type == file_type_bl) { | |||
467 | is_bl = 1; | |||
468 | } | |||
469 | else if (image_type == file_type_mts) { | |||
470 | is_bl = 0; | |||
471 | } | |||
472 | else { | |||
473 | printf("Not supported image type!\n"); | |||
474 | return -EINVAL22; | |||
475 | } | |||
476 | ||||
477 | pages_per_blk = 1 << (context->block_size_log2 | |||
478 | - context->page_size_log2); | |||
479 | ||||
480 | g_soc_config->get_value(token_hash_size, | |||
481 | &hash_size, context->bct); | |||
482 | token = is_bl
| |||
483 | g_soc_config->get_value(token, &image_max, context->bct); | |||
484 | ||||
485 | hash_buffer = calloc(1, hash_size); | |||
486 | if (hash_buffer == NULL((void*)0)) | |||
487 | return -ENOMEM12; | |||
488 | ||||
489 | if (enable_debug) { | |||
490 | printf("writing %s\n", is_bl ? "bootloader" : "mts image"); | |||
491 | printf(" redundancy = %d\n", context->redundancy); | |||
492 | } | |||
493 | ||||
494 | /* Make room for the image in the BCT. */ | |||
495 | ||||
496 | /* Determine how many to move. | |||
497 | * Note that this code will count Mts[0] only if there is already | |||
498 | * a mts in the device. | |||
499 | */ | |||
500 | GET_FIELD(is_bl, 0, version, &image_version)do { if (is_bl) { g_soc_config->getbl_param(0, token_bl_version , &image_version, context->bct);; } else { g_soc_config ->get_mts_info(context, 0, token_mts_info_version, &image_version );; } } while (0);; | |||
501 | token = is_bl
| |||
502 | g_soc_config->get_value(token, &image_used, context->bct); | |||
503 | for (image_instance = 0; image_instance < image_used; image_instance++) { | |||
504 | uint32_t tmp; | |||
505 | GET_FIELD(is_bl, image_instance, version, &tmp)do { if (is_bl) { g_soc_config->getbl_param(image_instance , token_bl_version, &tmp, context->bct);; } else { g_soc_config ->get_mts_info(context, image_instance, token_mts_info_version , &tmp);; } } while (0);; | |||
506 | if (tmp == image_version) | |||
507 | image_move_count++; | |||
508 | } | |||
509 | ||||
510 | /* Adjust the move count, if needed, to avoid overflowing the mts table. | |||
511 | * This can happen due to too much redundancy. | |||
512 | */ | |||
513 | image_move_count = MIN(image_move_count, image_max - context->redundancy)(((image_move_count)<(image_max - context->redundancy)) ?(image_move_count):(image_max - context->redundancy)); | |||
514 | ||||
515 | /* Move the mts entries down. */ | |||
516 | image_move_remaining = image_move_count; | |||
517 | while (image_move_remaining > 0) { | |||
518 | uint32_t inst_from = image_move_remaining - 1; | |||
519 | uint32_t inst_to = | |||
520 | image_move_remaining + context->redundancy - 1; | |||
521 | ||||
522 | COPY_FIELD(is_bl, inst_from, inst_to, version)do { if (is_bl) { do { uint32_t v; g_soc_config->getbl_param (inst_from, token_bl_version, &v, context->bct);; do { g_soc_config->setbl_param(inst_to, token_bl_version, & (v), context->bct); } while (0);; } while (0);; } else { do { uint32_t v; g_soc_config->get_mts_info(context, inst_from , token_mts_info_version, &v);; do { g_soc_config->set_mts_info (context, inst_to, token_mts_info_version, v); } while (0);; } while (0);; } } while (0);; | |||
523 | COPY_FIELD(is_bl, inst_from, inst_to, start_blk)do { if (is_bl) { do { uint32_t v; g_soc_config->getbl_param (inst_from, token_bl_start_blk, &v, context->bct);; do { g_soc_config->setbl_param(inst_to, token_bl_start_blk, & (v), context->bct); } while (0);; } while (0);; } else { do { uint32_t v; g_soc_config->get_mts_info(context, inst_from , token_mts_info_start_blk, &v);; do { g_soc_config->set_mts_info (context, inst_to, token_mts_info_start_blk, v); } while (0); ; } while (0);; } } while (0);; | |||
524 | COPY_FIELD(is_bl, inst_from, inst_to, start_page)do { if (is_bl) { do { uint32_t v; g_soc_config->getbl_param (inst_from, token_bl_start_page, &v, context->bct);; do { g_soc_config->setbl_param(inst_to, token_bl_start_page, &(v), context->bct); } while (0);; } while (0);; } else { do { uint32_t v; g_soc_config->get_mts_info(context, inst_from , token_mts_info_start_page, &v);; do { g_soc_config-> set_mts_info(context, inst_to, token_mts_info_start_page, v); } while (0);; } while (0);; } } while (0);; | |||
525 | COPY_FIELD(is_bl, inst_from, inst_to, length)do { if (is_bl) { do { uint32_t v; g_soc_config->getbl_param (inst_from, token_bl_length, &v, context->bct);; do { g_soc_config ->setbl_param(inst_to, token_bl_length, &(v), context-> bct); } while (0);; } while (0);; } else { do { uint32_t v; g_soc_config ->get_mts_info(context, inst_from, token_mts_info_length, & v);; do { g_soc_config->set_mts_info(context, inst_to, token_mts_info_length , v); } while (0);; } while (0);; } } while (0);; | |||
526 | COPY_FIELD(is_bl, inst_from, inst_to, load_addr)do { if (is_bl) { do { uint32_t v; g_soc_config->getbl_param (inst_from, token_bl_load_addr, &v, context->bct);; do { g_soc_config->setbl_param(inst_to, token_bl_load_addr, & (v), context->bct); } while (0);; } while (0);; } else { do { uint32_t v; g_soc_config->get_mts_info(context, inst_from , token_mts_info_load_addr, &v);; do { g_soc_config->set_mts_info (context, inst_to, token_mts_info_load_addr, v); } while (0); ; } while (0);; } } while (0);; | |||
527 | COPY_FIELD(is_bl, inst_from, inst_to, entry_point)do { if (is_bl) { do { uint32_t v; g_soc_config->getbl_param (inst_from, token_bl_entry_point, &v, context->bct);; do { g_soc_config->setbl_param(inst_to, token_bl_entry_point , &(v), context->bct); } while (0);; } while (0);; } else { do { uint32_t v; g_soc_config->get_mts_info(context, inst_from , token_mts_info_entry_point, &v);; do { g_soc_config-> set_mts_info(context, inst_to, token_mts_info_entry_point, v) ; } while (0);; } while (0);; } } while (0);; | |||
528 | COPY_FIELD(is_bl, inst_from, inst_to, attribute)do { if (is_bl) { do { uint32_t v; g_soc_config->getbl_param (inst_from, token_bl_attribute, &v, context->bct);; do { g_soc_config->setbl_param(inst_to, token_bl_attribute, & (v), context->bct); } while (0);; } while (0);; } else { do { uint32_t v; g_soc_config->get_mts_info(context, inst_from , token_mts_info_attribute, &v);; do { g_soc_config->set_mts_info (context, inst_to, token_mts_info_attribute, v); } while (0); ; } while (0);; } } while (0);; | |||
529 | ||||
530 | if (is_bl) { | |||
531 | g_soc_config->getbl_param(inst_from, | |||
532 | token_bl_crypto_hash, | |||
533 | (uint32_t*)hash_buffer, | |||
534 | context->bct); | |||
535 | g_soc_config->setbl_param(inst_to, | |||
536 | token_bl_crypto_hash, | |||
537 | (uint32_t*)hash_buffer, | |||
538 | context->bct); | |||
539 | } | |||
540 | ||||
541 | image_move_remaining--; | |||
542 | } | |||
543 | ||||
544 | /* Read the image into memory. */ | |||
545 | if (read_from_image( | |||
546 | is_bl
| |||
547 | 0, | |||
548 | is_bl
| |||
549 | &image_storage, | |||
550 | &image_actual_size, | |||
551 | image_type) == 1) { | |||
552 | printf("Error reading image %s.\n", | |||
553 | is_bl ? context->newbl_filename : context->mts_filename); | |||
554 | exit(1); | |||
555 | } | |||
556 | ||||
557 | pages_in_image = iceil_log2(image_actual_size, context->page_size_log2); | |||
558 | ||||
559 | current_blk = context->next_bct_blk; | |||
560 | current_page = 0; | |||
561 | for (image_instance = 0; image_instance < context->redundancy; | |||
562 | image_instance++) { | |||
563 | ||||
564 | pagesremaining = pages_in_image; | |||
565 | /* Advance to the next block if needed. */ | |||
566 | if (current_page
| |||
567 | current_blk++; | |||
568 | current_page = 0; | |||
569 | } | |||
570 | ||||
571 | virtual_blk = 0; | |||
572 | ||||
573 | while (pagesremaining > 0) { | |||
574 | /* Update the bad block table with relative | |||
575 | * bad blocks. | |||
576 | */ | |||
577 | if (virtual_blk == 0) { | |||
578 | SET_DATA(is_bl,do { if (is_bl) set_bl_data(context, image_instance, current_blk , current_page, image_actual_size); else set_mts_data(context , image_instance, current_blk, current_page, image_actual_size ); } while (0); | |||
579 | context,do { if (is_bl) set_bl_data(context, image_instance, current_blk , current_page, image_actual_size); else set_mts_data(context , image_instance, current_blk, current_page, image_actual_size ); } while (0); | |||
580 | image_instance,do { if (is_bl) set_bl_data(context, image_instance, current_blk , current_page, image_actual_size); else set_mts_data(context , image_instance, current_blk, current_page, image_actual_size ); } while (0); | |||
581 | current_blk,do { if (is_bl) set_bl_data(context, image_instance, current_blk , current_page, image_actual_size); else set_mts_data(context , image_instance, current_blk, current_page, image_actual_size ); } while (0); | |||
582 | current_page,do { if (is_bl) set_bl_data(context, image_instance, current_blk , current_page, image_actual_size); else set_mts_data(context , image_instance, current_blk, current_page, image_actual_size ); } while (0); | |||
583 | image_actual_size)do { if (is_bl) set_bl_data(context, image_instance, current_blk , current_page, image_actual_size); else set_mts_data(context , image_instance, current_blk, current_page, image_actual_size ); } while (0);; | |||
584 | } | |||
585 | ||||
586 | if (pagesremaining > pages_per_blk) { | |||
587 | current_blk++; | |||
588 | virtual_blk++; | |||
589 | pagesremaining -= pages_per_blk; | |||
590 | } else { | |||
591 | current_page = pagesremaining; | |||
592 | pagesremaining = 0; | |||
593 | } | |||
594 | } | |||
595 | } | |||
596 | ||||
597 | /* Scan forwards to write each copy. */ | |||
598 | for (image_instance = 0; image_instance < context->redundancy; | |||
599 | image_instance++) { | |||
600 | ||||
601 | /* Create a local copy of the BCT data */ | |||
602 | buffer = malloc(pages_in_image * context->page_size); | |||
603 | if (buffer == NULL((void*)0)) | |||
604 | return -ENOMEM12; | |||
| ||||
605 | ||||
606 | memset(buffer, 0, pages_in_image * context->page_size); | |||
607 | memcpy(buffer, image_storage, image_actual_size); | |||
608 | ||||
609 | insert_padding(buffer, image_actual_size); | |||
610 | ||||
611 | pagesremaining = pages_in_image; | |||
612 | ||||
613 | if (is_bl) { | |||
614 | GET_BL_FIELD(image_instance, start_blk, ¤t_blk)g_soc_config->getbl_param(image_instance, token_bl_start_blk , ¤t_blk, context->bct);; | |||
615 | GET_BL_FIELD(image_instance, start_page, ¤t_page)g_soc_config->getbl_param(image_instance, token_bl_start_page , ¤t_page, context->bct);; | |||
616 | ||||
617 | /* Encrypt and compute hash */ | |||
618 | sign_data_block(buffer, | |||
619 | image_actual_size, | |||
620 | hash_buffer); | |||
621 | g_soc_config->setbl_param(image_instance, | |||
622 | token_bl_crypto_hash, | |||
623 | (uint32_t*)hash_buffer, | |||
624 | context->bct); | |||
625 | } | |||
626 | ||||
627 | GET_FIELD(is_bl, image_instance, start_blk, ¤t_blk)do { if (is_bl) { g_soc_config->getbl_param(image_instance , token_bl_start_blk, ¤t_blk, context->bct);; } else { g_soc_config->get_mts_info(context, image_instance, token_mts_info_start_blk , ¤t_blk);; } } while (0);; | |||
628 | GET_FIELD(is_bl, image_instance, start_page, ¤t_page)do { if (is_bl) { g_soc_config->getbl_param(image_instance , token_bl_start_page, ¤t_page, context->bct);; } else { g_soc_config->get_mts_info(context, image_instance , token_mts_info_start_page, ¤t_page);; } } while ( 0);; | |||
629 | ||||
630 | /* Write the BCT data to the storage device, | |||
631 | * picking up ECC errors | |||
632 | */ | |||
633 | src = buffer; | |||
634 | ||||
635 | /* Write pages as we go. */ | |||
636 | virtual_blk = 0; | |||
637 | while (pagesremaining) { | |||
638 | if (current_page == 0) { | |||
639 | /* Erase the block before writing into it. */ | |||
640 | erase_block(context, current_blk); | |||
641 | } | |||
642 | ||||
643 | err = write_page(context, | |||
644 | current_blk, current_page, src); | |||
645 | if (err != 0) | |||
646 | goto fail; | |||
647 | pagesremaining--; | |||
648 | src += context->page_size; | |||
649 | current_page++; | |||
650 | if (current_page >= pages_per_blk) { | |||
651 | current_page = 0; | |||
652 | current_blk++; | |||
653 | virtual_blk++; | |||
654 | } | |||
655 | context->last_blk = current_blk; | |||
656 | } | |||
657 | context->next_bct_blk = context->last_blk + 1; | |||
658 | free(buffer); | |||
659 | } | |||
660 | ||||
661 | image_used = context->redundancy + image_move_count; | |||
662 | token = is_bl ? token_bootloader_used : token_mts_used; | |||
663 | g_soc_config->set_value(token, &image_used, context->bct); | |||
664 | ||||
665 | if (enable_debug) { | |||
666 | for (i = 0; i < image_max; i++) { | |||
667 | uint32_t version; | |||
668 | uint32_t start_blk; | |||
669 | uint32_t start_page; | |||
670 | uint32_t length; | |||
671 | uint32_t load_addr; | |||
672 | uint32_t entry_point; | |||
673 | ||||
674 | GET_FIELD(is_bl, i, version, &version)do { if (is_bl) { g_soc_config->getbl_param(i, token_bl_version , &version, context->bct);; } else { g_soc_config-> get_mts_info(context, i, token_mts_info_version, &version );; } } while (0);; | |||
675 | GET_FIELD(is_bl, i, start_blk, &start_blk)do { if (is_bl) { g_soc_config->getbl_param(i, token_bl_start_blk , &start_blk, context->bct);; } else { g_soc_config-> get_mts_info(context, i, token_mts_info_start_blk, &start_blk );; } } while (0);; | |||
676 | GET_FIELD(is_bl, i, start_page, &start_page)do { if (is_bl) { g_soc_config->getbl_param(i, token_bl_start_page , &start_page, context->bct);; } else { g_soc_config-> get_mts_info(context, i, token_mts_info_start_page, &start_page );; } } while (0);; | |||
677 | GET_FIELD(is_bl, i, length, &length)do { if (is_bl) { g_soc_config->getbl_param(i, token_bl_length , &length, context->bct);; } else { g_soc_config->get_mts_info (context, i, token_mts_info_length, &length);; } } while ( 0);; | |||
678 | GET_FIELD(is_bl, i, load_addr, &load_addr)do { if (is_bl) { g_soc_config->getbl_param(i, token_bl_load_addr , &load_addr, context->bct);; } else { g_soc_config-> get_mts_info(context, i, token_mts_info_load_addr, &load_addr );; } } while (0);; | |||
679 | GET_FIELD(is_bl, i, entry_point, &entry_point)do { if (is_bl) { g_soc_config->getbl_param(i, token_bl_entry_point , &entry_point, context->bct);; } else { g_soc_config-> get_mts_info(context, i, token_mts_info_entry_point, &entry_point );; } } while (0);; | |||
680 | ||||
681 | printf("%s%s[%d]: %d %04d %04d %04d 0x%08x 0x%08x\n", | |||
682 | i < image_used ? " " : "**", | |||
683 | is_bl ? "BL" : "MTS", | |||
684 | i, | |||
685 | version, | |||
686 | start_blk, | |||
687 | start_page, | |||
688 | length, | |||
689 | load_addr, | |||
690 | entry_point); | |||
691 | if (is_bl) { | |||
692 | g_soc_config->getbl_param(i, | |||
693 | token_bl_crypto_hash, | |||
694 | (uint32_t*)hash_buffer, | |||
695 | context->bct); | |||
696 | for (j = 0; j < hash_size / 4; j++) { | |||
697 | printf("%08x", | |||
698 | *((uint32_t*)(hash_buffer + 4*j))); | |||
699 | } | |||
700 | printf("\n"); | |||
701 | } | |||
702 | } | |||
703 | } | |||
704 | free(image_storage); | |||
705 | free(hash_buffer); | |||
706 | return 0; | |||
707 | ||||
708 | fail: | |||
709 | /* Cleanup. */ | |||
710 | free(buffer); | |||
711 | free(image_storage); | |||
712 | free(hash_buffer); | |||
713 | printf("Write image failed, error: %d.\n", err); | |||
714 | return err; | |||
715 | } | |||
716 | ||||
717 | void | |||
718 | update_context(struct build_image_context_rec *context) | |||
719 | { | |||
720 | g_soc_config->get_value(token_partition_size, | |||
721 | &context->partition_size, | |||
722 | context->bct); | |||
723 | g_soc_config->get_value(token_page_size_log2, | |||
724 | &context->page_size_log2, | |||
725 | context->bct); | |||
726 | g_soc_config->get_value(token_block_size_log2, | |||
727 | &context->block_size_log2, | |||
728 | context->bct); | |||
729 | g_soc_config->get_value(token_odm_data, | |||
730 | &context->odm_data, | |||
731 | context->bct); | |||
732 | ||||
733 | context->page_size = 1 << context->page_size_log2; | |||
734 | context->block_size = 1 << context->block_size_log2; | |||
735 | context->pages_per_blk = 1 << (context->block_size_log2 - | |||
736 | context->page_size_log2); | |||
737 | } | |||
738 | ||||
739 | /* | |||
740 | * Allocate and initialize the memory for bct data. | |||
741 | * | |||
742 | * @param context The main context pointer | |||
743 | * @return 0 for success | |||
744 | */ | |||
745 | int | |||
746 | init_bct(struct build_image_context_rec *context) | |||
747 | { | |||
748 | /* Allocate space for the bct. */ | |||
749 | context->bct = malloc(context->bct_size); | |||
750 | ||||
751 | if (context->bct == NULL((void*)0)) | |||
752 | return -ENOMEM12; | |||
753 | ||||
754 | memset(context->bct, 0, context->bct_size); | |||
755 | context->bct_init = 1; | |||
756 | ||||
757 | return 0; | |||
758 | } | |||
759 | ||||
760 | /* | |||
761 | * Read the bct data from given file to allocated memory. | |||
762 | * Assign the global parse interface to corresponding hardware interface | |||
763 | * according to the boot data version in bct file. | |||
764 | * | |||
765 | * @param context The main context pointer | |||
766 | * @return 0 for success | |||
767 | */ | |||
768 | int | |||
769 | read_bct_file(struct build_image_context_rec *context) | |||
770 | { | |||
771 | uint8_t *bct_storage; /* Holds the Bl after reading */ | |||
772 | uint32_t bct_actual_size; /* In bytes */ | |||
773 | file_type bct_filetype = file_type_bct; | |||
774 | int err = 0; | |||
775 | ||||
776 | if (read_from_image(context->bct_filename, | |||
777 | 0, | |||
778 | NVBOOT_CONFIG_TABLE_SIZE_MAX(10 * 1024), | |||
779 | &bct_storage, | |||
780 | &bct_actual_size, | |||
781 | bct_filetype) == 1) { | |||
782 | printf("Error reading bct file %s.\n", context->bct_filename); | |||
783 | exit(1); | |||
784 | } | |||
785 | ||||
786 | context->bct_size = bct_actual_size; | |||
787 | if (context->bct_init != 1) | |||
788 | err = init_bct(context); | |||
789 | if (err != 0) { | |||
790 | printf("Context initialization failed. Aborting.\n"); | |||
791 | return err; | |||
792 | } | |||
793 | memcpy(context->bct, bct_storage, context->bct_size); | |||
794 | free(bct_storage); | |||
795 | ||||
796 | if (!data_is_valid_bct(context)) | |||
797 | return -ENODATA61; | |||
798 | ||||
799 | return err; | |||
800 | } | |||
801 | ||||
802 | /* | |||
803 | * Update the next_bct_blk and make it point to the next | |||
804 | * new blank block according to bct_copy given. | |||
805 | * | |||
806 | * @param context The main context pointer | |||
807 | */ | |||
808 | static void | |||
809 | find_new_bct_blk(build_image_context *context) | |||
810 | { | |||
811 | uint32_t max_bct_search_blks; | |||
812 | ||||
813 | assert(context)((context) ? (void) (0) : __assert_fail ("context", "util/nvidia/cbootimage/src/data_layout.c" , 813, __extension__ __PRETTY_FUNCTION__)); | |||
814 | ||||
815 | g_soc_config->get_value(token_max_bct_search_blks, | |||
816 | &max_bct_search_blks, context->bct); | |||
817 | ||||
818 | if (context->next_bct_blk > max_bct_search_blks) { | |||
819 | printf("Error: Unable to locate a journal block.\n"); | |||
820 | exit(1); | |||
821 | } | |||
822 | context->next_bct_blk++; | |||
823 | } | |||
824 | ||||
825 | /* | |||
826 | * Initialization before bct and bootloader update. | |||
827 | * Find the new blank block and erase it. | |||
828 | * | |||
829 | * @param context The main context pointer | |||
830 | * @return 0 for success | |||
831 | */ | |||
832 | int | |||
833 | begin_update(build_image_context *context) | |||
834 | { | |||
835 | uint32_t hash_size; | |||
836 | uint32_t reserved_size; | |||
837 | uint32_t reserved_offset; | |||
838 | int err = 0; | |||
839 | int i; | |||
840 | ||||
841 | assert(context)((context) ? (void) (0) : __assert_fail ("context", "util/nvidia/cbootimage/src/data_layout.c" , 841, __extension__ __PRETTY_FUNCTION__)); | |||
842 | ||||
843 | if (context->page_size_log2 < NVBOOT_AES_BLOCK_SIZE_LOG24) { | |||
844 | printf("Page size is too small; likely config file error\n"); | |||
845 | return 1; | |||
846 | } | |||
847 | ||||
848 | /* Ensure that the BCT block & page data is current. */ | |||
849 | if (enable_debug) { | |||
850 | uint32_t block_size_log2; | |||
851 | uint32_t page_size_log2; | |||
852 | ||||
853 | g_soc_config->get_value(token_block_size_log2, | |||
854 | &block_size_log2, context->bct); | |||
855 | g_soc_config->get_value(token_page_size_log2, | |||
856 | &page_size_log2, context->bct); | |||
857 | ||||
858 | printf("begin_update(): bct data: b=%d p=%d\n", | |||
859 | block_size_log2, page_size_log2); | |||
860 | } | |||
861 | ||||
862 | g_soc_config->set_value(token_boot_data_version, | |||
863 | &(context->boot_data_version), context->bct); | |||
864 | g_soc_config->get_value(token_hash_size, | |||
865 | &hash_size, context->bct); | |||
866 | g_soc_config->get_value(token_reserved_size, | |||
867 | &reserved_size, context->bct); | |||
868 | g_soc_config->get_value(token_reserved_offset, | |||
869 | &reserved_offset, context->bct); | |||
870 | /* Set the odm data */ | |||
871 | g_soc_config->set_value(token_odm_data, | |||
872 | &(context->odm_data), context->bct); | |||
873 | ||||
874 | /* Initialize the bad block table field. */ | |||
875 | g_soc_config->init_bad_block_table(context); | |||
876 | /* Fill the reserved data w/the padding pattern. */ | |||
877 | write_padding(context->bct + reserved_offset, reserved_size); | |||
878 | ||||
879 | /* Create the pad before the BCT starting at block 1 */ | |||
880 | for (i = 0; i < context->pre_bct_pad_blocks; i++) { | |||
881 | find_new_bct_blk(context); | |||
882 | err = erase_block(context, i); | |||
883 | if (err != 0) | |||
884 | goto fail; | |||
885 | } | |||
886 | /* Find the next bct block starting at block pre_bct_pad_blocks. */ | |||
887 | for (i = 0; i < context->bct_copy; i++) { | |||
888 | find_new_bct_blk(context); | |||
889 | err = erase_block(context, i + context->pre_bct_pad_blocks); | |||
890 | if (err != 0) | |||
891 | goto fail; | |||
892 | } | |||
893 | return 0; | |||
894 | fail: | |||
895 | printf("Erase block failed, error: %d.\n", err); | |||
896 | return err; | |||
897 | } | |||
898 | ||||
899 | /* | |||
900 | * Write the BCT(s) starting at slot 0 of block context->pre_bct_pad_blocks. | |||
901 | * | |||
902 | * @param context The main context pointer | |||
903 | * @return 0 for success | |||
904 | */ | |||
905 | static int | |||
906 | finish_update(build_image_context *context) | |||
907 | { | |||
908 | int err = 0; | |||
909 | int i; | |||
910 | ||||
911 | for (i = 0; i < context->bct_copy; i++) { | |||
912 | err = write_bct(context, i + context->pre_bct_pad_blocks, 0); | |||
913 | if (err != 0) | |||
914 | goto fail; | |||
915 | } | |||
916 | ||||
917 | return 0; | |||
918 | fail: | |||
919 | printf("Write BCT failed, error: %d.\n", err); | |||
920 | return err; | |||
921 | } | |||
922 | ||||
923 | /* | |||
924 | * For now, ignore end state. | |||
925 | */ | |||
926 | int | |||
927 | update_bl(build_image_context *context) | |||
928 | { | |||
929 | if (enable_debug) | |||
930 | printf("**update_bl()\n"); | |||
931 | ||||
932 | if (begin_update(context) != 0) | |||
933 | return 1; | |||
934 | if (write_image(context, file_type_bl) != 0) | |||
935 | return 1; | |||
936 | if (finish_update(context) != 0) | |||
937 | return 1; | |||
938 | return 0; | |||
939 | } | |||
940 | ||||
941 | int | |||
942 | update_mts_image(build_image_context *context) | |||
943 | { | |||
944 | if (enable_debug) | |||
945 | printf("**update_mts()\n"); | |||
946 | ||||
947 | if (begin_update(context) != 0) | |||
948 | return 1; | |||
949 | if (write_image(context, file_type_mts) != 0) | |||
950 | return 1; | |||
951 | if (finish_update(context) != 0) | |||
952 | return 1; | |||
953 | return 0; | |||
954 | } | |||
955 | ||||
956 | /* | |||
957 | * To write the current image: | |||
958 | * Loop over all blocks in the block data list: | |||
959 | * Write out the data of real blocks. | |||
960 | * Write out 0's for unused blocks. | |||
961 | * Stop on the last used page of the last used block. | |||
962 | * | |||
963 | * @param context The main context pointer | |||
964 | * @return 0 for success | |||
965 | */ | |||
966 | int | |||
967 | write_block_raw(build_image_context *context) | |||
968 | { | |||
969 | block_data *block_list; | |||
970 | block_data *block; | |||
971 | uint32_t blk_number; | |||
972 | uint32_t last_blk; | |||
973 | uint32_t pages_to_write; | |||
974 | uint8_t *data; | |||
975 | uint8_t *empty_blk = NULL((void*)0); | |||
976 | ||||
977 | assert(context != NULL)((context != ((void*)0)) ? (void) (0) : __assert_fail ("context != NULL" , "util/nvidia/cbootimage/src/data_layout.c", 977, __extension__ __PRETTY_FUNCTION__)); | |||
978 | assert(context->memory)((context->memory) ? (void) (0) : __assert_fail ("context->memory" , "util/nvidia/cbootimage/src/data_layout.c", 978, __extension__ __PRETTY_FUNCTION__)); | |||
979 | ||||
980 | block_list = context->memory; | |||
981 | ||||
982 | /* Compute the end of the image. */ | |||
983 | block_list = context->memory; | |||
984 | while (block_list->next) | |||
985 | block_list = block_list->next; | |||
986 | ||||
987 | last_blk = block_list->blk_number; | |||
988 | ||||
989 | /* Loop over all the storage from block 0, page 0 to | |||
990 | *last_blk, Lastpage | |||
991 | */ | |||
992 | for (blk_number = 0; blk_number <= last_blk; blk_number++) { | |||
993 | block = find_block(blk_number, context->memory); | |||
994 | if (block) { | |||
995 | pages_to_write = (blk_number == last_blk) ? | |||
996 | block->pages_used : | |||
997 | context->pages_per_blk; | |||
998 | data = block->data; | |||
999 | } else { | |||
1000 | /* Allocate empty_blk if needed. */ | |||
1001 | if (empty_blk == NULL((void*)0)) { | |||
1002 | empty_blk = malloc(context->block_size); | |||
1003 | if (!empty_blk) | |||
1004 | return -ENOMEM12; | |||
1005 | memset(empty_blk, 0, context->block_size); | |||
1006 | } | |||
1007 | pages_to_write = context->pages_per_blk; | |||
1008 | data = empty_blk; | |||
1009 | } | |||
1010 | /* Write the data */ | |||
1011 | { | |||
1012 | size_t bytes = pages_to_write * context->page_size; | |||
1013 | ||||
1014 | if (fwrite(data, 1, bytes, context->raw_file) != bytes) { | |||
1015 | if (empty_blk) free(empty_blk); | |||
1016 | return -1; | |||
1017 | } | |||
1018 | } | |||
1019 | } | |||
1020 | ||||
1021 | if (empty_blk) free(empty_blk); | |||
1022 | return 0; | |||
1023 | } | |||
1024 | ||||
1025 | int write_data_block(FILE *fp, uint32_t offset, uint32_t size, uint8_t *buffer) | |||
1026 | { | |||
1027 | if (fseek(fp, offset, 0)) | |||
1028 | return -1; | |||
1029 | ||||
1030 | return fwrite(buffer, 1, size, fp); | |||
1031 | } | |||
1032 | ||||
1033 | int data_is_valid_bct(build_image_context *context) | |||
1034 | { | |||
1035 | /* get proper soc_config pointer by polling each supported chip */ | |||
1036 | if (if_bct_is_t20_get_soc_config(context, &g_soc_config)) | |||
1037 | return 1; | |||
1038 | if (if_bct_is_t30_get_soc_config(context, &g_soc_config)) | |||
1039 | return 1; | |||
1040 | if (if_bct_is_t114_get_soc_config(context, &g_soc_config)) | |||
1041 | return 1; | |||
1042 | if (if_bct_is_t124_get_soc_config(context, &g_soc_config)) | |||
1043 | return 1; | |||
1044 | if (if_bct_is_t132_get_soc_config(context, &g_soc_config)) | |||
1045 | return 1; | |||
1046 | if (if_bct_is_t210_get_soc_config(context, &g_soc_config)) | |||
1047 | return 1; | |||
1048 | ||||
1049 | return 0; | |||
1050 | } | |||
1051 | ||||
1052 | int get_bct_size_from_image(build_image_context *context) | |||
1053 | { | |||
1054 | uint8_t buffer[NVBOOT_CONFIG_TABLE_SIZE_MIN4080]; | |||
1055 | uint32_t bct_size = 0; | |||
1056 | FILE *fp; | |||
1057 | ||||
1058 | fp = fopen(context->input_image_filename, "r"); | |||
1059 | if (!fp) | |||
1060 | return -ENODATA61; | |||
1061 | ||||
1062 | if (fread(buffer, 1, NVBOOT_CONFIG_TABLE_SIZE_MIN4080, fp) != NVBOOT_CONFIG_TABLE_SIZE_MIN4080) { | |||
1063 | fclose(fp); | |||
1064 | return -ENODATA61; | |||
1065 | } | |||
1066 | ||||
1067 | context->bct = buffer; | |||
1068 | if (data_is_valid_bct(context) && g_soc_config->get_bct_size) | |||
1069 | bct_size = g_soc_config->get_bct_size(); | |||
1070 | ||||
1071 | fclose(fp); | |||
1072 | context->bct = 0; | |||
1073 | return bct_size; | |||
1074 | } | |||
1075 | ||||
1076 | int resign_bl(build_image_context *context) | |||
1077 | { | |||
1078 | int ret; | |||
1079 | uint8_t *buffer, *image; | |||
1080 | uint32_t image_instance = 0; /* support only one instance */ | |||
1081 | uint32_t image_actual_size; /* In bytes */ | |||
1082 | uint32_t bl_length; | |||
1083 | uint32_t pages_in_image; | |||
1084 | uint32_t blk_size, page_size, current_blk, current_page; | |||
1085 | uint32_t offset; | |||
1086 | ||||
1087 | /* read in bl from image */ | |||
1088 | g_soc_config->get_value(token_block_size, &blk_size, context->bct); | |||
1089 | g_soc_config->get_value(token_page_size, &page_size, context->bct); | |||
1090 | ||||
1091 | GET_BL_FIELD(image_instance, start_blk, ¤t_blk)g_soc_config->getbl_param(image_instance, token_bl_start_blk , ¤t_blk, context->bct);; | |||
1092 | GET_BL_FIELD(image_instance, start_page, ¤t_page)g_soc_config->getbl_param(image_instance, token_bl_start_page , ¤t_page, context->bct);; | |||
1093 | GET_BL_FIELD(image_instance, length, &bl_length)g_soc_config->getbl_param(image_instance, token_bl_length, &bl_length, context->bct);; | |||
1094 | ||||
1095 | offset = current_blk * blk_size + | |||
1096 | current_page * page_size; | |||
1097 | ||||
1098 | if (read_from_image(context->input_image_filename, | |||
1099 | offset, bl_length, | |||
1100 | &image, &image_actual_size, file_type_bin)) { | |||
1101 | printf("Error reading image file %s.\n", | |||
1102 | context->input_image_filename); | |||
1103 | return -ENOMEM12; | |||
1104 | } | |||
1105 | ||||
1106 | pages_in_image = ICEIL(image_actual_size, page_size)(((image_actual_size) + (page_size) - 1)/(page_size)); | |||
1107 | ||||
1108 | /* Create a local copy of the bl */ | |||
1109 | if ((buffer = malloc(pages_in_image * page_size)) == NULL((void*)0)) { | |||
1110 | ret = -ENOMEM12; | |||
1111 | goto fail; | |||
1112 | } | |||
1113 | ||||
1114 | memset(buffer, 0, pages_in_image * page_size); | |||
1115 | memcpy(buffer, image, image_actual_size); | |||
1116 | ||||
1117 | insert_padding(buffer, image_actual_size); | |||
1118 | ||||
1119 | /* sign bl */ | |||
1120 | ret = sign_bl(context, buffer, image_actual_size, image_instance); | |||
1121 | free (buffer); | |||
1122 | fail: | |||
1123 | free (image); | |||
1124 | return ret; | |||
1125 | } |