• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  * @brief    FOTA patch application program
15  */
16 
17 #include <stdint.h>
18 #include <stddef.h>
19 #include <stdbool.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include "securec.h"
23 #include "common_def.h"
24 #include "upg_patch_info.h"
25 #include "upg_alloc.h"
26 #include "upg_debug.h"
27 #include "upg_porting.h"
28 #include "errcode.h"
29 #include "LzmaDec.h"
30 #include "upg_common_porting.h"
31 #include "upg_common.h"
32 #include "upg_config.h"
33 
34 #include "upg_patch.h"
35 
36 #define Z_OK                           SZ_OK
37 #define ZIP_STREAM_END                 99
38 #define WORD_WIDTH                     4
39 
40 /* Code style related constants */
41 #define PATCH_KNVD_STR                 "KNVD"
42 #define PATCH_KNVD_STR_LEN             4
43 #define PAGE_STATUS_BIT_SEARCH_START   1
44 #define PAGE_STATUS_BIT_SEARCH_END     5
45 #define PAGE_STATUS_BIT_SEARCH_INC     2
46 
fota_patch_free(void * mem)47 STATIC void fota_patch_free(void *mem)
48 {
49     if (mem == NULL) {
50         return;
51     }
52 
53     /* first words of the allocated memory is an int32_t indicating how much memory is allocated... */
54     int32_t *q = ((int32_t *)mem) - 1;
55     upg_free(q);
56 }
57 
fota_patch_alloc(size_t size)58 STATIC void* fota_patch_alloc(size_t size)
59 {
60     volatile int32_t *p = NULL;
61     uint32_t len = size + (uint32_t)sizeof(int32_t);
62     p = (int32_t*)upg_malloc(len);
63     if (p == NULL) {
64         upg_log_err("[UPG] upg_malloc failure for requested size = 0x%x\r\n", (uint32_t)size);
65         return NULL;
66     }
67     /* This will panic if it fails so no need to check the return value. */
68     (void)memset_s((int32_t *)p, len, 0, len);
69 
70     *p = (int32_t)size;
71 
72     return (void*)(p + 1);
73 }
74 
lzma_malloc(ISzAllocPtr p,size_t size)75 STATIC void* lzma_malloc(ISzAllocPtr p, size_t size)
76 {
77     unused(p);
78     return fota_patch_alloc(size);
79 }
80 
lzma_free(ISzAllocPtr p,void * address)81 STATIC void lzma_free(ISzAllocPtr p, void *address)
82 {
83     unused(p);
84     fota_patch_free(address);
85 }
86 
fota_pkg_flash_read_image(patch * desc,uint32_t length,int32_t location,uint8_t * dest)87 STATIC errcode_t fota_pkg_flash_read_image(patch *desc, uint32_t length, int32_t location, uint8_t *dest)
88 {
89     if (desc->use_plain_text_cache) {
90         /* Read from the plain text cache. */
91         uint8_t *src = NULL;
92 
93         if (desc->image_cache == NULL) {
94             return ERRCODE_FAIL;
95         }
96         src = desc->image_cache + location;
97         /* This will panic if it fails so no need to check the return value. */
98         (void)memcpy_s(dest, length, src, length);
99     } else {
100         errcode_t ret = ERRCODE_SUCC;
101         ret = upg_read_old_image_data((uint32_t)location, dest, &length, desc->image_id);
102         if (ret != ERRCODE_SUCC) {
103             upg_log_err("[UPG] fota_pkg_flash_read_image read flash error. ret = 0x%x\r\n", ret);
104             return ret;
105         }
106     }
107     return ERRCODE_SUCC;
108 }
109 
fota_pkg_flash_prep_page_contents_for_write(patch * desc,uint32_t image_page_no,uint8_t * page_contents)110 STATIC errcode_t fota_pkg_flash_prep_page_contents_for_write(patch *desc, uint32_t image_page_no,
111                                                              uint8_t *page_contents)
112 {
113     errcode_t ret = ERRCODE_SUCC;
114     uint8_t *dest = NULL;
115 
116     if (desc->use_plain_text_cache) {
117         /* Update the plaintext cache. */
118         if (desc->image_cache == NULL) {
119             return ERRCODE_FAIL;
120         }
121         dest = desc->image_cache + image_page_no * UPG_FLASH_PAGE_SIZE;
122         /* This will panic if it fails so no need to check the return value. */
123         (void)memcpy_s(dest, UPG_FLASH_PAGE_SIZE, page_contents, UPG_FLASH_PAGE_SIZE);
124     }
125 
126     return ret;
127 }
128 
fota_pkg_plaintext_flash_cache_init(patch * desc)129 STATIC errcode_t fota_pkg_plaintext_flash_cache_init(patch *desc)
130 {
131     errcode_t ret = ERRCODE_SUCC;
132 
133     if (!desc->use_plain_text_cache) {
134         return ret;
135     }
136 
137     /* 以下为加解密时使用 */
138     uint32_t image_len = desc->image_flash_length;
139     upg_log_info("[UPG] cache_init: flash_offset = 0x%x, len = 0x%x\r\n", desc->image_flash_offset, image_len);
140 
141     desc->image_cache = (uint8_t*)upg_malloc(image_len);
142     upg_log_info("[UPG] cache_init: desc->image_cache = 0x%x\r\n", (uint32_t)(uintptr_t)desc->image_cache);
143     if (desc->image_cache == NULL) {
144         upg_log_err("[UPG] cache_init: malloc failure\r\n");
145         return ERRCODE_MALLOC;
146     }
147 
148     /* Cache the Plain Text region. */
149     uint8_t *dst_addr = desc->image_cache;
150     uint32_t src_offset = desc->image_flash_offset;
151     ret = upg_read_old_image_data(src_offset, dst_addr, &image_len, desc->image_id);
152 
153     return ret;
154 }
155 
read_diff_data_from_ram(const uint8_t * addr,uint8_t * data,uint32_t length)156 STATIC bool read_diff_data_from_ram(const uint8_t *addr, uint8_t *data, uint32_t length)
157 {
158     size_t copy_size = length;
159     /* This will panic if it fails so no need to check the return value. */
160     (void)memcpy_s(data, length, addr, copy_size);
161     return true;
162 }
163 
read_diff_data_to_ram(uint32_t offsets,uint8_t * data,uint32_t length,patch_state_t * state)164 STATIC bool read_diff_data_to_ram(uint32_t offsets, uint8_t *data, uint32_t length, patch_state_t *state)
165 {
166     uint32_t read_len = length;
167     bool success = true;
168 
169     memset_s(data, DECOMPRESSION_SIZE, 0, DECOMPRESSION_SIZE);
170     if (state->desc->patch_contents_ram_copy != 0) {
171         success = read_diff_data_from_ram((uint8_t *)(uintptr_t)(state->desc->patch_contents_ram_copy + offsets),
172                                           data, read_len);
173     } else {
174         if (upg_read_fota_pkg_data((uint32_t)state->desc->patch_contents_flash_offset + offsets,
175                                    (uint8_t *)data, &read_len) != ERRCODE_SUCC) {
176             success = false;
177         }
178     }
179     if (!success) {
180         upg_log_err("[UPG] read diff to ram error");
181         return false;
182     }
183 
184     return true;
185 }
186 
zip_init_helper(zip_context_t * z,patch_state_t * state)187 STATIC errcode_t zip_init_helper(zip_context_t *z, patch_state_t *state)
188 {
189     SRes sres;
190     bool success;
191     uint32_t i;
192     uint8_t cdata[LZMA_PROPS_SIZE + HN_LZMA_SIZEOF_IMGSIZE];
193 
194     /* Configure compressed patch data pointer and copy routine */
195     z->cdata = (unsigned char *)fota_patch_alloc(DECOMPRESSION_SIZE);
196     if (z->cdata == NULL) {
197         state->err_code = ERRCODE_MALLOC;
198         upg_log_err("[UPG] z->cdata alloc failure, err_code = 0x%x\r\n", state->err_code);
199         return state->err_code;
200     }
201     read_diff_data_to_ram(0, z->cdata, DECOMPRESSION_SIZE, state);
202 
203     /* Decode the properties from the header */
204     success = read_diff_data_from_ram(z->cdata, cdata, LZMA_PROPS_SIZE + HN_LZMA_SIZEOF_IMGSIZE);
205     if (!success) {
206         state->err_code = ERRCODE_FAIL;
207         fota_patch_free(z->cdata);
208         upg_log_err("[UPG] zip_init_helper Decode the properties from the header false!");
209         return state->err_code;
210     }
211 
212     sres = LzmaDec_Allocate(z->dec, cdata, LZMA_PROPS_SIZE, &state->lzma_alloc);
213     if (sres != SZ_OK) {
214         state->err_code = ERRCODE_FAIL;
215         fota_patch_free(z->cdata);
216         upg_log_err("[UPG] zip_init_helper LzmaDec_Allocate is false!");
217         return state->err_code;
218     }
219     LzmaDec_Init(z->dec);
220     z->offset = LZMA_PROPS_SIZE;
221     z->cdata_len = state->desc->patch_contents_len - (LZMA_PROPS_SIZE + HN_LZMA_SIZEOF_IMGSIZE);
222     z->unpacked_len = 0;
223     for (i = 0; i < HN_LZMA_SIZEOF_IMGSIZE; i++) {
224         z->unpacked_len += ((uint32_t)(cdata[(uint32_t)z->offset + i])) << (i * NUM_BITS_PER_BYTE);
225     }
226     z->unpacked_so_far = 0;
227     z->offset += HN_LZMA_SIZEOF_IMGSIZE;
228     return ERRCODE_SUCC;
229 }
230 
zip_init(patch_state_t * state)231 STATIC zip_context_t *zip_init(patch_state_t *state)
232 {
233     errcode_t ret;
234     zip_context_t *z = fota_patch_alloc(sizeof(zip_context_t));
235     if (z == NULL) {
236         state->err_code = ERRCODE_MALLOC;
237         upg_log_err("[UPG] zip_init z alloc failure, err_code = 0x%x\r\n", state->err_code);
238         return z;
239     }
240 
241     z->dec = fota_patch_alloc(sizeof(CLzmaDec));
242     if (z->dec == NULL) {
243         state->err_code = ERRCODE_MALLOC;
244         fota_patch_free(z);
245         z = NULL;
246         upg_log_err("[UPG] zip_init z->dec alloc failure, err_code = 0x%x\r\n", state->err_code);
247         return z;
248     }
249     LzmaDec_Construct(z->dec);
250     /* LZMA is absolute trash.  Required to prevent a segfault */
251     z->dec->probs = NULL;
252 
253     ret = zip_init_helper(z, state);
254     if (ret != ERRCODE_SUCC) {
255         fota_patch_free(z->dec);
256         fota_patch_free(z);
257         z = NULL;
258     }
259     return z;
260 }
261 
zip_mem_read(patch_state_t * state,int32_t * error,zip_context_t * z,unsigned char * dest,int32_t len)262 STATIC int32_t zip_mem_read(patch_state_t *state, int32_t *error, zip_context_t *z, unsigned char *dest, int32_t len)
263 {
264     SizeT src_len, dest_len;
265     dest_len = (SizeT)len;
266     uint32_t done_len = 0;
267 
268     while (done_len != (uint32_t)len) {
269         src_len = uapi_min(state->desc->patch_contents_len - (uint32_t)(z->offset), DECOMPRESSION_SIZE);
270         if (!read_diff_data_to_ram((uint32_t)z->offset, (uint8_t *)z->cdata, (uint32_t)src_len, state)) {
271             state->err_code = ERRCODE_UPG_FILE_READ_FAIL;
272             upg_log_err("[UPG] LZMA zip_mem_read: read diff error, err_code = 0x%x\r\n", state->err_code);
273             return 0;
274         }
275 
276         ELzmaStatus status = 0;
277         SRes ret;
278         ret = LzmaDec_DecodeToBuf(z->dec, dest + done_len, &dest_len, z->cdata, &src_len, LZMA_FINISH_ANY, &status);
279         if (ret != SZ_OK) {
280             state->err_code = (errcode_t)ret;
281             upg_log_err("[UPG] LZMA zip_mem_read: Decode error, err_code = 0x%x\r\n", state->err_code);
282             return 0;
283         }
284 
285         z->offset += (int32_t)src_len;
286         *error = (status == LZMA_STATUS_NOT_FINISHED) ? Z_OK : ZIP_STREAM_END;
287         z->unpacked_so_far += dest_len;
288         done_len += dest_len;
289         dest_len = (uint32_t)len - done_len;
290 
291         if (status == LZMA_STATUS_FINISHED_WITH_MARK) {
292             break;
293         }
294     }
295 
296     return (int32_t)done_len;
297 }
298 
zip_end(patch_state_t * state,zip_context_t * z)299 STATIC void zip_end(patch_state_t *state, zip_context_t *z)
300 {
301     LzmaDec_Free(z->dec, &state->lzma_alloc);
302     fota_patch_free(z->cdata);
303     fota_patch_free(z->dec);
304     fota_patch_free(z);
305 }
306 
read_image_block(patch_state_t * state,uint32_t size,int32_t location,uint8_t * dest)307 STATIC void read_image_block(patch_state_t *state, uint32_t size, int32_t location, uint8_t *dest)
308 {
309     if (state->err_code != ERRCODE_SUCC) {
310         upg_log_err("[UPG] read_image_block state err_code = 0x%x\r\n", state->err_code);
311         /* Do not process anything if an error occurred */
312         return;
313     }
314 
315     /* Perform flash reads of the image using injected function to handle any decryption required. */
316     state->err_code = fota_pkg_flash_read_image(state->desc, size, location, dest);
317     if (state->err_code != ERRCODE_SUCC) {
318         upg_log_err("[UPG] ERROR read_image_block, err_code = 0x%x\r\n", state->err_code);
319         return;
320     }
321 }
322 
write_image_block(patch_state_t * state,uint32_t size,int32_t location,const uint8_t * source)323 void write_image_block(patch_state_t *state, uint32_t size, int32_t location, const uint8_t *source)
324 {
325     if (state->err_code != ERRCODE_SUCC) {
326         upg_log_err("[UPG] write_image_block state err_code = 0x%x\r\n", state->err_code);
327         /* Do not process anything if an error occurred */
328         return;
329     }
330 
331     if (upg_write_new_image_data((uint32_t)location, (uint8_t *)source, &size, state->desc->image_id, true) !=
332         ERRCODE_SUCC) {
333         state->err_code = ERRCODE_FAIL;
334         upg_log_err("[UPG] write_image_block write err_code = 0x%x\r\n", state->err_code);
335         return;
336     }
337 
338     upg_calculate_and_notify_process((uint32_t)(state->page_last_written + 1));
339 }
340 
341 /*
342  * buffer file contains
343  *  1.  a page of buffer_size
344  *  2.  a set of bytes, one byte per page.
345  * **N.B.** in a real, flash-based implementation, these bits would have
346  * to be spaced out in accordance with the flash's access rules.
347  */
fota_buffers_has_contents(patch_state_t * state)348 STATIC bool fota_buffers_has_contents(patch_state_t *state)
349 {
350     fota_buffers_t *buffer = NULL;
351     uint32_t   i;
352     bool  buffers_set = true;
353     errcode_t ret;
354 
355     if (state->err_code != ERRCODE_SUCC) {
356         upg_log_err("[UPG] fota_buffers_has_contents state err_code = 0x%x\r\n", state->err_code);
357         /* Do not process anything if an error occurred */
358         return buffers_set;
359     }
360     buffer = fota_patch_alloc(sizeof(fota_buffers_t));
361     if (buffer == NULL) {
362         state->err_code = ERRCODE_MALLOC;
363         upg_log_err("[UPG] fota_buffers_has_contents: cannot allocate read buffer, err_code = 0x%x\r\n",
364             state->err_code);
365         goto ret_free;
366     }
367 
368     ret = upg_flash_read(state->desc->buffers_flash_offset, sizeof(fota_buffers_t), (uint8_t*)(uintptr_t)buffer);
369     if (ret != ERRCODE_SUCC) {
370         state->err_code = ret;
371         upg_log_err("[UPG] fota_buffers_has_contents: cannot read buffers, err_code = 0x%x\r\n", state->err_code);
372         goto ret_free;
373     }
374 
375     for (i = 0; i < (sizeof(fota_buffers_t) / WORD_WIDTH); i++) {
376         if (*((uint32_t *)(uintptr_t)buffer + i) != 0xffffffff) {
377             /* The buffer was not erased */
378             upg_log_err("[UPG] fota_buffers_has_contents: buffers are not erased  i = %d, val = 0x%x\r\n",
379                 i, *(((uint32_t*)(uintptr_t)buffer) + i));
380             goto ret_free;
381         }
382     }
383     /* The buffer has been erased */
384     buffers_set = false;
385 
386 ret_free:
387     fota_patch_free(buffer);
388     return buffers_set;
389 }
390 
read_page_buffer(patch_state_t * state,uint8_t * dest)391 STATIC void read_page_buffer(patch_state_t *state, uint8_t *dest)
392 {
393     if (state->err_code != ERRCODE_SUCC) {
394         upg_log_err("[UPG] read_page_buffer state err_code = 0x%x\r\n", state->err_code);
395         /* Do not process anything if an error occurred */
396         return;
397     }
398 
399     if (upg_flash_read(state->desc->buffers_flash_offset, UPG_FLASH_PAGE_SIZE, dest) != ERRCODE_SUCC) {
400         state->err_code = ERRCODE_FAIL;
401         upg_log_err("[UPG] read_page_buffer: cannot read buffer, err_code = 0x%x\r\n", state->err_code);
402         return;
403     }
404 }
405 
replace_page_buffer(patch_state_t * state,uint8_t * source)406 STATIC void replace_page_buffer(patch_state_t *state, uint8_t *source)
407 {
408     if (state->err_code != ERRCODE_SUCC) {
409         upg_log_err("[UPG] replace_page_buffer state err_code = 0x%x\r\n", state->err_code);
410         /* Do not process anything if an error occurred */
411         return;
412     }
413 
414     if (upg_flash_write(state->desc->buffers_flash_offset, UPG_FLASH_PAGE_SIZE, source, true) != ERRCODE_SUCC) {
415         state->err_code = ERRCODE_FAIL;
416         upg_log_err("[UPG] replace_page_buffer: cannot write buffer, err_code = 0x%x\r\n", state->err_code);
417         return;
418     }
419 }
420 
read_page_status(patch_state_t * state,int32_t page_no)421 STATIC uint8_t read_page_status(patch_state_t *state, int32_t page_no)
422 {
423     uint32_t  val = 0;
424     uint32_t  page_num = state->desc->image_flash_offset / UPG_FLASH_PAGE_SIZE + (uint32_t)page_no;
425     uint32_t offset =
426         state->desc->buffers_flash_offset + state->desc->buffers_length + ((uint32_t)sizeof(uint8_t) * page_num);
427 
428     if (state->err_code != ERRCODE_SUCC) {
429         upg_log_err("[UPG] read_page_status state err_code = 0x%x\r\n", state->err_code);
430         /* Do not process anything if an error occurred */
431         return 0x00;
432     }
433 
434     if (upg_flash_read(offset, sizeof(uint8_t), (uint8_t *)&val) != ERRCODE_SUCC) {
435         state->err_code = ERRCODE_FAIL;
436         upg_log_err("[UPG] read_page_status: cannot read status, err_code = 0x%x\r\n", state->err_code);
437         return 0x00;
438     }
439     return (uint8_t)val;
440 }
441 
write_page_status(patch_state_t * state,int32_t page_no,uint8_t val)442 STATIC void write_page_status(patch_state_t *state, int32_t page_no, uint8_t val)
443 {
444     uint32_t page_num = state->desc->image_flash_offset / UPG_FLASH_PAGE_SIZE + (uint32_t)page_no;
445     uint32_t offset =
446         state->desc->buffers_flash_offset + state->desc->buffers_length + ((uint32_t)sizeof(val) * page_num);
447     uint32_t old = 0;
448 
449     if (state->err_code != ERRCODE_SUCC) {
450         upg_log_err("[UPG] write_page_status state err_code = 0x%x\r\n", state->err_code);
451         /* Do not process anything if an error occurred */
452         return;
453     }
454 
455     if (upg_flash_read(offset, sizeof(val), (uint8_t *)&old) != ERRCODE_SUCC) {
456         state->err_code = ERRCODE_FAIL;
457         upg_log_err("[UPG] write_page_status: cannot read old status, err_code = 0x%x\r\n", state->err_code);
458         return;
459     }
460     if ((val & ~((uint8_t)old)) != 0) {
461         upg_log_info("[UPG] write_page_status: Trying to set bits 0->1 at offset = 0x%x, with 0x%x -> 0x%x\r\n",
462             offset, (uint32_t)old, (uint32_t)val);
463     }
464     if (upg_flash_write(offset, sizeof(val), &val, false) != ERRCODE_SUCC) {
465         state->err_code = ERRCODE_FAIL;
466         upg_log_err("[UPG] write_page_status: cannot write status, err_code = 0x%x\r\n", state->err_code);
467         return;
468     }
469 }
470 
erase_fota_buffers(patch_state_t * state)471 STATIC void erase_fota_buffers(patch_state_t *state)
472 {
473     if (state->err_code != ERRCODE_SUCC) {
474         upg_log_err("[UPG] erase_fota_buffers state err_code = 0x%x\r\n", state->err_code);
475         /* Do not process anything if an error occurred */
476         return;
477     }
478 
479     if (upg_flash_erase(state->desc->buffers_flash_offset, state->desc->buffers_length) != ERRCODE_SUCC) {
480         state->err_code = ERRCODE_FAIL;
481         upg_log_err("[UPG] erase_fota_buffers: cannot erase the fota buffers, err_code = 0x%x\r\n",
482             state->err_code);
483         return;
484     }
485 }
486 
erase_image_flash_page(patch_state_t * state,int32_t image_page)487 STATIC void erase_image_flash_page(patch_state_t *state, int32_t image_page)
488 {
489     if (state->err_code != ERRCODE_SUCC) {
490         upg_log_err("[UPG] erase_image_flash_page state err_code = 0x%x\r\n", state->err_code);
491         return;
492     }
493 
494     errcode_t ret;
495     ret = upg_flash_erase(state->desc->image_flash_offset + (image_page * UPG_FLASH_PAGE_SIZE), UPG_FLASH_PAGE_SIZE);
496     if (ret != ERRCODE_SUCC) {
497         upg_log_err("[UPG] read_byte state err_code = 0x%x\r\n", state->err_code);
498         state->err_code = ERRCODE_FAIL;
499         return;
500     }
501 }
502 
503 /*
504  * In applying an in-place patch, the flash writes get applied a page at a time.
505  * Sometimes the page gets written to more than once.  In fact, an individual page can get
506  * written to up to 3 times.    (Ok, there may be several updates within a page.  But there
507  * will only be a maximum of 3 writes.
508  *
509  * here's a page:
510  *                    d  d  d  d  d  d  d  d  d  d  d  d  d  d  d  d  d  d  d
511 
512  * here's the 3 types of write operations, a b and c
513  *                    a5 a4 a3 a2 a1 b1 b2 b3 b4 b5 b6 b7 b8 b9 c4 c3 c2 c2 c1
514  *         (<--------) <----------a  b---->----->->---------->  <-----------c (<--------)
515  *
516  * so this function page_write_type() spots these different operations based on the first and
517  * last value used.
518  */
page_write_type(const patch_state_t * state,int32_t first,int32_t last)519 STATIC unsigned char page_write_type(const patch_state_t *state, int32_t first, int32_t last)
520 {
521     if (state->err_code != ERRCODE_SUCC) {
522         upg_log_err("[UPG] page_write_type state err_code = 0x%x\r\n", state->err_code);
523         /* Do not process anything if an error occurred */
524         return 0xff;
525     }
526 
527     const int32_t limit = UPG_FLASH_PAGE_SIZE - 1;
528     if (((first == 0) && (last == limit)) || ((first == limit) && (last == 0))) {
529         /* it's a full page. */
530         upg_log_info("[UPG] STANDARD A\r\n");
531         return PAGE_WRITE_STANDARD;
532     }
533 
534     if ((first > 0) && (first < limit) && (last > 0) && (last < limit)) {
535         /* it's a section from the middle */
536         upg_log_info("[UPG] STANDARD B\r\n");
537         return PAGE_WRITE_STANDARD;
538     }
539 
540     if ((first == 0) || (last == 0)) {
541         upg_log_info("[UPG] PARTIAL_START\r\n");
542         return PAGE_WRITE_PARTIAL_START;
543     }
544     return PAGE_WRITE_PARTIAL_END;
545 }
546 
write_flash_page_skip_done(patch_state_t * state)547 STATIC void write_flash_page_skip_done(patch_state_t *state)
548 {
549     if (state == NULL || state->err_code != ERRCODE_SUCC || state->desc == NULL) {
550         upg_log_err("[UPG] write_flash_page_skip_done state error");
551         /* Do not process anything if an error occurred */
552         return;
553     }
554 
555     if (state->local_buffer_page != -1) {
556         const int32_t r = read_page_status(state, state->local_buffer_page);
557         const int32_t t = page_write_type(state, state->page_first_written, state->page_last_written);
558         if (((uint32_t)r & (uint32_t)t) == 0) {
559             upg_calculate_and_notify_process(UPG_FLASH_PAGE_SIZE);
560 
561             upg_log_info("[UPG] Skipping! page = 0x%x\r\n", (uint32_t)state->local_buffer_page);
562             upg_log_info("[UPG]   type = 0x%x permitted = 0x%x (first = 0x%x last = 0x%x)\r\n",
563                 (uint32_t)t, (uint32_t)r, (uint32_t)state->page_first_written, (uint32_t)state->page_last_written);
564             if (state->done_skipping) {
565                 upg_log_err("[UPG] Corrupt flash! We have written valid pages, but now we're back to skipping!");
566             }
567         } else if (((uint32_t)r & ((uint32_t)t >> 1)) == 0) {
568             /* So this means the W bit for the operation was set, but B was cleared.  We should never be */
569             /* in this state; the recovery operation should mark this as completed. */
570             upg_log_err("[UPG] Corrupt flash!Page write bits are not as expected.page = 0x%x, status = 0x%x\r\n",
571                 (uint32_t)state->local_buffer_page, (uint32_t)read_page_status(state, state->local_buffer_page));
572         } else {
573             const uint32_t unsigned_t = (uint32_t) t;
574             const uint32_t unsigned_r = (uint32_t) r;
575             const uint32_t val = unsigned_r & ~(unsigned_t>>1);
576             /* Prepare the image page contents for writing performing any encryption necessary. */
577             /* Any error returned put into the state err_code to be handled. */
578             state->err_code = fota_pkg_flash_prep_page_contents_for_write(state->desc,
579                                                                           (uint32_t)state->local_buffer_page,
580                                                                           state->local_buffer);
581             state->done_skipping = 1;
582             replace_page_buffer(state, state->local_buffer);
583             /* mark the bits to show the buffer is good.  (Clear B) */
584 
585             write_page_status(state, state->local_buffer_page, (uint8_t)val);
586 
587             /* write the whole UPG_FLASH_PAGE_SIZE block */
588             write_image_block(state, UPG_FLASH_PAGE_SIZE,
589                               state->local_buffer_page * UPG_FLASH_PAGE_SIZE, state->local_buffer);
590             if (state->err_code == ERRCODE_SUCC) {
591                 /* mark the bits to show it's written.  (Clear W (and B)) */
592                 write_page_status(state, state->local_buffer_page,
593                     (uint8_t)(unsigned_r & ~(unsigned_t | (unsigned_t >> 1))));
594             }
595         }
596     }
597 }
598 
599 /*
600  * Note, in order to do the recovery thing, write_byte will SKIP those pages that
601  * have already been written, in an 'restartable' manner
602  * to permit recovery from an incomplete update operation.
603  */
write_byte(patch_state_t * state,int32_t dest_offset,unsigned char val)604 STATIC void write_byte(patch_state_t *state, int32_t dest_offset, unsigned char val)
605 {
606     int32_t dest_offset_page;
607     if (state->err_code != ERRCODE_SUCC) {
608         upg_log_err("[UPG] write_byte state err_code = 0x%x\r\n", state->err_code);
609         /* Do not process anything if an error occurred */
610         return;
611     }
612 
613     dest_offset_page = dest_offset / UPG_FLASH_PAGE_SIZE;
614     if (dest_offset_page != state->local_buffer_page) {
615         /* write back the old page */
616         write_flash_page_skip_done(state);
617         /* check to see if we have a page to write back, AND if we have written this already. */
618          /* now populate state->local_buffer with the next page's values. */
619         read_image_block(state, UPG_FLASH_PAGE_SIZE, dest_offset_page * UPG_FLASH_PAGE_SIZE, state->local_buffer);
620         state->local_buffer_page = dest_offset_page;
621         state->page_first_written = dest_offset % UPG_FLASH_PAGE_SIZE;
622     }
623     state->local_buffer[dest_offset % UPG_FLASH_PAGE_SIZE] = val;
624     state->page_last_written = dest_offset % UPG_FLASH_PAGE_SIZE;
625 }
626 
read_byte(patch_state_t * state,int32_t dest_offset)627 STATIC unsigned char read_byte(patch_state_t *state, int32_t dest_offset)
628 {
629     int32_t dest_offset_page;
630 
631     if (state->err_code != ERRCODE_SUCC) {
632         upg_log_err("[UPG] read_byte state err_code = 0x%x\r\n", state->err_code);
633         /* Do not process anything if an error occurred */
634         return 0xff;
635     }
636 
637     dest_offset_page = dest_offset / UPG_FLASH_PAGE_SIZE;
638     if (dest_offset_page == state->local_buffer_page) {
639         return state->local_buffer[dest_offset % UPG_FLASH_PAGE_SIZE];
640     } else {
641         uint32_t b = 0;
642         read_image_block(state, 1, dest_offset, (uint8_t *)&b);
643         return (uint8_t)b;
644     }
645 }
646 
647 
finish_write(patch_state_t * state)648 STATIC void finish_write(patch_state_t *state)
649 {
650     if (state->err_code != ERRCODE_SUCC) {
651         upg_log_err("[UPG] finish_write state err_code = 0x%x\r\n", state->err_code);
652         /* Do not process anything if an error occurred */
653         return;
654     }
655 
656     write_flash_page_skip_done(state);
657     state->local_buffer_page = -1;
658 }
659 
660 /**
661  * @brief  Sanity check the diff after obtaining a control block.
662  *
663  * @param aps    apply_patch(...) function state.
664  * @param state  fota patching state.
665  * @return       true if processing should proceed with this control block or false if processing should stop.
666  */
apply_patch_get_control_block_sanity_check(const apply_patch_state_t * aps,patch_state_t * state)667 STATIC bool apply_patch_get_control_block_sanity_check(const apply_patch_state_t *aps, patch_state_t *state)
668 {
669     if (aps->newpos + aps->cb.copy > (uint32_t)(state->desc->newsize)) {
670         state->err_code = ERRCODE_UPG_CHECK_FOTA_ERROR;
671         upg_log_err("[UPG] Corrupt patch 4, err_code = 0x%x\r\n", state->err_code);
672         return false;
673     }
674     if (aps->oldpos + aps->cb.copy > (uint32_t)(state->desc->maxsize)) {
675         state->err_code = ERRCODE_UPG_CHECK_FOTA_ERROR;
676         upg_log_err("[UPG] Corrupt patch 4a, err_code = 0x%x\r\n", state->err_code);
677         return false;
678     }
679 #if (UPG_CFG_DEBUG_PRINT_ENABLED == YES)
680     if (state->desc->bottom_up) {
681         if (aps->newpos <= aps->oldpos) {
682             upg_log_info("[UPG] NCkA\r\n");
683         } else {
684             upg_log_info("[UPG] RCkB\r\n");
685         }
686     } else {
687         if (aps->newpos <= aps->oldpos) {
688             upg_log_info("[UPG] NCkC\r\n");
689         } else {
690             upg_log_info("[UPG] RCkD\r\n");
691         }
692     }
693 #endif
694     return true;
695 }
696 
697 /**
698  * @brief  Fetch the control block from the diff.
699  *
700  * @param aps    apply_patch(...) function state.
701  * @param state  fota patching state.
702  * @return       true if processing should proceed with this control block or false if processing should stop.
703  */
apply_patch_get_control_block(apply_patch_state_t * aps,patch_state_t * state)704 STATIC bool apply_patch_get_control_block(apply_patch_state_t *aps, patch_state_t *state)
705 {
706     /* Read control data */
707     aps->lenread =
708         (uint32_t)zip_mem_read(state, &(aps->cerror), aps->zcontext, (unsigned char *)&(aps->cb), sizeof(aps->cb));
709     if ((aps->lenread < sizeof(aps->cb)) || ((aps->cerror != Z_OK) && (aps->cerror != ZIP_STREAM_END))) {
710         state->err_code = ERRCODE_UPG_CHECK_FOTA_ERROR;
711         upg_log_err("[UPG] Corrupt patch 3a (data exhausted), err_code = 0x%x\r\n", state->err_code);
712         return false;
713     }
714     if (memcmp((unsigned char *)&(aps->cb), PATCH_KNVD_STR, PATCH_KNVD_STR_LEN) != 0) {
715         state->err_code = ERRCODE_UPG_CHECK_FOTA_ERROR;
716         upg_log_err("[UPG] Corrupt patch 3b (not magic number), err_code = 0x%x\r\n", state->err_code);
717         return false;
718     }
719     aps->blockcount++;
720 
721     /* Sanity-check */
722     return apply_patch_get_control_block_sanity_check(aps, state);
723 }
724 
725 /**
726  * @brief Apply a delta chunk for a bottom up patch
727  *
728  * @param aps    apply_patch(...) function state.
729  * @param state  fota patching state.
730  */
apply_patch_delta_chunk_bottom_up(apply_patch_state_t * aps,patch_state_t * state)731 STATIC void apply_patch_delta_chunk_bottom_up(apply_patch_state_t *aps, patch_state_t *state)
732 {
733     int32_t newsize = state->desc->newsize;
734     int32_t chunk_offset;
735     int32_t rpos;
736     int32_t wpos;
737 
738     if (aps->newpos <= aps->oldpos) {
739         for (chunk_offset = 0; (chunk_offset < aps->chunk_size) && (state->err_code == ERRCODE_SUCC);
740              chunk_offset++) {
741             rpos = newsize - 1 - (aps->oldpos + chunk_offset + aps->chunk_start);
742             wpos = newsize - 1 - (aps->newpos + chunk_offset + aps->chunk_start);
743             write_byte(state, wpos, read_byte(state, rpos) + aps->unpackedbuf[chunk_offset]);
744         }
745     } else {
746         for (chunk_offset = 0; (chunk_offset < aps->chunk_size) && (state->err_code == ERRCODE_SUCC);
747              chunk_offset++) {
748             rpos = newsize - 1 - (aps->oldpos + ((int32_t)aps->cb.copy - 1 - (chunk_offset + aps->chunk_start)));
749             wpos = newsize - 1 - (aps->newpos + ((int32_t)aps->cb.copy - 1 - (chunk_offset + aps->chunk_start)));
750             write_byte(state, wpos, read_byte(state, rpos) + aps->unpackedbuf[chunk_offset]);
751         }
752     }
753 }
754 
755 /**
756  * @brief Apply a delta chunk for a top down patch
757  *
758  * @param aps    apply_patch(...) function state.
759  * @param state  fota patching state.
760  */
apply_patch_delta_chunk_top_down(apply_patch_state_t * aps,patch_state_t * state)761 STATIC void apply_patch_delta_chunk_top_down(apply_patch_state_t *aps, patch_state_t *state)
762 {
763     int32_t chunk_offset;
764     int32_t rpos;
765     int32_t wpos;
766 
767     if (aps->newpos <= aps->oldpos) {
768         for (chunk_offset = 0; (chunk_offset < aps->chunk_size) && (state->err_code == ERRCODE_SUCC);
769              chunk_offset++) {
770             rpos = aps->oldpos + chunk_offset + aps->chunk_start;
771             wpos = aps->newpos + chunk_offset + aps->chunk_start;
772             write_byte(state, wpos, read_byte(state, rpos) + aps->unpackedbuf[chunk_offset]);
773         }
774     } else {
775         for (chunk_offset = 0; (chunk_offset < aps->chunk_size) && (state->err_code == ERRCODE_SUCC);
776              chunk_offset++) {
777             rpos = aps->oldpos + ((int32_t)aps->cb.copy - 1 - (chunk_offset + aps->chunk_start));
778             wpos = aps->newpos + ((int32_t)aps->cb.copy - 1 - (chunk_offset + aps->chunk_start));
779             write_byte(state, wpos, read_byte(state, rpos) + aps->unpackedbuf[chunk_offset]);
780         }
781     }
782 }
783 
784 /**
785  * @brief  Process the code deltas within the diff for a section of the image.
786  *
787  * @param aps    apply_patch(...) function state.
788  * @param state  fota patching state.
789  * @return       true if processing should be continue onto the next chunk or false if processing should stop.
790  */
apply_patch_delta_chunk(apply_patch_state_t * aps,patch_state_t * state,int32_t * cctotal)791 STATIC bool apply_patch_delta_chunk(apply_patch_state_t *aps, patch_state_t *state, int32_t *cctotal)
792 {
793     aps->chunk_size = uapi_min((int32_t)DECOMPRESSION_SIZE, (int32_t)aps->cb.copy - aps->chunk_start);
794     *cctotal += aps->chunk_size;
795 
796     aps->unpackedbuf = fota_patch_alloc((uint32_t)aps->chunk_size);
797     if (aps->unpackedbuf == NULL) {
798         state->err_code = ERRCODE_MALLOC;
799         upg_log_err("[UPG] malloc failure, err_code = 0x%x\r\n", state->err_code);
800         /* Exit loop to immediately handle the error */
801         return false;
802     }
803 
804     aps->lenread = (uint32_t)zip_mem_read(state, (int32_t *)&(aps->cerror), aps->zcontext, aps->unpackedbuf,
805                                           aps->chunk_size);
806     if (((int32_t)aps->lenread < aps->chunk_size) ||
807         ((aps->cerror != Z_OK) && (aps->cerror != ZIP_STREAM_END))) {
808         state->err_code = ERRCODE_UPG_CHECK_FOTA_ERROR;
809         fota_patch_free(aps->unpackedbuf);
810         aps->unpackedbuf = NULL;
811         upg_log_err("[UPG] Corrupt patch 5 (data exhausted), err_code = 0x%x\r\n", state->err_code);
812         /* Exit loop to immediately handle the error */
813         return false;
814     }
815 
816     /* add diff data to previous data.   It's IN PLACE!!!!! */
817     if (state->desc->bottom_up) {
818         apply_patch_delta_chunk_bottom_up(aps, state);
819     } else {
820         apply_patch_delta_chunk_top_down(aps, state);
821     }
822 
823     /* Free any previously allocated memory */
824     fota_patch_free(aps->unpackedbuf);
825     aps->unpackedbuf = NULL;
826     upg_watchdog_kick();
827 
828     return true;
829 }
830 
831 
832 /**
833  * @brief  Process the code deltas within the diff for a section of code.
834  *
835  * @param aps    apply_patch(...) function state.
836  * @param state  fota patching state.
837  * @return       true if processing should be continued or false if processing should stop.
838  */
apply_patch_deltas(apply_patch_state_t * aps,patch_state_t * state)839 STATIC bool apply_patch_deltas(apply_patch_state_t *aps, patch_state_t *state)
840 {
841     int32_t cctotal = 0;
842 
843     for (aps->chunk_start = 0; (aps->chunk_start < (int32_t)(aps->cb.copy)) && (state->err_code == ERRCODE_SUCC);
844          aps->chunk_start += (int32_t)DECOMPRESSION_SIZE) {
845         if (!apply_patch_delta_chunk(aps, state, &cctotal)) {
846             break;
847         }
848     }
849     /* Ensure that any allocated memory has been freed even if there has been an error */
850     fota_patch_free(aps->unpackedbuf);
851     aps->unpackedbuf = NULL;
852     /* return if there has been an error */
853     if (state->err_code != ERRCODE_SUCC) {
854         upg_log_err("[UPG] apply_patch b state err_code = 0x%x\r\n", state->err_code);
855         return false;
856     }
857     /* Adjust pointers */
858     aps->newpos += (int32_t)aps->cb.copy;
859     aps->oldpos += (int32_t)aps->cb.copy;
860 
861     /* Sanity-check */
862     if ((aps->newpos + (int32_t)aps->cb.extra) > state->desc->newsize) {
863         state->err_code = ERRCODE_UPG_CHECK_FOTA_ERROR;
864         upg_log_err("[UPG] Corrupt patch 6, err_code = 0x%x\r\n", state->err_code);
865         return false;
866     }
867 
868     return true;
869 }
870 
871 /**
872  * @brief Apply an extra chunk for a bottom up patch
873  *
874  * @param aps    apply_patch(...) function state.
875  * @param state  fota patching state.
876  */
apply_patch_extra_chunk_bottom_up(apply_patch_state_t * aps,patch_state_t * state)877 STATIC void apply_patch_extra_chunk_bottom_up(apply_patch_state_t *aps, patch_state_t *state)
878 {
879     int32_t newsize = state->desc->newsize;
880     int32_t chunk_offset;
881     int32_t wpos;
882 
883     for (chunk_offset = 0; (chunk_offset < aps->chunk_size) && (state->err_code == ERRCODE_SUCC);
884          chunk_offset++) {
885         wpos = newsize - 1 - (aps->newpos + chunk_offset + aps->chunk_start);
886         write_byte(state, wpos, aps->unpackedbuf[chunk_offset]);
887     }
888 }
889 
890 /**
891  * @brief Apply an extra chunk for a top down patch
892  *
893  * @param aps    apply_patch(...) function state.
894  * @param state  fota patching state.
895  */
apply_patch_extra_chunk_top_down(apply_patch_state_t * aps,patch_state_t * state)896 STATIC void apply_patch_extra_chunk_top_down(apply_patch_state_t *aps, patch_state_t *state)
897 {
898     int32_t chunk_offset;
899     int32_t wpos;
900 
901     for (chunk_offset = 0; (chunk_offset < aps->chunk_size) && (state->err_code == ERRCODE_SUCC);
902          chunk_offset++) {
903         wpos = aps->newpos + chunk_offset + aps->chunk_start;
904         write_byte(state, wpos, aps->unpackedbuf[chunk_offset]);
905     }
906 }
907 
908 /**
909  * @brief  Process the code extras within the diff for a section of code.
910  *
911  * @param aps    apply_patch(...) function state.
912  * @param state  fota patching state.
913  * @return       true if processing should be continued or false if processing should stop.
914  */
apply_patch_extra_chunk(apply_patch_state_t * aps,patch_state_t * state)915 STATIC bool apply_patch_extra_chunk(apply_patch_state_t *aps, patch_state_t *state)
916 {
917     aps->chunk_size = uapi_min((int32_t)DECOMPRESSION_SIZE, (int32_t)aps->cb.extra - aps->chunk_start);
918 
919     aps->unpackedbuf = fota_patch_alloc((uint32_t)aps->chunk_size);
920     if (aps->unpackedbuf == NULL) {
921         state->err_code = ERRCODE_MALLOC;
922         upg_log_err("[UPG] malloc failure, err_code = 0x%x\r\n", state->err_code);
923         return false;
924     }
925 
926     aps->lenread = (uint32_t)zip_mem_read(state, &(aps->cerror), aps->zcontext, aps->unpackedbuf, aps->chunk_size);
927     if ((int32_t)aps->lenread < aps->chunk_size) {
928         state->err_code = ERRCODE_UPG_CHECK_FOTA_ERROR;
929         fota_patch_free(aps->unpackedbuf);
930         aps->unpackedbuf = NULL;
931         upg_log_err("[UPG] Corrupt patch 7a (data exhausted), err_code = 0x%x\r\n", state->err_code);
932         return false;
933     }
934     if (((aps->cerror != Z_OK) && (aps->cerror != ZIP_STREAM_END))) {
935         state->err_code = ERRCODE_UPG_CHECK_FOTA_ERROR;
936         upg_log_err("[UPG] Corrupt patch 7, returned(data corrupted) = 0x%x, err_code = 0x%x\r\n",
937             (uint32_t)aps->cerror, state->err_code);
938     }
939     if (state->desc->bottom_up) {
940         apply_patch_extra_chunk_bottom_up(aps, state);
941     } else {
942         apply_patch_extra_chunk_top_down(aps, state);
943     }
944     fota_patch_free(aps->unpackedbuf);
945     aps->unpackedbuf = NULL;
946 
947     return true;
948 }
949 
950 /**
951  * @brief  Process the code extras within the diff for a section of code.
952  *
953  * @param aps    apply_patch(...) function state.
954  * @param state  fota patching state.
955  * @return       true if processing should be continued or false if processing should stop.
956  */
apply_patch_extras(apply_patch_state_t * aps,patch_state_t * state)957 STATIC bool apply_patch_extras(apply_patch_state_t *aps, patch_state_t *state)
958 {
959     for (aps->chunk_start = 0; (aps->chunk_start < (int32_t)(aps->cb.extra)) && (state->err_code == ERRCODE_SUCC);
960          aps->chunk_start += (int32_t)DECOMPRESSION_SIZE) {
961         if (!apply_patch_extra_chunk(aps, state)) {
962             break;
963         }
964     }
965     /* Ensure that any allocated memory has been freed even if there has been an error */
966     fota_patch_free(aps->unpackedbuf);
967     aps->unpackedbuf = NULL;
968 
969     /* return if there has been an error */
970     if (state->err_code != ERRCODE_SUCC) {
971         upg_log_err("[UPG] apply_patch c state err_code = 0x%x\r\n", state->err_code);
972         return false;
973     }
974     /* Adjust pointers */
975     aps->newpos += (int32_t)aps->cb.extra;
976     aps->oldpos += aps->cb.seek;
977 
978     /* more sanity */
979     if (aps->newpos > state->desc->newsize) {
980         state->err_code = ERRCODE_UPG_CHECK_FOTA_ERROR;
981         upg_log_err("[UPG] Corrupt patch 8 (overran destination), err_code = 0x%x\r\n", state->err_code);
982         return false;
983     }
984     if (aps->oldpos >= (state->desc->maxsize)) {
985         state->err_code = ERRCODE_UPG_CHECK_FOTA_ERROR;
986         upg_log_err("[UPG] Corrupt patch 9 (overran source), err_code = 0x%x\r\n", state->err_code);
987         return false;
988     }
989 
990     return true;
991 }
992 
apply_patch(patch_state_t * state)993 STATIC void apply_patch(patch_state_t *state)
994 {
995     apply_patch_state_t aps;
996 
997     if (state == NULL || state->err_code != ERRCODE_SUCC || state->desc == NULL) {
998         upg_log_err("[UPG] apply_patch state error");
999         /* Do not process anything if an error occurred */
1000         return;
1001     }
1002 
1003     aps.zcontext = zip_init(state);
1004     if ((aps.zcontext == NULL) || (state->err_code != ERRCODE_SUCC)) {
1005         upg_log_err("[UPG] aps.zcontext init state err_code = 0x%x\r\n", state->err_code);
1006         return;
1007     }
1008     aps.oldpos = 0;
1009     aps.newpos = 0;
1010     aps.blockcount = 0;
1011     aps.unpackedbuf = NULL;
1012 
1013     /* main patching loop */
1014     while ((aps.newpos < state->desc->newsize) && (state->err_code == ERRCODE_SUCC)) {
1015         /* Get the next control block */
1016         if (!apply_patch_get_control_block(&aps, state)) {
1017             break;
1018         }
1019 
1020         /* Apply diff deltas */
1021         if (!apply_patch_deltas(&aps, state)) {
1022             break;
1023         }
1024 
1025         /* Read extra string */
1026         if (!apply_patch_extras(&aps, state)) {
1027             break;
1028         }
1029     };
1030     /* complete the write */
1031     finish_write(state);
1032     /* Ensure that any allocated memory has been freed even if there has been an error */
1033     fota_patch_free(aps.unpackedbuf);
1034     if (aps.zcontext != NULL) {
1035         /* Clean up the compressed reads */
1036         zip_end(state, aps.zcontext);
1037     }
1038 }
1039 
erase_redundant_pages(patch_state_t * state)1040 STATIC void erase_redundant_pages(patch_state_t *state)
1041 {
1042     /* Erase any old image pages if new image is smaller */
1043     uint32_t num_old_pages = state->desc->num_old_pages;
1044     uint32_t num_new_pages = state->desc->num_new_pages;
1045     if (num_old_pages > num_new_pages) {
1046         for (uint32_t page = num_new_pages; page < num_old_pages; page++) {
1047             erase_image_flash_page(state, (int32_t)page);
1048         }
1049     }
1050 }
1051 
process_patch_init(patch_state_t * state,patch * desc,process_patch_state_t * pps)1052 STATIC void process_patch_init(patch_state_t *state, patch *desc, process_patch_state_t *pps)
1053 {
1054     state->desc = desc;
1055     state->lzma_alloc.Alloc = lzma_malloc;
1056     state->lzma_alloc.Free = lzma_free;
1057     state->local_buffer = fota_patch_alloc(UPG_FLASH_PAGE_SIZE);
1058     if (state->local_buffer == NULL) {
1059         upg_log_err("[UPG] local_buffer malloc error");
1060         state->err_code = ERRCODE_MALLOC;
1061     } else {
1062         state->err_code = ERRCODE_SUCC;
1063     }
1064     state->local_buffer_page = -1;
1065     state->page_first_written = -1;
1066     state->page_last_written = -1;
1067     state->done_skipping = false;
1068 
1069     pps->recovery_buffer = NULL;
1070     pps->recovery_found = false;
1071 #if (UPG_CFG_DEBUG_PRINT_ENABLED == YES)
1072     upg_log_info("[UPG] Starting patching process\r\n");
1073     upg_log_info("[UPG] desc->bottom_up = 0x%x\r\n", (uint32_t)desc->bottom_up);
1074     upg_log_info("[UPG] desc->buffers_flash_offset = 0x%x\r\n", desc->buffers_flash_offset);
1075     upg_log_info("[UPG] desc->buffers_length = 0x%x\r\n", desc->buffers_length);
1076     upg_log_info("[UPG] desc->failpoint = 0x%x\r\n", (uint32_t)desc->failpoint);
1077     upg_log_info("[UPG] desc->image_flash_offset = 0x%x\r\n", desc->image_flash_offset);
1078     upg_log_info("[UPG] desc->maxsize = 0x%x\r\n", (uint32_t)desc->maxsize);
1079     upg_log_info("[UPG] desc->newsize = 0x%x\r\n", (uint32_t)desc->newsize);
1080     upg_log_info("[UPG] desc->oldsize = 0x%x\r\n", (uint32_t)desc->oldsize);
1081     upg_log_info("[UPG] desc->patch_contents_flash_offset = 0x%x\r\n", desc->patch_contents_flash_offset);
1082     upg_log_info("[UPG] desc->patch_contents_len = 0x%x\r\n", desc->patch_contents_len);
1083 #endif
1084 }
1085 
process_patch_recover_page(patch_state_t * state,process_patch_state_t * pps,uint32_t page_no,int32_t page_status,int32_t status_bit)1086 STATIC void process_patch_recover_page(patch_state_t *state, process_patch_state_t *pps, uint32_t page_no,
1087                                        int32_t page_status, int32_t status_bit)
1088 {
1089     if (pps->recovery_found) {
1090         state->err_code = ERRCODE_FAIL;
1091         upg_log_err("[UPG] Corrupt flash recovery - we can't have more than one page in progress!!!\r\n");
1092         upg_log_err("[UPG]     page = 0x%x, bit = 0x%x, err_code = 0x%x\r\n",
1093             page_no, (uint32_t)status_bit, state->err_code);
1094         return;
1095     }
1096     pps->recovery_buffer = fota_patch_alloc(UPG_FLASH_PAGE_SIZE);
1097     if (pps->recovery_buffer == NULL) {
1098         state->err_code = ERRCODE_MALLOC;
1099         upg_log_err("[UPG] err_code = 0x%x\r\n", state->err_code);
1100         return;
1101     }
1102     /* extract contents to recovery_buffer */
1103     read_page_buffer(state, pps->recovery_buffer);
1104     if (state->err_code != ERRCODE_SUCC) {
1105         upg_log_err("[UPG] process_patch read_page_buffer err_code = 0x%x\r\n", state->err_code);
1106         fota_patch_free(pps->recovery_buffer);
1107         pps->recovery_buffer = NULL;
1108         return;
1109     }
1110 
1111     /* write page */
1112     write_image_block(state, UPG_FLASH_PAGE_SIZE, (int32_t)page_no * UPG_FLASH_PAGE_SIZE, pps->recovery_buffer);
1113 
1114     fota_patch_free(pps->recovery_buffer);
1115     pps->recovery_buffer = NULL;
1116 
1117     const uint32_t page_status_unsigned = (uint32_t) page_status;
1118     const uint32_t status_bit_unsigned  = (uint32_t) status_bit;
1119 
1120     /* it's the new page now, so clear down this operation. */
1121     write_page_status(state, (int32_t)page_no,
1122         (uint8_t)(page_status_unsigned & ~((1UL << status_bit_unsigned) | (1UL << (status_bit_unsigned - 1)))));
1123     pps->recovery_found = true;
1124 }
1125 
process_patch_check_page_buffer_recovery(patch_state_t * state,process_patch_state_t * pps)1126 STATIC void process_patch_check_page_buffer_recovery(patch_state_t *state, process_patch_state_t *pps)
1127 {
1128     int32_t page_no;
1129     int32_t status_bit;
1130 
1131     /* pass through the bits, and if there's a buffer page written, with the corresponding page deleted,
1132      * then write the buffer to the duff page. */
1133     for (page_no = 0; (page_no < (int32_t)state->desc->num_maxsize_pages) && (state->err_code == ERRCODE_SUCC);
1134          page_no++) {
1135         const int32_t page_status = read_page_status(state, page_no);
1136         const uint32_t page_status_unsigned = (uint32_t)page_status;
1137         for (status_bit = PAGE_STATUS_BIT_SEARCH_START;
1138              (status_bit <= PAGE_STATUS_BIT_SEARCH_END) && (state->err_code == ERRCODE_SUCC);
1139              status_bit += PAGE_STATUS_BIT_SEARCH_INC) {
1140             const uint32_t status_bit_unsigned = (uint32_t)status_bit;
1141             if (((page_status_unsigned & (1UL << status_bit_unsigned)) != 0) &&
1142                 ((page_status_unsigned & (1UL << (status_bit_unsigned - 1))) == 0)) {
1143                 process_patch_recover_page(state, pps, (uint32_t)page_no, page_status, status_bit);
1144             }
1145         }
1146     }
1147 }
1148 
process_patch_perform_recovery(patch_state_t * state,process_patch_state_t * pps)1149 STATIC void process_patch_perform_recovery(patch_state_t *state, process_patch_state_t *pps)
1150 {
1151     /* Cache the recovery image in RAM if required, determine if old signature page is encrypted */
1152     state->err_code = fota_pkg_plaintext_flash_cache_init(state->desc);
1153     if (state->err_code != ERRCODE_SUCC) {
1154         upg_log_err("[UPG] process_patch - caching recovery flash failure err_code = 0x%x\r\n", state->err_code);
1155         return;
1156     }
1157 
1158     /* Check if there is a page buffer written that needs to be written back to flash. */
1159     process_patch_check_page_buffer_recovery(state, pps);
1160     if (state->err_code != ERRCODE_SUCC) {
1161         upg_log_err("[UPG] process_patch state err_code = 0x%x\r\n", state->err_code);
1162         return;
1163     }
1164 #if (UPG_CFG_DEBUG_PRINT_ENABLED == YES)
1165     if (!pps->recovery_found) {
1166         upg_log_info("[UPG] No buffer page required recovery.\r\n");
1167         upg_log_info("[UPG] (This implies that the failure must have occurred\r\n");
1168         upg_log_info("[UPG] while writing to the buffer, not while erasing or writing the target flash.\r\n");
1169     } else {
1170         upg_log_info("[UPG] Ready to continue patching\r\n");
1171     }
1172     upg_log_info("[UPG] Recovery complete\r\n");
1173 #endif
1174 }
1175 
process_patch(patch * desc)1176 errcode_t process_patch(patch *desc)
1177 {
1178     patch_state_t state;
1179     process_patch_state_t pps;
1180     process_patch_init(&state, desc, &pps);
1181     if (state.err_code != ERRCODE_SUCC) {
1182         return state.err_code;
1183     }
1184 
1185     /* check if there is a patch in progress and continue it if so. */
1186     if (fota_buffers_has_contents(&state)) {
1187         process_patch_perform_recovery(&state, &pps);
1188         if (state.err_code != ERRCODE_SUCC) {
1189             goto ret_free;
1190         }
1191     } else {
1192         /* Cache non-recovery SEMAIN as required */
1193         state.err_code = fota_pkg_plaintext_flash_cache_init(desc);
1194         if (state.err_code != ERRCODE_SUCC) {
1195             upg_log_err("[UPG] process_patch - caching flash failure err_code = 0x%x\r\n", state.err_code);
1196             goto ret_free;
1197         }
1198 
1199         erase_fota_buffers(&state);
1200     }
1201     /* apply the zipped patch.  This will in turn use the write_byte_skip_done functions
1202      * which means an interrupted write should resume and (potentially) complete ok. */
1203     apply_patch(&state);
1204 
1205     erase_redundant_pages(&state);
1206     erase_fota_buffers(&state);
1207 
1208 ret_free:
1209     fota_patch_free(state.local_buffer);
1210     fota_patch_free(pps.recovery_buffer);
1211     return state.err_code;
1212 }
1213 
fota_pkg_task_code_diff_cleanup_actions(patch * patch_desc)1214 STATIC void fota_pkg_task_code_diff_cleanup_actions(patch *patch_desc)
1215 {
1216     /* Clean allocated cache, Freeing a NULL is benign so no check for FOTA_PKG_TASK_ID_SEMAIN_CODE needed */
1217     upg_free(patch_desc->image_cache);
1218     patch_desc->image_cache = NULL;
1219 }
1220 
init_patch_description_with_task_info(const upg_image_header_t * image,patch * patch_desc)1221 STATIC void init_patch_description_with_task_info(const upg_image_header_t *image, patch *patch_desc)
1222 {
1223     /* This will panic if it fails so no need to check the return value. */
1224     (void)memset_s(patch_desc, sizeof(patch), 0, sizeof(patch));
1225 
1226     patch_desc->image_id = image->image_id;
1227     patch_desc->maxsize = uapi_max((int32_t)image->new_image_len, (int32_t)image->old_image_len);
1228     patch_desc->newsize = (int32_t)image->new_image_len;
1229     patch_desc->oldsize = (int32_t)image->old_image_len;
1230     patch_desc->num_new_pages = (uint32_t)(patch_desc->newsize + (UPG_FLASH_PAGE_SIZE - 1)) / UPG_FLASH_PAGE_SIZE;
1231     patch_desc->num_old_pages = (uint32_t)(patch_desc->oldsize + (UPG_FLASH_PAGE_SIZE - 1)) / UPG_FLASH_PAGE_SIZE;
1232     patch_desc->num_maxsize_pages = uapi_max(patch_desc->num_new_pages, patch_desc->num_old_pages);
1233     patch_desc->new_sig_page = patch_desc->num_new_pages - 1;
1234     patch_desc->old_sig_page = patch_desc->num_old_pages - 1;
1235 
1236     patch_desc->patch_contents_ram_copy = 0;
1237     patch_desc->patch_contents_flash_offset = (uint32_t)image->image_offset;
1238     patch_desc->patch_contents_len = image->image_len;
1239     patch_desc->bottom_up = image->old_image_len < image->new_image_len;
1240     patch_desc->image_encrypted = false;
1241     /* No failure injection */
1242     patch_desc->failpoint = 0;
1243     patch_desc->failfn = NULL;
1244     /* Image read and prepare for writing functions. */
1245     patch_desc->fetch_image_contents_fn = fota_pkg_flash_read_image;
1246     patch_desc->prep_image_contents_for_write_fn = fota_pkg_flash_prep_page_contents_for_write;
1247     patch_desc->plaintext_flash_cache_init_fn = fota_pkg_plaintext_flash_cache_init;
1248     patch_desc->copy_recovered_buffer_to_flash_cache_fn = NULL;
1249     patch_desc->encrypt_flash_page_fn = NULL;
1250 }
1251 
fota_pkg_task_apply_code_diff(const upg_image_header_t * image)1252 errcode_t fota_pkg_task_apply_code_diff(const upg_image_header_t *image)
1253 {
1254     errcode_t ret;
1255     patch     *desc;
1256     uint32_t   fota_data_addr;
1257     uint32_t   fota_data_len;
1258     if (image == NULL) {
1259         upg_log_err("[UPG] task_apply_code_diff image is NULL");
1260         return ERRCODE_FAIL;
1261     }
1262 
1263     desc = fota_patch_alloc(sizeof(patch));
1264     if (desc == NULL) {
1265         upg_log_err("[UPG] patch *desc malloc failed");
1266         return ERRCODE_MALLOC;
1267     }
1268     init_patch_description_with_task_info(image, desc);
1269 
1270     ret = upg_get_partition_info(image->image_id, &desc->image_flash_offset, &desc->image_flash_length);
1271     if (ret != ERRCODE_SUCC) {
1272         fota_patch_free(desc);
1273         return ret;
1274     }
1275 
1276     /* Get the metadata buffer area */
1277     ret = upg_get_progress_status_start_addr(&fota_data_addr, &fota_data_len);
1278     if (ret != ERRCODE_SUCC) {
1279         upg_log_err("[UPG] fota_pkg_task_apply_code_diff get area addr faile, ret = 0x%x\r\n", ret);
1280         fota_patch_free(desc);
1281         return ret;
1282     }
1283     desc->buffers_flash_offset = fota_data_addr;
1284     desc->buffers_length = FOTA_DATA_BUFFER_AREA_LEN;
1285 
1286     /* Update patch description structure with task specific parameters and run through
1287      * any required initialisation functions done on a per task basis */
1288     if (ret == ERRCODE_SUCC) {
1289         /* Attempt to apply the patch */
1290         ret = process_patch(desc);
1291     }
1292 
1293     fota_pkg_task_code_diff_cleanup_actions(desc);
1294     fota_patch_free(desc);
1295     return ret;
1296 }