boot: zephyr: fix flash page layout hacks
Zephyr now has proper page layout APIs in its flash driver. Use these
to implement flash_area_get_sectors() and flash_area_to_sectors() when
they are available. Leave the existing implementation behind as a
"legacy" version, for flash drivers which lack page layout support.
This lets us obtain all the target support we need for nRF and STM32
targets entirely from the operating system.
There are two cases where OS-level support is still not enough:
- NXP K6x targets still need an SoC family header, because their flash
driver does not yet support CONFIG_FLASH_PAGE_LAYOUT.
- The arduino_101 target needs partition and flash alignment
definitions in its DTS, and a flash driver with page layout support
as well, so its board-specific header must remain for now.
Fixing these is left to future work. Once that is done,
boot/zephyr/targets/ can be removed completely.
Signed-off-by: Marti Bolivar <marti.bolivar@linaro.org>
diff --git a/boot/zephyr/flash_map_legacy.c b/boot/zephyr/flash_map_legacy.c
new file mode 100644
index 0000000..2bfa182
--- /dev/null
+++ b/boot/zephyr/flash_map_legacy.c
@@ -0,0 +1,138 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * @file
+ * @brief Legacy flash fallbacks
+ *
+ * This file contains hacks for flash drivers without page layout
+ * support. They're hacks because they guess a page layout that may be
+ * incorrect, but is likely to "work". Needless to say, such guesswork
+ * is undesirable in trusted bootloader code.
+ *
+ * The behavior is:
+ *
+ * - If FLASH_AREA_IMAGE_SECTOR_SIZE is defined (this was used by
+ * older Zephyr ports), the image sectors have uniform sector sizes.
+ * We also assume that's the size of the scratch sectors.
+ *
+ * - Otherwise, we assume that the size of the entire scratch area is
+ * a least common multiple of all sector sizes, and use that as
+ * FLASH_AREA_IMAGE_SECTOR_SIZE.
+ */
+
+#define BOOT_LOG_LEVEL BOOT_LOG_LEVEL_INFO
+#include "bootutil/bootutil_log.h"
+
+#include <flash_map/flash_map.h>
+#include <inttypes.h>
+#include <target.h>
+
+#warning "The flash driver lacks page layout support; falling back on hacks."
+
+#if !defined(FLASH_AREA_IMAGE_SECTOR_SIZE)
+#define FLASH_AREA_IMAGE_SECTOR_SIZE FLASH_AREA_IMAGE_SCRATCH_SIZE
+#endif
+
+extern int flash_area_get_bounds(int idx, uint32_t *off, uint32_t *len);
+
+int flash_area_to_sectors(int idx, int *cnt, struct flash_area *ret)
+{
+ uint32_t off;
+ uint32_t len;
+ uint32_t max_cnt = *cnt;
+ uint32_t rem_len;
+
+ if (flash_area_get_bounds(idx, &off, &len)) {
+ return -1;
+ }
+
+ if (*cnt < 1) {
+ return -1;
+ }
+
+ rem_len = len;
+ *cnt = 0;
+ while (rem_len > 0 && *cnt < max_cnt) {
+ if (rem_len < FLASH_AREA_IMAGE_SECTOR_SIZE) {
+ BOOT_LOG_ERR("area %d size 0x%x not divisible by sector size 0x%x",
+ idx, len, FLASH_AREA_IMAGE_SECTOR_SIZE);
+ return -1;
+ }
+
+ ret[*cnt].fa_id = idx;
+ ret[*cnt].fa_device_id = 0;
+ ret[*cnt].pad16 = 0;
+ ret[*cnt].fa_off = off + (FLASH_AREA_IMAGE_SECTOR_SIZE * (*cnt));
+ ret[*cnt].fa_size = FLASH_AREA_IMAGE_SECTOR_SIZE;
+ *cnt = *cnt + 1;
+ rem_len -= FLASH_AREA_IMAGE_SECTOR_SIZE;
+ }
+
+ if (*cnt >= max_cnt) {
+ BOOT_LOG_ERR("flash area %d sector count overflow", idx);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Lookup the sector map for a given flash area. This should fill in
+ * `ret` with all of the sectors in the area. `*cnt` will be set to
+ * the storage at `ret` and should be set to the final number of
+ * sectors in this area.
+ */
+int flash_area_get_sectors(int idx, uint32_t *cnt, struct flash_sector *ret)
+{
+ uint32_t off;
+ uint32_t len;
+ uint32_t max_cnt = *cnt;
+ uint32_t rem_len;
+
+ if (flash_area_get_bounds(idx, &off, &len)) {
+ return -1;
+ }
+
+ if (*cnt < 1) {
+ return -1;
+ }
+
+ rem_len = len;
+ *cnt = 0;
+ while (rem_len > 0 && *cnt < max_cnt) {
+ if (rem_len < FLASH_AREA_IMAGE_SECTOR_SIZE) {
+ BOOT_LOG_ERR("area %d size 0x%x not divisible by sector size 0x%x",
+ idx, len, FLASH_AREA_IMAGE_SECTOR_SIZE);
+ return -1;
+ }
+
+ ret[*cnt].fs_off = FLASH_AREA_IMAGE_SECTOR_SIZE * (*cnt);
+ ret[*cnt].fs_size = FLASH_AREA_IMAGE_SECTOR_SIZE;
+ *cnt = *cnt + 1;
+ rem_len -= FLASH_AREA_IMAGE_SECTOR_SIZE;
+ }
+
+ if (*cnt >= max_cnt) {
+ BOOT_LOG_ERR("flash area %d sector count overflow", idx);
+ return -1;
+ }
+
+ return 0;
+}