diff --git a/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0001-Implement-support-for-environment-encryption-by-CAAM.patch b/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0001-Implement-support-for-environment-encryption-by-CAAM.patch new file mode 100644 index 000000000..eb8bca7f3 --- /dev/null +++ b/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0001-Implement-support-for-environment-encryption-by-CAAM.patch @@ -0,0 +1,606 @@ +From 58977c4d6709f6ce4dc444e844b3665b031c556f Mon Sep 17 00:00:00 2001 +From: Gabriel Valcazar +Date: Wed, 7 Apr 2021 09:15:07 +0200 +Subject: [PATCH 1/3] Implement support for environment encryption by CAAM + +Use the md5sum of HWID words (on the device tree) as key modifier. This is +based on the u-boot-fw-utils implementation of the CAAM encryption support. + +Port a subset of U-Boot's md5 implementation. + +https://jira.digi.com/browse/DEL-7410 +https://jira.digi.com/browse/DEL-7185 +https://jira.digi.com/browse/DEL-2836 + +Signed-off-by: Diaz de Grenu, Jose +Signed-off-by: Gonzalo Ruiz +Signed-off-by: Hector Palacios +Signed-off-by: Gabriel Valcazar +--- + src/CMakeLists.txt | 2 + + src/caam_keyblob.h | 42 +++++++ + src/md5.c | 275 ++++++++++++++++++++++++++++++++++++++++++++ + src/md5.h | 24 ++++ + src/uboot_env.c | 131 +++++++++++++++++++++ + src/uboot_private.h | 4 + + 6 files changed, 478 insertions(+) + create mode 100644 src/caam_keyblob.h + create mode 100644 src/md5.c + create mode 100644 src/md5.h + +diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt +index a04dd11..659594a 100644 +--- a/src/CMakeLists.txt ++++ b/src/CMakeLists.txt +@@ -1,6 +1,8 @@ + cmake_minimum_required (VERSION 2.6) + # Sources and private headers + SET(libubootenv_SOURCES ++ md5.c ++ md5.h + uboot_env.c + uboot_private.h + ) +diff --git a/src/caam_keyblob.h b/src/caam_keyblob.h +new file mode 100644 +index 0000000..e313e87 +--- /dev/null ++++ b/src/caam_keyblob.h +@@ -0,0 +1,42 @@ ++/* ++ * CAAM public-level include definitions for the key blob ++ * ++ * Copyright (C) 2015 Freescale Semiconductor, Inc. ++ */ ++ ++#ifndef CAAM_KEYBLOB_H ++#define CAAM_KEYBLOB_H ++ ++#include ++#include ++ ++struct caam_kb_data { ++ char *rawkey; ++ size_t rawkey_len; ++ char *keyblob; ++ size_t keyblob_len; ++ char *keymod; ++ size_t keymod_len; ++}; ++ ++#define CAAM_KB_MAGIC 'I' ++ ++/** ++ * DOC: CAAM_KB_ENCRYPT - generate a key blob from raw key ++ * ++ * Takes an caam_kb_data struct and returns it with the key blob ++ */ ++#define CAAM_KB_ENCRYPT _IOWR(CAAM_KB_MAGIC, 0, struct caam_kb_data) ++ ++/** ++ * DOC: CAAM_KB_DECRYPT - get keys from a key blob ++ * ++ * Takes an caam_kb_data struct and returns it with the raw key. ++ */ ++#define CAAM_KB_DECRYPT _IOWR(CAAM_KB_MAGIC, 1, struct caam_kb_data) ++ ++#ifndef GENMEM_KEYMOD_LEN ++#define GENMEM_KEYMOD_LEN 16 ++#endif ++ ++#endif /* CAAM_KEYBLOB_H */ +diff --git a/src/md5.c b/src/md5.c +new file mode 100644 +index 0000000..47ae8bf +--- /dev/null ++++ b/src/md5.c +@@ -0,0 +1,275 @@ ++/* ++ * This file was transplanted with slight modifications from Linux sources ++ * (fs/cifs/md5.c) into U-Boot by Bartlomiej Sieka . ++ */ ++ ++/* ++ * This code implements the MD5 message-digest algorithm. ++ * The algorithm is due to Ron Rivest. This code was ++ * written by Colin Plumb in 1993, no copyright is claimed. ++ * This code is in the public domain; do with it what you wish. ++ * ++ * Equivalent code is available from RSA Data Security, Inc. ++ * This code has been tested against that, and is equivalent, ++ * except that you don't need to include two pages of legalese ++ * with every copy. ++ * ++ * To compute the message digest of a chunk of bytes, declare an ++ * MD5Context structure, pass it to MD5Init, call MD5Update as ++ * needed on buffers full of bytes, and then call MD5Final, which ++ * will fill a supplied 16-byte array with the digest. ++ */ ++ ++/* This code slightly modified to fit into Samba by ++ abartlet@samba.org Jun 2001 ++ and to fit the cifs vfs by ++ Steve French sfrench@us.ibm.com */ ++ ++#include ++#include ++ ++#include "md5.h" ++ ++static void ++MD5Transform(uint32_t buf[4], uint32_t const in[16]); ++ ++/* ++ * Note: this code is harmless on little-endian machines. ++ */ ++static void ++byteReverse(unsigned char *buf, unsigned longs) ++{ ++ uint32_t t; ++ do { ++ t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 | ++ ((unsigned) buf[1] << 8 | buf[0]); ++ *(uint32_t *) buf = t; ++ buf += 4; ++ } while (--longs); ++} ++ ++/* ++ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious ++ * initialization constants. ++ */ ++static void ++MD5Init(struct MD5Context *ctx) ++{ ++ ctx->buf[0] = 0x67452301; ++ ctx->buf[1] = 0xefcdab89; ++ ctx->buf[2] = 0x98badcfe; ++ ctx->buf[3] = 0x10325476; ++ ++ ctx->bits[0] = 0; ++ ctx->bits[1] = 0; ++} ++ ++/* ++ * Update context to reflect the concatenation of another buffer full ++ * of bytes. ++ */ ++static void ++MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len) ++{ ++ register uint32_t t; ++ ++ /* Update bitcount */ ++ ++ t = ctx->bits[0]; ++ if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t) ++ ctx->bits[1]++; /* Carry from low to high */ ++ ctx->bits[1] += len >> 29; ++ ++ t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ ++ ++ /* Handle any leading odd-sized chunks */ ++ ++ if (t) { ++ unsigned char *p = (unsigned char *) ctx->in + t; ++ ++ t = 64 - t; ++ if (len < t) { ++ memmove(p, buf, len); ++ return; ++ } ++ memmove(p, buf, t); ++ byteReverse(ctx->in, 16); ++ MD5Transform(ctx->buf, (uint32_t *) ctx->in); ++ buf += t; ++ len -= t; ++ } ++ /* Process data in 64-byte chunks */ ++ ++ while (len >= 64) { ++ memmove(ctx->in, buf, 64); ++ byteReverse(ctx->in, 16); ++ MD5Transform(ctx->buf, (uint32_t *) ctx->in); ++ buf += 64; ++ len -= 64; ++ } ++ ++ /* Handle any remaining bytes of data. */ ++ ++ memmove(ctx->in, buf, len); ++} ++ ++/* ++ * Final wrapup - pad to 64-byte boundary with the bit pattern ++ * 1 0* (64-bit count of bits processed, MSB-first) ++ */ ++static void ++MD5Final(unsigned char digest[16], struct MD5Context *ctx) ++{ ++ unsigned int count; ++ unsigned char *p; ++ ++ /* Compute number of bytes mod 64 */ ++ count = (ctx->bits[0] >> 3) & 0x3F; ++ ++ /* Set the first char of padding to 0x80. This is safe since there is ++ always at least one byte free */ ++ p = ctx->in + count; ++ *p++ = 0x80; ++ ++ /* Bytes of padding needed to make 64 bytes */ ++ count = 64 - 1 - count; ++ ++ /* Pad out to 56 mod 64 */ ++ if (count < 8) { ++ /* Two lots of padding: Pad the first block to 64 bytes */ ++ memset(p, 0, count); ++ byteReverse(ctx->in, 16); ++ MD5Transform(ctx->buf, (uint32_t *) ctx->in); ++ ++ /* Now fill the next block with 56 bytes */ ++ memset(ctx->in, 0, 56); ++ } else { ++ /* Pad block to 56 bytes */ ++ memset(p, 0, count - 8); ++ } ++ byteReverse(ctx->in, 14); ++ ++ /* Append length in bits and transform */ ++ ctx->in32[14] = ctx->bits[0]; ++ ctx->in32[15] = ctx->bits[1]; ++ ++ MD5Transform(ctx->buf, (uint32_t *) ctx->in); ++ byteReverse((unsigned char *) ctx->buf, 4); ++ memmove(digest, ctx->buf, 16); ++ memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ ++} ++ ++/* The four core functions - F1 is optimized somewhat */ ++ ++/* #define F1(x, y, z) (x & y | ~x & z) */ ++#define F1(x, y, z) (z ^ (x & (y ^ z))) ++#define F2(x, y, z) F1(z, x, y) ++#define F3(x, y, z) (x ^ y ^ z) ++#define F4(x, y, z) (y ^ (x | ~z)) ++ ++/* This is the central step in the MD5 algorithm. */ ++#define MD5STEP(f, w, x, y, z, data, s) \ ++ ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) ++ ++/* ++ * The core of the MD5 algorithm, this alters an existing MD5 hash to ++ * reflect the addition of 16 longwords of new data. MD5Update blocks ++ * the data and converts bytes into longwords for this routine. ++ */ ++static void ++MD5Transform(uint32_t buf[4], uint32_t const in[16]) ++{ ++ register uint32_t a, b, c, d; ++ ++ a = buf[0]; ++ b = buf[1]; ++ c = buf[2]; ++ d = buf[3]; ++ ++ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); ++ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); ++ MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); ++ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); ++ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); ++ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); ++ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); ++ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); ++ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); ++ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); ++ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); ++ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); ++ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); ++ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); ++ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); ++ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); ++ ++ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); ++ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); ++ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); ++ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); ++ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); ++ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); ++ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); ++ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); ++ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); ++ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); ++ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); ++ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); ++ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); ++ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); ++ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); ++ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); ++ ++ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); ++ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); ++ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); ++ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); ++ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); ++ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); ++ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); ++ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); ++ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); ++ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); ++ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); ++ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); ++ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); ++ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); ++ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); ++ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); ++ ++ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); ++ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); ++ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); ++ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); ++ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); ++ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); ++ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); ++ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); ++ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); ++ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); ++ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); ++ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); ++ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); ++ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); ++ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); ++ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); ++ ++ buf[0] += a; ++ buf[1] += b; ++ buf[2] += c; ++ buf[3] += d; ++} ++ ++/* ++ * Calculate and store in 'output' the MD5 digest of 'len' bytes at ++ * 'input'. 'output' must have enough space to hold 16 bytes. ++ */ ++void ++md5 (unsigned char *input, int len, unsigned char output[16]) ++{ ++ struct MD5Context context; ++ ++ MD5Init(&context); ++ MD5Update(&context, input, len); ++ MD5Final(output, &context); ++} +diff --git a/src/md5.h b/src/md5.h +new file mode 100644 +index 0000000..02a9a9d +--- /dev/null ++++ b/src/md5.h +@@ -0,0 +1,24 @@ ++/* ++ * This file was transplanted with slight modifications from Linux sources ++ * (fs/cifs/md5.h) into U-Boot by Bartlomiej Sieka . ++ */ ++ ++#ifndef _MD5_H ++#define _MD5_H ++ ++struct MD5Context { ++ uint32_t buf[4]; ++ uint32_t bits[2]; ++ union { ++ unsigned char in[64]; ++ uint32_t in32[16]; ++ }; ++}; ++ ++/* ++ * Calculate and store in 'output' the MD5 digest of 'len' bytes at ++ * 'input'. 'output' must have enough space to hold 16 bytes. ++ */ ++void md5 (unsigned char *input, int len, unsigned char output[16]); ++ ++#endif /* _MD5_H */ +diff --git a/src/uboot_env.c b/src/uboot_env.c +index c9a900f..53b3576 100644 +--- a/src/uboot_env.c ++++ b/src/uboot_env.c +@@ -33,11 +33,21 @@ + #include + #include + #include ++#include + #include + #include + ++#include "caam_keyblob.h" ++#include "md5.h" + #include "uboot_private.h" + ++/* ++ * The BLOB includes a random AES-256 key (32 bytes) and a ++ * Message Authentication Code (MAC) (16 bytes) ++ */ ++#define BLOB_OVERHEAD 48 ++#define CAAM_KEY_DEV "/dev/caam_kb" ++ + #define UBI_MAX_VOLUME 128 + + #define DEVICE_MTD_NAME "/dev/mtd" +@@ -840,6 +850,105 @@ static int set_obsolete_flag(struct uboot_flash_env *dev) + return ret; + } + ++static int is_env_encrypted(void) ++{ ++ const char *dt_prop = "/proc/device-tree/digi,uboot-env,encrypted"; ++ ++ return access(dt_prop, F_OK) != -1; ++} ++ ++#define MAX_HWID_WORDS 4 ++static int env_caam_get_keymod(unsigned char output[16]) ++{ ++ int i; ++ int len; ++ int fd; ++ uint32_t ocotp_hwid[MAX_HWID_WORDS]; ++ char dt_prop[32]; ++ ++ for (i = 0; i < MAX_HWID_WORDS; i++) { ++ sprintf(dt_prop, "/proc/device-tree/digi,hwid_%d", i); ++ if (access(dt_prop, F_OK) != -1) { ++ char buf[sizeof(uint32_t)]; ++ ++ fd = open(dt_prop, O_RDONLY); ++ if (fd < 0) ++ return fd; ++ len = read(fd, buf, sizeof(uint32_t)); ++ if (len < 0) { ++ close(fd); ++ return -1; ++ } ++ ocotp_hwid[i] = ntohl(*(uint32_t *)buf); ++ close(fd); ++ } else { ++ break; ++ } ++ } ++ ++ /* Calculate md5sum on the raw HWID array */ ++ md5((unsigned char *)(&ocotp_hwid), sizeof(uint32_t) * i, output); ++ ++ return 0; ++} ++ ++static int env_caam_crypt(char *data, unsigned int size, const int enc) ++{ ++ struct caam_kb_data enc_data; ++ int fd; ++ int ret = 0; ++ const int len = size; ++ int ioctl_mode; ++ char *buffer; ++ unsigned char key_modifier[16]; ++ ++ ret = env_caam_get_keymod(key_modifier); ++ if (ret) ++ return ret; ++ ++ enc_data.keymod = (char *)key_modifier; ++ enc_data.keymod_len = sizeof(key_modifier); ++ ++ enc_data.keyblob_len = len; ++ enc_data.rawkey_len = len - BLOB_OVERHEAD; ++ ++ buffer = malloc(len); ++ if (!buffer) { ++ printf("Could not allocate memory\n"); ++ return -1; ++ } ++ ++ if (enc) { ++ enc_data.rawkey = data; ++ ioctl_mode = CAAM_KB_ENCRYPT; ++ enc_data.keyblob = buffer; ++ } else { ++ enc_data.keyblob = data; ++ ioctl_mode = CAAM_KB_DECRYPT; ++ enc_data.rawkey = buffer; ++ } ++ ++ if ((fd = open(CAAM_KEY_DEV, O_RDWR)) < 0) { ++ ret = fd; ++ goto free; ++ } ++ ++ ret = ioctl(fd, ioctl_mode, &enc_data); ++ if (ret) { ++ printf("CAAM_KEY_DEV ioctl failed: %d\n", ret); ++ goto out; ++ } ++ ++ memcpy(data, buffer, enc ? len : len - BLOB_OVERHEAD); ++ ++out: ++ close(fd); ++free: ++ free(buffer); ++ ++ return ret; ++} ++ + int libuboot_env_store(struct uboot_ctx *ctx) + { + struct var_entry *entry; +@@ -914,6 +1023,15 @@ int libuboot_env_store(struct uboot_ctx *ctx) + ((struct uboot_env_redund *)image)->flags = flags; + } + ++ if (ctx->encrypted) { ++ ret = env_caam_crypt(data, ctx->usable_size, 1); ++ if (ret) { ++ fprintf(stderr, ++ "Error: can't encrypt env for flash\n"); ++ return ret; ++ } ++ } ++ + *(uint32_t *)image = crc32(0, (uint8_t *)data, ctx->size - offsetdata); + + copy = ctx->redundant ? (ctx->current ? 0 : 1) : 0; +@@ -978,6 +1096,13 @@ static int libuboot_load(struct uboot_ctx *ctx) + } + crc = *(uint32_t *)(buf[i] + offsetcrc); + dev->crc = crc32(0, (uint8_t *)data, ctx->size - offsetdata); ++ if (ctx->encrypted) { ++ ret = env_caam_crypt((char *)data, ctx->usable_size, 0); ++ if (ret) { ++ fprintf(stderr, "Error: can't decrypt environment\n"); ++ return ret; ++ } ++ } + crcenv[i] = dev->crc == crc; + if (ctx->redundant) + dev->flags = *(uint8_t *)(buf[i] + offsetflags); +@@ -1258,6 +1383,11 @@ int libuboot_read_config(struct uboot_ctx *ctx, const char *config) + break; + } + } ++ ++ ctx->usable_size = ctx->size - sizeof(uint32_t); ++ if (ctx->redundant) ++ ctx->usable_size -= sizeof(char); ++ + if (ndev == 0) + retval = -EINVAL; + +@@ -1446,6 +1576,7 @@ int libuboot_initialize(struct uboot_ctx **out, + return -ENOMEM; + + ctx->valid = false; ++ ctx->encrypted = is_env_encrypted(); + ret = libuboot_configure(ctx, envdevs); + + if (ret < 0) { +diff --git a/src/uboot_private.h b/src/uboot_private.h +index 4b7a9f9..22c8c14 100644 +--- a/src/uboot_private.h ++++ b/src/uboot_private.h +@@ -111,10 +111,14 @@ LIST_HEAD(vars, var_entry); + struct uboot_ctx { + /** true if the environment is redundant */ + bool redundant; ++ /** true if the environment is encrypted */ ++ bool encrypted; + /** set to valid after a successful load */ + bool valid; + /** size of the environment */ + size_t size; ++ /** usable environment size */ ++ unsigned int usable_size; + /** devices where environment is stored */ + struct uboot_flash_env envdevs[2]; + /** Set which device contains the current(last valid) environment */ +-- +2.17.1 + diff --git a/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0002-Implement-U-Boot-environment-access-functions.patch b/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0002-Implement-U-Boot-environment-access-functions.patch new file mode 100644 index 000000000..b00080cf9 --- /dev/null +++ b/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0002-Implement-U-Boot-environment-access-functions.patch @@ -0,0 +1,161 @@ +From 00d0ef9a96cf5480146c800c64557f7c88ac9db4 Mon Sep 17 00:00:00 2001 +From: Gabriel Valcazar +Date: Wed, 7 Apr 2021 11:35:15 +0200 +Subject: [PATCH 2/3] Implement U-Boot environment access functions + +Keep the same function signatures as u-boot-fw-utils, so that all code making +use of this functionality remains compatible. Use the libubootenv +implementation of the fw_printenv and fw_setenv apps as reference. + +https://jira.digi.com/browse/DEL-7410 + +Signed-off-by: Javier Viguera +Signed-off-by: Jose Diaz de Grenu +Signed-off-by: Gonzalo Ruiz +Signed-off-by: Gabriel Valcazar +--- + src/libuboot.h | 23 ++++++++++++ + src/uboot_env.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 119 insertions(+) + +diff --git a/src/libuboot.h b/src/libuboot.h +index bfcaeb1..b15969f 100644 +--- a/src/libuboot.h ++++ b/src/libuboot.h +@@ -159,6 +159,29 @@ const char *libuboot_getname(void *entry); + */ + const char *libuboot_getvalue(void *entry); + ++/* ++ * Get U-Boot's environment variable. ++ * ++ * Params: ++ * 'name' (input) Name of the environment variable ++ * 'value' (output) Pointer to the variable's value ++ * (NULL if not found) ++ * ++ * Return: 0 on sucess, -1 on failure ++ */ ++int uboot_getenv(char *name, const char **value); ++ ++/* ++ * Set U-Boot's environment variable. ++ * ++ * Params: ++ * 'name' (input) Name of the environment variable ++ * 'value' (input) Value of the environment variable ++ * ++ * Return: 0 on sucess, -1 on failure ++ */ ++int uboot_setenv(char *name, char *value); ++ + #ifdef __cplusplus + } + #endif +diff --git a/src/uboot_env.c b/src/uboot_env.c +index 53b3576..bcc4af9 100644 +--- a/src/uboot_env.c ++++ b/src/uboot_env.c +@@ -1617,3 +1617,99 @@ void libuboot_close(struct uboot_ctx *ctx) { + void libuboot_exit(struct uboot_ctx *ctx) { + free(ctx); + } ++ ++static int uboot_common_init(struct uboot_ctx *ctx) ++{ ++ const char *cfgfname = "/etc/fw_env.config"; ++ const char *defenvfile = "/etc/u-boot-initial-env"; ++ ++ if (libuboot_read_config(ctx, cfgfname) < 0) { ++ fprintf(stderr, "Configuration file wrong or corrupted\n"); ++ return -1; ++ } ++ ++ if (libuboot_open(ctx) < 0) { ++ fprintf(stderr, "Cannot read environment, using default\n"); ++ if (libuboot_load_file(ctx, defenvfile) < 0) { ++ fprintf(stderr, "Cannot read default environment from file\n"); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++/* ++ * Function: uboot_getenv ++ * Description: get U-Boot's environment variable ++ */ ++int uboot_getenv(char *name, const char **value) ++{ ++ struct uboot_ctx *ctx; ++ int ret = 0; ++ ++ ret = libuboot_initialize(&ctx, NULL); ++ if (ret < 0) { ++ fprintf(stderr, "Cannot initialize environment\n"); ++ goto err; ++ } ++ ++ ret = uboot_common_init(ctx); ++ if (ret < 0) ++ goto err; ++ ++ *value = libuboot_get_env(ctx, name); ++ ++err: ++ libuboot_close(ctx); ++ libuboot_exit(ctx); ++ ++ return ret ? -1 : 0; ++} ++ ++/* ++ * Function: uboot_setenv ++ * Description: set U-Boot's environment variable ++ */ ++int uboot_setenv(char *name, char *value) ++{ ++ struct uboot_ctx *ctx; ++ bool need_store = false; ++ const char *curr; ++ int ret = 0; ++ ++ ret = libuboot_initialize(&ctx, NULL); ++ if (ret < 0) { ++ fprintf(stderr, "Cannot initialize environment\n"); ++ goto err; ++ } ++ ++ ret = uboot_common_init(ctx); ++ if (ret < 0) ++ goto err; ++ ++ curr = libuboot_get_env(ctx, name); ++ if (value == NULL) { ++ if (curr != NULL) { ++ libuboot_set_env(ctx, name, NULL); ++ need_store = true; ++ } ++ } else { ++ if (curr == NULL || strcmp(curr, value) != 0) { ++ libuboot_set_env(ctx, name, value); ++ need_store = true; ++ } ++ } ++ ++ if (need_store) { ++ ret = libuboot_env_store(ctx); ++ if (ret) ++ fprintf(stderr, "Error storing the env\n"); ++ } ++ ++err: ++ libuboot_close(ctx); ++ libuboot_exit(ctx); ++ ++ return ret ? -1 : 0; ++} +-- +2.17.1 + diff --git a/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0003-tools-env-add-support-to-set-dynamic-location-of-env.patch b/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0003-tools-env-add-support-to-set-dynamic-location-of-env.patch new file mode 100644 index 000000000..14937f598 --- /dev/null +++ b/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/0003-tools-env-add-support-to-set-dynamic-location-of-env.patch @@ -0,0 +1,178 @@ +From cd5e40f6dbef29a04cdfabec47fd3674d764f74e Mon Sep 17 00:00:00 2001 +From: Gabriel Valcazar +Date: Wed, 7 Apr 2021 13:47:37 +0200 +Subject: [PATCH 3/3] tools: env: add support to set dynamic location of + environment copies + +A mechanism was added in U-Boot to set the location of environment copies +dynamically in a shared area. If the config file sets both copies to the same +offset, a function will be called to set the offset of each copy to the first +two good NAND sectors within the specified area. + +The config file should contain the sector size and the number of sectors of the +area, like in this example: + + # Device name Offset Size Erase-size No.Blocks + /dev/mtd1 0x0 0x20000 0x20000 8 + /dev/mtd1 0x0 0x20000 0x20000 8 + +https://jira.digi.com/browse/DUB-741 +https://jira.digi.com/browse/DEL-7410 + +Signed-off-by: Hector Palacios +Signed-off-by: Gonzalo Ruiz +Signed-off-by: Gabriel Valcazar +--- + src/uboot_env.c | 88 +++++++++++++++++++++++++++++++++++++++++++-- + src/uboot_private.h | 4 +++ + 2 files changed, 90 insertions(+), 2 deletions(-) + +diff --git a/src/uboot_env.c b/src/uboot_env.c +index bcc4af9..71fef10 100644 +--- a/src/uboot_env.c ++++ b/src/uboot_env.c +@@ -431,6 +431,73 @@ static int check_env_device(struct uboot_ctx *ctx, struct uboot_flash_env *dev) + return 0; + } + ++static bool set_dynamic_location(struct uboot_ctx *ctx) ++{ ++ int fd, i, nsectors, rc; ++ loff_t offset, blocksize, tmp; ++ int dev = 0; ++ int copies = 1; ++ bool ret = false; ++ ++ if (ctx->redundant) ++ copies++; ++ ++ fd = open(ctx->envdevs[dev].devname, O_RDONLY); ++ if (fd < 0) { ++ fprintf(stderr, "Can't open %s: %s\n", ctx->envdevs[dev].devname, ++ strerror(errno)); ++ goto error; ++ } ++ ++ /* Set initial block to start looking for environment */ ++ offset = ctx->envdevs[dev].offset; ++ /* Use variables for common values */ ++ blocksize = ctx->envdevs[dev].sectorsize; ++ /* Look for the number of sectors specified for the primary copy */ ++ nsectors = ctx->envdevs[dev].envsectors; ++ ++ for (i = 0; i < nsectors && copies; i++) { ++ rc = 0; ++ ++ /* ++ * The implementation of is_nand_badblock() expects dev->fd to ++ * be initialized, but it isn't at this point, so re-implementat ++ * it here. Copy the offset to a temporary variable so the ++ * original offset doesn't get overwritten by the ioctl. ++ */ ++ if (ctx->envdevs[dev].mtdinfo.type == MTD_NANDFLASH) { ++ tmp = offset; ++ rc = ioctl(fd, MEMGETBADBLOCK, &tmp); ++ } ++ ++ if (rc < 0) { ++ goto error; ++ } else if (!rc) { ++ /* ++ * Set first good block as primary (no matter if it is ++ * the other copy. After all, the 'current' copy is ++ * determined by the active flag. ++ */ ++ ctx->envdevs[dev].offset = offset; ++ copies--; ++ dev++; ++ } ++ offset += blocksize; ++ } ++ ++ while (copies) { ++ /* No good sectors available. Set offset out of bounds */ ++ ctx->envdevs[dev].offset = offset; ++ copies--; ++ dev++; ++ } ++ ret = true; ++ ++error: ++ close(fd); ++ return ret; ++} ++ + static bool check_compatible_devices(struct uboot_ctx *ctx) + { + if (!ctx->redundant) +@@ -442,6 +509,12 @@ static bool check_compatible_devices(struct uboot_ctx *ctx) + return false; + if (ctx->envdevs[0].envsize != ctx->envdevs[1].envsize) + return false; ++ if (ctx->envdevs[0].offset == ctx->envdevs[1].offset) { ++ ctx->dynamic_env = true; ++ ctx->top_limit = ctx->envdevs[0].offset + ++ (ctx->envdevs[0].envsectors * ctx->envdevs[0].sectorsize); ++ return set_dynamic_location(ctx); ++ } + + return true; + } +@@ -485,7 +558,7 @@ static int fileread(struct uboot_flash_env *dev, void *data) + return ret; + } + +-static int mtdread(struct uboot_flash_env *dev, void *data) ++static int mtdread(struct uboot_flash_env *dev, void *data, bool is_dynamic, loff_t top_limit) + { + size_t count; + size_t blocksize; +@@ -504,6 +577,17 @@ static int mtdread(struct uboot_flash_env *dev, void *data) + ret = read(dev->fd, data, dev->envsize); + break; + case MTD_NANDFLASH: ++ if (!is_dynamic) ++ top_limit = ((dev->offset / dev->envsize) + ++ dev->envsectors) * dev->envsize; ++ ++ if (dev->offset >= top_limit) { ++ /* End of range is reached */ ++ fprintf(stderr, "Too few good blocks within range\n"); ++ ret = -EIO; ++ break; ++ } ++ + if (dev->offset) + if (lseek(dev->fd, dev->offset, SEEK_SET) < 0) { + ret = -EIO; +@@ -579,7 +663,7 @@ static int devread(struct uboot_ctx *ctx, unsigned int copy, void *data) + ret = fileread(dev, data); + break; + case DEVICE_MTD: +- ret = mtdread(dev, data); ++ ret = mtdread(dev, data, ctx->dynamic_env, ctx->top_limit); + break; + case DEVICE_UBI: + ret = ubiread(dev, data); +diff --git a/src/uboot_private.h b/src/uboot_private.h +index 22c8c14..591df20 100644 +--- a/src/uboot_private.h ++++ b/src/uboot_private.h +@@ -113,10 +113,14 @@ struct uboot_ctx { + bool redundant; + /** true if the environment is encrypted */ + bool encrypted; ++ /** true if the environment is dynamic */ ++ bool dynamic_env; + /** set to valid after a successful load */ + bool valid; + /** size of the environment */ + size_t size; ++ /** top limit of the dynamic environment */ ++ loff_t top_limit; + /** usable environment size */ + unsigned int usable_size; + /** devices where environment is stored */ +-- +2.17.1 + diff --git a/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/mmc/fw_env.config b/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/mmc/fw_env.config new file mode 100644 index 000000000..040cd8e30 --- /dev/null +++ b/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/mmc/fw_env.config @@ -0,0 +1,7 @@ +# Configuration file for fw_(printenv/setenv) utility. +# Up to two entries are valid, in this case the redundant +# environment sector is assumed present. + +# Device name Offset Size +/dev/mmcblk0boot1 0x1C0000 0x4000 +/dev/mmcblk0boot1 0x1E0000 0x4000 diff --git a/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/mtd/fw_env.config b/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/mtd/fw_env.config new file mode 100644 index 000000000..e31ceca4d --- /dev/null +++ b/meta-digi-arm/recipes-bsp/libubootenv/libubootenv/mtd/fw_env.config @@ -0,0 +1,9 @@ +# Configuration file for fw_(printenv/setenv) utility. +# Up to two entries are valid, in this case the redundant +# environment sector is assumed present. +# If both copies are set to the same offset, an automatic mechanism will +# determine the first good sectors where each copy lives, skipping bad blocks. + +# Device name Offset Size Erase-size No.Blocks +/dev/##MTDINDEX## ##ENV_OFFSET## ##ENV_SIZE## ##ERASEBLOCK## ##NBLOCKS## +/dev/##MTDINDEX## ##ENV_REDUND_OFFSET## ##ENV_SIZE## ##ERASEBLOCK## ##NBLOCKS## diff --git a/meta-digi-arm/recipes-bsp/libubootenv/libubootenv_%.bbappend b/meta-digi-arm/recipes-bsp/libubootenv/libubootenv_%.bbappend new file mode 100644 index 000000000..ad7129acb --- /dev/null +++ b/meta-digi-arm/recipes-bsp/libubootenv/libubootenv_%.bbappend @@ -0,0 +1,63 @@ +# Copyright (C) 2021, Digi International Inc. + +FILESEXTRAPATHS_prepend := "${THISDIR}/${BPN}:" + +SRC_URI += " \ + file://${STORAGE_MEDIA}/fw_env.config \ + file://0001-Implement-support-for-environment-encryption-by-CAAM.patch \ + file://0002-Implement-U-Boot-environment-access-functions.patch \ + file://0003-tools-env-add-support-to-set-dynamic-location-of-env.patch \ +" + +do_install_append() { + install -d ${D}${sysconfdir} + install -m 0644 ${WORKDIR}/${STORAGE_MEDIA}/fw_env.config ${D}${sysconfdir}/ +} + +pkg_postinst_ontarget_${PN}() { + CONFIG_FILE="/etc/fw_env.config" + MMCDEV="$(sed -ne 's,.*root=/dev/mmcblk\([0-9]\)p.*,\1,g;T;p' /proc/cmdline)" + if [ -n "${MMCDEV}" ]; then + sed -i -e "s,^/dev/mmcblk[^[:blank:]]\+,/dev/mmcblk${MMCDEV},g" ${CONFIG_FILE} + fi + + PARTTABLE="/proc/mtd" + MTDINDEX="$(sed -ne "s/\(^mtd[0-9]\+\):.*\.*/\1/g;T;p" ${PARTTABLE} 2>/dev/null)" + if [ -n "${MTDINDEX}" ]; then + # Initialize variables for fixed offset values + # (backwards compatible with old U-Boot) + ENV_OFFSET="${UBOOT_ENV_OFFSET}" + ENV_REDUND_OFFSET="${UBOOT_ENV_SIZE}" + ENV_SIZE="${UBOOT_ENV_SIZE}" + ERASEBLOCK="" + NBLOCKS="" + + if [ -f "/proc/device-tree/digi,uboot,dynamic-env" ]; then + # Update variables for dynamic environment + # - Both copies starting at the same offset + ENV_REDUND_OFFSET="${UBOOT_ENV_OFFSET}" + # - Calculated erase block size + ERASEBLOCK="$(grep "^${MTDINDEX}:" ${PARTTABLE} | awk '{printf("0x%d",$3)}')" + # - Calculated number of blocks + MTDSIZE="$(grep "^${MTDINDEX}:" ${PARTTABLE} | awk '{printf("0x%d",$2)}')" + NBLOCKS="$(((MTDSIZE - UBOOT_ENV_OFFSET) / ERASEBLOCK))" + # If a range was provided, calculate the number of + # blocks in the range and use that number, unless they + # exceed the total number of blocks available in the + # whole partition. + if [ -n "${UBOOT_ENV_RANGE}" ]; then + RANGE_BLOCKS="$((UBOOT_ENV_RANGE / ERASEBLOCK))" + [ "${RANGE_BLOCKS}" -lt "${NBLOCKS}" ] && NBLOCKS="${RANGE_BLOCKS}" + fi + fi + + # Substitute stub with configuration and calculated values + sed -i -e "s/##MTDINDEX##/${MTDINDEX}/g" \ + -e "s/##ENV_OFFSET##/${ENV_OFFSET}/g" \ + -e "s/##ENV_REDUND_OFFSET##/${ENV_REDUND_OFFSET}/g" \ + -e "s/##ENV_SIZE##/${ENV_SIZE}/g" \ + -e "s/##ERASEBLOCK##/${ERASEBLOCK}/g" \ + -e "s/##NBLOCKS##/${NBLOCKS}/g" \ + ${CONFIG_FILE} + fi +}