blob: 556e4220c26831ef8f7efd384d46bdca340bd8e4 [file] [log] [blame]
Shubham Kulkarni052561d2021-07-20 11:42:44 +05301/*
2 * Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
Gustavo Henrique Niheid985d222021-11-12 14:21:12 -03007#include <stdbool.h>
Shubham Kulkarni052561d2021-07-20 11:42:44 +05308#include <stdlib.h>
Gustavo Henrique Niheid985d222021-11-12 14:21:12 -03009#include <string.h>
Shubham Kulkarni052561d2021-07-20 11:42:44 +053010
Gustavo Henrique Niheid985d222021-11-12 14:21:12 -030011#include <bootutil/bootutil.h>
12#include <bootutil/bootutil_log.h>
Shubham Kulkarni052561d2021-07-20 11:42:44 +053013
Shubham Kulkarnicd869652021-07-20 11:44:08 +053014#include "esp_err.h"
Shubham Kulkarnicd869652021-07-20 11:44:08 +053015#include "bootloader_flash_priv.h"
16
Gustavo Henrique Niheid985d222021-11-12 14:21:12 -030017#include "flash_map_backend/flash_map_backend.h"
18#include "sysflash/sysflash.h"
19
Gustavo Henrique Nihei74a27422021-10-29 09:25:55 -030020#ifndef ARRAY_SIZE
21# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
22#endif
23
24#ifndef MIN
25# define MIN(a, b) (((a) < (b)) ? (a) : (b))
26#endif
27
28#ifndef ALIGN_UP
29# define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
30#endif
31
32#ifndef ALIGN_DOWN
33# define ALIGN_DOWN(num, align) ((num) & ~((align) - 1))
34#endif
35
36#ifndef ALIGN_OFFSET
37# define ALIGN_OFFSET(num, align) ((num) & ((align) - 1))
38#endif
39
40#ifndef IS_ALIGNED
41# define IS_ALIGNED(num, align) (ALIGN_OFFSET((num), (align)) == 0)
42#endif
43
44#define FLASH_BUFFER_SIZE 256 /* SPI Flash block size */
45
46_Static_assert(IS_ALIGNED(FLASH_BUFFER_SIZE, 4), "Buffer size for SPI Flash operations must be 4-byte aligned.");
Shubham Kulkarni052561d2021-07-20 11:42:44 +053047
48#define BOOTLOADER_START_ADDRESS 0x1000
49#define BOOTLOADER_SIZE CONFIG_ESP_BOOTLOADER_SIZE
50#define APPLICATION_PRIMARY_START_ADDRESS CONFIG_ESP_APPLICATION_PRIMARY_START_ADDRESS
51#define APPLICATION_SECONDARY_START_ADDRESS CONFIG_ESP_APPLICATION_SECONDARY_START_ADDRESS
52#define APPLICATION_SIZE CONFIG_ESP_APPLICATION_SIZE
53#define SCRATCH_OFFSET CONFIG_ESP_SCRATCH_OFFSET
54#define SCRATCH_SIZE CONFIG_ESP_SCRATCH_SIZE
55
Shubham Kulkarni052561d2021-07-20 11:42:44 +053056extern int ets_printf(const char *fmt, ...);
57
58static const struct flash_area bootloader = {
59 .fa_id = FLASH_AREA_BOOTLOADER,
60 .fa_device_id = FLASH_DEVICE_INTERNAL_FLASH,
61 .fa_off = BOOTLOADER_START_ADDRESS,
62 .fa_size = BOOTLOADER_SIZE,
63};
64
65static const struct flash_area primary_img0 = {
66 .fa_id = FLASH_AREA_IMAGE_PRIMARY(0),
67 .fa_device_id = FLASH_DEVICE_INTERNAL_FLASH,
68 .fa_off = APPLICATION_PRIMARY_START_ADDRESS,
69 .fa_size = APPLICATION_SIZE,
70};
71
72static const struct flash_area secondary_img0 = {
73 .fa_id = FLASH_AREA_IMAGE_SECONDARY(0),
74 .fa_device_id = FLASH_DEVICE_INTERNAL_FLASH,
75 .fa_off = APPLICATION_SECONDARY_START_ADDRESS,
76 .fa_size = APPLICATION_SIZE,
77};
78
79static const struct flash_area scratch_img0 = {
80 .fa_id = FLASH_AREA_IMAGE_SCRATCH,
81 .fa_device_id = FLASH_DEVICE_INTERNAL_FLASH,
82 .fa_off = SCRATCH_OFFSET,
83 .fa_size = SCRATCH_SIZE,
84};
85
86static const struct flash_area *s_flash_areas[] = {
87 &bootloader,
88 &primary_img0,
89 &secondary_img0,
90 &scratch_img0,
91};
92
93static const struct flash_area *prv_lookup_flash_area(uint8_t id) {
94 for (size_t i = 0; i < ARRAY_SIZE(s_flash_areas); i++) {
95 const struct flash_area *area = s_flash_areas[i];
96 if (id == area->fa_id) {
97 return area;
98 }
99 }
100 return NULL;
101}
102
103int flash_area_open(uint8_t id, const struct flash_area **area_outp)
104{
Gustavo Henrique Niheid985d222021-11-12 14:21:12 -0300105 BOOT_LOG_DBG("%s: ID=%d", __func__, (int)id);
Shubham Kulkarni052561d2021-07-20 11:42:44 +0530106 const struct flash_area *area = prv_lookup_flash_area(id);
107 *area_outp = area;
108 return area != NULL ? 0 : -1;
109}
110
111void flash_area_close(const struct flash_area *area)
112{
113
114}
115
Gustavo Henrique Nihei74a27422021-10-29 09:25:55 -0300116static bool aligned_flash_read(uintptr_t addr, void *dest, size_t size)
117{
118 if (IS_ALIGNED(addr, 4) && IS_ALIGNED((uintptr_t)dest, 4) && IS_ALIGNED(size, 4)) {
119 /* A single read operation is enough when when all parameters are aligned */
120
121 return bootloader_flash_read(addr, dest, size, true) == ESP_OK;
122 }
123
124 const uint32_t aligned_addr = ALIGN_DOWN(addr, 4);
125 const uint32_t addr_offset = ALIGN_OFFSET(addr, 4);
126 uint32_t bytes_remaining = size;
127 uint8_t read_data[FLASH_BUFFER_SIZE] = {0};
128
129 /* Align the read address to 4-byte boundary and ensure read size is a multiple of 4 bytes */
130
131 uint32_t bytes = MIN(bytes_remaining + addr_offset, sizeof(read_data));
132 if (bootloader_flash_read(aligned_addr, read_data, ALIGN_UP(bytes, 4), true) != ESP_OK) {
133 return false;
134 }
135
136 /* Skip non-useful data which may have been read for adjusting the alignment */
137
138 uint32_t bytes_read = bytes - addr_offset;
139 memcpy(dest, &read_data[addr_offset], bytes_read);
140
141 bytes_remaining -= bytes_read;
142
143 /* Read remaining data from Flash in case requested size is greater than buffer size */
144
145 uint32_t offset = bytes;
146
147 while (bytes_remaining != 0) {
148 bytes = MIN(bytes_remaining, sizeof(read_data));
149 if (bootloader_flash_read(aligned_addr + offset, read_data, ALIGN_UP(bytes, 4), true) != ESP_OK) {
150 return false;
151 }
152
153 memcpy(&((uint8_t *)dest)[bytes_read], read_data, bytes);
154
155 offset += bytes;
156 bytes_read += bytes;
157 bytes_remaining -= bytes;
158 }
159
160 return true;
161}
162
Shubham Kulkarni052561d2021-07-20 11:42:44 +0530163int flash_area_read(const struct flash_area *fa, uint32_t off, void *dst,
164 uint32_t len)
165{
166 if (fa->fa_device_id != FLASH_DEVICE_INTERNAL_FLASH) {
167 return -1;
168 }
169
170 const uint32_t end_offset = off + len;
171 if (end_offset > fa->fa_size) {
Gustavo Henrique Niheid985d222021-11-12 14:21:12 -0300172 BOOT_LOG_ERR("%s: Out of Bounds (0x%x vs 0x%x)", __func__, end_offset, fa->fa_size);
Shubham Kulkarni052561d2021-07-20 11:42:44 +0530173 return -1;
174 }
Gustavo Henrique Nihei74a27422021-10-29 09:25:55 -0300175
176 bool success = aligned_flash_read(fa->fa_off + off, dst, len);
177 if (!success) {
Gustavo Henrique Niheid985d222021-11-12 14:21:12 -0300178 BOOT_LOG_ERR("%s: Flash read failed", __func__);
Gustavo Henrique Nihei74a27422021-10-29 09:25:55 -0300179
Shubham Kulkarnicd869652021-07-20 11:44:08 +0530180 return -1;
181 }
Gustavo Henrique Nihei74a27422021-10-29 09:25:55 -0300182
Shubham Kulkarni052561d2021-07-20 11:42:44 +0530183 return 0;
184}
185
186int flash_area_write(const struct flash_area *fa, uint32_t off, const void *src,
187 uint32_t len)
188{
189 if (fa->fa_device_id != FLASH_DEVICE_INTERNAL_FLASH) {
190 return -1;
191 }
192
193 const uint32_t end_offset = off + len;
194 if (end_offset > fa->fa_size) {
Gustavo Henrique Niheid985d222021-11-12 14:21:12 -0300195 BOOT_LOG_ERR("%s: Out of Bounds (0x%x vs 0x%x)", __func__, end_offset, fa->fa_size);
Shubham Kulkarni052561d2021-07-20 11:42:44 +0530196 return -1;
197 }
198
Shubham Kulkarnicd869652021-07-20 11:44:08 +0530199 const uint32_t start_addr = fa->fa_off + off;
Gustavo Henrique Niheid985d222021-11-12 14:21:12 -0300200 BOOT_LOG_DBG("%s: Addr: 0x%08x Length: %d", __func__, (int)start_addr, (int)len);
Shubham Kulkarni052561d2021-07-20 11:42:44 +0530201
Gustavo Henrique Nihei33a38312021-11-05 15:51:22 -0300202 if (bootloader_flash_write(start_addr, (void *)src, len, false) != ESP_OK) {
Gustavo Henrique Niheid985d222021-11-12 14:21:12 -0300203 BOOT_LOG_ERR("%s: Flash write failed", __func__);
Shubham Kulkarnicd869652021-07-20 11:44:08 +0530204 return -1;
205 }
Shubham Kulkarni052561d2021-07-20 11:42:44 +0530206
207 return 0;
208}
209
210int flash_area_erase(const struct flash_area *fa, uint32_t off, uint32_t len)
211{
212 if (fa->fa_device_id != FLASH_DEVICE_INTERNAL_FLASH) {
213 return -1;
214 }
215
216 if ((len % FLASH_SECTOR_SIZE) != 0 || (off % FLASH_SECTOR_SIZE) != 0) {
Gustavo Henrique Niheid985d222021-11-12 14:21:12 -0300217 BOOT_LOG_ERR("%s: Not aligned on sector Offset: 0x%x Length: 0x%x",
218 __func__, (int)off, (int)len);
Shubham Kulkarni052561d2021-07-20 11:42:44 +0530219 return -1;
220 }
221
222 const uint32_t start_addr = fa->fa_off + off;
Gustavo Henrique Niheid985d222021-11-12 14:21:12 -0300223 BOOT_LOG_DBG("%s: Addr: 0x%08x Length: %d", __func__, (int)start_addr, (int)len);
Shubham Kulkarni052561d2021-07-20 11:42:44 +0530224
Shubham Kulkarnicd869652021-07-20 11:44:08 +0530225 if (bootloader_flash_erase_range(start_addr, len) != ESP_OK) {
Gustavo Henrique Niheid985d222021-11-12 14:21:12 -0300226 BOOT_LOG_ERR("%s: Flash erase failed", __func__);
Shubham Kulkarnicd869652021-07-20 11:44:08 +0530227 return -1;
228 }
Shubham Kulkarni052561d2021-07-20 11:42:44 +0530229#if VALIDATE_PROGRAM_OP
230 for (size_t i = 0; i < len; i++) {
231 uint8_t *val = (void *)(start_addr + i);
232 if (*val != 0xff) {
Gustavo Henrique Niheid985d222021-11-12 14:21:12 -0300233 BOOT_LOG_ERR("%s: Erase at 0x%x Failed", __func__, (int)val);
Shubham Kulkarni052561d2021-07-20 11:42:44 +0530234 assert(0);
235 }
236 }
237#endif
238
239 return 0;
240}
241
242size_t flash_area_align(const struct flash_area *area)
243{
244 return 4;
245}
246
247uint8_t flash_area_erased_val(const struct flash_area *area)
248{
249 return 0xff;
250}
251
252int flash_area_get_sectors(int fa_id, uint32_t *count,
253 struct flash_sector *sectors)
254{
255 const struct flash_area *fa = prv_lookup_flash_area(fa_id);
256 if (fa->fa_device_id != FLASH_DEVICE_INTERNAL_FLASH) {
257 return -1;
258 }
259
260 const size_t sector_size = FLASH_SECTOR_SIZE;
261 uint32_t total_count = 0;
262 for (size_t off = 0; off < fa->fa_size; off += sector_size) {
263 // Note: Offset here is relative to flash area, not device
264 sectors[total_count].fs_off = off;
265 sectors[total_count].fs_size = sector_size;
266 total_count++;
267 }
268
269 *count = total_count;
270 return 0;
271}
272
273int flash_area_id_from_multi_image_slot(int image_index, int slot)
274{
Gustavo Henrique Niheid985d222021-11-12 14:21:12 -0300275 BOOT_LOG_DBG("%s", __func__);
Shubham Kulkarni052561d2021-07-20 11:42:44 +0530276 switch (slot) {
277 case 0:
278 return FLASH_AREA_IMAGE_PRIMARY(image_index);
279 case 1:
280 return FLASH_AREA_IMAGE_SECONDARY(image_index);
281 }
282
Gustavo Henrique Niheid985d222021-11-12 14:21:12 -0300283 BOOT_LOG_ERR("Unexpected Request: image_index=%d, slot=%d", image_index, slot);
Shubham Kulkarni052561d2021-07-20 11:42:44 +0530284 return -1; /* flash_area_open will fail on that */
285}
286
287int flash_area_id_from_image_slot(int slot)
288{
Almir Okatod5320292021-06-18 02:00:40 -0300289 return flash_area_id_from_multi_image_slot(0, slot);
Shubham Kulkarni052561d2021-07-20 11:42:44 +0530290}
291
292int flash_area_to_sectors(int idx, int *cnt, struct flash_area *fa)
293{
Almir Okatod5320292021-06-18 02:00:40 -0300294 return -1;
Shubham Kulkarni052561d2021-07-20 11:42:44 +0530295}
296
297void mcuboot_assert_handler(const char *file, int line, const char *func)
298{
299 ets_printf("assertion failed: file \"%s\", line %d, func: %s\n", file, line, func);
300 abort();
301}