blob: f6be0472ac742d41fd01e306f635657b39aa44c0 [file] [log] [blame]
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +02001/*
2 * SPDX-License-Identifier: Apache-2.0
3 *
4 * Copyright (c) 2017-2019 Linaro LTD
5 * Copyright (c) 2016-2019 JUUL Labs
6 * Copyright (c) 2019-2020 Arm Limited
7 * Copyright (c) 2020 Cypress Semiconductors
8 *
9 * Original license:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one
12 * or more contributor license agreements. See the NOTICE file
13 * distributed with this work for additional information
14 * regarding copyright ownership. The ASF licenses this file
15 * to you under the Apache License, Version 2.0 (the
16 * "License"); you may not use this file except in compliance
17 * with the License. You may obtain a copy of the License at
18 *
19 * http://www.apache.org/licenses/LICENSE-2.0
20 *
21 * Unless required by applicable law or agreed to in writing,
22 * software distributed under the License is distributed on an
23 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
24 * KIND, either express or implied. See the License for the
25 * specific language governing permissions and limitations
26 * under the License.
27 */
28
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020029#include "crc32c.h"
30#include <string.h>
Roman Okhrimenko977b3752022-03-31 14:40:48 +030031#include <stdlib.h>
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020032#include "swap_status.h"
33
34#ifdef MCUBOOT_SWAP_USING_STATUS
35
Roman Okhrimenko977b3752022-03-31 14:40:48 +030036static uint8_t record_buff[BOOT_SWAP_STATUS_ROW_SZ];
37static uint8_t status_buff[BOOT_SWAP_STATUS_PAYLD_SZ];
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020038
39const uint32_t stat_part_magic[] = {
40 BOOT_SWAP_STATUS_MAGIC
41};
42
Roman Okhrimenko977b3752022-03-31 14:40:48 +030043static inline uint32_t calc_rec_idx(uint32_t value)
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020044{
Roman Okhrimenko977b3752022-03-31 14:40:48 +030045 return value / BOOT_SWAP_STATUS_PAYLD_SZ;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020046}
47
Roman Okhrimenko977b3752022-03-31 14:40:48 +030048static inline uint32_t calc_record_offs(uint32_t offs)
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020049{
Roman Okhrimenko977b3752022-03-31 14:40:48 +030050 return BOOT_SWAP_STATUS_ROW_SZ * calc_rec_idx(offs);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020051}
52
Roman Okhrimenko977b3752022-03-31 14:40:48 +030053static inline uint32_t calc_record_crc(const uint8_t *data, uint32_t length)
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020054{
Roman Okhrimenko977b3752022-03-31 14:40:48 +030055 return crc32c_checksum(data, length);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020056}
57
Roman Okhrimenko977b3752022-03-31 14:40:48 +030058static inline uint32_t pack_bytes_u32(const uint8_t *data)
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020059{
Roman Okhrimenko977b3752022-03-31 14:40:48 +030060 uint32_t result = 0U;
61
62 result = ((uint32_t)data[3U] << 24U) | ((uint32_t)data[2U] << 16U) |
63 ((uint32_t)data[1U] << 8U) | (uint32_t)data[0U];
64
65 return result;
66}
67
68int32_t swap_status_init_offset(uint8_t area_id)
69{
70 uint8_t order[] = {
71 FLASH_AREA_IMAGE_PRIMARY(0U)
72 , FLASH_AREA_IMAGE_SECONDARY(0U)
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020073#ifdef MCUBOOT_SWAP_USING_SCRATCH
Roman Okhrimenko977b3752022-03-31 14:40:48 +030074 , FLASH_AREA_IMAGE_SCRATCH
75#endif /* MCUBOOT_SWAP_USING_SCRATCH */
76#if BOOT_IMAGE_NUMBER >= 2
77 , FLASH_AREA_IMAGE_PRIMARY(1U)
78 , FLASH_AREA_IMAGE_SECONDARY(1U)
79#endif /* BOOT_IMAGE_NUMBER >= 2 */
80#if BOOT_IMAGE_NUMBER >= 3
81 , FLASH_AREA_IMAGE_PRIMARY(2U)
82 , FLASH_AREA_IMAGE_SECONDARY(2U)
83#endif /* BOOT_IMAGE_NUMBER >= 3 */
84#if BOOT_IMAGE_NUMBER == 4
85 , FLASH_AREA_IMAGE_PRIMARY(3U)
86 , FLASH_AREA_IMAGE_SECONDARY(3U)
87#endif /* BOOT_IMAGE_NUMBER == 4 */
88 };
89
90 int32_t result = -1;
91 int32_t offset = 0;
92 uint32_t i;
93
94 for (i = 0U; i < sizeof(order) / sizeof(order[0U]); i++) {
95 if (order[i] == area_id) {
96 result = offset;
97 break;
98 }
99 offset += BOOT_SWAP_STATUS_SIZE;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200100 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300101
102 return result;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200103}
104
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300105static int swap_status_read_record(uint32_t rec_offset, uint8_t *data, uint32_t *copy_counter, uint32_t *max_idx)
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200106{ /* returns BOOT_SWAP_STATUS_PAYLD_SZ of data */
107 int rc = -1;
108
109 uint32_t fin_offset;
110 uint32_t data_offset = 0;
111 uint32_t counter, crc, magic;
112 uint32_t crc_fail = 0;
113 uint32_t magic_fail = 0;
114 uint32_t max_cnt = 0;
115
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200116 const struct flash_area *fap_stat = NULL;
117
118 rc = flash_area_open(FLASH_AREA_IMAGE_SWAP_STATUS, &fap_stat);
119 if (rc != 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300120 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200121 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300122 else {
123 /* loop over copies/duplicates */
124 for (uint32_t i = 0; i < BOOT_SWAP_STATUS_MULT; i++) {
125 /* calculate final duplicate offset */
126 fin_offset = rec_offset + i * BOOT_SWAP_STATUS_D_SIZE;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200127
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300128 rc = flash_area_read(fap_stat, fin_offset, record_buff, sizeof(record_buff));
129 if (rc != 0) {
130 return -1;
131 }
132 else {
133 /* read magic value to know if area was pre-erased */
134 magic = pack_bytes_u32(&record_buff[BOOT_SWAP_STATUS_PAYLD_SZ]);
135 if (magic == BOOT_SWAP_STATUS_MAGIC) { /* read CRC */
136 crc = pack_bytes_u32(&record_buff[BOOT_SWAP_STATUS_ROW_SZ -
137 BOOT_SWAP_STATUS_CRC_SZ]);
138 /* check record data integrity first */
139 if (crc == calc_record_crc(record_buff, BOOT_SWAP_STATUS_ROW_SZ-BOOT_SWAP_STATUS_CRC_SZ)) {
140 /* look for counter */
141 counter = pack_bytes_u32(&record_buff[BOOT_SWAP_STATUS_ROW_SZ -
142 BOOT_SWAP_STATUS_CNT_SZ -
143 BOOT_SWAP_STATUS_CRC_SZ]);
144 /* find out counter max */
145 if (counter >= max_cnt) {
146 max_cnt = counter;
147 *max_idx = i;
148 data_offset = fin_offset;
149 }
150 }
151 /* if crc != calculated() */
152 else {
153 crc_fail++;
154 }
155 }
156 else {
157 magic_fail++;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200158 }
159 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200160 }
161 }
162 /* no magic found - status area is pre-erased, start from scratch */
163 if (magic_fail == BOOT_SWAP_STATUS_MULT) {
164 /* emulate last index was received, so next will start from beginning */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300165 *max_idx = BOOT_SWAP_STATUS_MULT - 1U;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200166 *copy_counter = 0;
167 /* return all erased values */
168 (void)memset(data, (int32_t)flash_area_erased_val(fap_stat), BOOT_SWAP_STATUS_PAYLD_SZ);
169 }
170 else {
171 /* no valid CRC found - status pre-read failure */
172 if (crc_fail == BOOT_SWAP_STATUS_MULT) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300173 rc = -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200174 }
175 else {
176 *copy_counter = max_cnt;
177 /* read payload data */
178 rc = flash_area_read(fap_stat, data_offset, data, BOOT_SWAP_STATUS_PAYLD_SZ);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300179 if (rc != 0) {
180 rc = -1;
181 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200182 }
183 }
184 flash_area_close(fap_stat);
185
186 /* return back duplicate index */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300187 return rc;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200188}
189
190static int swap_status_write_record(uint32_t rec_offset, uint32_t copy_num, uint32_t copy_counter, const uint8_t *data)
191{ /* it receives explicitly BOOT_SWAP_STATUS_PAYLD_SZ of data */
192 int rc = -1;
193
194 uint32_t fin_offset;
195 /* increment counter field */
196 uint32_t next_counter = copy_counter + 1U;
197 uint32_t next_crc;
198
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200199 const struct flash_area *fap_stat = NULL;
200
201 rc = flash_area_open(FLASH_AREA_IMAGE_SWAP_STATUS, &fap_stat);
202 if (rc != 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300203 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200204 }
205
206 /* copy data into buffer */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300207 (void)memcpy(record_buff, data, BOOT_SWAP_STATUS_PAYLD_SZ);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200208 /* append next counter to whole record row */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300209 (void)memcpy(&record_buff[BOOT_SWAP_STATUS_ROW_SZ-BOOT_SWAP_STATUS_CNT_SZ-BOOT_SWAP_STATUS_CRC_SZ],
210 (uint8_t *)&next_counter,
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200211 BOOT_SWAP_STATUS_CNT_SZ);
212 /* append record magic */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300213 (void)memcpy(&record_buff[BOOT_SWAP_STATUS_PAYLD_SZ], (const uint8_t *)stat_part_magic, BOOT_SWAP_STATUS_MGCREC_SZ);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200214
215 /* calculate CRC field*/
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300216 next_crc = calc_record_crc(record_buff, BOOT_SWAP_STATUS_ROW_SZ-BOOT_SWAP_STATUS_CRC_SZ);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200217
218 /* append new CRC to whole record row */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300219 (void)memcpy(&record_buff[BOOT_SWAP_STATUS_ROW_SZ-BOOT_SWAP_STATUS_CRC_SZ],
220 (uint8_t *)&next_crc,
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200221 BOOT_SWAP_STATUS_CRC_SZ);
222
223 /* we already know what copy number was last and correct */
224 /* increment duplicate index */
225 /* calculate final duplicate offset */
226 if (copy_num == (BOOT_SWAP_STATUS_MULT - 1U)) {
227 copy_num = 0;
228 }
229 else {
230 copy_num++;
231 }
232 fin_offset = rec_offset + copy_num*BOOT_SWAP_STATUS_D_SIZE;
233
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300234 /* erase obsolete status record before write */
235 rc = flash_area_erase(fap_stat, fin_offset, sizeof(record_buff));
236 if (rc != 0) {
237 return -1;
238 }
239
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200240 /* write prepared record into flash */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300241 rc = flash_area_write(fap_stat, fin_offset, record_buff, sizeof(record_buff));
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200242
243 flash_area_close(fap_stat);
244
245 return rc;
246}
247
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300248static int boot_magic_decode(uint8_t *magic)
249{
250 if (memcmp(magic, (const uint8_t *)boot_img_magic, BOOT_MAGIC_SZ) == 0) {
251 return BOOT_MAGIC_GOOD;
252 }
253 return BOOT_MAGIC_BAD;
254}
255
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200256/**
257 * Updates len bytes of status partition with values from *data-pointer.
258 *
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300259 * @param target_area_id Target area id for which status is being written.
260 * Not a status-partition area id.
261 * @param offset Status byte offset inside status table. Should not include CRC and CNT.
262 * @param data Pointer to data status table to needs to be updated with.
263 * @param len Number of bytes to be written
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200264 *
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300265 * @return 0 on success; -1 on failure.
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200266 */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300267int swap_status_update(uint8_t target_area_id, uint32_t offs, const void *data, uint32_t len)
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200268{
269 int rc = -1;
270
271 int32_t init_offs;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300272 uint32_t copy_num = 0;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200273
274 uint32_t rec_offs;
275 uint32_t copy_sz;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300276 uint32_t copy_counter = 0;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200277 uint32_t data_idx = 0;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300278 uint32_t buff_idx = offs % BOOT_SWAP_STATUS_PAYLD_SZ;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200279
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300280 if ((UINT32_MAX - offs) < len) {
281 return -1;
282 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200283
284 /* check if end of data is still inside writable area */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300285 if ((offs + len) > BOOT_SWAP_STATUS_D_SIZE_RAW) {
286 return -1;
287 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200288
289 /* pre-calculate sub-area offset */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300290 init_offs = swap_status_init_offset(target_area_id);
291 if (init_offs < 0) {
292 return -1;
293 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200294
295 /* will start from it
296 * this will be write-aligned */
297 rec_offs = (uint32_t)init_offs + calc_record_offs(offs);
298
299 /* go over all records to be updated */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300300 while (len != 0U) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200301 /* preserve record */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300302 rc = swap_status_read_record(rec_offs, status_buff, &copy_counter, &copy_num);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200303 /* it returns copy number */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300304 if (rc < 0)
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200305 { /* something went wrong while read, exit */
306 rc = -1;
307 break;
308 }
309 /* update record data */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300310 if (len > BOOT_SWAP_STATUS_PAYLD_SZ) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200311 copy_sz = BOOT_SWAP_STATUS_PAYLD_SZ - buff_idx;
312 }
313 else {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300314 copy_sz = len;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200315 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300316
317 (void)memcpy(status_buff + buff_idx, (const uint8_t *)data + data_idx, copy_sz);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200318 buff_idx = 0;
319
320 /* write record back */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300321 rc = swap_status_write_record(rec_offs, copy_num, copy_counter, status_buff);
322 if (rc != 0) {
323 break;
324 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200325
326 /* proceed to next record */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300327 if (len < BOOT_SWAP_STATUS_PAYLD_SZ) {
328 len = 0;
329 }
330 else {
331 len -= BOOT_SWAP_STATUS_PAYLD_SZ;
332 rec_offs += BOOT_SWAP_STATUS_ROW_SZ;
333 data_idx += BOOT_SWAP_STATUS_PAYLD_SZ;
334 }
335
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200336 }
337 return rc;
338}
339
340/**
341 * Reads len bytes of status partition with values from *data-pointer.
342 *
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300343 * @param target_area_id Target area id for which status is being read.
344 * Not a status-partition area id.
345 * @param offset Status byte offset inside status table. Should not include CRC and CNT.
346 * @param data Pointer to data where status table values will be written.
347 * @param len Number of bytes to be read from status table.
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200348 *
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300349 * @return 0 on success; -1 on failure.
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200350 */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300351int swap_status_retrieve(uint8_t target_area_id, uint32_t offs, void *data, uint32_t len)
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200352{
353 int rc = 0;
354
355 int32_t init_offs;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300356 uint32_t copy_num = 0;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200357
358 uint32_t rec_offs;
359 uint32_t copy_sz;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300360 uint32_t copy_counter = 0;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200361 uint32_t data_idx = 0;
362 uint32_t buff_idx = offs % BOOT_SWAP_STATUS_PAYLD_SZ;
363
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300364 if ((UINT32_MAX - offs) < len) {
365 return -1;
366 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200367
368 /* check if end of data is still inside writable area */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300369 if ((offs + len) > BOOT_SWAP_STATUS_D_SIZE_RAW) {
370 return -1;
371 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200372
373 /* pre-calculate sub-area offset */
374 init_offs = swap_status_init_offset(target_area_id);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300375 if (init_offs < 0) {
376 return -1;
377 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200378
379 /* will start from it
380 * this will be write-aligned */
381 rec_offs = (uint32_t)init_offs + calc_record_offs(offs);
382
383 /* go over all records to be updated */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300384 while (len != 0U) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200385 /* preserve record */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300386 rc = swap_status_read_record(rec_offs, status_buff, &copy_counter, &copy_num);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200387 /* it returns copy number */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300388 if (rc < 0) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200389 /* something went wrong while read, exit */
390 rc = -1;
391 break;
392 }
393 /* update record data */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300394 if (len > BOOT_SWAP_STATUS_PAYLD_SZ) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200395 copy_sz = BOOT_SWAP_STATUS_PAYLD_SZ - buff_idx;
396 }
397 else {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300398 copy_sz = len;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200399 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300400
401 (void)memcpy((uint8_t *)data + data_idx, status_buff + buff_idx, copy_sz);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200402 buff_idx = 0;
403
404 /* proceed to next record */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300405 if (len < BOOT_SWAP_STATUS_PAYLD_SZ) {
406 len = 0;
407 }
408 else {
409 len -= BOOT_SWAP_STATUS_PAYLD_SZ;
410 rec_offs += BOOT_SWAP_STATUS_ROW_SZ;
411 data_idx += BOOT_SWAP_STATUS_PAYLD_SZ;
412 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200413 }
414 return rc;
415}
416
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300417/**
418 * Copy trailer from status partition to primary image and set copy_done flag.
419 * This function calls only once, before set copy_done flag in status trailer
420 *
421 * @param fap Target area id for which status is being read.
422 *
423 * @return 0 on success; -1 on failure.
424 */
425int swap_status_to_image_trailer(const struct flash_area *fap)
426{
427 uint8_t erased_val;
428 uint8_t stat_erased_val;
429 const uint8_t *copy_src;
430 uint32_t cur_trailer_pos;
431 uint32_t primary_trailer_sz;
432 uint32_t primary_trailer_buf_sz;
433 uint32_t align = CY_FLASH_ALIGN;
434 int rc = 0;
435 const struct flash_area *fap_stat = NULL;
436 uint8_t primary_trailer_buf[MAX_TRAILER_BUF_SIZE];
437
438 /* get the erased flash byte for status partition */
439 rc = flash_area_open(FLASH_AREA_IMAGE_SWAP_STATUS, &fap_stat);
440 if (rc != 0) {
441 return rc;
442 }
443 stat_erased_val = flash_area_erased_val(fap_stat);
444 flash_area_close(fap_stat);
445
446 /* get status partition trailer size and copy it to buffer */
447 const uint32_t status_trailer_buf_sz = BOOT_SWAP_STATUS_SWAPSZ_SZ + BOOT_SWAP_STATUS_SWAPINF_SZ +
448 BOOT_SWAP_STATUS_COPY_DONE_SZ + BOOT_SWAP_STATUS_IMG_OK_SZ + BOOT_SWAP_STATUS_MAGIC_SZ;
449 uint8_t status_trailer_buf[status_trailer_buf_sz];
450 (void)memset(&status_trailer_buf, 0, status_trailer_buf_sz);
451 rc = swap_status_retrieve(fap->fa_id, boot_swap_size_off(fap), (uint8_t *)status_trailer_buf, status_trailer_buf_sz);
452 if (rc != 0) {
453 return rc;
454 }
455
456 /* check trailer magic in status partition */
457 if (boot_magic_decode(&status_trailer_buf[status_trailer_buf_sz - BOOT_SWAP_STATUS_MAGIC_SZ]) != BOOT_MAGIC_GOOD) {
458 return -1;
459 }
460
461 /* get primary slot trailer size without status data fields */
462 primary_trailer_sz = boot_trailer_sz(0);
463
464 /* align image trailer buffer size to minimal write size */
465#if !defined(__BOOTSIM__)
466 align = flash_area_align(fap);
467#else
468 align = CY_FLASH_ALIGN;
469#endif
470
471 if ((align > MAX_TRAILER_BUF_SIZE) || (align == 0U)) {
472 return -1;
473 }
474
475 primary_trailer_buf_sz = align;
476 while (primary_trailer_buf_sz < primary_trailer_sz) {
477 primary_trailer_buf_sz += align;
478 }
479 if (primary_trailer_buf_sz > MAX_TRAILER_BUF_SIZE) {
480 return -1;
481 }
482
483 /* erase primary slot trailer */
484 rc= flash_area_erase(fap, fap->fa_size - primary_trailer_buf_sz, primary_trailer_buf_sz);
485 if (rc != 0) {
486 return rc;
487 }
488
489 /* erase trailer area */
490 erased_val = flash_area_erased_val(fap); /* stat_erased_val and erased_val may differ! */
491 (void)memset(&primary_trailer_buf[primary_trailer_buf_sz-primary_trailer_sz], (int) erased_val, primary_trailer_sz);
492
493 /* copy and align flags and data from status_trailer_buf to primary_trailer_buf
494 Status part trailer --> Pimary image trailer */
495
496 /* copy trailer magic */
497 cur_trailer_pos = primary_trailer_buf_sz - BOOT_SWAP_STATUS_MAGIC_SZ;
498 copy_src = &status_trailer_buf[status_trailer_buf_sz - BOOT_SWAP_STATUS_MAGIC_SZ];
499 if (stat_erased_val != erased_val &&
500 bootutil_buffer_is_filled(copy_src, stat_erased_val, BOOT_SWAP_STATUS_MAGIC_SZ)) {
501
502 (void)memset(&primary_trailer_buf[cur_trailer_pos], (int)erased_val, BOOT_SWAP_STATUS_MAGIC_SZ);
503 }
504 else {
505 (void)memcpy(&primary_trailer_buf[cur_trailer_pos], copy_src, BOOT_SWAP_STATUS_MAGIC_SZ);
506 }
507
508 /* copy image_ok flag */
509 cur_trailer_pos -= BOOT_MAX_ALIGN;
510 copy_src = &status_trailer_buf[BOOT_SWAP_STATUS_SWAPSZ_SZ + BOOT_SWAP_STATUS_SWAPINF_SZ + BOOT_SWAP_STATUS_COPY_DONE_SZ];
511 if (stat_erased_val != erased_val && stat_erased_val == *copy_src) {
512 copy_src = &erased_val;
513 }
514 primary_trailer_buf[cur_trailer_pos] = *copy_src;
515
516 /* set copy_done flag */
517 cur_trailer_pos -= BOOT_MAX_ALIGN;
518 primary_trailer_buf[cur_trailer_pos] = BOOT_FLAG_SET;
519
520 /* copy swap_type flag */
521 cur_trailer_pos -= BOOT_MAX_ALIGN;
522 copy_src = &status_trailer_buf[BOOT_SWAP_STATUS_SWAPSZ_SZ];
523 if (stat_erased_val != erased_val && stat_erased_val == *copy_src) {
524 copy_src = &erased_val;
525 }
526 primary_trailer_buf[cur_trailer_pos] = *copy_src;
527
528 /* copy swap_size field */
529 cur_trailer_pos -= BOOT_MAX_ALIGN;
530 if (stat_erased_val != erased_val &&
531 bootutil_buffer_is_filled(status_trailer_buf, stat_erased_val, BOOT_SWAP_STATUS_SWAPSZ_SZ)) {
532
533 (void)memset(&primary_trailer_buf[cur_trailer_pos], (int)erased_val, BOOT_SWAP_STATUS_SWAPSZ_SZ);
534 }
535 else {
536 (void)memcpy(&primary_trailer_buf[cur_trailer_pos], status_trailer_buf, BOOT_SWAP_STATUS_SWAPSZ_SZ);
537 }
538
539 /* write primary image trailer with copy_done flag set */
540 rc = flash_area_write(fap, fap->fa_size - primary_trailer_buf_sz, primary_trailer_buf, primary_trailer_buf_sz);
541
542 return rc;
543}
544
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200545#endif /* MCUBOOT_SWAP_USING_STATUS */