blob: 00565774d51828674b9fc7cf5864233d85c23600 [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"
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +030033#include "sysflash/sysflash.h"
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020034
35#ifdef MCUBOOT_SWAP_USING_STATUS
36
Roman Okhrimenko977b3752022-03-31 14:40:48 +030037static uint8_t record_buff[BOOT_SWAP_STATUS_ROW_SZ];
38static uint8_t status_buff[BOOT_SWAP_STATUS_PAYLD_SZ];
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020039
40const uint32_t stat_part_magic[] = {
41 BOOT_SWAP_STATUS_MAGIC
42};
43
Roman Okhrimenko977b3752022-03-31 14:40:48 +030044static inline uint32_t calc_rec_idx(uint32_t value)
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020045{
Roman Okhrimenko977b3752022-03-31 14:40:48 +030046 return value / BOOT_SWAP_STATUS_PAYLD_SZ;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020047}
48
Roman Okhrimenko977b3752022-03-31 14:40:48 +030049static inline uint32_t calc_record_offs(uint32_t offs)
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020050{
Roman Okhrimenko977b3752022-03-31 14:40:48 +030051 return BOOT_SWAP_STATUS_ROW_SZ * calc_rec_idx(offs);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020052}
53
Roman Okhrimenko977b3752022-03-31 14:40:48 +030054static inline uint32_t calc_record_crc(const uint8_t *data, uint32_t length)
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020055{
Roman Okhrimenko977b3752022-03-31 14:40:48 +030056 return crc32c_checksum(data, length);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020057}
58
Roman Okhrimenko977b3752022-03-31 14:40:48 +030059static inline uint32_t pack_bytes_u32(const uint8_t *data)
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +020060{
Roman Okhrimenko977b3752022-03-31 14:40:48 +030061 uint32_t result = 0U;
62
63 result = ((uint32_t)data[3U] << 24U) | ((uint32_t)data[2U] << 16U) |
64 ((uint32_t)data[1U] << 8U) | (uint32_t)data[0U];
65
66 return result;
67}
68
69int32_t swap_status_init_offset(uint8_t area_id)
70{
Roman Okhrimenko977b3752022-03-31 14:40:48 +030071 int32_t result = -1;
72 int32_t offset = 0;
73 uint32_t i;
74
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +030075#ifdef MCUBOOT_SWAP_USING_SCRATCH
76 #define ADD_ARRAY_MEMBER_FOR_SCRATCH (1U)
77#else
78 #define ADD_ARRAY_MEMBER_FOR_SCRATCH (0U)
79#endif /* MCUBOOT_SWAP_USING_SCRATCH */
80
81 /* we always have at least 2 images in BOOT and UPGRADE slots */
82#define ARR_SIZE (SLOTS_FOR_IMAGE + ADD_ARRAY_MEMBER_FOR_SCRATCH + ((uint8_t)BOOT_IMAGE_NUMBER - 1U) * SLOTS_FOR_IMAGE)
83
84 uint8_t slots_ids[ARR_SIZE];
85
86 slots_ids[0] = FLASH_AREA_IMAGE_PRIMARY(0U);
87 slots_ids[1] = FLASH_AREA_IMAGE_SECONDARY(0U);
88
89#ifdef MCUBOOT_SWAP_USING_SCRATCH
90 /* The third position of SCRATCH is saved as it was before */
91 slots_ids[2] = FLASH_AREA_IMAGE_SCRATCH;
92#endif /* MCUBOOT_SWAP_USING_SCRATCH */
93
94#if (BOOT_IMAGE_NUMBER > 1)
95
96 uint8_t primary_slots_per_id = SLOTS_FOR_IMAGE + ADD_ARRAY_MEMBER_FOR_SCRATCH;
97 uint8_t secondary_slots_per_id = primary_slots_per_id + 1U;
98
99 for (i = 1U; i < (uint32_t) BOOT_IMAGE_NUMBER; ++i)
100 {
101 slots_ids[primary_slots_per_id] = FLASH_AREA_IMAGE_PRIMARY( i );
102 slots_ids[secondary_slots_per_id] = FLASH_AREA_IMAGE_SECONDARY( i );
103 primary_slots_per_id += 2U;
104 secondary_slots_per_id += 2U;
105 }
106
107#endif /* BOOT_IMAGE_NUMBER > 1 */
108
109 for (i = 0U; i < ARR_SIZE; i++) {
110 if (slots_ids[i] == area_id) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300111 result = offset;
112 break;
113 }
114 offset += BOOT_SWAP_STATUS_SIZE;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200115 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300116
117 return result;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200118}
119
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300120static 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 +0200121{ /* returns BOOT_SWAP_STATUS_PAYLD_SZ of data */
122 int rc = -1;
123
124 uint32_t fin_offset;
125 uint32_t data_offset = 0;
126 uint32_t counter, crc, magic;
127 uint32_t crc_fail = 0;
128 uint32_t magic_fail = 0;
129 uint32_t max_cnt = 0;
130
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200131 const struct flash_area *fap_stat = NULL;
132
133 rc = flash_area_open(FLASH_AREA_IMAGE_SWAP_STATUS, &fap_stat);
134 if (rc != 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300135 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200136 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300137 else {
138 /* loop over copies/duplicates */
139 for (uint32_t i = 0; i < BOOT_SWAP_STATUS_MULT; i++) {
140 /* calculate final duplicate offset */
141 fin_offset = rec_offset + i * BOOT_SWAP_STATUS_D_SIZE;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200142
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300143 rc = flash_area_read(fap_stat, fin_offset, record_buff, sizeof(record_buff));
144 if (rc != 0) {
145 return -1;
146 }
147 else {
148 /* read magic value to know if area was pre-erased */
149 magic = pack_bytes_u32(&record_buff[BOOT_SWAP_STATUS_PAYLD_SZ]);
150 if (magic == BOOT_SWAP_STATUS_MAGIC) { /* read CRC */
151 crc = pack_bytes_u32(&record_buff[BOOT_SWAP_STATUS_ROW_SZ -
152 BOOT_SWAP_STATUS_CRC_SZ]);
153 /* check record data integrity first */
154 if (crc == calc_record_crc(record_buff, BOOT_SWAP_STATUS_ROW_SZ-BOOT_SWAP_STATUS_CRC_SZ)) {
155 /* look for counter */
156 counter = pack_bytes_u32(&record_buff[BOOT_SWAP_STATUS_ROW_SZ -
157 BOOT_SWAP_STATUS_CNT_SZ -
158 BOOT_SWAP_STATUS_CRC_SZ]);
159 /* find out counter max */
160 if (counter >= max_cnt) {
161 max_cnt = counter;
162 *max_idx = i;
163 data_offset = fin_offset;
164 }
165 }
166 /* if crc != calculated() */
167 else {
168 crc_fail++;
169 }
170 }
171 else {
172 magic_fail++;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200173 }
174 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200175 }
176 }
177 /* no magic found - status area is pre-erased, start from scratch */
178 if (magic_fail == BOOT_SWAP_STATUS_MULT) {
179 /* emulate last index was received, so next will start from beginning */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300180 *max_idx = BOOT_SWAP_STATUS_MULT - 1U;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200181 *copy_counter = 0;
182 /* return all erased values */
183 (void)memset(data, (int32_t)flash_area_erased_val(fap_stat), BOOT_SWAP_STATUS_PAYLD_SZ);
184 }
185 else {
186 /* no valid CRC found - status pre-read failure */
187 if (crc_fail == BOOT_SWAP_STATUS_MULT) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300188 rc = -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200189 }
190 else {
191 *copy_counter = max_cnt;
192 /* read payload data */
193 rc = flash_area_read(fap_stat, data_offset, data, BOOT_SWAP_STATUS_PAYLD_SZ);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300194 if (rc != 0) {
195 rc = -1;
196 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200197 }
198 }
199 flash_area_close(fap_stat);
200
201 /* return back duplicate index */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300202 return rc;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200203}
204
205static int swap_status_write_record(uint32_t rec_offset, uint32_t copy_num, uint32_t copy_counter, const uint8_t *data)
206{ /* it receives explicitly BOOT_SWAP_STATUS_PAYLD_SZ of data */
207 int rc = -1;
208
209 uint32_t fin_offset;
210 /* increment counter field */
211 uint32_t next_counter = copy_counter + 1U;
212 uint32_t next_crc;
213
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200214 const struct flash_area *fap_stat = NULL;
215
216 rc = flash_area_open(FLASH_AREA_IMAGE_SWAP_STATUS, &fap_stat);
217 if (rc != 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300218 return -1;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200219 }
220
221 /* copy data into buffer */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300222 (void)memcpy(record_buff, data, BOOT_SWAP_STATUS_PAYLD_SZ);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200223 /* append next counter to whole record row */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300224 (void)memcpy(&record_buff[BOOT_SWAP_STATUS_ROW_SZ-BOOT_SWAP_STATUS_CNT_SZ-BOOT_SWAP_STATUS_CRC_SZ],
225 (uint8_t *)&next_counter,
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200226 BOOT_SWAP_STATUS_CNT_SZ);
227 /* append record magic */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300228 (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 +0200229
230 /* calculate CRC field*/
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300231 next_crc = calc_record_crc(record_buff, BOOT_SWAP_STATUS_ROW_SZ-BOOT_SWAP_STATUS_CRC_SZ);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200232
233 /* append new CRC to whole record row */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300234 (void)memcpy(&record_buff[BOOT_SWAP_STATUS_ROW_SZ-BOOT_SWAP_STATUS_CRC_SZ],
235 (uint8_t *)&next_crc,
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200236 BOOT_SWAP_STATUS_CRC_SZ);
237
238 /* we already know what copy number was last and correct */
239 /* increment duplicate index */
240 /* calculate final duplicate offset */
241 if (copy_num == (BOOT_SWAP_STATUS_MULT - 1U)) {
242 copy_num = 0;
243 }
244 else {
245 copy_num++;
246 }
247 fin_offset = rec_offset + copy_num*BOOT_SWAP_STATUS_D_SIZE;
248
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300249 /* erase obsolete status record before write */
250 rc = flash_area_erase(fap_stat, fin_offset, sizeof(record_buff));
251 if (rc != 0) {
252 return -1;
253 }
254
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200255 /* write prepared record into flash */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300256 rc = flash_area_write(fap_stat, fin_offset, record_buff, sizeof(record_buff));
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200257
258 flash_area_close(fap_stat);
259
260 return rc;
261}
262
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300263static int boot_magic_decode(uint8_t *magic)
264{
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300265 if (memcmp((const void *)magic, (const void *)&boot_img_magic.val, BOOT_MAGIC_SZ) == 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300266 return BOOT_MAGIC_GOOD;
267 }
268 return BOOT_MAGIC_BAD;
269}
270
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200271/**
272 * Updates len bytes of status partition with values from *data-pointer.
273 *
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300274 * @param target_area_id Target area id for which status is being written.
275 * Not a status-partition area id.
276 * @param offset Status byte offset inside status table. Should not include CRC and CNT.
277 * @param data Pointer to data status table to needs to be updated with.
278 * @param len Number of bytes to be written
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200279 *
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300280 * @return 0 on success; -1 on failure.
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200281 */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300282int swap_status_update(uint8_t target_area_id, uint32_t offs, const void *data, uint32_t len)
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200283{
284 int rc = -1;
285
286 int32_t init_offs;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300287 uint32_t copy_num = 0;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200288
289 uint32_t rec_offs;
290 uint32_t copy_sz;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300291 uint32_t copy_counter = 0;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200292 uint32_t data_idx = 0;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300293 uint32_t buff_idx = offs % BOOT_SWAP_STATUS_PAYLD_SZ;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200294
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300295 if ((UINT32_MAX - offs) < len) {
296 return -1;
297 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200298
299 /* check if end of data is still inside writable area */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300300 if ((offs + len) > BOOT_SWAP_STATUS_D_SIZE_RAW) {
301 return -1;
302 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200303
304 /* pre-calculate sub-area offset */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300305 init_offs = swap_status_init_offset(target_area_id);
306 if (init_offs < 0) {
307 return -1;
308 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200309
310 /* will start from it
311 * this will be write-aligned */
312 rec_offs = (uint32_t)init_offs + calc_record_offs(offs);
313
314 /* go over all records to be updated */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300315 while (len != 0U) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200316 /* preserve record */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300317 rc = swap_status_read_record(rec_offs, status_buff, &copy_counter, &copy_num);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200318 /* it returns copy number */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300319 if (rc < 0)
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200320 { /* something went wrong while read, exit */
321 rc = -1;
322 break;
323 }
324 /* update record data */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300325 if (len > BOOT_SWAP_STATUS_PAYLD_SZ) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200326 copy_sz = BOOT_SWAP_STATUS_PAYLD_SZ - buff_idx;
327 }
328 else {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300329 copy_sz = len;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200330 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300331
332 (void)memcpy(status_buff + buff_idx, (const uint8_t *)data + data_idx, copy_sz);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200333 buff_idx = 0;
334
335 /* write record back */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300336 rc = swap_status_write_record(rec_offs, copy_num, copy_counter, status_buff);
337 if (rc != 0) {
338 break;
339 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200340
341 /* proceed to next record */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300342 if (len < BOOT_SWAP_STATUS_PAYLD_SZ) {
343 len = 0;
344 }
345 else {
346 len -= BOOT_SWAP_STATUS_PAYLD_SZ;
347 rec_offs += BOOT_SWAP_STATUS_ROW_SZ;
348 data_idx += BOOT_SWAP_STATUS_PAYLD_SZ;
349 }
350
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200351 }
352 return rc;
353}
354
355/**
356 * Reads len bytes of status partition with values from *data-pointer.
357 *
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300358 * @param target_area_id Target area id for which status is being read.
359 * Not a status-partition area id.
360 * @param offset Status byte offset inside status table. Should not include CRC and CNT.
361 * @param data Pointer to data where status table values will be written.
362 * @param len Number of bytes to be read from status table.
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200363 *
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300364 * @return 0 on success; -1 on failure.
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200365 */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300366int swap_status_retrieve(uint8_t target_area_id, uint32_t offs, void *data, uint32_t len)
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200367{
368 int rc = 0;
369
370 int32_t init_offs;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300371 uint32_t copy_num = 0;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200372
373 uint32_t rec_offs;
374 uint32_t copy_sz;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300375 uint32_t copy_counter = 0;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200376 uint32_t data_idx = 0;
377 uint32_t buff_idx = offs % BOOT_SWAP_STATUS_PAYLD_SZ;
378
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300379 if ((UINT32_MAX - offs) < len) {
380 return -1;
381 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200382
383 /* check if end of data is still inside writable area */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300384 if ((offs + len) > BOOT_SWAP_STATUS_D_SIZE_RAW) {
385 return -1;
386 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200387
388 /* pre-calculate sub-area offset */
389 init_offs = swap_status_init_offset(target_area_id);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300390 if (init_offs < 0) {
391 return -1;
392 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200393
394 /* will start from it
395 * this will be write-aligned */
396 rec_offs = (uint32_t)init_offs + calc_record_offs(offs);
397
398 /* go over all records to be updated */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300399 while (len != 0U) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200400 /* preserve record */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300401 rc = swap_status_read_record(rec_offs, status_buff, &copy_counter, &copy_num);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200402 /* it returns copy number */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300403 if (rc < 0) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200404 /* something went wrong while read, exit */
405 rc = -1;
406 break;
407 }
408 /* update record data */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300409 if (len > BOOT_SWAP_STATUS_PAYLD_SZ) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200410 copy_sz = BOOT_SWAP_STATUS_PAYLD_SZ - buff_idx;
411 }
412 else {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300413 copy_sz = len;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200414 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300415
416 (void)memcpy((uint8_t *)data + data_idx, status_buff + buff_idx, copy_sz);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200417 buff_idx = 0;
418
419 /* proceed to next record */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300420 if (len < BOOT_SWAP_STATUS_PAYLD_SZ) {
421 len = 0;
422 }
423 else {
424 len -= BOOT_SWAP_STATUS_PAYLD_SZ;
425 rec_offs += BOOT_SWAP_STATUS_ROW_SZ;
426 data_idx += BOOT_SWAP_STATUS_PAYLD_SZ;
427 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200428 }
429 return rc;
430}
431
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300432/**
433 * Copy trailer from status partition to primary image and set copy_done flag.
434 * This function calls only once, before set copy_done flag in status trailer
435 *
436 * @param fap Target area id for which status is being read.
437 *
438 * @return 0 on success; -1 on failure.
439 */
440int swap_status_to_image_trailer(const struct flash_area *fap)
441{
442 uint8_t erased_val;
443 uint8_t stat_erased_val;
444 const uint8_t *copy_src;
445 uint32_t cur_trailer_pos;
446 uint32_t primary_trailer_sz;
447 uint32_t primary_trailer_buf_sz;
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300448 uint32_t align = MEMORY_ALIGN;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300449 int rc = 0;
450 const struct flash_area *fap_stat = NULL;
451 uint8_t primary_trailer_buf[MAX_TRAILER_BUF_SIZE];
452
453 /* get the erased flash byte for status partition */
454 rc = flash_area_open(FLASH_AREA_IMAGE_SWAP_STATUS, &fap_stat);
455 if (rc != 0) {
456 return rc;
457 }
458 stat_erased_val = flash_area_erased_val(fap_stat);
459 flash_area_close(fap_stat);
460
461 /* get status partition trailer size and copy it to buffer */
462 const uint32_t status_trailer_buf_sz = BOOT_SWAP_STATUS_SWAPSZ_SZ + BOOT_SWAP_STATUS_SWAPINF_SZ +
463 BOOT_SWAP_STATUS_COPY_DONE_SZ + BOOT_SWAP_STATUS_IMG_OK_SZ + BOOT_SWAP_STATUS_MAGIC_SZ;
464 uint8_t status_trailer_buf[status_trailer_buf_sz];
465 (void)memset(&status_trailer_buf, 0, status_trailer_buf_sz);
466 rc = swap_status_retrieve(fap->fa_id, boot_swap_size_off(fap), (uint8_t *)status_trailer_buf, status_trailer_buf_sz);
467 if (rc != 0) {
468 return rc;
469 }
470
471 /* check trailer magic in status partition */
472 if (boot_magic_decode(&status_trailer_buf[status_trailer_buf_sz - BOOT_SWAP_STATUS_MAGIC_SZ]) != BOOT_MAGIC_GOOD) {
473 return -1;
474 }
475
476 /* get primary slot trailer size without status data fields */
477 primary_trailer_sz = boot_trailer_sz(0);
478
479 /* align image trailer buffer size to minimal write size */
480#if !defined(__BOOTSIM__)
481 align = flash_area_align(fap);
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300482 /* TODO: this code needs to be refined. It is introduced to overcome
483 * situation when MCUBootApp lives in internal memory, but user app
484 * is executed from different type memory - external in XIP mode in
485 * this case. This situation now arise on PSOC6 when XIP execution is
486 * used, bay may be applicable to other devices, where solution is
487 * distributed between memories with different write/erase sizes.
488 */
489#ifdef CY_BOOT_USE_EXTERNAL_FLASH
490 if (align > MEMORY_ALIGN) {
491 align = MEMORY_ALIGN;
492 }
493#endif
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300494#else
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300495 align = MEMORY_ALIGN;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300496#endif
497
498 if ((align > MAX_TRAILER_BUF_SIZE) || (align == 0U)) {
499 return -1;
500 }
501
502 primary_trailer_buf_sz = align;
503 while (primary_trailer_buf_sz < primary_trailer_sz) {
504 primary_trailer_buf_sz += align;
505 }
506 if (primary_trailer_buf_sz > MAX_TRAILER_BUF_SIZE) {
507 return -1;
508 }
509
510 /* erase primary slot trailer */
511 rc= flash_area_erase(fap, fap->fa_size - primary_trailer_buf_sz, primary_trailer_buf_sz);
512 if (rc != 0) {
513 return rc;
514 }
515
516 /* erase trailer area */
517 erased_val = flash_area_erased_val(fap); /* stat_erased_val and erased_val may differ! */
518 (void)memset(&primary_trailer_buf[primary_trailer_buf_sz-primary_trailer_sz], (int) erased_val, primary_trailer_sz);
519
520 /* copy and align flags and data from status_trailer_buf to primary_trailer_buf
521 Status part trailer --> Pimary image trailer */
522
523 /* copy trailer magic */
524 cur_trailer_pos = primary_trailer_buf_sz - BOOT_SWAP_STATUS_MAGIC_SZ;
525 copy_src = &status_trailer_buf[status_trailer_buf_sz - BOOT_SWAP_STATUS_MAGIC_SZ];
526 if (stat_erased_val != erased_val &&
527 bootutil_buffer_is_filled(copy_src, stat_erased_val, BOOT_SWAP_STATUS_MAGIC_SZ)) {
528
529 (void)memset(&primary_trailer_buf[cur_trailer_pos], (int)erased_val, BOOT_SWAP_STATUS_MAGIC_SZ);
530 }
531 else {
532 (void)memcpy(&primary_trailer_buf[cur_trailer_pos], copy_src, BOOT_SWAP_STATUS_MAGIC_SZ);
533 }
534
535 /* copy image_ok flag */
536 cur_trailer_pos -= BOOT_MAX_ALIGN;
537 copy_src = &status_trailer_buf[BOOT_SWAP_STATUS_SWAPSZ_SZ + BOOT_SWAP_STATUS_SWAPINF_SZ + BOOT_SWAP_STATUS_COPY_DONE_SZ];
538 if (stat_erased_val != erased_val && stat_erased_val == *copy_src) {
539 copy_src = &erased_val;
540 }
541 primary_trailer_buf[cur_trailer_pos] = *copy_src;
542
543 /* set copy_done flag */
544 cur_trailer_pos -= BOOT_MAX_ALIGN;
545 primary_trailer_buf[cur_trailer_pos] = BOOT_FLAG_SET;
546
547 /* copy swap_type flag */
548 cur_trailer_pos -= BOOT_MAX_ALIGN;
549 copy_src = &status_trailer_buf[BOOT_SWAP_STATUS_SWAPSZ_SZ];
550 if (stat_erased_val != erased_val && stat_erased_val == *copy_src) {
551 copy_src = &erased_val;
552 }
553 primary_trailer_buf[cur_trailer_pos] = *copy_src;
554
555 /* copy swap_size field */
556 cur_trailer_pos -= BOOT_MAX_ALIGN;
557 if (stat_erased_val != erased_val &&
558 bootutil_buffer_is_filled(status_trailer_buf, stat_erased_val, BOOT_SWAP_STATUS_SWAPSZ_SZ)) {
559
560 (void)memset(&primary_trailer_buf[cur_trailer_pos], (int)erased_val, BOOT_SWAP_STATUS_SWAPSZ_SZ);
561 }
562 else {
563 (void)memcpy(&primary_trailer_buf[cur_trailer_pos], status_trailer_buf, BOOT_SWAP_STATUS_SWAPSZ_SZ);
564 }
565
566 /* write primary image trailer with copy_done flag set */
567 rc = flash_area_write(fap, fap->fa_size - primary_trailer_buf_sz, primary_trailer_buf, primary_trailer_buf_sz);
568
569 return rc;
570}
571
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200572#endif /* MCUBOOT_SWAP_USING_STATUS */