Some sunxi boards boot from raw NAND using an Allwinner flash layout. Factory data is stored in redundant secure-storage blocks after the U-Boot proper area.
Mainline U-Boot needs to preserve this area when generating NAND partition tables. It may also need to read factory data, such as the Ethernet MAC address. Add helpers to locate secure-storage marker blocks, read checksummed store_object items through the MTD ECC path, set ethaddr from a configurable key, and generate runtime mtdparts that place UBI after the last secure-storage marker. Secure-storage block discovery intentionally mirrors the existing NAND layout: use marker-only discovery from the computed U-Boot proper end to block 50. Item data remains checksum and CRC validated before use. Signed-off-by: James Hilliard <[email protected]> --- board/sunxi/Kconfig | 39 +++ board/sunxi/Makefile | 3 + board/sunxi/board.c | 119 +++++++ board/sunxi/nand_secure_storage.c | 521 ++++++++++++++++++++++++++++++ board/sunxi/nand_secure_storage.h | 42 +++ 5 files changed, 724 insertions(+) create mode 100644 board/sunxi/nand_secure_storage.c create mode 100644 board/sunxi/nand_secure_storage.h diff --git a/board/sunxi/Kconfig b/board/sunxi/Kconfig index 084a8b0c6ca..c3826f0ade9 100644 --- a/board/sunxi/Kconfig +++ b/board/sunxi/Kconfig @@ -22,3 +22,42 @@ config SPL_IMAGE_TYPE string default "sunxi_egon" if SPL_IMAGE_TYPE_SUNXI_EGON default "sunxi_toc0" if SPL_IMAGE_TYPE_SUNXI_TOC0 + +config SUNXI_NAND_SECURE_STORAGE + bool "Allwinner NAND secure storage support" + depends on NAND_SUNXI && MTD_RAW_NAND + help + Enable support for reading the Allwinner raw NAND secure-storage + area from U-Boot proper. This is used by some sunxi boards to + preserve factory data, such as MAC addresses, when booting a + mainline NAND layout. + +config SUNXI_NAND_SECURE_STORAGE_ETHADDR + bool "Read ethaddr from Allwinner NAND secure storage" + depends on SUNXI_NAND_SECURE_STORAGE && NET + select CRC32 + help + Read the configured secure-storage key and use it as the primary + Ethernet MAC address before the normal sunxi fallback environment + value is generated. + +config SUNXI_NAND_SECURE_STORAGE_ETHADDR_KEY + string "NAND secure-storage key name for ethaddr" + depends on SUNXI_NAND_SECURE_STORAGE_ETHADDR + default "mac" + help + Name of the secure-storage item containing the primary Ethernet MAC + address. The store_object payload is parsed like a U-Boot + Ethernet environment variable. + +config SUNXI_NAND_SECURE_STORAGE_MTD_PARTS + bool "Generate NAND mtdparts around secure storage" + depends on SUNXI_NAND_SECURE_STORAGE && SYS_MTDPARTS_RUNTIME + help + Generate the default NAND mtdparts at runtime by locating + secure-storage marker blocks and placing the UBI partition immediately + after the last marker. This avoids hard-coding the secure-storage + offset, which may shift when bad blocks are present before or inside + the secure-storage window. Only SLC raw NAND is supported; MLC/TLC + parts need Allwinner's LSB-block-size mapping, which is not available + here. diff --git a/board/sunxi/Makefile b/board/sunxi/Makefile index ee82493117a..fda2a0bfe76 100644 --- a/board/sunxi/Makefile +++ b/board/sunxi/Makefile @@ -8,6 +8,9 @@ # Wolfgang Denk, DENX Software Engineering, [email protected]. obj-y += board.o obj-$(CONFIG_SUN7I_GMAC) += gmac.o +ifndef CONFIG_XPL_BUILD +obj-$(CONFIG_SUNXI_NAND_SECURE_STORAGE) += nand_secure_storage.o +endif obj-$(CONFIG_MACH_SUN4I) += dram_sun4i_auto.o obj-$(CONFIG_MACH_SUN5I) += dram_sun5i_auto.o obj-$(CONFIG_MACH_SUN7I) += dram_sun5i_auto.o diff --git a/board/sunxi/board.c b/board/sunxi/board.c index 3d1afec7c66..19a0402eb03 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -50,9 +50,126 @@ #include <spl.h> #include <sy8106a.h> #include <asm/setup.h> +#include <vsprintf.h> + +#include "nand_secure_storage.h" DECLARE_GLOBAL_DATA_PTR; +#if IS_ENABLED(CONFIG_SYS_MTDPARTS_RUNTIME) && !defined(CONFIG_XPL_BUILD) +#define SUNXI_NAND_MTDIDS_MAXLEN 128 +#define SUNXI_NAND_MTDPARTS_MAXLEN 512 + +static int sunxi_mtdparts_append(char *buf, size_t size, int *len, + const char *fmt, ...) +{ + size_t avail; + va_list args; + int ret; + + if (*len < 0 || (size_t)*len >= size) + return -ENOSPC; + + avail = size - (size_t)*len; + va_start(args, fmt); + ret = vsnprintf(buf + *len, avail, fmt, args); + va_end(args); + if (ret < 0 || (size_t)ret >= avail) + return -ENOSPC; + + *len += ret; + return 0; +} + +static int sunxi_mtdparts_add(char *buf, size_t size, int *len, + const char *name, u64 part_size, u64 offset, + bool ro) +{ + return sunxi_mtdparts_append(buf, size, len, "0x%llx@0x%llx(%s)%s,", + (unsigned long long)part_size, + (unsigned long long)offset, name, + ro ? "ro" : ""); +} + +void board_mtdparts_default(const char **mtdids, const char **mtdparts) +{ + static char ids[SUNXI_NAND_MTDIDS_MAXLEN]; + static char parts[SUNXI_NAND_MTDPARTS_MAXLEN]; + static bool generated; + struct sunxi_nand_secure_storage_info ss; + u32 i; + int len, ret; + + *mtdids = NULL; + *mtdparts = NULL; + + if (!IS_ENABLED(CONFIG_SUNXI_NAND_SECURE_STORAGE_MTD_PARTS)) + return; + + if (generated) { + *mtdids = ids; + *mtdparts = parts; + return; + } + + ret = sunxi_nand_secure_storage_locate(&ss); + if (ret) { + debug("sunxi secure storage: no dynamic mtdparts: %d\n", ret); + return; + } + + if (!ss.mtd_name || !ss.mtd_size || !ss.spl_copy_size || + !ss.spl_copy_count || !ss.uboot_size || !ss.secure_size) { + debug("sunxi secure storage: invalid dynamic mtdparts geometry\n"); + return; + } + + if (ss.uboot_offset + ss.uboot_size > ss.secure_offset || + ss.secure_end >= ss.mtd_size) { + debug("sunxi secure storage: dynamic mtdparts would overlap\n"); + return; + } + + len = snprintf(ids, sizeof(ids), "nand0=%s", ss.mtd_name); + if (len < 0 || len >= sizeof(ids)) + return; + + len = snprintf(parts, sizeof(parts), "%s:", ss.mtd_name); + if (len < 0 || len >= sizeof(parts)) + goto err; + + for (i = 0; i < ss.spl_copy_count; i++) { + char name[16]; + + ret = snprintf(name, sizeof(name), "spl-%u", i); + if (ret < 0 || (size_t)ret >= sizeof(name)) + goto err; + if (sunxi_mtdparts_add(parts, sizeof(parts), &len, name, + ss.spl_copy_size, + ss.spl_copy_size * i, false)) + goto err; + } + + if (sunxi_mtdparts_add(parts, sizeof(parts), &len, "uboot", + ss.uboot_size, ss.uboot_offset, false)) + goto err; + if (sunxi_mtdparts_add(parts, sizeof(parts), &len, "securestorage", + ss.secure_size, ss.secure_offset, true)) + goto err; + if (sunxi_mtdparts_append(parts, sizeof(parts), &len, "-@0x%llx(UBI)", + (unsigned long long)ss.secure_end)) + goto err; + + generated = true; + *mtdids = ids; + *mtdparts = parts; + return; + +err: + ids[0] = '\0'; +} +#endif + void i2c_init_board(void) { #ifdef CONFIG_I2C0_ENABLE @@ -792,6 +909,8 @@ static void setup_environment(const void *fdt) char ethaddr[16]; int i; + sunxi_nand_secure_storage_setup_ethaddr(); + if (!get_unique_sid(sid)) return; diff --git a/board/sunxi/nand_secure_storage.c b/board/sunxi/nand_secure_storage.c new file mode 100644 index 00000000000..f786a47430a --- /dev/null +++ b/board/sunxi/nand_secure_storage.c @@ -0,0 +1,521 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Allwinner raw NAND secure-storage support. + * + * The Allwinner NAND layout stores redundant secure-storage blocks + * immediately after the U-Boot proper area. The blocks are identified by an + * OOB marker and their pages are read through the normal NAND ECC/randomizer + * path. + */ + +#ifdef CONFIG_SUNXI_NAND_SECURE_STORAGE_ETHADDR +#include <env.h> +#include <net.h> +#include <u-boot/crc.h> +#endif +#include <asm/unaligned.h> +#include <memalign.h> +#include <nand.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/log2.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/rawnand.h> +#include <linux/sizes.h> +#include <linux/types.h> + +#include "nand_secure_storage.h" + +/* + * The Allwinner NAND layout scans up to block 50 and starts scanning at + * uboot_next_block. The U-Boot range below follows the geometry-dependent + * defaults used when no stored NAND partition table is present. + */ +#define SS_SCAN_END_BLOCK 50 + +#define SS_SMALL_NAND_MAX_BLOCK_SIZE SZ_1M +#define SS_SMALL_NAND_MIN_BLOCK_SIZE SZ_128K +#define SS_SMALL_NAND_ALWAYS_BLOCK_SIZE SZ_512K +#define SS_SMALL_NAND_UBOOT_START 8 +#define SS_SMALL_NAND_UBOOT_SIZE SZ_4M +#define SS_MEDIUM_NAND_MAX_BLOCK_SIZE SZ_2M +#define SS_BIG_NAND_UBOOT_START 4 +#define SS_BIG_NAND_1M_UBOOT_BLOCKS 20 +#define SS_BIG_NAND_2M_UBOOT_BLOCKS 10 +#define SS_BIG_NAND_MIN_UBOOT_BLOCKS 8 + +/* + * The H616/sun50iw9 NAND layout uses the 128-page SPL-copy geometry. + * Only unrelated SUN8IW18 and SUN50IW11 SoC families use the 256-page + * variant. + */ +#define SS_SPL_PAGE_CNT_PER_COPY 128 + +#define SS_OOB_MAGIC_OFF 1 +#define SS_OOB_CHECKSUM_OFF 3 +#define SS_OOB_MAGIC 0xaa5c +#define SS_OOB_MAGIC_SIZE (SS_OOB_MAGIC_OFF + sizeof(u16)) +#define SS_OOB_CHECKSUM_SIZE (SS_OOB_CHECKSUM_OFF + sizeof(u32)) + +#ifdef CONFIG_SUNXI_NAND_SECURE_STORAGE_ETHADDR +#define SS_ITEM_SIZE SZ_4K +#define SS_EMPTY_SUM 0x1234 +#define SS_ITEMS_PER_BLOCK 32 +#define SS_MAP_MAX_ENTRIES (SS_ITEMS_PER_BLOCK - 1) +#define SS_NAME_LEN 64 + +#define SS_STORE_MAGIC 0x17253948 +#define SS_STORE_MAX_LEN 0xc00 +#endif + +struct ss_info { + struct mtd_info *mtd; + u32 first_block; + u32 last_block; + u32 marker_count; + u32 page_size; + u32 oob_size; + u32 erase_size; + u32 pages_per_block; + u32 spl_copy_blocks; + u32 spl_copy_count; + u32 uboot_start_block; + u32 uboot_next_block; +}; + +#ifdef CONFIG_SUNXI_NAND_SECURE_STORAGE_ETHADDR +struct ss_object { + u32 magic; + u32 id; + char name[SS_NAME_LEN]; + u32 re_encrypt; + u32 version; + u32 write_protect; + u32 reserved[3]; + u32 actual_len; + u8 data[SS_STORE_MAX_LEN]; + u32 crc; +} __packed; + +static u32 ss_get_le32(const void *buf, size_t offset) +{ + return get_unaligned_le32((const u8 *)buf + offset); +} +#endif + +static bool ss_oob_has_magic(const u8 *oob) +{ + return get_unaligned_be16(oob + SS_OOB_MAGIC_OFF) == SS_OOB_MAGIC; +} + +static int ss_read_ecc_page(struct ss_info *ss, u32 block, u32 page, void *buf, + u8 *oob) +{ + struct mtd_oob_ops ops = {}; + loff_t offs = (loff_t)block * ss->erase_size + + (loff_t)page * ss->page_size; + int ret; + + ops.mode = MTD_OPS_PLACE_OOB; + ops.len = ss->page_size; + ops.ooblen = ss->oob_size; + ops.datbuf = buf; + ops.oobbuf = oob; + + ret = mtd_read_oob(ss->mtd, offs, &ops); + if (ret && !mtd_is_bitflip(ret)) + return ret; + + if (ops.retlen != ss->page_size || ops.oobretlen != ss->oob_size) + return -EIO; + + return 0; +} + +#ifdef CONFIG_SUNXI_NAND_SECURE_STORAGE_ETHADDR +static u32 ss_page_sum(const void *buf, size_t len) +{ + const u8 *bytes = buf; + u32 sum = SS_EMPTY_SUM; + size_t i; + + for (i = 0; i < len / sizeof(u32); i++) + sum += get_unaligned_le32(bytes + i * sizeof(u32)); + + return sum; +} + +static int ss_read_page(struct ss_info *ss, u32 block, u32 page, void *buf, + u8 *oob, u32 len) +{ + u32 sum; + int ret; + + ret = ss_read_ecc_page(ss, block, page, buf, oob); + if (ret) + return ret; + + if (!ss_oob_has_magic(oob)) + return -ENOENT; + + sum = ss_page_sum(buf, len); + if (sum != get_unaligned_be32(oob + SS_OOB_CHECKSUM_OFF)) + return -EBADMSG; + if (sum == SS_EMPTY_SUM) + return -ENODATA; + + return 0; +} + +static int ss_read_replicated_page(struct ss_info *ss, u32 block, u32 page, + void *buf, u8 *oob, u32 len) +{ + int ret = -ENOENT; + + for (; page < ss->pages_per_block; page += SS_ITEMS_PER_BLOCK) { + ret = ss_read_page(ss, block, page, buf, oob, len); + if (!ret) + return 0; + } + + return ret; +} +#endif + +static bool ss_is_secure_block(struct ss_info *ss, u32 block, void *pagebuf, + u8 *oob) +{ + if (ss_read_ecc_page(ss, block, 0, pagebuf, oob)) + return false; + + return ss_oob_has_magic(oob); +} + +static void ss_default_uboot_range(struct ss_info *ss) +{ + u32 block_size = ss->erase_size; + u32 uboot_blocks; + + if (ss->erase_size <= SS_SMALL_NAND_ALWAYS_BLOCK_SIZE || + (ss->erase_size <= SS_SMALL_NAND_MAX_BLOCK_SIZE && + ss->pages_per_block <= 128)) { + if (block_size < SS_SMALL_NAND_MIN_BLOCK_SIZE) + block_size = SS_SMALL_NAND_MIN_BLOCK_SIZE; + block_size = roundup_pow_of_two(block_size); + + ss->uboot_start_block = SS_SMALL_NAND_UBOOT_START; + uboot_blocks = SS_SMALL_NAND_UBOOT_SIZE / block_size; + } else if (ss->erase_size <= SS_SMALL_NAND_MAX_BLOCK_SIZE) { + ss->uboot_start_block = SS_BIG_NAND_UBOOT_START; + uboot_blocks = SS_BIG_NAND_1M_UBOOT_BLOCKS; + } else if (ss->erase_size <= SS_MEDIUM_NAND_MAX_BLOCK_SIZE) { + ss->uboot_start_block = SS_BIG_NAND_UBOOT_START; + uboot_blocks = SS_BIG_NAND_2M_UBOOT_BLOCKS; + } else { + ss->uboot_start_block = SS_BIG_NAND_UBOOT_START; + uboot_blocks = SS_BIG_NAND_MIN_UBOOT_BLOCKS; + } + + ss->uboot_next_block = ss->uboot_start_block + uboot_blocks; +} + +static void ss_default_spl_layout(struct ss_info *ss) +{ + ss->spl_copy_blocks = + DIV_ROUND_UP(SS_SPL_PAGE_CNT_PER_COPY, ss->pages_per_block); + + /* + * The SPL-copy writer silently stops once the next SPL copy would + * overlap U-Boot proper. Keep the same floor division here. + */ + if (ss->spl_copy_blocks) + ss->spl_copy_count = + ss->uboot_start_block / ss->spl_copy_blocks; +} + +static int ss_scan_blocks(struct ss_info *ss) +{ + struct mtd_info *mtd; + u64 total_blocks; + u32 block, end_block; + int ret; + + nand_init(); + + mtd = get_nand_dev_by_index(0); + if (!mtd) + return -ENODEV; + if (!mtd->writesize || !mtd->erasesize || !mtd->oobsize) + return -EINVAL; + if (mtd_mod_by_ws(mtd->erasesize, mtd)) + return -EINVAL; + if (mtd->oobsize < SS_OOB_MAGIC_SIZE) + return -EINVAL; + if (IS_ENABLED(CONFIG_SUNXI_NAND_SECURE_STORAGE_ETHADDR) && + mtd->oobsize < SS_OOB_CHECKSUM_SIZE) + return -EINVAL; + if (!nand_is_slc(mtd_to_nand(mtd))) + return -EOPNOTSUPP; + + memset(ss, 0, sizeof(*ss)); + ss->mtd = mtd; + ss->page_size = mtd->writesize; + ss->oob_size = mtd->oobsize; + ss->erase_size = mtd->erasesize; + ss->pages_per_block = mtd_div_by_ws(mtd->erasesize, mtd); + ss_default_uboot_range(ss); + ss_default_spl_layout(ss); + + ALLOC_CACHE_ALIGN_BUFFER(u8, pagebuf, ss->page_size); + ALLOC_CACHE_ALIGN_BUFFER(u8, oob, ss->oob_size); + + total_blocks = mtd_div_by_eb(mtd->size, mtd); + end_block = min_t(u64, total_blocks, SS_SCAN_END_BLOCK); + + if (ss->uboot_next_block >= end_block) + return -ENOENT; + + for (block = ss->uboot_next_block; block < end_block; block++) { + ret = mtd_block_isbad(mtd, (loff_t)block * ss->erase_size); + if (ret > 0) + continue; + if (ret < 0) + return ret; + if (!ss_is_secure_block(ss, block, pagebuf, oob)) + continue; + + if (!ss->marker_count) + ss->first_block = block; + ss->last_block = block; + ss->marker_count++; + } + + if (!ss->marker_count) + return -ENOENT; + + return 0; +} + +static int ss_find_blocks(struct ss_info *ss) +{ + static struct ss_info cached_ss; + static bool cached; + int ret; + + if (cached) { + *ss = cached_ss; + return 0; + } + + ret = ss_scan_blocks(ss); + if (ret) + return ret; + + cached_ss = *ss; + cached = true; + + return 0; +} + +int sunxi_nand_secure_storage_locate(struct sunxi_nand_secure_storage_info *info) +{ + struct ss_info ss; + int ret; + + if (!info) + return -EINVAL; + + ret = ss_find_blocks(&ss); + if (ret) + return ret; + + memset(info, 0, sizeof(*info)); + info->mtd_name = ss.mtd->name; + info->mtd_size = ss.mtd->size; + info->spl_copy_size = (u64)ss.spl_copy_blocks * ss.erase_size; + info->spl_copy_count = ss.spl_copy_count; + info->uboot_offset = (u64)ss.uboot_start_block * ss.erase_size; + info->uboot_size = (u64)(ss.uboot_next_block - ss.uboot_start_block) * + ss.erase_size; + info->secure_offset = (u64)ss.first_block * ss.erase_size; + info->secure_size = (u64)(ss.last_block - ss.first_block + 1) * + ss.erase_size; + info->secure_end = (u64)(ss.last_block + 1) * ss.erase_size; + + return 0; +} + +#ifdef CONFIG_SUNXI_NAND_SECURE_STORAGE_ETHADDR +static int ss_read_item(struct ss_info *ss, u32 item, void *buf) +{ + u32 pages_per_item = SS_ITEM_SIZE / ss->page_size; + u32 page_len = pages_per_item == 1 ? SS_ITEM_SIZE : ss->page_size; + u32 page; + int ret; + + if (ss->page_size > SS_ITEM_SIZE || SS_ITEM_SIZE % ss->page_size) + return -EINVAL; + if ((item + 1) * pages_per_item > ss->pages_per_block) + return -EINVAL; + + ALLOC_CACHE_ALIGN_BUFFER(u8, oob, ss->oob_size); + + for (page = 0; page < pages_per_item; page++) { + u8 *dst = (u8 *)buf + page * ss->page_size; + u32 raw_page = item * pages_per_item + page; + + ret = ss_read_replicated_page(ss, ss->first_block, raw_page, + dst, oob, page_len); + if (ret && ss->last_block != ss->first_block) + ret = ss_read_replicated_page(ss, ss->last_block, + raw_page, dst, oob, + page_len); + if (ret) + return ret; + } + + return 0; +} + +static bool ss_object_name_matches(const struct ss_object *object, + const char *key) +{ + size_t key_len = strlen(key); + size_t name_len = strnlen(object->name, SS_NAME_LEN); + + return name_len == key_len && !memcmp(object->name, key, key_len); +} + +static int ss_find_item(const char *map, const char *key, u32 *item) +{ + size_t key_len = strlen(key); + u32 pos = 0; + u32 nr = 1; + + if (key_len >= SS_NAME_LEN) + return -ENAMETOOLONG; + + while (pos < SS_ITEM_SIZE && map[pos]) { + const char *entry = map + pos; + const char *colon; + size_t entry_len = strnlen(entry, SS_ITEM_SIZE - pos); + + if (entry_len == SS_ITEM_SIZE - pos) + return -EINVAL; + if (nr > SS_MAP_MAX_ENTRIES) + return -ENOSPC; + + colon = memchr(entry, ':', entry_len); + if (!colon || colon == entry || colon + 1 == entry + entry_len) + return -EINVAL; + + if (colon - entry == key_len && !memcmp(entry, key, key_len)) { + *item = nr; + return 0; + } + + pos += entry_len + 1; + nr++; + } + + return -ENOENT; +} + +static int ss_get_payload(const void *item, const char *key, const u8 **payload, + u32 *len) +{ + const struct ss_object *object = item; + u32 actual_len, stored_crc, crc; + + if (ss_get_le32(item, offsetof(struct ss_object, magic)) != + SS_STORE_MAGIC) + return -EINVAL; + + stored_crc = ss_get_le32(item, offsetof(struct ss_object, crc)); + crc = crc32(0, item, offsetof(struct ss_object, crc)); + if (crc != stored_crc) + return -EBADMSG; + if (!ss_object_name_matches(object, key)) + return -ENOENT; + + actual_len = ss_get_le32(item, offsetof(struct ss_object, actual_len)); + if (actual_len > SS_STORE_MAX_LEN) + return -EINVAL; + + *payload = ((const struct ss_object *)item)->data; + *len = actual_len; + + return 0; +} + +static bool ss_parse_mac(const u8 *buf, u32 len, u8 *mac) +{ + char text[ARP_HLEN_ASCII + 1]; + size_t text_len; + + text_len = strnlen((const char *)buf, len); + if (!text_len || text_len > ARP_HLEN_ASCII) + return false; + + memcpy(text, buf, text_len); + text[text_len] = '\0'; + string_to_enetaddr(text, mac); + + return is_valid_ethaddr(mac); +} + +static int ss_read_mac(const char *key, u8 *mac) +{ + struct ss_info ss; + const u8 *payload; + u32 item, len; + int ret; + + ret = ss_find_blocks(&ss); + if (ret) + return ret; + + ALLOC_CACHE_ALIGN_BUFFER(u8, itembuf, SS_ITEM_SIZE); + + ret = ss_read_item(&ss, 0, itembuf); + if (ret) + return ret; + + ret = ss_find_item((const char *)itembuf, key, &item); + if (ret) + return ret; + + ret = ss_read_item(&ss, item, itembuf); + if (ret) + return ret; + + ret = ss_get_payload(itembuf, key, &payload, &len); + if (ret) + return ret; + + return ss_parse_mac(payload, len, mac) ? 0 : -EINVAL; +} + +void sunxi_nand_secure_storage_setup_ethaddr(void) +{ + const char *key = CONFIG_SUNXI_NAND_SECURE_STORAGE_ETHADDR_KEY; + static bool attempted; + u8 mac[ARP_HLEN]; + int ret; + + if (attempted || !key[0] || eth_env_get_enetaddr("ethaddr", mac)) + return; + + attempted = true; + + ret = ss_read_mac(key, mac); + if (ret) { + printf("Secure storage: failed to read key '%s' (%d)\n", + key, ret); + return; + } + + eth_env_set_enetaddr("ethaddr", mac); + printf("Secure storage mac: %pM\n", mac); +} +#endif diff --git a/board/sunxi/nand_secure_storage.h b/board/sunxi/nand_secure_storage.h new file mode 100644 index 00000000000..45b20659c0b --- /dev/null +++ b/board/sunxi/nand_secure_storage.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Allwinner NAND secure storage helpers. + */ + +#ifndef SUNXI_NAND_SECURE_STORAGE_H +#define SUNXI_NAND_SECURE_STORAGE_H + +#include <linux/errno.h> +#include <linux/kconfig.h> +#include <linux/types.h> + +struct sunxi_nand_secure_storage_info { + const char *mtd_name; + u64 mtd_size; + u64 spl_copy_size; + u32 spl_copy_count; + u64 uboot_offset; + u64 uboot_size; + u64 secure_offset; + u64 secure_size; + u64 secure_end; +}; + +#if IS_ENABLED(CONFIG_SUNXI_NAND_SECURE_STORAGE) && !defined(CONFIG_XPL_BUILD) +int sunxi_nand_secure_storage_locate(struct sunxi_nand_secure_storage_info *info); +#else +static inline int +sunxi_nand_secure_storage_locate(struct sunxi_nand_secure_storage_info *info) +{ + return -ENODEV; +} +#endif + +#if IS_ENABLED(CONFIG_SUNXI_NAND_SECURE_STORAGE_ETHADDR) && \ + !defined(CONFIG_XPL_BUILD) +void sunxi_nand_secure_storage_setup_ethaddr(void); +#else +static inline void sunxi_nand_secure_storage_setup_ethaddr(void) {} +#endif + +#endif -- 2.53.0

