1 /*
2 * Copyright (c) 2017, 2020 Nordic Semiconductor ASA
3 * Copyright (c) 2017 Linaro Limited
4 * Copyright (c) 2020 Gerson Fernando Budke <nandojve@gmail.com>
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8 #include <zephyr/types.h>
9 #include <stddef.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <zephyr/dfu/flash_img.h>
13 #include <zephyr/storage/flash_map.h>
14 #include <zephyr/storage/stream_flash.h>
15
16 #ifdef CONFIG_IMG_ERASE_PROGRESSIVELY
17 #include <bootutil/bootutil_public.h>
18 #include <zephyr/dfu/mcuboot.h>
19 #endif
20
21 #include <zephyr/devicetree.h>
22 #ifdef CONFIG_TRUSTED_EXECUTION_NONSECURE
23 #define UPLOAD_FLASH_AREA_LABEL slot1_ns_partition
24 #else
25 #if FIXED_PARTITION_EXISTS(slot1_partition)
26 #define UPLOAD_FLASH_AREA_LABEL slot1_partition
27 #else
28 #define UPLOAD_FLASH_AREA_LABEL slot0_partition
29 #endif
30 #endif
31
32 /* FIXED_PARTITION_ID() values used below are auto-generated by DT */
33 #define UPLOAD_FLASH_AREA_ID FIXED_PARTITION_ID(UPLOAD_FLASH_AREA_LABEL)
34 #define UPLOAD_FLASH_AREA_CONTROLLER \
35 DT_GPARENT(DT_NODELABEL(UPLOAD_FLASH_AREA_LABEL))
36
37 #if DT_NODE_HAS_PROP(UPLOAD_FLASH_AREA_CONTROLLER, write_block_size)
38 #define FLASH_WRITE_BLOCK_SIZE \
39 DT_PROP(UPLOAD_FLASH_AREA_CONTROLLER, write_block_size)
40
41 BUILD_ASSERT((CONFIG_IMG_BLOCK_BUF_SIZE % FLASH_WRITE_BLOCK_SIZE == 0),
42 "CONFIG_IMG_BLOCK_BUF_SIZE is not a multiple of "
43 "FLASH_WRITE_BLOCK_SIZE");
44 #endif
45
scramble_mcuboot_trailer(struct flash_img_context * ctx)46 static int scramble_mcuboot_trailer(struct flash_img_context *ctx)
47 {
48 int rc = 0;
49
50 #ifdef CONFIG_IMG_ERASE_PROGRESSIVELY
51 if (stream_flash_bytes_written(&ctx->stream) == 0) {
52 off_t toff = boot_get_trailer_status_offset(ctx->flash_area->fa_size);
53 off_t offset;
54 size_t size;
55 const struct flash_parameters *fparams =
56 flash_get_parameters(flash_area_get_device(ctx->flash_area));
57 #ifdef CONFIG_STREAM_FLASH_ERASE
58 /* for erasable devices prgressive-erase works only along with
59 * CONFIG_STREAM_FLASH_ERASE option.
60 */
61 if (flash_params_get_erase_cap(fparams) & FLASH_ERASE_C_EXPLICIT) {
62 /* On devices with explicit erase we are aligning to page
63 * layout.
64 */
65 struct flash_pages_info info;
66
67 rc = flash_get_page_info_by_offs(flash_area_get_device(ctx->flash_area),
68 toff, &info);
69 if (rc != 0) {
70 return rc;
71 }
72 offset = info.start_offset;
73 size = info.size;
74
75 } else
76 #endif
77 {
78 /* On devices with no erase, we are aligning to write block
79 * size.
80 */
81 offset = (toff + fparams->write_block_size - 1) &
82 ~(fparams->write_block_size - 1);
83 /* No alignment correction needed here, offset is corrected already
84 * and, size should be aligned.
85 */
86 size = ctx->flash_area->fa_size - offset;
87 }
88
89 rc = flash_area_flatten(ctx->flash_area, offset, size);
90 }
91 #endif
92
93 return rc;
94 }
95
96
flash_img_buffered_write(struct flash_img_context * ctx,const uint8_t * data,size_t len,bool flush)97 int flash_img_buffered_write(struct flash_img_context *ctx, const uint8_t *data,
98 size_t len, bool flush)
99 {
100 int rc;
101
102 /* If there is a need to erase the trailer, that should happen before any
103 * write is done to partition.
104 */
105 rc = scramble_mcuboot_trailer(ctx);
106 if (rc != 0) {
107 return rc;
108 }
109
110
111 /* if CONFIG_IMG_ERASE_PROGRESSIVELY is enabled the enabled CONFIG_STREAM_FLASH_ERASE
112 * ensures that stream_flash erases flash progresively.
113 */
114 rc = stream_flash_buffered_write(&ctx->stream, data, len, flush);
115 if (!flush) {
116 return rc;
117 }
118
119 flash_area_close(ctx->flash_area);
120 ctx->flash_area = NULL;
121
122 return rc;
123 }
124
flash_img_bytes_written(struct flash_img_context * ctx)125 size_t flash_img_bytes_written(struct flash_img_context *ctx)
126 {
127 return stream_flash_bytes_written(&ctx->stream);
128 }
129
flash_img_init_id(struct flash_img_context * ctx,uint8_t area_id)130 int flash_img_init_id(struct flash_img_context *ctx, uint8_t area_id)
131 {
132 int rc;
133 const struct device *flash_dev;
134
135 rc = flash_area_open(area_id,
136 (const struct flash_area **)&(ctx->flash_area));
137 if (rc) {
138 return rc;
139 }
140
141 flash_dev = flash_area_get_device(ctx->flash_area);
142
143 return stream_flash_init(&ctx->stream, flash_dev, ctx->buf,
144 CONFIG_IMG_BLOCK_BUF_SIZE, ctx->flash_area->fa_off,
145 ctx->flash_area->fa_size, NULL);
146 }
147
flash_img_init(struct flash_img_context * ctx)148 int flash_img_init(struct flash_img_context *ctx)
149 {
150 return flash_img_init_id(ctx, UPLOAD_FLASH_AREA_ID);
151 }
152
153 #if defined(CONFIG_IMG_ENABLE_IMAGE_CHECK)
flash_img_check(struct flash_img_context * ctx,const struct flash_img_check * fic,uint8_t area_id)154 int flash_img_check(struct flash_img_context *ctx,
155 const struct flash_img_check *fic,
156 uint8_t area_id)
157 {
158 struct flash_area_check fac;
159 int rc;
160
161 if (!ctx || !fic) {
162 return -EINVAL;
163 }
164
165 rc = flash_area_open(area_id,
166 (const struct flash_area **)&(ctx->flash_area));
167 if (rc) {
168 return rc;
169 }
170
171 fac.match = fic->match;
172 fac.clen = fic->clen;
173 fac.off = 0;
174 fac.rbuf = ctx->buf;
175 fac.rblen = sizeof(ctx->buf);
176
177 rc = flash_area_check_int_sha256(ctx->flash_area, &fac);
178
179 flash_area_close(ctx->flash_area);
180 ctx->flash_area = NULL;
181
182 return rc;
183 }
184 #endif
185