You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by cc...@apache.org on 2019/01/11 21:50:59 UTC
[mynewt-core] 02/03: sys/mfg: 2.0 support
This is an automated email from the ASF dual-hosted git repository.
ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-core.git
commit 83a59b74d1b784c1be5dddf4b6039584753c824a
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Fri Dec 14 15:59:50 2018 -0800
sys/mfg: 2.0 support
This commit replaces 1.0 mfgimage support with support for version 2.0.
For more information regarding mfgimage 2.0, see the documentation at:
`docs/os/modules/mfg/mfg.rst`.
Also see this email thread:
https://lists.apache.org/thread.html/4185891ef587a778722a39fe5a1ae78bfd0dc7ab7e9348a7ea147df7@%3Cdev.mynewt.apache.org%3E
---
sys/flash_map/src/flash_map.c | 29 ++-
sys/id/src/id.c | 52 +++--
sys/mfg/include/mfg/mfg.h | 117 +++++++++--
sys/mfg/pkg.yml | 1 +
sys/mfg/src/mfg.c | 451 ++++++++++++++++++++++++------------------
sys/mfg/syscfg.yml | 8 +
6 files changed, 420 insertions(+), 238 deletions(-)
diff --git a/sys/flash_map/src/flash_map.c b/sys/flash_map/src/flash_map.c
index 98c58d0..88c11e5 100644
--- a/sys/flash_map/src/flash_map.c
+++ b/sys/flash_map/src/flash_map.c
@@ -349,36 +349,33 @@ flash_map_read_mfg(int max_areas,
struct flash_area *out_areas, int *out_num_areas)
{
struct mfg_meta_flash_area meta_flash_area;
- struct mfg_meta_tlv tlv;
+ struct mfg_reader reader;
struct flash_area *fap;
- uint32_t off;
int rc;
*out_num_areas = 0;
- off = 0;
/* Ensure manufacturing meta region has been located in flash. */
- rc = mfg_init();
- if (rc != 0) {
- return rc;
- }
+ mfg_init();
+
+ mfg_open(&reader);
while (1) {
if (*out_num_areas >= max_areas) {
return -1;
}
- rc = mfg_next_tlv_with_type(&tlv, &off, MFG_META_TLV_TYPE_FLASH_AREA);
+ rc = mfg_seek_next_with_type(&reader, MFG_META_TLV_TYPE_FLASH_AREA);
switch (rc) {
case 0:
break;
- case MFG_EDONE:
+ case SYS_EDONE:
return 0;
default:
return rc;
}
- rc = mfg_read_tlv_flash_area(&tlv, off, &meta_flash_area);
+ rc = mfg_read_tlv_flash_area(&reader, &meta_flash_area);
if (rc != 0) {
return rc;
}
@@ -409,16 +406,16 @@ flash_map_init(void)
/* Use the hardcoded default flash map. This is done for two reasons:
* 1. A minimal flash map configuration is required to boot strap the
- * process of reading the flash map from the manufacturing meta region.
- * In particular, a FLASH_AREA_BOOTLOADER entry is required, as the meta
- * region is located at the end of the boot loader area.
- * 2. If we fail to read the flash map from the meta region, the system
- * continues to use the default flash map.
+ * process of reading the flash map from the manufacturing meta regions.
+ * In particular, a FLASH_AREA_BOOTLOADER entry is required for the boot
+ * MMR, as well as an entry for each extended MMR.
+ * 2. If we fail to read the flash map from the MMRs, the system continues
+ * to use the default flash map.
*/
flash_map = sysflash_map_dflt;
flash_map_entries = sizeof sysflash_map_dflt / sizeof sysflash_map_dflt[0];
- /* Attempt to read the flash map from the manufacturing meta region. On
+ /* Attempt to read the flash map from the manufacturing meta regions. On
* success, use the new flash map instead of the default hardcoded one.
*/
rc = flash_map_read_mfg(sizeof mfg_areas / sizeof mfg_areas[0],
diff --git a/sys/id/src/id.c b/sys/id/src/id.c
index f1dfe3e..79a7c87 100644
--- a/sys/id/src/id.c
+++ b/sys/id/src/id.c
@@ -30,6 +30,8 @@
#include "id/id.h"
+#define ID_BASE64_MFG_HASH_SZ (BASE64_ENCODE_SIZE(MFG_HASH_SZ))
+
static char *id_conf_get(int argc, char **argv, char *val, int val_len_max);
static int id_conf_set(int argc, char **argv, char *val);
static int id_conf_export(void (*export_func)(char *name, char *val),
@@ -56,8 +58,8 @@ char id_manufacturer[ID_MANUFACTURER_MAX_LEN];
char id_model[ID_MODEL_MAX_LEN];
#endif
-/** Base64-encoded null-terminated manufacturing hash. */
-char id_mfghash[BASE64_ENCODE_SIZE(MFG_HASH_SZ) + 1];
+/** Colon-delimited null-terminated list of base64-encoded mfgimage hashes. */
+char id_mfghash[MYNEWT_VAL(MFG_MAX_MMRS) * (ID_BASE64_MFG_HASH_SZ + 1)];
struct conf_handler id_conf = {
.ch_name = "id",
@@ -177,27 +179,43 @@ static void
id_read_mfghash(void)
{
uint8_t raw_hash[MFG_HASH_SZ];
- struct mfg_meta_tlv tlv;
- uint32_t off;
+ struct mfg_reader reader;
+ int str_off;
int rc;
memset(id_mfghash, 0, sizeof id_mfghash);
- /* Find hash TLV in the manufacturing meta region. */
- off = 0;
- rc = mfg_next_tlv_with_type(&tlv, &off, MFG_META_TLV_TYPE_HASH);
- if (rc != 0) {
- return;
- }
+ mfg_open(&reader);
- /* Read the TLV contents. */
- rc = mfg_read_tlv_hash(&tlv, off, raw_hash);
- if (rc != 0) {
- return;
- }
+ str_off = 0;
+ while (1) {
+ rc = mfg_seek_next_with_type(&reader, MFG_META_TLV_TYPE_HASH);
+ if (rc != 0) {
+ return;
+ }
+
+ if (str_off + ID_BASE64_MFG_HASH_SZ + 1 > sizeof id_mfghash) {
+ return;
+ }
- /* Store the SHA256 hash as a base64-encoded string. */
- base64_encode(raw_hash, sizeof raw_hash, id_mfghash, 1);
+ /* Read the TLV contents. */
+ rc = mfg_read_tlv_hash(&reader, raw_hash);
+ if (rc != 0) {
+ return;
+ }
+
+ /* Append a delimiter if this isn't the first hash. */
+ if (str_off != 0) {
+ id_mfghash[str_off] = ':';
+ str_off++;
+ }
+
+ /* Append the SHA256 hash as a base64-encoded string. */
+ base64_encode(raw_hash, sizeof raw_hash, &id_mfghash[str_off], 1);
+ str_off += ID_BASE64_MFG_HASH_SZ;
+
+ id_mfghash[str_off] = '\0';
+ }
}
void
diff --git a/sys/mfg/include/mfg/mfg.h b/sys/mfg/include/mfg/mfg.h
index 4b61b5c..34e0d20 100644
--- a/sys/mfg/include/mfg/mfg.h
+++ b/sys/mfg/include/mfg/mfg.h
@@ -20,11 +20,6 @@
#ifndef H_MFG_
#define H_MFG_
-#define MFG_EUNINIT 1
-#define MFG_EBADDATA 2
-#define MFG_EDONE 3
-#define MFG_EFLASH 4
-
#define MFG_HASH_SZ 32
#define MFG_META_TLV_TYPE_HASH 0x01
@@ -33,33 +28,125 @@
/** Informational only; not read by firmware. */
#define MFG_META_TLV_TYPE_FLASH_TRAITS 0x03
+#define MFG_META_TLV_TYPE_MMR_REF 0x04
+
struct mfg_meta_tlv {
uint8_t type;
uint8_t size;
/* Followed by packed data. */
-};
+} __attribute__((packed));
struct mfg_meta_flash_area {
uint8_t area_id;
uint8_t device_id;
- uint16_t pad16;
uint32_t offset;
uint32_t size;
-};
+} __attribute__((packed));
/** Informational only; not read by firmware. */
struct mfg_meta_flash_traits {
uint8_t device_id;
uint8_t min_write_sz;
+} __attribute__((packed));
+
+struct mfg_meta_mmr_ref {
+ uint8_t area_id;
+} __attribute__((packed));
+
+/**
+ * Object used for reading records from the manufacturing space. The
+ * `mfg_open()` function should be used to construct a reader object.
+ */
+struct mfg_reader {
+ /** Public (read-only). */
+ struct mfg_meta_tlv cur_tlv;
+
+ /** Private. */
+ uint8_t mmr_idx;
+ uint32_t offset;
};
-int mfg_next_tlv(struct mfg_meta_tlv *tlv, uint32_t *off);
-int mfg_next_tlv_with_type(struct mfg_meta_tlv *tlv, uint32_t *off,
- uint8_t type);
-int mfg_read_tlv_flash_area(const struct mfg_meta_tlv *tlv, uint32_t off,
+/**
+ * Opens the manufacturing space for reading. The resulting `mfg_reader`
+ * object should be passed to subsequent seek and read functions.
+ */
+void mfg_open(struct mfg_reader *out_reader);
+
+/**
+ * Seeks to the next mfg TLV. The caller must initialize the supplied
+ * `mfg_reader` with `mfg_open()` prior to calling this function.
+ *
+ * @param reader The reader to seek with.
+ *
+ * @return 0 if the next TLV was successfully seeked to.
+ * SYS_EDONE if there are no additional TLVs
+ * available.
+ * Other MFG error code on failure.
+ */
+int mfg_seek_next(struct mfg_reader *reader);
+/**
+ * Seeks to the next mfg TLV with the specified type. The caller must
+ * initialize the supplied `mfg_reader` with `mfg_open()` prior to calling this
+ * function.
+ *
+ * @param reader The reader to seek with.
+ * @param type The type of TLV to seek to; one of the
+ * MFG_META_TLV_TYPE_[...] constants.
+ *
+ * @return 0 if the next TLV was successfully seeked to.
+ * SYS_EDONE if there are no additional TLVs
+ * with the specified type available.
+ * Other MFG error code on failure.
+ */
+int mfg_seek_next_with_type(struct mfg_reader *reader, uint8_t type);
+
+/**
+ * Reads a hash TLV from the manufacturing space. This function should
+ * only be called when the provided reader is pointing at a TLV with the
+ * MFG_META_TLV_TYPE_HASH type.
+ *
+ * @param reader The reader to read with.
+ * @param out_mr (out) On success, the retrieved MMR reference
+ * information gets written here.
+ *
+ * @return 0 on success; MFG error code on failure.
+ */
+int mfg_read_tlv_hash(const struct mfg_reader *reader, void *out_hash);
+
+/**
+ * Reads a flash-area TLV from the manufacturing space. This function should
+ * only be called when the provided reader is pointing at a TLV with the
+ * MFG_META_TLV_TYPE_FLASH_AREA type.
+ *
+ * @param reader The reader to read with.
+ * @param out_mfa (out) On success, the retrieved flash area
+ * information gets written here.
+ *
+ * @return 0 on success; MFG error code on failure.
+ */
+int mfg_read_tlv_flash_area(const struct mfg_reader *reader,
struct mfg_meta_flash_area *out_mfa);
-int mfg_read_tlv_hash(const struct mfg_meta_tlv *tlv, uint32_t off,
- void *out_hash);
-int mfg_init(void);
+
+/**
+ * Reads an MMR ref TLV from the manufacturing space. This function should
+ * only be called when the provided reader is pointing at a TLV with the
+ * MFG_META_TLV_TYPE_MMR_REF type.
+ *
+ * @param reader The reader to read with.
+ * @param out_mr (out) On success, the retrieved MMR reference
+ * information gets written here.
+ *
+ * @return 0 on success; MFG error code on failure.
+ */
+int mfg_read_tlv_mmr_ref(const struct mfg_reader *reader,
+ struct mfg_meta_mmr_ref *out_mr);
+
+/**
+ * Initializes the mfg package.
+ */
+void mfg_init(void);
+
+#define MFG_LOG(lvl_, ...) \
+ MODLOG_ ## lvl_(MYNEWT_VAL(MFG_LOG_MODULE), __VA_ARGS__)
#endif
diff --git a/sys/mfg/pkg.yml b/sys/mfg/pkg.yml
index 42fb19f..94d7840 100644
--- a/sys/mfg/pkg.yml
+++ b/sys/mfg/pkg.yml
@@ -27,6 +27,7 @@ pkg.keywords:
pkg.deps:
- "@apache-mynewt-core/kernel/os"
- "@apache-mynewt-core/sys/flash_map"
+ - "@apache-mynewt-core/sys/log/modlog"
# sys/flash_map must get initialized before sys/mfg.
pkg.init:
diff --git a/sys/mfg/src/mfg.c b/sys/mfg/src/mfg.c
index 5684776..d9a2bda 100644
--- a/sys/mfg/src/mfg.c
+++ b/sys/mfg/src/mfg.c
@@ -19,6 +19,7 @@
#include <string.h>
#include "os/mynewt.h"
+#include "modlog/modlog.h"
#include "mfg/mfg.h"
/**
@@ -28,8 +29,6 @@
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * |Version (0x01) | 0xff padding |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | TLV type | TLV size | TLV data ("TLV size" bytes) ~
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ~
* ~ ~
@@ -38,7 +37,7 @@
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ~
* ~ ~
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Region size | 0xff padding |
+ * | Region size | Version | 0xff padding |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Magic (0x3bb2a269) |
* +-+-+-+-+-+--+-+-+-+-end of boot loader area+-+-+-+-+-+-+-+-+-+-+
@@ -47,149 +46,148 @@
* purposes.
*
* Fields:
- * <Header>
- * 1. Version: Manufacturing meta version number; always 0x01.
- *
* <TLVs>
- * 2. TLV type: Indicates the type of data to follow.
- * 3. TLV size: The number of bytes of data to follow.
- * 4. TLV data: "TLV size" bytes of data.
+ * 1. TLV type: Indicates the type of data to follow.
+ * 2. TLV size: The number of bytes of data to follow.
+ * 3. TLV data: "TLV size" bytes of data.
*
* <Footer>
- * 5. Region size: The size, in bytes, of the entire manufacturing meta region;
- * includes header, TLVs, and footer.
- * 6. Magic: indicates the presence of the manufacturing meta region.
+ * 4. Region size: The size, in bytes, of the entire manufacturing meta region;
+ * includes TLVs and footer.
+ * 5. Version: Manufacturing meta version number; always 0x02.
+ * 6. Magic: Indicates the presence of the manufacturing meta region.
*/
#define MFG_META_MAGIC 0x3bb2a269
-#define MFG_META_HEADER_SZ 4
-#define MFG_META_FOOTER_SZ 8
-#define MFG_META_TLV_SZ 2
-#define MFG_META_FLASH_AREA_SZ 12
-
-struct {
- uint8_t valid:1;
- uint32_t off;
- uint32_t size;
-} mfg_state;
+#define MFG_META_VERSION 2
+#define MFG_META_FOOTER_SZ (sizeof (struct mfg_meta_footer))
+#define MFG_META_TLV_SZ (sizeof (struct mfg_meta_tlv))
-struct mfg_meta_header {
+struct mfg_meta_footer {
+ uint16_t size;
uint8_t version;
uint8_t pad8;
- uint16_t pad16;
+ uint32_t magic;
};
-struct mfg_meta_footer {
- uint16_t size;
- uint16_t pad16;
- uint32_t magic;
+/** Represents an MMR after it has been read from flash. */
+struct mfg_mmr {
+ /* Flash area containing MMR. */
+ uint8_t area_id;
+
+ /* Offset within flash area of start of MMR. */
+ uint32_t offset;
+
+ /* Total size of MMR (TLVs + footer). */
+ uint32_t size;
};
-_Static_assert(sizeof (struct mfg_meta_header) == MFG_META_HEADER_SZ,
- "mfg_meta_header must be 4 bytes");
-_Static_assert(sizeof (struct mfg_meta_footer) == MFG_META_FOOTER_SZ,
- "mfg_meta_footer must be 8 bytes");
-_Static_assert(sizeof (struct mfg_meta_flash_area) == MFG_META_FLASH_AREA_SZ,
- "mfg_meta_flash_area must be 12 bytes");
+/** The full set of MMRs comprised by all installed mfgimages. */
+static struct mfg_mmr mfg_mmrs[MYNEWT_VAL(MFG_MAX_MMRS)];
+static int mfg_num_mmrs;
+
+/** True if MMR detection has occurred. */
+static bool mfg_initialized;
+
+void
+mfg_open(struct mfg_reader *out_reader)
+{
+ /* Ensure MMRs have been detected. */
+ mfg_init();
+
+ /* Start at MMR index 0. */
+ *out_reader = (struct mfg_reader) { 0 };
+}
/**
- * Retrieves a TLV header from the mfg meta region. To request the first TLV
- * in the region, specify an offset of 0. To request a subsequent TLV, specify
- * the values retrieved by the previous call to this function.
+ * Seeks to the next mfg TLV.
*
- * @param tlv (in / out) Input: The previously-read TLV header; not used
- * as input when requesting the first TLV.
- * Output: On success, the requested TLV header
- * gets written here.
- * @param off (in / out) Input: The flash-area-offset of the previously
- * read TLV header; 0 when requesting the
- * first TLV.
- * Output: On success, the flash-area-offset of
- * the retrieved TLV header.
+ * @param reader The reader to seek with.
*
- * @return 0 if a TLV header was successfully retrieved;
- * MFG_EDONE if there are no additional TLVs to
- * read;
+ * @return 0 if the next TLV was successfully seeked to.
+ * SYS_EDONE if there are no additional TLVs
+ * available.
+ * SYS_EAGAIN if the end of the current MMR is
+ * reached, but additional MMRs are available
+ * for reading.
* Other MFG error code on failure.
*/
-int
-mfg_next_tlv(struct mfg_meta_tlv *tlv, uint32_t *off)
+static int
+mfg_seek_next_aux(struct mfg_reader *reader)
{
const struct flash_area *fap;
+ const struct mfg_mmr *mmr;
int rc;
- if (!mfg_state.valid) {
- return MFG_EUNINIT;
+ if (reader->mmr_idx >= mfg_num_mmrs) {
+ /* The reader is expired. */
+ return SYS_EINVAL;
}
- rc = flash_area_open(FLASH_AREA_BOOTLOADER, &fap);
+ mmr = &mfg_mmrs[reader->mmr_idx];
+
+ rc = flash_area_open(mmr->area_id, &fap);
if (rc != 0) {
- rc = MFG_EFLASH;
- goto done;
+ return SYS_EIO;
}
- if (*off == 0) {
- *off = mfg_state.off + MFG_META_HEADER_SZ;
+ if (reader->offset == 0) {
+ /* First seek; advance to the start of the MMR. */
+ reader->offset = mmr->offset;
} else {
- /* Advance past current TLV. */
- *off += MFG_META_TLV_SZ + tlv->size;
+ /* Follow-up seek; skip the current TLV. */
+ reader->offset += MFG_META_TLV_SZ + reader->cur_tlv.size;
}
- if (*off + MFG_META_FOOTER_SZ >= fap->fa_size) {
- /* Reached end of boot area; no more TLVs. */
- return MFG_EDONE;
+ if (reader->offset >= fap->fa_size - MFG_META_FOOTER_SZ) {
+ /* Reached end of the MMR; advance to the next MMR if one exists. */
+ if (reader->mmr_idx + 1 >= mfg_num_mmrs) {
+ rc = SYS_EDONE;
+ } else {
+ reader->offset = 0;
+ reader->mmr_idx++;
+ rc = SYS_EAGAIN;
+ }
+ goto done;
}
- /* Read next TLV. */
- memset(tlv, 0, sizeof *tlv);
- rc = flash_area_read(fap, *off, tlv, MFG_META_TLV_SZ);
+ /* Read current TLV header. */
+ rc = flash_area_read(fap, reader->offset, &reader->cur_tlv,
+ MFG_META_TLV_SZ);
if (rc != 0) {
- rc = MFG_EFLASH;
+ rc = SYS_EIO;
goto done;
}
- rc = 0;
-
done:
flash_area_close(fap);
return rc;
}
-/**
- * Retrieves a TLV header of the specified type from the mfg meta region. To
- * request the first TLV in the region, specify an offset of 0. To request a
- * subsequent TLV, specify the values retrieved by the previous call to this
- * function.
- *
- * @param tlv (in / out) Input: The previously-read TLV header; not used
- * as input when requesting the first TLV.
- * Output: On success, the requested TLV header
- * gets written here.
- * @param off (in / out) Input: The flash-area-offset of the previously
- * read TLV header; 0 when requesting the
- * first TLV.
- * Output: On success, the flash-area-offset of
- * the retrieved TLV header.
- * @param type The type of TLV to retrieve; one of the
- * MFG_META_TLV_TYPE_[...] constants.
- *
- * @return 0 if a TLV header was successfully retrieved;
- * MFG_EDONE if there are no additional TLVs of
- * the specified type to read;
- * Other MFG error code on failure.
- */
int
-mfg_next_tlv_with_type(struct mfg_meta_tlv *tlv, uint32_t *off, uint8_t type)
+mfg_seek_next(struct mfg_reader *reader)
+{
+ int rc;
+
+ do {
+ rc = mfg_seek_next_aux(reader);
+ } while (rc == SYS_EAGAIN);
+
+ return rc;
+}
+
+int
+mfg_seek_next_with_type(struct mfg_reader *reader, uint8_t type)
{
int rc;
while (1) {
- rc = mfg_next_tlv(tlv, off);
+ rc = mfg_seek_next(reader);
if (rc != 0) {
break;
}
- if (tlv->type == type) {
+ if (reader->cur_tlv.type == type) {
break;
}
@@ -200,149 +198,222 @@ mfg_next_tlv_with_type(struct mfg_meta_tlv *tlv, uint32_t *off, uint8_t type)
}
/**
- * Reads a flash-area TLV from the manufacturing meta region. This function
- * should only be called after a TLV has been identified as having the
- * MFG_META_TLV_TYPE_FLASH_AREA type.
- *
- * @param tlv The header of the TLV to read. This header
- * should have been retrieved via a call to
- * mfg_next_tlv() or mfg_next_tlv_with_type().
- * @param off The flash-area-offset of the TLV header. Note:
- * this is the offset of the TLV header, not
- * the TLV data.
- * @param out_mfa (out) On success, the retrieved flash area
- * information gets written here.
- *
- * @return 0 on success; MFG error code on failure.
+ * Opens the flash area pointed to by the provided reader.
*/
-int
-mfg_read_tlv_flash_area(const struct mfg_meta_tlv *tlv, uint32_t off,
- struct mfg_meta_flash_area *out_mfa)
+static int
+mfg_open_flash_area(const struct mfg_reader *reader,
+ const struct flash_area **fap)
+{
+ const struct mfg_mmr *mmr;
+ int rc;
+
+ assert(reader->mmr_idx < mfg_num_mmrs);
+ mmr = &mfg_mmrs[reader->mmr_idx];
+
+ rc = flash_area_open(mmr->area_id, fap);
+ if (rc != 0) {
+ return SYS_EIO;
+ }
+
+ return 0;
+}
+
+static int
+mfg_read_tlv_body(const struct mfg_reader *reader, void *dst, int max_size)
{
const struct flash_area *fap;
int read_sz;
int rc;
- rc = flash_area_open(FLASH_AREA_BOOTLOADER, &fap);
+ rc = mfg_open_flash_area(reader, &fap);
if (rc != 0) {
- rc = MFG_EFLASH;
- goto done;
+ return rc;
}
- memset(out_mfa, 0, sizeof *out_mfa);
+ memset(dst, 0, max_size);
+
+ read_sz = min(max_size, reader->cur_tlv.size);
+ rc = flash_area_read(fap, reader->offset + MFG_META_TLV_SZ, dst, read_sz);
+ flash_area_close(fap);
- read_sz = min(MFG_META_FLASH_AREA_SZ, tlv->size);
- rc = flash_area_read(fap, off + MFG_META_TLV_SZ, out_mfa, read_sz);
if (rc != 0) {
- rc = MFG_EFLASH;
- goto done;
+ return SYS_EIO;
}
- rc = 0;
+ return 0;
+}
+
+int
+mfg_read_tlv_flash_area(const struct mfg_reader *reader,
+ struct mfg_meta_flash_area *out_mfa)
+{
+ return mfg_read_tlv_body(reader, out_mfa, sizeof *out_mfa);
+}
-done:
- flash_area_close(fap);
- return rc;
+int
+mfg_read_tlv_mmr_ref(const struct mfg_reader *reader,
+ struct mfg_meta_mmr_ref *out_mr)
+{
+ return mfg_read_tlv_body(reader, out_mr, sizeof *out_mr);
+}
+
+int
+mfg_read_tlv_hash(const struct mfg_reader *reader, void *out_hash)
+{
+ return mfg_read_tlv_body(reader, out_hash, MFG_HASH_SZ);
}
/**
- * Reads a hash TLV from the manufacturing meta region. This function should
- * only be called after a TLV has been identified as having the
- * MFG_META_TLV_TYPE_HASH type.
- *
- * @param tlv The header of the TLV to read. This header
- * should have been retrieved via a call to
- * mfg_next_tlv() or mfg_next_tlv_with_type().
- * @param off The flash-area-offset of the TLV header. Note:
- * this is the offset of the TLV header, not
- * the TLV data.
- * @param out_hash (out) On success, the retrieved SHA256 hash gets
- * written here. This buffer must be at least
- * 32 bytes wide.
- *
- * @return 0 on success; MFG error code on failure.
+ * Reads an MMR from the end of the specified flash area.
*/
-int
-mfg_read_tlv_hash(const struct mfg_meta_tlv *tlv, uint32_t off, void *out_hash)
+static int
+mfg_read_mmr(uint8_t area_id, struct mfg_mmr *out_mmr)
{
const struct flash_area *fap;
- int read_sz;
+ struct mfg_meta_footer ftr;
int rc;
- rc = flash_area_open(FLASH_AREA_BOOTLOADER, &fap);
+ rc = flash_area_open(area_id, &fap);
if (rc != 0) {
- rc = MFG_EFLASH;
- goto done;
+ return SYS_EIO;
}
- read_sz = min(MFG_HASH_SZ, tlv->size);
- rc = flash_area_read(fap, off + MFG_META_TLV_SZ, out_hash, read_sz);
+ /* Read the MMR footer. */
+ rc = flash_area_read(fap, fap->fa_size - sizeof ftr, &ftr, sizeof ftr);
+ flash_area_close(fap);
+
if (rc != 0) {
- rc = MFG_EFLASH;
- goto done;
+ return SYS_EIO;
}
- rc = 0;
+ if (ftr.magic != MFG_META_MAGIC) {
+ return SYS_ENODEV;
+ }
-done:
- flash_area_close(fap);
- return rc;
+ if (ftr.version != MFG_META_VERSION) {
+ return SYS_ENOTSUP;
+ }
+
+ if (ftr.size > fap->fa_size) {
+ return SYS_ENODEV;
+ }
+
+ *out_mmr = (struct mfg_mmr) {
+ .area_id = area_id,
+ .offset = fap->fa_size - ftr.size,
+ .size = ftr.size,
+ };
+
+ return 0;
+}
+
+/**
+ * Reads an MMR from the end of the specified flash area. On success, the
+ * global MMR list is populated with the result for subsequent reading.
+ */
+static int
+mfg_read_next_mmr(uint8_t area_id)
+{
+ int rc;
+ int i;
+
+ /* Detect if this MMR has already been read. */
+ for (i = 0; i < mfg_num_mmrs; i++) {
+ if (mfg_mmrs[i].area_id == area_id) {
+ return SYS_EALREADY;
+ }
+ }
+
+ if (mfg_num_mmrs >= MYNEWT_VAL(MFG_MAX_MMRS)) {
+ return SYS_ENOMEM;
+ }
+
+ rc = mfg_read_mmr(area_id, &mfg_mmrs[mfg_num_mmrs]);
+ if (rc != 0) {
+ return rc;
+ }
+
+ mfg_num_mmrs++;
+ return 0;
+}
+
+/**
+ * Reads all MMR ref TLVs in the specified MMR. The global MMR list is
+ * populated with the results for subsequent reading.
+ */
+static int
+mfg_read_mmr_refs(void)
+{
+ struct mfg_meta_mmr_ref mmr_ref;
+ struct mfg_reader reader;
+ int rc;
+
+ mfg_open(&reader);
+
+ /* Repeatedly find and read the next MMR ref TLV. As new MMRs are read,
+ * they are added to the global list and become available in this loop.
+ */
+ while (true) {
+ rc = mfg_seek_next_with_type(&reader, MFG_META_TLV_TYPE_MMR_REF);
+ switch (rc) {
+ case 0:
+ /* Found an MMR ref TLV. Read it below. */
+ break;
+
+ case SYS_EDONE:
+ /* No more MMR ref TLVs. */
+ return 0;
+
+ default:
+ return rc;
+ }
+
+ rc = mfg_read_tlv_mmr_ref(&reader, &mmr_ref);
+ if (rc != 0) {
+ return rc;
+ }
+
+ rc = mfg_read_next_mmr(mmr_ref.area_id);
+ if (rc != 0 && rc != SYS_EALREADY) {
+ return rc;
+ }
+ }
+
+ return 0;
}
/**
* Locates the manufacturing meta region in flash. This function must be
* called before any TLVs can be read. No-op if this function has already
* executed successfully.
- *
- * @return 0 on success; MFG error code on failure.
*/
-int
+void
mfg_init(void)
{
- const struct flash_area *fap;
- struct mfg_meta_footer ftr;
- uint16_t off;
int rc;
- /* Ensure this function only gets called by sysinit. */
- SYSINIT_ASSERT_ACTIVE();
-
- if (mfg_state.valid) {
- /* Already initialized. */
- return 0;
+ if (mfg_initialized) {
+ return;
}
+ mfg_initialized = true;
- mfg_state.valid = 0;
+ /* Ensure this function only gets called by sysinit. */
+ SYSINIT_ASSERT_ACTIVE();
- rc = flash_area_open(FLASH_AREA_BOOTLOADER, &fap);
+ /* Read the first MMR from the boot loader area. */
+ rc = mfg_read_next_mmr(FLASH_AREA_BOOTLOADER);
if (rc != 0) {
- rc = MFG_EFLASH;
- goto done;
+ goto err;
}
- off = fap->fa_size - sizeof ftr;
- rc = flash_area_read(fap, off, &ftr, sizeof ftr);
+ /* Read all MMR references. */
+ rc = mfg_read_mmr_refs();
if (rc != 0) {
- rc = MFG_EFLASH;
- goto done;
- }
-
- if (ftr.magic != MFG_META_MAGIC) {
- rc = MFG_EBADDATA;
- goto done;
- }
- if (ftr.size > fap->fa_size) {
- rc = MFG_EBADDATA;
- goto done;
+ goto err;
}
- mfg_state.valid = 1;
- mfg_state.off = fap->fa_size - ftr.size;
- mfg_state.size = ftr.size;
+ return;
- rc = 0;
-
-done:
- flash_area_close(fap);
- return rc;
+err:
+ MFG_LOG(ERROR, "failed to read MMRs: rc=%d", rc);
}
diff --git a/sys/mfg/syscfg.yml b/sys/mfg/syscfg.yml
index 10f84f5..3bc0f16 100644
--- a/sys/mfg/syscfg.yml
+++ b/sys/mfg/syscfg.yml
@@ -18,7 +18,15 @@
#
syscfg.defs:
+ MFG_MAX_MMRS:
+ description: >
+ The maximum allowed MMRs in the manufacturing space. Excess MMRs
+ are not read.
+ value: 2
MFG_SYSINIT_STAGE:
description: >
Sysinit stage for manufacturing support.
value: 100
+ MFG_LOG_MODULE:
+ description: 'Numeric module ID to use for manufacturing log messages'
+ value: 128