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 <[email protected]> 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
