diff --git a/apps/slinky/pkg.yml b/apps/slinky/pkg.yml index 3c10131237..93db421c47 100644 --- a/apps/slinky/pkg.yml +++ b/apps/slinky/pkg.yml @@ -44,15 +44,3 @@ pkg.deps: pkg.deps.I2C_0: test/i2c_scan pkg.deps.I2C_1: test/i2c_scan pkg.deps.I2C_2: test/i2c_scan - -pkg.deps.CONFIG_NFFS: - - "@apache-mynewt-core/fs/nffs" - -pkg.deps.CONFIG_LITTLEFS: - - "@apache-mynewt-core/fs/littlefs" - -pkg.deps.CONFIG_FCB: - - "@apache-mynewt-core/fs/fcb" - -pkg.deps.REBOOT_LOG_FCB: - - "@apache-mynewt-core/fs/fcb" diff --git a/fs/fcb2/include/fcb/fcb2.h b/fs/fcb2/include/fcb/fcb2.h index e089fccbce..2f0c720902 100644 --- a/fs/fcb2/include/fcb/fcb2.h +++ b/fs/fcb2/include/fcb/fcb2.h @@ -304,6 +304,15 @@ int fcb2_clear(struct fcb2 *fcb); */ int fcb2_area_info(struct fcb2 *fcb, int sector, int *elemsp, int *bytesp); +/** + * Length of data in flash considering alignment + * + * @param range Active range + * @param len Length to be calculated using alignment + * + */ +int fcb2_len_in_flash(const struct flash_sector_range *range, uint16_t len); + #ifdef __cplusplus } diff --git a/fs/fcb2/src/fcb.c b/fs/fcb2/src/fcb.c index e8a65ff123..0f1e31ee3f 100644 --- a/fs/fcb2/src/fcb.c +++ b/fs/fcb2/src/fcb.c @@ -101,6 +101,15 @@ fcb2_init(struct fcb2 *fcb) return rc; } +int +fcb2_len_in_flash(const struct flash_sector_range *range, uint16_t len) +{ + if (range->fsr_align <= 1) { + return len; + } + return (len + (range->fsr_align - 1)) & ~(range->fsr_align - 1); +} + int fcb2_free_sector_cnt(struct fcb2 *fcb) { diff --git a/fs/fcb2/src/fcb_priv.h b/fs/fcb2/src/fcb_priv.h index d02784fab5..6f91ff09f7 100644 --- a/fs/fcb2/src/fcb_priv.h +++ b/fs/fcb2/src/fcb_priv.h @@ -40,15 +40,6 @@ struct fcb2_sector_info { uint16_t si_sector_in_range; /* Sector number relative to si_range */ }; -static inline int -fcb2_len_in_flash(const struct flash_sector_range *range, uint16_t len) -{ - if (range->fsr_align <= 1) { - return len; - } - return (len + (range->fsr_align - 1)) & ~(range->fsr_align - 1); -} - int fcb2_getnext_in_area(struct fcb2 *fcb, struct fcb2_entry *loc); static inline int diff --git a/hw/mcu/native/src/hal_flash.c b/hw/mcu/native/src/hal_flash.c index b39b5158ce..439f9d4fa0 100644 --- a/hw/mcu/native/src/hal_flash.c +++ b/hw/mcu/native/src/hal_flash.c @@ -152,7 +152,7 @@ static int flash_native_write_internal(uint32_t address, const void *src, uint32_t length, int allow_overwrite) { - static uint8_t buf[256]; + uint8_t buf[256] = {0}; uint32_t cur; uint32_t end; int chunk_sz; diff --git a/sys/log/full/include/log/log.h b/sys/log/full/include/log/log.h index 7e874ceb06..b3bc481959 100644 --- a/sys/log/full/include/log/log.h +++ b/sys/log/full/include/log/log.h @@ -75,18 +75,18 @@ struct log_storage_info { }; #endif -typedef int (*log_walk_func_t)(struct log *, struct log_offset *log_offset, +typedef int (*log_walk_func_t)(struct log *log, struct log_offset *log_offset, const void *dptr, uint16_t len); typedef int (*log_walk_body_func_t)(struct log *log, struct log_offset *log_offset, const struct log_entry_hdr *hdr, const void *dptr, uint16_t len); -typedef int (*lh_read_func_t)(struct log *, const void *dptr, void *buf, +typedef int (*lh_read_func_t)(struct log *log, const void *dptr, void *buf, uint16_t offset, uint16_t len); -typedef int (*lh_read_mbuf_func_t)(struct log *, const void *dptr, struct os_mbuf *om, +typedef int (*lh_read_mbuf_func_t)(struct log *log, const void *dptr, struct os_mbuf *om, uint16_t offset, uint16_t len); -typedef int (*lh_append_func_t)(struct log *, void *buf, int len); +typedef int (*lh_append_func_t)(struct log *log, void *buf, int len); typedef int (*lh_append_body_func_t)(struct log *log, const struct log_entry_hdr *hdr, const void *body, int body_len); @@ -94,16 +94,19 @@ typedef int (*lh_append_mbuf_func_t)(struct log *, struct os_mbuf *om); typedef int (*lh_append_mbuf_body_func_t)(struct log *log, const struct log_entry_hdr *hdr, struct os_mbuf *om); -typedef int (*lh_walk_func_t)(struct log *, +typedef int (*lh_walk_func_t)(struct log *log, log_walk_func_t walk_func, struct log_offset *log_offset); -typedef int (*lh_flush_func_t)(struct log *); +typedef int (*lh_flush_func_t)(struct log *log); +typedef uint16_t (*lh_read_entry_len_func_t)(struct log *log, const void *dptr); #if MYNEWT_VAL(LOG_STORAGE_INFO) -typedef int (*lh_storage_info_func_t)(struct log *, struct log_storage_info *); +typedef int (*lh_storage_info_func_t)(struct log *log, struct log_storage_info *); #endif #if MYNEWT_VAL(LOG_STORAGE_WATERMARK) -typedef int (*lh_set_watermark_func_t)(struct log *, uint32_t); +typedef int (*lh_set_watermark_func_t)(struct log *log, uint32_t); #endif -typedef int (*lh_registered_func_t)(struct log *); +typedef int (*lh_registered_func_t)(struct log *log); +/* This calculates length based on alignment of underlying medium */ +typedef int (*lh_len_in_medium_func_t)(struct log *log, uint16_t len); struct log_handler { int log_type; @@ -116,6 +119,8 @@ struct log_handler { lh_walk_func_t log_walk; lh_walk_func_t log_walk_sector; lh_flush_func_t log_flush; + lh_read_entry_len_func_t log_read_entry_len; + lh_len_in_medium_func_t log_len_in_medium; #if MYNEWT_VAL(LOG_STORAGE_INFO) lh_storage_info_func_t log_storage_info; #endif @@ -129,8 +134,12 @@ struct log_handler { /* Image hash length to be looged */ #define LOG_IMG_HASHLEN 4 -/* Flags used to indicate type of data in reserved payload*/ -#define LOG_FLAGS_IMG_HASH (1 << 0) +/* Flags used to indicate type of data in reserved payload */ +#define LOG_FLAGS_IMG_HASH (1 << 0) +#define LOG_FLAGS_TLV_SUPPORT (1 << 1) + +#define LOG_TLV_NUM_ENTRIES (1 << 0) +#define LOG_TLV_NUM_TLVS (1 << 1) #if MYNEWT_VAL(LOG_VERSION) == 3 struct log_entry_hdr { @@ -138,16 +147,56 @@ struct log_entry_hdr { uint32_t ue_index; uint8_t ue_module; uint8_t ue_level; - uint8_t ue_etype:4; - uint8_t ue_flags:4; + uint8_t ue_etype : 4; + uint8_t ue_flags : 4; uint8_t ue_imghash[4]; -}__attribute__((__packed__)); + /* Number of entries field which helps in calculating number of + * entries per log, these go on incrementing similar to an index + * but per log. + */ + uint32_t ue_num_entries; +} __attribute__((__packed__)); + +struct log_tlv { + uint8_t len; + uint8_t tag; + /* Value is of variable size appended based on len, + * val is logged after the tag and len are logged + */ +} __attribute__((__packed__)); + #else #error "Unsupported log version" #endif #define LOG_BASE_ENTRY_HDR_SIZE (15) +#define LOG_NUM_ENTRIES_SIZE (sizeof(((struct log *)0)->l_num_entries)) +#define LOG_NUM_TLVS_SIZE (1) + +#if MYNEWT_VAL(LOG_FCB2) +#define LF_MAX_ALIGN LOG_FCB2_MAX_ALIGN +#else +#define LF_MAX_ALIGN LOG_FCB_MAX_ALIGN +#endif + +#define LOG_FCB_MAX_TLV_SIZE(__tlv_name__) \ + /* sizeof(struct log_tlv)) + alignment */ \ + (LF_MAX_ALIGN + \ + /* Max size per value of TLV including alignment */ \ + (LOG_ ## __tlv_name__ ## _SIZE/LF_MAX_ALIGN) ? \ + (LOG_ ## __tlv_name__ ## _SIZE + LF_MAX_ALIGN) : \ + LF_MAX_ALIGN) + +#define LOG_FCB_MAX_TLVS_SIZE LOG_FCB_MAX_TLV_SIZE(NUM_ENTRIES) + \ + LOG_FCB_MAX_TLV_SIZE(NUM_TLVS) + +#define LOG_FCB_EXT_HDR_SIZE LOG_BASE_ENTRY_HDR_SIZE + LOG_IMG_HASHLEN + \ + LF_MAX_ALIGN + +#define LOG_FCB_FLAT_BUF_SIZE (LOG_FCB_EXT_HDR_SIZE > LOG_FCB_MAX_TLVS_SIZE) ? \ + LOG_FCB_EXT_HDR_SIZE : LOG_FCB_MAX_TLVS_SIZE + #define LOG_MODULE_STR(module) log_module_get_name(module) #if MYNEWT_VAL(LOG_LEVEL) <= LOG_LEVEL_DEBUG @@ -213,6 +262,7 @@ struct log { #if !MYNEWT_VAL(LOG_GLOBAL_IDX) uint32_t l_idx; #endif + uint32_t l_num_entries; #if MYNEWT_VAL(LOG_STATS) STATS_SECT_DECL(logs) l_stats; #endif @@ -511,6 +561,18 @@ void log_printf(struct log *log, uint8_t module, uint8_t level, int log_read(struct log *log, const void *dptr, void *buf, uint16_t off, uint16_t len); +/** + * Reads entry length from the specified log. + * + * @param log The log to read from. + * @param dptr Medium-specific data describing the area to + * read from; typically obtained by a call to + * `log_walk`. + * @return The number of bytes of entry length; 0 on failure. + */ +uint16_t +log_read_entry_len(struct log *log, const void *dptr); + /** * @brief Reads a single log entry header. * @@ -524,15 +586,37 @@ int log_read(struct log *log, const void *dptr, void *buf, uint16_t off, */ int log_read_hdr(struct log *log, const void *dptr, struct log_entry_hdr *hdr); +/** + * @brief Reads a single log entry trailer. + * + * @param log The log to read from. + * @param dptr Medium-specific data describing the area to + * read from; typically obtained by a call to + * `log_walk`. + * @param tlv tlv type + * @param buf Value buffer + * + * @return 0 on success; nonzero on failure. + */ +int log_read_trailer(struct log *log, const void *dptr, uint16_t tlv, void *buf); + /** * @brief Reads the header length * * @param hdr Ptr to the header - * + * * @return Length of the header */ -uint16_t -log_hdr_len(const struct log_entry_hdr *hdr); +uint16_t log_hdr_len(const struct log_entry_hdr *hdr); + +/** + * @brief Reads the trailer length + * + * @param hdr Ptr to the header + * + * @return Length of the trailer + */ +uint16_t log_trailer_len(struct log *log, const struct log_entry_hdr *hdr); /** * @brief Reads data from the body of a log entry into a flat buffer. @@ -725,6 +809,33 @@ log_set_rotate_notify_cb(struct log *log, log_notify_rotate_cb *cb); int log_set_watermark(struct log *log, uint32_t index); #endif +/** + * Fill number of entries + * + * @param log Ptr to log structure + * @param dptr Ptr to data to be read + * @param num_entries Ptr to number of entries + * @param offset Offset of the num of entries field in the log entry + * + * @return 0 on success, non-zero on failure + */ +int log_fill_num_entries(struct log *log, const void *dptr, + uint32_t *num_entries, + uint16_t offset); +/** + * Fill number of tlvs + * + * @param log Ptr to log structure + * @param dptr Ptr to data to be read + * @param num_entries Ptr to number of entries + * @param offset Offset of the num of entries field in the log entry + * + * @return 0 on success, non-zero on failure + */ +int +log_fill_num_tlvs(struct log *log, const void *dptr, uint8_t *num_tlvs, + uint16_t offset); + /** * Fill log current image hash * @@ -735,6 +846,37 @@ int log_set_watermark(struct log *log, uint32_t index); int log_fill_current_img_hash(struct log_entry_hdr *hdr); +/** + * Reads the log entry's header from the specified log and log index + * + * @param log The log to read from. + * @param idx Index of the log entry to read header from + * @param out_hdr On success, the last entry header gets written + * here. + * + * @return 0 on success; nonzero on failure. + */ +int +log_read_hdr_by_idx(struct log *log, uint32_t idx, struct log_entry_hdr *out_hdr); + +/** + * Get number of entries in log + * + * @param log The log to get number of entries for + * @param idx The log index to read number of entries from + * @param num_entries Ptr to fill up number of entries in log + */ +int +log_get_entries(struct log *log, uint32_t idx, uint32_t *entries); + +/* Get the length of data in medium - storage (fcb/fcb2), memory or stream + * + * @param log The log to get number of entries for + * @param len Length in medium with padding if any + */ +int +log_len_in_medium(struct log *log, uint16_t len); + /* Handler exports */ #if MYNEWT_VAL(LOG_CONSOLE) extern const struct log_handler log_console_handler; diff --git a/sys/log/full/selftest/align1_img_hash_num_entries/pkg.yml b/sys/log/full/selftest/align1_img_hash_num_entries/pkg.yml new file mode 100644 index 0000000000..56700bf5f2 --- /dev/null +++ b/sys/log/full/selftest/align1_img_hash_num_entries/pkg.yml @@ -0,0 +1,30 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +pkg.name: sys/log/full/selftest/align1_img_hash_num_entries +pkg.type: unittest +pkg.description: "Log unit tests; flash-alignment=1." +pkg.author: "Apache Mynewt " +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + +pkg.deps: + - "@apache-mynewt-core/sys/console/stub" + - "@apache-mynewt-core/sys/log/full" + - "@apache-mynewt-core/sys/log/full/selftest/util" + - "@apache-mynewt-core/test/testutil" + - "@apache-mynewt-core/boot/stub" diff --git a/sys/log/full/selftest/align1_img_hash_num_entries/src/log_test_align1.c b/sys/log/full/selftest/align1_img_hash_num_entries/src/log_test_align1.c new file mode 100644 index 0000000000..6fb73ffba7 --- /dev/null +++ b/sys/log/full/selftest/align1_img_hash_num_entries/src/log_test_align1.c @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "os/mynewt.h" +#include "log_test_util/log_test_util.h" + +int +main(int argc, char **argv) +{ + log_test_suite_cbmem_flat(); + log_test_suite_cbmem_mbuf(); + log_test_suite_fcb_flat(); + log_test_suite_fcb_mbuf(); + log_test_suite_misc(); + + return tu_any_failed; +} diff --git a/sys/log/full/selftest/align1_img_hash_num_entries/syscfg.yml b/sys/log/full/selftest/align1_img_hash_num_entries/syscfg.yml new file mode 100644 index 0000000000..8d445d0503 --- /dev/null +++ b/sys/log/full/selftest/align1_img_hash_num_entries/syscfg.yml @@ -0,0 +1,30 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.vals: + LOG_FCB: 1 + MCU_FLASH_MIN_WRITE_SIZE: 1 + + # The mbuf append tests allocate lots of mbufs; ensure no exhaustion. + MSYS_1_BLOCK_COUNT: 1000 + LOG_FLAGS_IMAGE_HASH: 1 + LOG_FLAGS_TLV_SUPPORT: 1 + LOG_TLV_NUM_ENTRIES: 1 + IMGMGR_DUMMY_HDR: 1 + LOG_MGMT: 0 + IMG_MGMT: 0 diff --git a/sys/log/full/selftest/align1_num_entries/pkg.yml b/sys/log/full/selftest/align1_num_entries/pkg.yml new file mode 100644 index 0000000000..8a0bf7d105 --- /dev/null +++ b/sys/log/full/selftest/align1_num_entries/pkg.yml @@ -0,0 +1,30 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +pkg.name: sys/log/full/selftest/align1_num_entries +pkg.type: unittest +pkg.description: "Log unit tests; flash-alignment=1." +pkg.author: "Apache Mynewt " +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + +pkg.deps: + - "@apache-mynewt-core/sys/console/stub" + - "@apache-mynewt-core/sys/log/full" + - "@apache-mynewt-core/sys/log/full/selftest/util" + - "@apache-mynewt-core/test/testutil" + - "@apache-mynewt-core/boot/stub" diff --git a/sys/log/full/selftest/align1_num_entries/src/log_test_align1.c b/sys/log/full/selftest/align1_num_entries/src/log_test_align1.c new file mode 100644 index 0000000000..6fb73ffba7 --- /dev/null +++ b/sys/log/full/selftest/align1_num_entries/src/log_test_align1.c @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "os/mynewt.h" +#include "log_test_util/log_test_util.h" + +int +main(int argc, char **argv) +{ + log_test_suite_cbmem_flat(); + log_test_suite_cbmem_mbuf(); + log_test_suite_fcb_flat(); + log_test_suite_fcb_mbuf(); + log_test_suite_misc(); + + return tu_any_failed; +} diff --git a/sys/log/full/selftest/align1_num_entries/syscfg.yml b/sys/log/full/selftest/align1_num_entries/syscfg.yml new file mode 100644 index 0000000000..a3b63983cc --- /dev/null +++ b/sys/log/full/selftest/align1_num_entries/syscfg.yml @@ -0,0 +1,29 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.vals: + LOG_FCB: 1 + MCU_FLASH_MIN_WRITE_SIZE: 1 + + # The mbuf append tests allocate lots of mbufs; ensure no exhaustion. + MSYS_1_BLOCK_COUNT: 1000 + LOG_FLAGS_TLV_SUPPORT: 1 + LOG_TLV_NUM_ENTRIES: 1 + IMGMGR_DUMMY_HDR: 1 + LOG_MGMT: 0 + IMG_MGMT: 0 diff --git a/sys/log/full/selftest/align4_num_entries/pkg.yml b/sys/log/full/selftest/align4_num_entries/pkg.yml new file mode 100644 index 0000000000..339101d7bb --- /dev/null +++ b/sys/log/full/selftest/align4_num_entries/pkg.yml @@ -0,0 +1,30 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +pkg.name: sys/log/full/selftest/align4_num_entries +pkg.type: unittest +pkg.description: "Log unit tests; flash-alignment=4." +pkg.author: "Apache Mynewt " +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + +pkg.deps: + - "@apache-mynewt-core/sys/console/stub" + - "@apache-mynewt-core/sys/log/full" + - "@apache-mynewt-core/sys/log/full/selftest/util" + - "@apache-mynewt-core/test/testutil" + - "@apache-mynewt-core/boot/stub" diff --git a/sys/log/full/selftest/align4_num_entries/src/log_test_align1.c b/sys/log/full/selftest/align4_num_entries/src/log_test_align1.c new file mode 100644 index 0000000000..6fb73ffba7 --- /dev/null +++ b/sys/log/full/selftest/align4_num_entries/src/log_test_align1.c @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "os/mynewt.h" +#include "log_test_util/log_test_util.h" + +int +main(int argc, char **argv) +{ + log_test_suite_cbmem_flat(); + log_test_suite_cbmem_mbuf(); + log_test_suite_fcb_flat(); + log_test_suite_fcb_mbuf(); + log_test_suite_misc(); + + return tu_any_failed; +} diff --git a/sys/log/full/selftest/align4_num_entries/src/log_test_align4.c b/sys/log/full/selftest/align4_num_entries/src/log_test_align4.c new file mode 100644 index 0000000000..b1c5a1d230 --- /dev/null +++ b/sys/log/full/selftest/align4_num_entries/src/log_test_align4.c @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "os/mynewt.h" +#include "log_test_util/log_test_util.h" + +int +main(int argc, char **argv) +{ + log_test_suite_cbmem_flat(); + + log_test_suite_cbmem_mbuf(); + log_test_suite_fcb_flat(); + +#if 0 + /* Current fcb mbuf implementation supports only + * 1 byte alignment + */ + log_test_suite_fcb_mbuf(); +#endif + + log_test_suite_misc(); + + return tu_any_failed; +} diff --git a/sys/log/full/selftest/align4_num_entries/syscfg.yml b/sys/log/full/selftest/align4_num_entries/syscfg.yml new file mode 100644 index 0000000000..a3b63983cc --- /dev/null +++ b/sys/log/full/selftest/align4_num_entries/syscfg.yml @@ -0,0 +1,29 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.vals: + LOG_FCB: 1 + MCU_FLASH_MIN_WRITE_SIZE: 1 + + # The mbuf append tests allocate lots of mbufs; ensure no exhaustion. + MSYS_1_BLOCK_COUNT: 1000 + LOG_FLAGS_TLV_SUPPORT: 1 + LOG_TLV_NUM_ENTRIES: 1 + IMGMGR_DUMMY_HDR: 1 + LOG_MGMT: 0 + IMG_MGMT: 0 diff --git a/sys/log/full/selftest/fcb2_align1_imghash/pkg.yml b/sys/log/full/selftest/fcb2_align1_imghash/pkg.yml new file mode 100644 index 0000000000..f931c7d494 --- /dev/null +++ b/sys/log/full/selftest/fcb2_align1_imghash/pkg.yml @@ -0,0 +1,30 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +pkg.name: sys/log/full/selftest/fcb2_align1_imghash +pkg.type: unittest +pkg.description: "Log unit tests; FCB2 flash-alignment=1." +pkg.author: "Apache Mynewt " +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + +pkg.deps: + - "@apache-mynewt-core/sys/console/stub" + - "@apache-mynewt-core/sys/log/full" + - "@apache-mynewt-core/sys/log/full/selftest/util" + - "@apache-mynewt-core/test/testutil" + - "@apache-mynewt-core/boot/stub" diff --git a/sys/log/full/selftest/fcb2_align1_imghash/src/log_test_align1.c b/sys/log/full/selftest/fcb2_align1_imghash/src/log_test_align1.c new file mode 100644 index 0000000000..6fb73ffba7 --- /dev/null +++ b/sys/log/full/selftest/fcb2_align1_imghash/src/log_test_align1.c @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "os/mynewt.h" +#include "log_test_util/log_test_util.h" + +int +main(int argc, char **argv) +{ + log_test_suite_cbmem_flat(); + log_test_suite_cbmem_mbuf(); + log_test_suite_fcb_flat(); + log_test_suite_fcb_mbuf(); + log_test_suite_misc(); + + return tu_any_failed; +} diff --git a/sys/log/full/selftest/fcb2_align1_imghash/syscfg.yml b/sys/log/full/selftest/fcb2_align1_imghash/syscfg.yml new file mode 100644 index 0000000000..fa4b33f97e --- /dev/null +++ b/sys/log/full/selftest/fcb2_align1_imghash/syscfg.yml @@ -0,0 +1,29 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.vals: + LOG_FCB2: 1 + MCU_FLASH_MIN_WRITE_SIZE: 1 + LOG_FLAGS_IMAGE_HASH: 1 + + # The mbuf append tests allocate lots of mbufs; ensure no exhaustion. + MSYS_1_BLOCK_COUNT: 1000 + LOG_FLAGS_IMAGE_HASH: 1 + IMGMGR_DUMMY_HDR: 1 + LOG_MGMT: 0 + IMG_MGMT: 0 diff --git a/sys/log/full/selftest/fcb2_align1_imghash_num_entries/pkg.yml b/sys/log/full/selftest/fcb2_align1_imghash_num_entries/pkg.yml new file mode 100644 index 0000000000..e84f61ad7c --- /dev/null +++ b/sys/log/full/selftest/fcb2_align1_imghash_num_entries/pkg.yml @@ -0,0 +1,30 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +pkg.name: sys/log/full/selftest/fcb2_align1_imghash_num_entries +pkg.type: unittest +pkg.description: "Log unit tests; FCB2 flash-alignment=1." +pkg.author: "Apache Mynewt " +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + +pkg.deps: + - "@apache-mynewt-core/sys/console/stub" + - "@apache-mynewt-core/sys/log/full" + - "@apache-mynewt-core/sys/log/full/selftest/util" + - "@apache-mynewt-core/test/testutil" + - "@apache-mynewt-core/boot/stub" diff --git a/sys/log/full/selftest/fcb2_align1_imghash_num_entries/src/log_test_align1.c b/sys/log/full/selftest/fcb2_align1_imghash_num_entries/src/log_test_align1.c new file mode 100644 index 0000000000..6fb73ffba7 --- /dev/null +++ b/sys/log/full/selftest/fcb2_align1_imghash_num_entries/src/log_test_align1.c @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "os/mynewt.h" +#include "log_test_util/log_test_util.h" + +int +main(int argc, char **argv) +{ + log_test_suite_cbmem_flat(); + log_test_suite_cbmem_mbuf(); + log_test_suite_fcb_flat(); + log_test_suite_fcb_mbuf(); + log_test_suite_misc(); + + return tu_any_failed; +} diff --git a/sys/log/full/selftest/fcb2_align1_imghash_num_entries/syscfg.yml b/sys/log/full/selftest/fcb2_align1_imghash_num_entries/syscfg.yml new file mode 100644 index 0000000000..9b36728a94 --- /dev/null +++ b/sys/log/full/selftest/fcb2_align1_imghash_num_entries/syscfg.yml @@ -0,0 +1,30 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.vals: + LOG_FCB2: 1 + MCU_FLASH_MIN_WRITE_SIZE: 1 + + # The mbuf append tests allocate lots of mbufs; ensure no exhaustion. + MSYS_1_BLOCK_COUNT: 1000 + LOG_FLAGS_IMAGE_HASH: 1 + LOG_FLAGS_TLV_SUPPORT: 1 + LOG_TLV_NUM_ENTRIES: 1 + IMGMGR_DUMMY_HDR: 1 + LOG_MGMT: 0 + IMG_MGMT: 0 diff --git a/sys/log/full/selftest/util/include/log_test_util/log_test_util.h b/sys/log/full/selftest/util/include/log_test_util/log_test_util.h index 90b77e4985..4c23c3733f 100644 --- a/sys/log/full/selftest/util/include/log_test_util/log_test_util.h +++ b/sys/log/full/selftest/util/include/log_test_util/log_test_util.h @@ -41,6 +41,7 @@ extern struct fcb2 log_fcb; #endif extern struct log my_log; extern char *ltu_str_logs[]; +extern uint8_t dummy_log_arr[]; struct os_mbuf *ltu_flat_to_fragged_mbuf(const void *flat, int len, int frag_sz); @@ -49,6 +50,9 @@ void ltu_setup_2fcbs(struct fcb_log *fcb_log1, struct log *log1, struct fcb_log *fcb_log2, struct log *log2); void ltu_setup_cbmem(struct cbmem *cbmem, struct log *log); void ltu_verify_contents(struct log *log); +uint16_t *ltu_get_ltu_off_arr(void); +uint16_t ltu_init_arr(void); +int ltu_num_strs(void); TEST_SUITE_DECL(log_test_suite_cbmem_flat); TEST_CASE_DECL(log_test_case_cbmem_append); diff --git a/sys/log/full/selftest/util/src/log_test_util.c b/sys/log/full/selftest/util/src/log_test_util.c index 2447cbb616..6ce9aeaa51 100644 --- a/sys/log/full/selftest/util/src/log_test_util.c +++ b/sys/log/full/selftest/util/src/log_test_util.c @@ -18,6 +18,7 @@ */ #include "log_test_util/log_test_util.h" +#include "log/log.h" #if MYNEWT_VAL(LOG_FCB) static struct flash_area fcb_areas[] = { @@ -46,6 +47,37 @@ static struct flash_sector_range fcb_range = { static int ltu_str_idx = 0; static int ltu_str_max_idx = 0; +struct dummy_log { + struct log_entry_hdr hdr; + uint32_t num_entries; + struct log_tlv tlv; +}; + +struct dummy_log dummy_log = { + .hdr = { + .ue_ts = 1, + .ue_module = 2, + .ue_etype = 3, + .ue_flags = 0 +#if MYNEWT_VAL(LOG_FLAGS_IMAGE_HASH) + | LOG_FLAGS_IMG_HASH +#endif +#if MYNEWT_VAL(LOG_FLAGS_TLV_SUPPORT) + | LOG_FLAGS_TLV_SUPPORT +#endif + , + .ue_etype = 0, + .ue_imghash = {1, 2, 3, 4}, + .ue_level = 3, + .ue_num_entries = 5 + }, + .num_entries = 0, + .tlv = { + .tag = LOG_TLV_NUM_ENTRIES, + .len = LOG_NUM_ENTRIES_SIZE + }, +}; + char *ltu_str_logs[] = { "testdata", "1testdata2", @@ -54,6 +86,10 @@ char *ltu_str_logs[] = { NULL }; +uint16_t ltu_off_arr[5]; + +uint8_t dummy_log_arr[2048]; + static uint8_t ltu_cbmem_buf[2048]; int @@ -66,6 +102,43 @@ ltu_num_strs(void) return i; } +uint16_t * +ltu_get_ltu_off_arr(void) +{ + return ltu_off_arr; +} + +uint16_t +ltu_init_arr(void) +{ + int i; + uint16_t offset = 0; + + for (i = 0; i < ltu_num_strs(); i++) { + TEST_ASSERT_FATAL(offset <= 2048); + ltu_off_arr[i] = offset; + memcpy(dummy_log_arr + offset, &dummy_log.hdr, LOG_BASE_ENTRY_HDR_SIZE); + offset += LOG_BASE_ENTRY_HDR_SIZE; +#if MYNEWT_VAL(LOG_FLAGS_IMAGE_HASH) + memcpy(dummy_log_arr + offset, + dummy_log.hdr.ue_imghash, LOG_IMG_HASHLEN); + offset += LOG_IMG_HASHLEN; +#endif + memcpy(dummy_log_arr + offset, ltu_str_logs[i], strlen(ltu_str_logs[i])); + offset += strlen(ltu_str_logs[i]); +#if MYNEWT_VAL(LOG_FLAGS_TLV_SUPPORT) +#if MYNEWT_VAL(LOG_TLV_NUM_ENTRIES) + memcpy(dummy_log_arr + offset, &dummy_log.num_entries, LOG_NUM_ENTRIES_SIZE); + offset += LOG_NUM_ENTRIES_SIZE; + memcpy(dummy_log_arr + offset, &dummy_log.tlv, sizeof(struct log_tlv)); + offset += sizeof(struct log_tlv); +#endif +#endif + } + ltu_off_arr[i] = offset; + return offset; +} + struct os_mbuf * ltu_flat_to_fragged_mbuf(const void *flat, int len, int frag_sz) { @@ -190,6 +263,8 @@ ltu_walk_verify(struct log *log, struct log_offset *log_offset, char data[128]; int dlen; uint16_t hdr_len; + uint16_t trailer_len; + uint16_t offset = 0; TEST_ASSERT(ltu_str_idx < ltu_str_max_idx); @@ -197,9 +272,17 @@ ltu_walk_verify(struct log *log, struct log_offset *log_offset, rc = log_read(log, dptr, &ueh, 0, LOG_BASE_ENTRY_HDR_SIZE); TEST_ASSERT(rc == LOG_BASE_ENTRY_HDR_SIZE); + offset = LOG_BASE_ENTRY_HDR_SIZE; + + if (ueh.ue_flags & LOG_FLAGS_IMG_HASH) { + rc = log_read(log, dptr, data, offset, LOG_IMG_HASHLEN); + TEST_ASSERT(rc == LOG_IMG_HASHLEN); + offset += LOG_IMG_HASHLEN; + } hdr_len = log_hdr_len(&ueh); - dlen = len - hdr_len; + trailer_len = log_trailer_len(log, &ueh); + dlen = len - hdr_len - trailer_len; TEST_ASSERT(dlen < sizeof(data)); rc = log_read(log, dptr, data, hdr_len, dlen); @@ -218,6 +301,12 @@ ltu_walk_verify(struct log *log, struct log_offset *log_offset, rc = log_read_body(log, dptr, data, 0, dlen); TEST_ASSERT(rc == dlen); +#if MYNEWT_VAL(LOG_FLAGS_TLV_SUPPORT) && MYNEWT_VAL(LOG_TLV_NUM_ENTRIES) + uint32_t num_entries; + rc = log_read_trailer(log, dptr, LOG_TLV_NUM_ENTRIES, &num_entries); + TEST_ASSERT(rc == 0); +#endif + TEST_ASSERT(strlen(ltu_str_logs[ltu_str_idx]) == dlen); TEST_ASSERT(!memcmp(ltu_str_logs[ltu_str_idx], data, dlen)); @@ -263,6 +352,8 @@ ltu_walk_body_verify(struct log *log, struct log_offset *log_offset, TEST_ASSERT(len < sizeof(data)); + len -= log_trailer_len(log, euh); + rc = log_read_body(log, dptr, data, 0, len); TEST_ASSERT(rc == len); diff --git a/sys/log/full/selftest/util/src/testcases/log_test_case_cbmem_append.c b/sys/log/full/selftest/util/src/testcases/log_test_case_cbmem_append.c index 180f3774f6..5f5d9d17ae 100644 --- a/sys/log/full/selftest/util/src/testcases/log_test_case_cbmem_append.c +++ b/sys/log/full/selftest/util/src/testcases/log_test_case_cbmem_append.c @@ -23,23 +23,26 @@ TEST_CASE_SELF(log_test_case_cbmem_append) { struct cbmem cbmem; struct log log; - uint8_t buf[256]; - char *str; - int body_len; + uint16_t len = 0; + uint16_t *off_arr; int i; int rc; + int num_strs = ltu_num_strs(); + struct log_entry_hdr *hdr; ltu_setup_cbmem(&cbmem, &log); + len = ltu_init_arr(); + TEST_ASSERT_FATAL(len != 0); - for (i = 0; ; i++) { - str = ltu_str_logs[i]; - if (!str) { - break; - } + off_arr = ltu_get_ltu_off_arr(); + TEST_ASSERT_FATAL(off_arr != NULL); - body_len = strlen(str); - memcpy(buf + LOG_HDR_SIZE, str, body_len); - rc = log_append_typed(&log, 0, 0, LOG_ETYPE_STRING, buf, body_len); + for (i = 0; i < num_strs; i++) { + hdr = (struct log_entry_hdr *)(dummy_log_arr + off_arr[i]); + len = off_arr[i+1] - off_arr[i] - log_hdr_len(hdr) - log_trailer_len(&log, hdr); + rc = log_append_typed(&log, 2, 3, LOG_ETYPE_STRING, + dummy_log_arr + off_arr[i], + len); TEST_ASSERT_FATAL(rc == 0); } diff --git a/sys/log/full/selftest/util/src/testcases/log_test_case_cbmem_append_body.c b/sys/log/full/selftest/util/src/testcases/log_test_case_cbmem_append_body.c index 0a7fb1c110..8948bacad3 100644 --- a/sys/log/full/selftest/util/src/testcases/log_test_case_cbmem_append_body.c +++ b/sys/log/full/selftest/util/src/testcases/log_test_case_cbmem_append_body.c @@ -23,18 +23,28 @@ TEST_CASE_SELF(log_test_case_cbmem_append_body) { struct cbmem cbmem; struct log log; - char *str; + uint16_t len = 0; + uint16_t *off_arr; int i; + int rc; + struct log_entry_hdr *hdr; + int num_strs = ltu_num_strs(); ltu_setup_cbmem(&cbmem, &log); + len = ltu_init_arr(); + TEST_ASSERT_FATAL(len != 0); - for (i = 0; ; i++) { - str = ltu_str_logs[i]; - if (!str) { - break; - } + off_arr = ltu_get_ltu_off_arr(); + TEST_ASSERT_FATAL(off_arr != NULL); - log_append_body(&log, 0, 0, LOG_ETYPE_STRING, str, strlen(str)); + for (i = 0; i < num_strs; i++) { + hdr = (struct log_entry_hdr *)(dummy_log_arr + off_arr[i]); + len = off_arr[i + 1] - off_arr[i] - + log_hdr_len(hdr) - log_trailer_len(&log, hdr); + rc = log_append_body(&log, 2, 3, LOG_ETYPE_STRING, + dummy_log_arr + off_arr[i] + log_hdr_len(hdr), + len); + TEST_ASSERT_FATAL(rc == 0); } ltu_verify_contents(&log); diff --git a/sys/log/full/selftest/util/src/testcases/log_test_case_cbmem_append_mbuf.c b/sys/log/full/selftest/util/src/testcases/log_test_case_cbmem_append_mbuf.c index 3bf305549a..d94c4fe71d 100644 --- a/sys/log/full/selftest/util/src/testcases/log_test_case_cbmem_append_mbuf.c +++ b/sys/log/full/selftest/util/src/testcases/log_test_case_cbmem_append_mbuf.c @@ -22,28 +22,30 @@ TEST_CASE_SELF(log_test_case_cbmem_append_mbuf) { struct cbmem cbmem; - struct os_mbuf *om; struct log log; - char *str; - int rc; + struct os_mbuf *om; + uint16_t len = 0; + uint16_t *off_arr; int i; + int rc; + struct log_entry_hdr *hdr; + int num_strs = ltu_num_strs(); ltu_setup_cbmem(&cbmem, &log); + len = ltu_init_arr(); + TEST_ASSERT_FATAL(len != 0); - for (i = 0; ; i++) { - str = ltu_str_logs[i]; - if (!str) { - break; - } + off_arr = ltu_get_ltu_off_arr(); + TEST_ASSERT_FATAL(off_arr != NULL); + for (i = 0; i < num_strs; i++) { + hdr = (struct log_entry_hdr *)(dummy_log_arr + off_arr[i]); + len = off_arr[i+1] - off_arr[i] - log_trailer_len(&log, hdr); /* Split chain into several mbufs. */ - om = ltu_flat_to_fragged_mbuf(str, strlen(str), 2); - - /* Prepend space for the entry header. */ - om = os_mbuf_prepend(om, LOG_HDR_SIZE); - TEST_ASSERT(om != NULL); + om = ltu_flat_to_fragged_mbuf(dummy_log_arr + off_arr[i], + len, 2); - rc = log_append_mbuf_typed(&log, 0, 0, LOG_ETYPE_STRING, om); + rc = log_append_mbuf_typed(&log, 2, 3, LOG_ETYPE_STRING, om); TEST_ASSERT_FATAL(rc == 0); } diff --git a/sys/log/full/selftest/util/src/testcases/log_test_case_cbmem_append_mbuf_body.c b/sys/log/full/selftest/util/src/testcases/log_test_case_cbmem_append_mbuf_body.c index fddb1bbc85..4dd0b026c1 100644 --- a/sys/log/full/selftest/util/src/testcases/log_test_case_cbmem_append_mbuf_body.c +++ b/sys/log/full/selftest/util/src/testcases/log_test_case_cbmem_append_mbuf_body.c @@ -24,22 +24,30 @@ TEST_CASE_SELF(log_test_case_cbmem_append_mbuf_body) struct cbmem cbmem; struct os_mbuf *om; struct log log; - char *str; int rc; int i; + uint16_t len; + int num_strs = ltu_num_strs(); + struct log_entry_hdr *hdr; + uint16_t *off_arr; ltu_setup_cbmem(&cbmem, &log); + len = ltu_init_arr(); + TEST_ASSERT_FATAL(len != 0); - for (i = 0; ; i++) { - str = ltu_str_logs[i]; - if (!str) { - break; - } + off_arr = ltu_get_ltu_off_arr(); + TEST_ASSERT_FATAL(off_arr != NULL); + + for (i = 0; i < num_strs; i++) { + hdr = (struct log_entry_hdr *)(dummy_log_arr + off_arr[i]); + len = off_arr[i + 1] - off_arr[i] - + log_hdr_len(hdr) - log_trailer_len(&log, hdr); /* Split chain into several mbufs. */ - om = ltu_flat_to_fragged_mbuf(str, strlen(str), 2); + om = ltu_flat_to_fragged_mbuf(dummy_log_arr + off_arr[i] + log_hdr_len(hdr), + len, 2); - rc = log_append_mbuf_body(&log, 0, 0, LOG_ETYPE_STRING, om); + rc = log_append_mbuf_body(&log, 2, 3, LOG_ETYPE_STRING, om); TEST_ASSERT_FATAL(rc == 0); } diff --git a/sys/log/full/selftest/util/src/testcases/log_test_case_cbmem_printf.c b/sys/log/full/selftest/util/src/testcases/log_test_case_cbmem_printf.c index f48b876571..f29bdcdb1e 100644 --- a/sys/log/full/selftest/util/src/testcases/log_test_case_cbmem_printf.c +++ b/sys/log/full/selftest/util/src/testcases/log_test_case_cbmem_printf.c @@ -23,18 +23,27 @@ TEST_CASE_SELF(log_test_case_cbmem_printf) { struct cbmem cbmem; struct log log; - char *str; int i; + uint16_t len = 0; + int num_strs = ltu_num_strs(); + uint16_t *off_arr; + struct log_entry_hdr *hdr; + char data[256]; ltu_setup_cbmem(&cbmem, &log); + len = ltu_init_arr(); + TEST_ASSERT_FATAL(len != 0); - for (i = 0; ; i++) { - str = ltu_str_logs[i]; - if (!str) { - break; - } + off_arr = ltu_get_ltu_off_arr(); + TEST_ASSERT_FATAL(off_arr != NULL); - log_printf(&log, 0, 0, str, strlen(str)); + for (i = 0; i < num_strs; i++) { + hdr = (struct log_entry_hdr *)(dummy_log_arr + off_arr[i]); + len = off_arr[i+1] - off_arr[i] - log_hdr_len(hdr) - log_trailer_len(&log, hdr); + memcpy(data, dummy_log_arr + off_arr[i] + log_hdr_len(hdr), + len); + data[len] = '\0'; + log_printf(&log, 0, 0, data, len); } ltu_verify_contents(&log); diff --git a/sys/log/full/selftest/util/src/testcases/log_test_case_fcb_append.c b/sys/log/full/selftest/util/src/testcases/log_test_case_fcb_append.c index 808188ce1a..3fe8f4e284 100644 --- a/sys/log/full/selftest/util/src/testcases/log_test_case_fcb_append.c +++ b/sys/log/full/selftest/util/src/testcases/log_test_case_fcb_append.c @@ -23,22 +23,27 @@ TEST_CASE_SELF(log_test_case_fcb_append) { struct fcb_log fcb_log; struct log log; - uint8_t buf[256]; - char *str; - int body_len; + uint16_t len = 0; + uint16_t *off_arr; int i; + int rc; + int num_strs = ltu_num_strs(); + struct log_entry_hdr *hdr; ltu_setup_fcb(&fcb_log, &log); + len = ltu_init_arr(); + TEST_ASSERT_FATAL(len != 0); - for (i = 0; ; i++) { - str = ltu_str_logs[i]; - if (!str) { - break; - } + off_arr = ltu_get_ltu_off_arr(); + TEST_ASSERT_FATAL(off_arr != NULL); - body_len = strlen(str); - memcpy(buf + LOG_HDR_SIZE, str, body_len); - log_append_typed(&log, 0, 0, LOG_ETYPE_STRING, buf, body_len); + for (i = 0;i < num_strs; i++) { + hdr = (struct log_entry_hdr *)(dummy_log_arr + off_arr[i]); + len = off_arr[i+1] - off_arr[i] - log_hdr_len(hdr) - log_trailer_len(&log, hdr); + rc = log_append_typed(&log, 2, 3, LOG_ETYPE_STRING, + dummy_log_arr + off_arr[i], + len); + TEST_ASSERT_FATAL(rc == 0); } ltu_verify_contents(&log); diff --git a/sys/log/full/selftest/util/src/testcases/log_test_case_fcb_append_body.c b/sys/log/full/selftest/util/src/testcases/log_test_case_fcb_append_body.c index 1d0a86637e..996ff647e5 100644 --- a/sys/log/full/selftest/util/src/testcases/log_test_case_fcb_append_body.c +++ b/sys/log/full/selftest/util/src/testcases/log_test_case_fcb_append_body.c @@ -23,18 +23,30 @@ TEST_CASE_SELF(log_test_case_fcb_append_body) { struct fcb_log fcb_log; struct log log; - char *str; + uint16_t len = 0; + uint16_t *off_arr; int i; + int rc; + struct log_entry_hdr *hdr; + int num_strs = ltu_num_strs(); ltu_setup_fcb(&fcb_log, &log); + len = ltu_init_arr(); + TEST_ASSERT_FATAL(len != 0); - for (i = 0; ; i++) { - str = ltu_str_logs[i]; - if (!str) { - break; - } - log_append_body(&log, 0, 0, LOG_ETYPE_STRING, str, strlen(str)); + off_arr = ltu_get_ltu_off_arr(); + TEST_ASSERT_FATAL(off_arr != NULL); + + for (i = 0; i < num_strs; i++) { + hdr = (struct log_entry_hdr *)(dummy_log_arr + off_arr[i]); + len = off_arr[i + 1] - off_arr[i] - + log_hdr_len(hdr) - log_trailer_len(&log, hdr); + rc = log_append_body(&log, 2, 3, LOG_ETYPE_STRING, + dummy_log_arr + off_arr[i] + log_hdr_len(hdr), + len); + TEST_ASSERT_FATAL(rc == 0); } ltu_verify_contents(&log); + } diff --git a/sys/log/full/selftest/util/src/testcases/log_test_case_fcb_append_mbuf.c b/sys/log/full/selftest/util/src/testcases/log_test_case_fcb_append_mbuf.c index e566c78bd7..7a3c2b0353 100644 --- a/sys/log/full/selftest/util/src/testcases/log_test_case_fcb_append_mbuf.c +++ b/sys/log/full/selftest/util/src/testcases/log_test_case_fcb_append_mbuf.c @@ -24,26 +24,28 @@ TEST_CASE_SELF(log_test_case_fcb_append_mbuf) struct fcb_log fcb_log; struct os_mbuf *om; struct log log; - char *str; int rc; int i; + int num_strs = ltu_num_strs(); + struct log_entry_hdr *hdr; + uint16_t *off_arr; + uint16_t len; ltu_setup_fcb(&fcb_log, &log); + len = ltu_init_arr(); + TEST_ASSERT_FATAL(len != 0); - for (i = 0; ; i++) { - str = ltu_str_logs[i]; - if (!str) { - break; - } + off_arr = ltu_get_ltu_off_arr(); + TEST_ASSERT_FATAL(off_arr != NULL); + for (i = 0; i < num_strs; i++) { + hdr = (struct log_entry_hdr *)(dummy_log_arr + off_arr[i]); + len = off_arr[i+1] - off_arr[i] - log_trailer_len(&log, hdr); /* Split chain into several mbufs. */ - om = ltu_flat_to_fragged_mbuf(str, strlen(str), 2); + om = ltu_flat_to_fragged_mbuf(dummy_log_arr + off_arr[i], + len, 2); - /* Prepend space for the entry header. */ - om = os_mbuf_prepend(om, LOG_HDR_SIZE); - TEST_ASSERT(om != NULL); - - rc = log_append_mbuf_typed(&log, 0, 0, LOG_ETYPE_STRING, om); + rc = log_append_mbuf_typed(&log, 2, 3, LOG_ETYPE_STRING, om); TEST_ASSERT_FATAL(rc == 0); } diff --git a/sys/log/full/selftest/util/src/testcases/log_test_case_fcb_append_mbuf_body.c b/sys/log/full/selftest/util/src/testcases/log_test_case_fcb_append_mbuf_body.c index 25d536479a..bc980835ab 100644 --- a/sys/log/full/selftest/util/src/testcases/log_test_case_fcb_append_mbuf_body.c +++ b/sys/log/full/selftest/util/src/testcases/log_test_case_fcb_append_mbuf_body.c @@ -24,22 +24,30 @@ TEST_CASE_SELF(log_test_case_fcb_append_mbuf_body) struct fcb_log fcb_log; struct os_mbuf *om; struct log log; - char *str; int rc; int i; + int num_strs = ltu_num_strs(); + struct log_entry_hdr *hdr; + uint16_t *off_arr; + uint16_t len; ltu_setup_fcb(&fcb_log, &log); + len = ltu_init_arr(); + TEST_ASSERT_FATAL(len != 0); - for (i = 0; ; i++) { - str = ltu_str_logs[i]; - if (!str) { - break; - } + off_arr = ltu_get_ltu_off_arr(); + TEST_ASSERT_FATAL(off_arr != NULL); + + for (i = 0; i < num_strs; i++) { + hdr = (struct log_entry_hdr *)(dummy_log_arr + off_arr[i]); + len = off_arr[i + 1] - off_arr[i] - + log_hdr_len(hdr) - log_trailer_len(&log, hdr); /* Split chain into several mbufs. */ - om = ltu_flat_to_fragged_mbuf(str, strlen(str), 2); + om = ltu_flat_to_fragged_mbuf(dummy_log_arr + off_arr[i] + log_hdr_len(hdr), + len, 2); - rc = log_append_mbuf_body(&log, 0, 0, LOG_ETYPE_STRING, om); + rc = log_append_mbuf_body(&log, 2, 3, LOG_ETYPE_STRING, om); TEST_ASSERT_FATAL(rc == 0); } diff --git a/sys/log/full/src/log.c b/sys/log/full/src/log.c index ad8f590aac..84443ebe48 100644 --- a/sys/log/full/src/log.c +++ b/sys/log/full/src/log.c @@ -312,11 +312,77 @@ struct log_read_hdr_arg { }; static int -log_read_hdr_walk(struct log *log, struct log_offset *log_offset, const void *dptr, - uint16_t len) +log_update_num_entries_hdr_walk(struct log *log, struct log_offset *log_offset, + const void *dptr, uint16_t len) +{ + uint32_t *num_entries; + uint16_t offset = 0; + int rc; + struct log_entry_hdr hdr; + + (void)offset; + num_entries = log_offset->lo_arg; + + rc = log_read(log, dptr, &hdr, 0, LOG_BASE_ENTRY_HDR_SIZE); + if (rc >= LOG_BASE_ENTRY_HDR_SIZE) { + *num_entries += 1; + return 0; + } + + return -1; +} + +static int +log_process_tlvs(struct log *log, const void *dptr, uint8_t num_tlvs, + uint16_t tlv_tag, void *buf, uint16_t len) +{ + struct log_tlv *tlv; + uint8_t tmpbuf[sizeof(*tlv) + 8] = {0}; + uint16_t offset; + int tlv_len; + int rc = SYS_ENOENT; + + offset = len; + tlv_len = log_len_in_medium(log, sizeof(*tlv)); + do { + offset -= tlv_len; + rc = log_read(log, dptr, tmpbuf, offset, tlv_len); + if (rc < tlv_len) { + return SYS_EINVAL; + } + tlv = (struct log_tlv *)tmpbuf; + + offset -= log_len_in_medium(log, tlv->len); + if (tlv->tag != tlv_tag) { + continue; + } + + switch (tlv_tag) { + case LOG_TLV_NUM_ENTRIES: + rc = log_fill_num_entries(log, dptr, buf, offset); + break; + case LOG_TLV_NUM_TLVS: + rc = log_fill_num_tlvs(log, dptr, buf, offset); + break; + default: + return SYS_ENOTSUP; + } + + if (!rc) { + return SYS_EOK; + } + } while (offset && num_tlvs); + + return SYS_EOK; +} + +static int +log_read_hdr_walk(struct log *log, struct log_offset *log_offset, + const void *dptr, uint16_t len) { struct log_read_hdr_arg *arg; int rc; + uint8_t num_tlvs = 0; arg = log_offset->lo_arg; @@ -332,10 +398,62 @@ log_read_hdr_walk(struct log *log, struct log_offset *log_offset, const void *dp } } + if (arg->hdr->ue_flags & LOG_FLAGS_TLV_SUPPORT) { + /* Read number of TLVs, if it does not exist + * num_tlvs = 0, so only one TLV will get read + * from the end of the entry + */ + rc = log_process_tlvs(log, dptr, 0, LOG_TLV_NUM_TLVS, + &num_tlvs, len); + if (!rc || rc == SYS_ENOTSUP) { + arg->read_success = 1; + } else { + arg->read_success = 0; + } + + if (!rc || rc == SYS_ENOTSUP) { + rc = log_process_tlvs(log, dptr, num_tlvs, LOG_TLV_NUM_ENTRIES, + &arg->hdr->ue_num_entries, len); + if (!rc || rc == SYS_ENOTSUP) { + arg->read_success = 1; + } else { + arg->read_success = 0; + } + } + } + /* Abort the walk; only one header needed. */ return 1; } +/** + * Update number of entries of the specified log. + * + * @param log The log to read from. + * @param num_entries Pointer to the number of entries. + * + * @return 0 on success; nonzero on failure. + */ +static int +log_update_num_entries(struct log *log, uint32_t *num_entries) +{ + struct log_offset log_offset; + int rc = 0; + + + log_offset.lo_arg = num_entries; + log_offset.lo_ts = 0; + log_offset.lo_index = 0; + log_offset.lo_data_len = 0; + + rc = log_walk(log, log_update_num_entries_hdr_walk, &log_offset); + if (rc) { + return -1; + } + + return 0; +} + /** * Reads the final log entry's header from the specified log. * @@ -367,6 +485,66 @@ log_read_last_hdr(struct log *log, struct log_entry_hdr *out_hdr) return 0; } +/** + * Get number of entries in log + * + * @param log The log to get number of entries for + * @param idx The log index to read number of entries from + * @param num_entries Ptr to fill up number of entries in log + * + * @return 0 on success, non-zero on failure + */ +int +log_get_entries(struct log *log, uint32_t idx, uint32_t *entries) +{ +#if MYNEWT_VAL(LOG_FLAGS_TLV_SUPPORT) && MYNEWT_VAL(LOG_TLV_NUM_ENTRIES) + int rc = 0; + struct log_entry_hdr hdr; + + rc = log_read_hdr_by_idx(log, idx, &hdr); + if (!rc) { + *entries = log->l_num_entries - hdr.ue_num_entries; + return SYS_EOK; + } else { + return rc; + } +#else + return SYS_ENOTSUP; +#endif +} + +/** + * Reads the log entry's header from the specified log and log index + * + * @param log The log to read from. + * @param idx Index of the log entry to read header from + * @param out_hdr On success, the last entry header gets written + * here. + * + * @return 0 on success; nonzero on failure. + */ +int +log_read_hdr_by_idx(struct log *log, uint32_t idx, struct log_entry_hdr *out_hdr) +{ + struct log_read_hdr_arg arg; + struct log_offset log_offset; + + arg.hdr = out_hdr; + arg.read_success = 0; + + log_offset.lo_arg = &arg; + log_offset.lo_ts = 0; + log_offset.lo_index = idx; + log_offset.lo_data_len = 0; + + log_walk(log, log_read_hdr_walk, &log_offset); + if (!arg.read_success) { + return -1; + } + + return 0; +} + /* * Associate an instantiation of a log with the logging infrastructure */ @@ -375,6 +553,7 @@ log_register(const char *name, struct log *log, const struct log_handler *lh, void *arg, uint8_t level) { struct log_entry_hdr hdr; + uint32_t num_entries = 0; int sr; int rc; @@ -413,13 +592,21 @@ log_register(const char *name, struct log *log, const struct log_handler *lh, } } - /* If this is a persisted log, read the index from its most recent entry. - * We need to ensure the index of all subseqently written entries is - * monotonically increasing. - */ if (log->l_log->log_type == LOG_TYPE_STORAGE) { + memset(&hdr, 0, sizeof(hdr)); rc = log_read_last_hdr(log, &hdr); if (rc == 0) { + /* If the number of entries are not set in the last header, + * it was probably not supported when the entry was logged. + * Count number of entries in this specific case + */ + if (!hdr.ue_num_entries) { + log_update_num_entries(log, &num_entries); + } + /* If this is a persisted log, read the index from its most + * recent entry. We need to ensure the index of all subsequently + * written entries is monotonically increasing. + */ OS_ENTER_CRITICAL(sr); #if MYNEWT_VAL(LOG_GLOBAL_IDX) if (hdr.ue_index >= g_log_info.li_next_index) { @@ -430,6 +617,15 @@ log_register(const char *name, struct log *log, const struct log_handler *lh, log->l_idx = hdr.ue_index + 1; } #endif + /* If this is a persisted log, read the num_entries from its most + * recent entry. We need to ensure the number of entries are + * monotonically increasing. + */ + if (!hdr.ue_num_entries) { + log->l_num_entries = num_entries; + } else if (hdr.ue_num_entries >= log->l_num_entries) { + log->l_num_entries = hdr.ue_num_entries + 1; + } OS_EXIT_CRITICAL(sr); } } @@ -446,11 +642,53 @@ log_set_append_cb(struct log *log, log_append_cb *cb) uint16_t log_hdr_len(const struct log_entry_hdr *hdr) { + uint16_t len; + + len = LOG_BASE_ENTRY_HDR_SIZE; if (hdr->ue_flags & LOG_FLAGS_IMG_HASH) { - return LOG_BASE_ENTRY_HDR_SIZE + LOG_IMG_HASHLEN; + len += LOG_IMG_HASHLEN; + } + + return len; +} + +int +log_len_in_medium(struct log *log, uint16_t len) +{ + if (log->l_log->log_len_in_medium) { + return log->l_log->log_len_in_medium(log, len); + } + + return len; +} + +uint16_t +log_trailer_len(struct log *log, const struct log_entry_hdr *hdr) +{ + uint16_t len = 0; + uint8_t num_tlvs = 0; + + (void)num_tlvs; + if (hdr->ue_flags & LOG_FLAGS_TLV_SUPPORT) { +#if MYNEWT_VAL(LOG_FLAGS_TLV_SUPPORT) +#if MYNEWT_VAL(LOG_TLV_NUM_ENTRIES) + len += log_len_in_medium(log, sizeof(struct log_tlv)) + + log_len_in_medium(log, LOG_NUM_ENTRIES_SIZE); + num_tlvs++; +#endif + /* Number of TLVs TLV is only written if there are more than + * one TLVS, else its just one TLV at the end + */ +#if MYNEWT_VAL(LOG_TLV_NUM_TLVS) + if (num_tlvs > 1) { + len += log_len_in_medium(log, sizeof(struct log_tlv)) + + log_len_in_medium(log, LOG_NUM_TLVS_SIZE); + } +#endif +#endif } - return LOG_BASE_ENTRY_HDR_SIZE; + return len; } void @@ -578,6 +816,11 @@ log_append_prepare(struct log *log, uint8_t module, uint8_t level, } #endif +#if MYNEWT_VAL(LOG_FLAGS_TLV_SUPPORT) && MYNEWT_VAL(LOG_TLV_NUM_ENTRIES) + ue->ue_flags |= LOG_FLAGS_TLV_SUPPORT; + ue->ue_num_entries = log->l_num_entries; +#endif + err: return (rc); } @@ -607,7 +850,7 @@ int log_append_typed(struct log *log, uint8_t module, uint8_t level, uint8_t etype, void *data, uint16_t len) { - struct log_entry_hdr *hdr; + struct log_entry_hdr hdr; int rc; LOG_STATS_INC(log, writes); @@ -617,20 +860,20 @@ log_append_typed(struct log *log, uint8_t module, uint8_t level, uint8_t etype, goto err; } - hdr = (struct log_entry_hdr *)data; - rc = log_append_prepare(log, module, level, etype, hdr); + hdr = *(struct log_entry_hdr *)data; + rc = log_append_prepare(log, module, level, etype, &hdr); if (rc != 0) { LOG_STATS_INC(log, drops); goto err; } - rc = log->l_log->log_append(log, data, len + log_hdr_len(hdr)); + rc = log->l_log->log_append(log, data, len + log_hdr_len(&hdr)); if (rc != 0) { LOG_STATS_INC(log, errs); goto err; } - log_call_append_cb(log, hdr->ue_index); + log_call_append_cb(log, hdr.ue_index); return (0); err: @@ -678,7 +921,7 @@ log_append_mbuf_typed_no_free(struct log *log, uint8_t module, uint8_t level, uint16_t hdr_len; int rc; - /* Remove a loyer of indirection for convenience. */ + /* Remove a layer of indirection for convenience. */ om = *om_ptr; LOG_STATS_INC(log, writes); @@ -945,6 +1188,20 @@ log_walk_body_section(struct log *log, log_walk_body_func_t walk_body_func, return rc; } +/** + * Reads entry length from the specified log. + * + * @return The number of bytes of entry length; 0 on failure. + */ +uint16_t +log_read_entry_len(struct log *log, const void *dptr) +{ + if (log->l_log->log_read_entry_len) { + return log->l_log->log_read_entry_len(log, dptr); + } + return 0; +} + /** * Reads from the specified log. * @@ -964,7 +1221,7 @@ log_read(struct log *log, const void *dptr, void *buf, uint16_t off, int log_read_hdr(struct log *log, const void *dptr, struct log_entry_hdr *hdr) { - int bytes_read; + int bytes_read = 0; bytes_read = log_read(log, dptr, hdr, 0, LOG_BASE_ENTRY_HDR_SIZE); if (bytes_read != LOG_BASE_ENTRY_HDR_SIZE) { @@ -982,6 +1239,78 @@ log_read_hdr(struct log *log, const void *dptr, struct log_entry_hdr *hdr) return 0; } +#if MYNEWT_VAL(LOG_FLAGS_TLV_SUPPORT) +static int +log_tlv_exists(uint16_t tlv) +{ + switch (tlv) { +#if MYNEWT_VAL(LOG_TLV_NUM_ENTRIES) + case LOG_TLV_NUM_ENTRIES: + return 0; +#endif + +#if MYNEWT_VAL(LOG_TLV_NUM_TLVS) + case LOG_TLV_NUM_TLVS: + return 0; +#endif + default: + return SYS_ENOTSUP; + } +} +#endif + +int +log_read_trailer(struct log *log, const void *dptr, uint16_t tlv, void *buf) +{ +#if MYNEWT_VAL(LOG_FLAGS_TLV_SUPPORT) + int rc; + struct log_entry_hdr hdr; + uint16_t entry_len; + uint8_t num_tlvs = 0; + + if (!buf) { + return SYS_EINVAL; + } + + rc = log_tlv_exists(tlv); + if (rc) { + return rc; + } + + rc = log_read_hdr(log, dptr, &hdr); + if (rc) { + return rc; + } + + if (hdr.ue_flags & LOG_FLAGS_TLV_SUPPORT) { + entry_len = log_read_entry_len(log, dptr); + if (tlv == LOG_TLV_NUM_TLVS) { + rc = log_process_tlvs(log, dptr, 0, LOG_TLV_NUM_TLVS, &num_tlvs, + entry_len); + if (rc) { + return rc; + } + + memcpy(buf, &num_tlvs, LOG_NUM_TLVS_SIZE); + } + + if (tlv == LOG_TLV_NUM_ENTRIES) { + rc = log_process_tlvs(log, dptr, num_tlvs, LOG_TLV_NUM_ENTRIES, + &hdr.ue_num_entries, entry_len); + if (rc) { + return rc; + } + + memcpy(buf, &hdr.ue_num_entries, LOG_NUM_ENTRIES_SIZE); + } + } + + return 0; +#else + return SYS_ENOTSUP; +#endif +} + int log_read_body(struct log *log, const void *dptr, void *buf, uint16_t off, uint16_t len) @@ -1032,6 +1361,8 @@ log_flush(struct log *log) { int rc; + log->l_num_entries = 0; + rc = log->l_log->log_flush(log); if (rc != 0) { goto err; @@ -1120,6 +1451,48 @@ log_set_max_entry_len(struct log *log, uint16_t max_entry_len) log->l_max_entry_len = max_entry_len; } +int +log_fill_num_entries(struct log *log, const void *dptr, uint32_t *num_entries, + uint16_t offset) +{ +#if MYNEWT_VAL(LOG_FLAGS_TLV_SUPPORT) && MYNEWT_VAL(LOG_TLV_NUM_ENTRIES) + int rc = 0; + uint32_t tmpdata; + + rc = log_read(log, dptr, &tmpdata, offset, LOG_NUM_ENTRIES_SIZE); + if (rc < LOG_NUM_ENTRIES_SIZE) { + return rc; + } + + *num_entries = tmpdata; + + return SYS_EOK; +#else + return SYS_ENOTSUP; +#endif +} + +int +log_fill_num_tlvs(struct log *log, const void *dptr, uint8_t *num_tlvs, + uint16_t offset) +{ +#if MYNEWT_VAL(LOG_FLAGS_TLV_SUPPORT) && MYNEWT_VAL(LOG_TLV_NUM_TLVS) + int rc = 0; + uint32_t tmpdata; + + rc = log_read(log, dptr, &tmpdata, offset, LOG_NUM_TLVS_SIZE); + if (rc < LOG_NUM_TLVS_SIZE) { + return rc; + } + + *num_tlvs = tmpdata; + + return SYS_EOK; +#else + return SYS_ENOTSUP; +#endif +} + int log_fill_current_img_hash(struct log_entry_hdr *hdr) { diff --git a/sys/log/full/src/log_cbmem.c b/sys/log/full/src/log_cbmem.c index e7194e71b0..dca84eec49 100644 --- a/sys/log/full/src/log_cbmem.c +++ b/sys/log/full/src/log_cbmem.c @@ -25,7 +25,9 @@ static int log_cbmem_append_body(struct log *log, const struct log_entry_hdr *hdr, const void *body, int body_len) { + int rc = 0; struct cbmem *cbmem; + uint8_t num_tlvs = 0; struct cbmem_scat_gath sg = { .entries = (struct cbmem_scat_gath_entry[]) { { @@ -40,21 +42,65 @@ log_cbmem_append_body(struct log *log, const struct log_entry_hdr *hdr, .flat_buf = body, .flat_len = body_len, }, + { + .flat_buf = &log->l_num_entries, + .flat_len = 0 + }, + { + .flat_buf = NULL, + .flat_len = 0, + }, + /* + * Number of tlvs will always get written at the end + */ + { + .flat_buf = &num_tlvs, + .flat_len = 0 + }, + { + .flat_buf = NULL, + .flat_len = 0, + }, }, - .count = 3, + .count = 7, }; if (hdr->ue_flags & LOG_FLAGS_IMG_HASH) { sg.entries[1].flat_len = LOG_IMG_HASHLEN; } + + if (hdr->ue_flags & LOG_FLAGS_TLV_SUPPORT) { +#if MYNEWT_VAL(LOG_FLAGS_TLV_SUPPORT) +#if MYNEWT_VAL(LOG_TLV_NUM_ENTRIES) + sg.entries[4].flat_buf = &(struct log_tlv) {LOG_NUM_ENTRIES_SIZE, LOG_TLV_NUM_ENTRIES}; + sg.entries[4].flat_len = sizeof(struct log_tlv); + sg.entries[3].flat_len = LOG_NUM_ENTRIES_SIZE; + num_tlvs++; +#endif +#if MYNEWT_VAL(LOG_TLV_NUM_TLVS) + /* Number of TLVs is only written if there are more than one TLVs */ + if (num_tlvs > 1) { + sg.entries[6].flat_buf = &(struct log_tlv) {LOG_NUM_TLVS_SIZE, LOG_TLV_NUM_TLVS}; + sg.entries[6].flat_len = sizeof(struct log_tlv); + sg.entries[5].flat_len = LOG_NUM_TLVS_SIZE; + } +#endif +#endif + } + cbmem = (struct cbmem *) log->l_arg; - return cbmem_append_scat_gath(cbmem, &sg); + rc = cbmem_append_scat_gath(cbmem, &sg); + + /* Increment after the log entries are written */ + log->l_num_entries++; + + return rc; } static int log_cbmem_append(struct log *log, void *buf, int len) -{ +{ uint16_t hdr_len; hdr_len = log_hdr_len(buf); @@ -67,7 +113,9 @@ static int log_cbmem_append_mbuf_body(struct log *log, const struct log_entry_hdr *hdr, struct os_mbuf *om) { + int rc = 0; struct cbmem *cbmem; + uint8_t num_tlvs = 0; struct cbmem_scat_gath sg = { .entries = (struct cbmem_scat_gath_entry[]) { { @@ -81,16 +129,60 @@ log_cbmem_append_mbuf_body(struct log *log, const struct log_entry_hdr *hdr, { .om = om, }, + { + .flat_buf = &log->l_num_entries, + .flat_len = 0 + }, + { + .flat_buf = NULL, + .flat_len = 0, + }, + /* + * Number of tlvs will always get written at the end + */ + { + .flat_buf = &num_tlvs, + .flat_len = 0 + }, + { + .flat_buf = NULL, + .flat_len = 0, + }, }, - .count = 3, + .count = 7, }; if (hdr->ue_flags & LOG_FLAGS_IMG_HASH) { sg.entries[1].flat_len = LOG_IMG_HASHLEN; } + + if (hdr->ue_flags & LOG_FLAGS_TLV_SUPPORT) { +#if MYNEWT_VAL(LOG_FLAGS_TLV_SUPPORT) +#if MYNEWT_VAL(LOG_TLV_NUM_ENTRIES) + sg.entries[4].flat_buf = &(struct log_tlv) {LOG_NUM_ENTRIES_SIZE, LOG_TLV_NUM_ENTRIES}; + sg.entries[4].flat_len = sizeof(struct log_tlv); + sg.entries[3].flat_len = LOG_NUM_ENTRIES_SIZE; + num_tlvs++; +#endif +#if MYNEWT_VAL(LOG_TLV_NUM_TLVS) + /* Number of TLVs is only written if there are more than one TLVs */ + if (num_tlvs > 1) { + sg.entries[6].flat_buf = &(struct log_tlv) {LOG_NUM_TLVS_SIZE, LOG_TLV_NUM_TLVS}; + sg.entries[6].flat_len = sizeof(struct log_tlv); + sg.entries[5].flat_len = LOG_NUM_TLVS_SIZE; + } +#endif +#endif + } + cbmem = (struct cbmem *) log->l_arg; - return cbmem_append_scat_gath(cbmem, &sg); + rc = cbmem_append_scat_gath(cbmem, &sg); + + /* Increment after the log entries are written */ + log->l_num_entries++; + + return rc; } static int @@ -110,25 +202,24 @@ log_cbmem_append_mbuf(struct log *log, struct os_mbuf *om) * We do a pull up twice, once so that the base header is * contiguous, so that we read the flags correctly, second * time is so that we account for the image hash as well. - */ + */ - os_mbuf_pullup(om, LOG_BASE_ENTRY_HDR_SIZE); - - /* + om = os_mbuf_pullup(om, LOG_BASE_ENTRY_HDR_SIZE); + + /* * We can just pass the om->om_data ptr as the log_entry_hdr * because the log_entry_hdr is a packed struct and does not * cause any alignment or padding issues - */ + */ hdr_len = log_hdr_len((struct log_entry_hdr *)om->om_data); - - os_mbuf_pullup(om, hdr_len); - - memcpy(&hdr, om->om_data, hdr_len); + om = os_mbuf_pullup(om, hdr_len); + + memcpy(&hdr, om->om_data, hdr_len); os_mbuf_adj(om, hdr_len); rc = log_cbmem_append_mbuf_body(log, &hdr, om); - + os_mbuf_prepend(om, hdr_len); memcpy(om->om_data, &hdr, hdr_len); @@ -136,6 +227,16 @@ log_cbmem_append_mbuf(struct log *log, struct os_mbuf *om) return rc; } +static uint16_t +log_cbmem_read_entry_len(struct log *log, const void *dptr) +{ + struct cbmem_entry_hdr *hdr; + + hdr = (struct cbmem_entry_hdr *) dptr; + + return hdr->ceh_len; +} + static int log_cbmem_read(struct log *log, const void *dptr, void *buf, uint16_t offset, uint16_t len) @@ -264,6 +365,7 @@ log_cbmem_storage_info(struct log *log, struct log_storage_info *info) const struct log_handler log_cbmem_handler = { .log_type = LOG_TYPE_MEMORY, .log_read = log_cbmem_read, + .log_read_entry_len = log_cbmem_read_entry_len, .log_read_mbuf = log_cbmem_read_mbuf, .log_append = log_cbmem_append, .log_append_body = log_cbmem_append_body, diff --git a/sys/log/full/src/log_fcb.c b/sys/log/full/src/log_fcb.c index 5f4df8e314..d60f244e21 100644 --- a/sys/log/full/src/log_fcb.c +++ b/sys/log/full/src/log_fcb.c @@ -26,6 +26,7 @@ #include "flash_map/flash_map.h" #include "fcb/fcb.h" #include "log/log.h" +#include /* Assume the flash alignment requirement is no stricter than 8. */ #define LOG_FCB_MAX_ALIGN 8 @@ -274,19 +275,20 @@ log_fcb_start_append(struct log *log, int len, struct fcb_entry *loc) } /** - * Calculates the number of message body bytes that should be included after - * the entry header in the first write. Inclusion of body bytes is necessary - * to satisfy the flash hardware's write alignment restrictions. + * Calculates the number of bytes that should be included after + * the entry header for the first write or before the trailer in the second + * write. Inclusion of bytes is necessary to satisfy the flash hardware's + * write alignment restrictions. */ static int -log_fcb_hdr_body_bytes(uint8_t align, uint8_t hdr_len) +log_fcb_hdr_trailer_bytes(uint16_t align, uint16_t len) { - uint8_t mod; + uint16_t mod; /* Assume power-of-two alignment for faster modulo calculation. */ assert((align & (align - 1)) == 0); - mod = hdr_len & (align - 1); + mod = len & (align - 1); if (mod == 0) { return 0; } @@ -294,31 +296,256 @@ log_fcb_hdr_body_bytes(uint8_t align, uint8_t hdr_len) return align - mod; } +static int +log_fcb_write_mbuf(struct fcb_entry *loc, struct os_mbuf *om) +{ + int rc; + + while (om) { + rc = flash_area_write(loc->fe_area, loc->fe_data_off, om->om_data, + om->om_len); + if (rc != 0) { + return SYS_EIO; + } + loc->fe_data_off += om->om_len; + om = SLIST_NEXT(om, om_next); + } + + return 0; +} + +#if MYNEWT_VAL(LOG_FLAGS_TLV_SUPPORT) +static int +log_fcb_mbuf_single_tlv_write(struct os_mbuf *om, struct log_tlv *tlv, + void *val, uint8_t f_align, + struct fcb_entry *loc) +{ + uint16_t offset = 0; + int alignment = 0; + int rc = 0; + uint8_t buf[LOG_FCB_MAX_ALIGN] = {0}; + + /* Writes the following reverse TLVs, value first then length and + * then tag: + * + * Reverse TLV: + * --------------------------------------------------------- + * | Value | Value alignment | | TLV alignment | + * --------------------------------------------------------- + * TLV alignment is necessary here to aid in writing the next TLV + * from updated loc->fe_data_off. + * + * - Value is at alignment boundary + * - struct tlv is at alignment boundary + * + * Both can be read independently. + */ + rc = os_mbuf_append(om, val, tlv->len); + if (rc) { + return rc; + } + offset += tlv->len; + + /* Calculate value alignment */ + alignment = log_fcb_hdr_trailer_bytes(f_align, tlv->len); + rc = os_mbuf_append(om, buf, alignment); + if (rc) { + return rc; + } + offset += alignment; + + rc = os_mbuf_append(om, tlv, sizeof(*tlv)); + if (rc) { + return rc; + } + offset += sizeof(*tlv); + + /* Calculate tlv alignment */ + alignment = log_fcb_hdr_trailer_bytes(f_align, offset); + offset += alignment; + + rc = os_mbuf_append(om, buf, alignment); + if (rc) { + return rc; + } + + rc = log_fcb_write_mbuf(loc, om); + if (rc) { + return rc; + } + + return rc; +} + +static int +log_fcb_single_tlv_write(uint8_t *buf, uint16_t buflen, struct log_tlv *tlv, + void *val, uint8_t f_align, struct fcb_entry *loc) +{ + uint16_t offset = 0; + int alignment = 0; + int rc = 0; + + memset(buf, 0, buflen); + + /* Writes the following reverse TLVs, value first then length and + * then tag: + * + * Reverse TLV: + * --------------------------------------------------------- + * | Value | Value alignment | | TLV alignment | + * --------------------------------------------------------- + * TLV alignment is necessary here to aid in writing the next TLV + * from updated loc->fe_data_off. + * + * - Value is at alignment boundary + * - struct tlv is at alignment boundary + * + * Both can be read independently. + */ + memcpy(buf, val, tlv->len); + offset += tlv->len; + + /* Calculate value alignment */ + alignment = log_fcb_hdr_trailer_bytes(f_align, offset); + offset += alignment; + + memcpy(buf + offset, tlv, sizeof(*tlv)); + offset += sizeof(*tlv); + + /* Calculate tlv alignment */ + alignment = log_fcb_hdr_trailer_bytes(f_align, offset); + offset += alignment; + + rc = flash_area_write(loc->fe_area, loc->fe_data_off, buf, offset); + if (rc != 0) { + return rc; + } + + loc->fe_data_off += offset; + + return rc; +} + +static int +log_fcb_mbuf_tlvs_write(struct log *log, struct os_mbuf *om, + struct fcb_entry *loc) +{ + int rc = 0; + struct fcb *fcb; + struct fcb_log *fcb_log; + struct log_tlv tlv; + uint8_t num_tlvs = 0; + + fcb_log = (struct fcb_log *)log->l_arg; + fcb = &fcb_log->fl_fcb; + + (void)fcb; + (void)fcb_log; + (void)tlv; + (void)num_tlvs; + +#if MYNEWT_VAL(LOG_TLV_NUM_ENTRIES) + tlv.tag = LOG_TLV_NUM_ENTRIES; + tlv.len = LOG_NUM_ENTRIES_SIZE; + rc = log_fcb_mbuf_single_tlv_write(om, &tlv, &log->l_num_entries, + fcb->f_align, loc); + log->l_num_entries++; +#endif + + /* Always write the number of TLVS TLV at the end + * if num_tlvs > 1 + */ +#if MYNEWT_VAL(LOG_TLV_NUM_TLVS) + if (num_tlvs > 1) { + tlv.tag = LOG_TLV_NUM_TLVS; + tlv.len = LOG_NUM_TLVS_SIZE; + rc = log_fcb_mbuf_single_tlv_write(om, &tlv, &num_tlvs, + fcb->f_align, loc); + } +#endif + + return rc; +} + +static int +log_fcb_tlvs_write(struct log *log, uint8_t *buf, uint16_t buflen, + struct fcb_entry *loc) +{ + int rc = 0; + struct fcb *fcb; + struct fcb_log *fcb_log; + struct log_tlv tlv; + uint8_t num_tlvs = 0; + + fcb_log = (struct fcb_log *)log->l_arg; + fcb = &fcb_log->fl_fcb; + + (void)fcb; + (void)fcb_log; + (void)tlv; + (void)num_tlvs; + +#if MYNEWT_VAL(LOG_TLV_NUM_ENTRIES) + tlv.tag = LOG_TLV_NUM_ENTRIES; + tlv.len = LOG_NUM_ENTRIES_SIZE; + rc = log_fcb_single_tlv_write(buf, buflen, &tlv, &log->l_num_entries, + fcb->f_align, loc); + if (rc) { + return rc; + } + log->l_num_entries++; + num_tlvs++; +#endif + + /* Always write the number of TLVS TLV at the end + * if num_tlvs > 1 + */ +#if MYNEWT_VAL(LOG_TLV_NUM_TLVS) + if (num_tlvs > 1) { + tlv.tag = LOG_TLV_NUM_TLVS; + tlv.len = LOG_NUM_TLVS_SIZE; + rc = log_fcb_single_tlv_write(buf, buflen, &tlv, &num_tlvs, + fcb->f_align, loc); + } +#endif + + return rc; +} +#endif + static int log_fcb_append_body(struct log *log, const struct log_entry_hdr *hdr, const void *body, int body_len) { - uint8_t buf[LOG_BASE_ENTRY_HDR_SIZE + LOG_IMG_HASHLEN + - LOG_FCB_MAX_ALIGN - 1]; + uint8_t buf[LOG_FCB_FLAT_BUF_SIZE] = {0}; struct fcb *fcb; struct fcb_entry loc; struct fcb_log *fcb_log; const uint8_t *u8p; int hdr_alignment; - int chunk_sz; + int trailer_alignment = 0; + int chunk_sz = 0; int rc; uint16_t hdr_len; + uint16_t trailer_len; + uint16_t padding = 0; + uint16_t offset = 0; fcb_log = (struct fcb_log *)log->l_arg; fcb = &fcb_log->fl_fcb; + (void)offset; + (void)padding; + (void)trailer_alignment; + if (fcb->f_align > LOG_FCB_MAX_ALIGN) { return SYS_ENOTSUP; } hdr_len = log_hdr_len(hdr); + trailer_len = log_trailer_len(log, hdr); - rc = log_fcb_start_append(log, hdr_len + body_len, &loc); + rc = log_fcb_start_append(log, hdr_len + body_len + trailer_len, &loc); if (rc != 0) { return rc; } @@ -328,7 +555,7 @@ log_fcb_append_body(struct log *log, const struct log_entry_hdr *hdr, * the flash alignment). If the hash flag is set, we have to account for * appending the hash right after the header. */ - hdr_alignment = log_fcb_hdr_body_bytes(fcb->f_align, hdr_len); + hdr_alignment = log_fcb_hdr_trailer_bytes(fcb->f_align, hdr_len); if (hdr_alignment > body_len) { chunk_sz = hdr_len + body_len; } else { @@ -346,6 +573,7 @@ log_fcb_append_body(struct log *log, const struct log_entry_hdr *hdr, if (hdr->ue_flags & LOG_FLAGS_IMG_HASH) { memcpy(buf + LOG_BASE_ENTRY_HDR_SIZE, hdr->ue_imghash, LOG_IMG_HASHLEN); } + memcpy(buf + hdr_len, u8p, hdr_alignment); rc = flash_area_write(loc.fe_area, loc.fe_data_off, buf, chunk_sz); @@ -353,16 +581,70 @@ log_fcb_append_body(struct log *log, const struct log_entry_hdr *hdr, return rc; } + loc.fe_data_off += chunk_sz; + /* Append the remainder of the message body. */ u8p += hdr_alignment; body_len -= hdr_alignment; - if (body_len > 0) { - rc = flash_area_write(loc.fe_area, loc.fe_data_off + chunk_sz, u8p, - body_len); - if (rc != 0) { - return rc; + if (hdr->ue_flags & LOG_FLAGS_TLV_SUPPORT) { +#if MYNEWT_VAL(LOG_FLAGS_TLV_SUPPORT) + /* This writes padding + trailer_alignment */ + + /* Calculate trailer alignment */ + trailer_alignment = log_fcb_hdr_trailer_bytes(fcb->f_align, chunk_sz + body_len); + + if (body_len > 0) { + padding = trailer_alignment ? fcb->f_align - trailer_alignment : 0; + /* Writes body - padding bytes */ + rc = flash_area_write(loc.fe_area, loc.fe_data_off, u8p, + body_len - padding); + if (rc != 0) { + return rc; + } + + loc.fe_data_off += body_len - padding; + + u8p = u8p + body_len - padding; + memset(buf, 0, sizeof(buf)); + memcpy(buf, u8p, padding); + offset = padding; + offset += trailer_alignment; + /* Writes the following: + * ----------------------------------------------------------------- + * | body: body_len - padding from end of body | trailer_alignment | + * ----------------------------------------------------------------- + */ + rc = flash_area_write(loc.fe_area, loc.fe_data_off, buf, offset); + if (rc != 0) { + return rc; + } + + loc.fe_data_off += offset; + + /* The first TLV gets appended after the padding + trailer_alignment + * Trailers start from updated loc.fe_data_off. + */ + rc = log_fcb_tlvs_write(log, buf, sizeof(buf), &loc); + if (rc) { + return rc; + } + } +#else + if (body_len > 0) { + rc = flash_area_write(loc.fe_area, loc.fe_data_off, u8p, body_len); + if (rc != 0) { + return rc; + } + } +#endif + } else { + if (body_len > 0) { + rc = flash_area_write(loc.fe_area, loc.fe_data_off, u8p, body_len); + if (rc != 0) { + return rc; + } } } @@ -385,25 +667,6 @@ log_fcb_append(struct log *log, void *buf, int len) len - hdr_len); } -static int -log_fcb_write_mbuf(struct fcb_entry *loc, struct os_mbuf *om) -{ - int rc; - - while (om) { - rc = flash_area_write(loc->fe_area, loc->fe_data_off, om->om_data, - om->om_len); - if (rc != 0) { - return SYS_EIO; - } - - loc->fe_data_off += om->om_len; - om = SLIST_NEXT(om, om_next); - } - - return 0; -} - static int log_fcb_append_mbuf_body(struct log *log, const struct log_entry_hdr *hdr, struct os_mbuf *om) @@ -424,7 +687,7 @@ log_fcb_append_mbuf_body(struct log *log, const struct log_entry_hdr *hdr, return SYS_ENOTSUP; } - len = log_hdr_len(hdr) + os_mbuf_len(om); + len = log_hdr_len(hdr) + os_mbuf_len(om) + log_trailer_len(log, hdr); rc = log_fcb_start_append(log, len, &loc); if (rc != 0) { return rc; @@ -446,9 +709,23 @@ log_fcb_append_mbuf_body(struct log *log, const struct log_entry_hdr *hdr, } loc.fe_data_off += LOG_IMG_HASHLEN; } - rc = log_fcb_write_mbuf(&loc, om); - if (rc != 0) { - return rc; + + if (hdr->ue_flags & LOG_FLAGS_TLV_SUPPORT) { +#if MYNEWT_VAL(LOG_FLAGS_TLV_SUPPORT) + /* The first TLV gets appended after the padding + trailer_alignment + * Trailers start from updated loc.fe_data_off. Write everything + * together + */ + rc = log_fcb_mbuf_tlvs_write(log, om, &loc); + if (rc != 0) { + return rc; + } +#endif + } else { + rc = log_fcb_write_mbuf(&loc, om); + if (rc != 0) { + return rc; + } } rc = fcb_append_finish(fcb, &loc); @@ -501,6 +778,20 @@ log_fcb_append_mbuf(struct log *log, struct os_mbuf *om) return rc; } +static uint16_t +log_fcb_read_entry_len(struct log *log, const void *dptr) +{ + struct fcb_entry *loc; + + loc = (struct fcb_entry *)dptr; + + if (!log || !dptr) { + return 0; + } + + return loc->fe_data_len; +} + static int log_fcb_read(struct log *log, const void *dptr, void *buf, uint16_t offset, uint16_t len) @@ -785,6 +1076,18 @@ log_fcb_new_watermark_index(struct log *log, struct log_offset *log_offset, } } +static int +log_fcb_len_in_medium(struct log *log, uint16_t len) +{ + struct fcb_log *fl; + struct fcb *fcb; + + fl = (struct fcb_log *)log->l_arg; + fcb = &fl->fl_fcb; + + return fcb_len_in_flash(fcb, len); +} + static int log_fcb_set_watermark(struct log *log, uint32_t index) { @@ -832,8 +1135,8 @@ log_fcb_copy_entry(struct log *log, struct fcb_entry *entry, struct fcb *dst_fcb) { struct log_entry_hdr ueh; - char data[MYNEWT_VAL(LOG_FCB_COPY_MAX_ENTRY_LEN) + LOG_BASE_ENTRY_HDR_SIZE + - LOG_IMG_HASHLEN]; + char data[MYNEWT_VAL(LOG_FCB_COPY_MAX_ENTRY_LEN) + + LOG_BASE_ENTRY_HDR_SIZE + LOG_IMG_HASHLEN]; uint16_t hdr_len; int dlen; int rc; @@ -846,7 +1149,6 @@ log_fcb_copy_entry(struct log *log, struct fcb_entry *entry, } hdr_len = log_hdr_len(&ueh); - dlen = min(entry->fe_data_len, MYNEWT_VAL(LOG_FCB_COPY_MAX_ENTRY_LEN) + hdr_len); @@ -972,23 +1274,25 @@ log_fcb_rtr_erase(struct log *log) } const struct log_handler log_fcb_handler = { - .log_type = LOG_TYPE_STORAGE, - .log_read = log_fcb_read, - .log_read_mbuf = log_fcb_read_mbuf, - .log_append = log_fcb_append, - .log_append_body = log_fcb_append_body, - .log_append_mbuf = log_fcb_append_mbuf, + .log_type = LOG_TYPE_STORAGE, + .log_read = log_fcb_read, + .log_read_mbuf = log_fcb_read_mbuf, + .log_append = log_fcb_append, + .log_append_body = log_fcb_append_body, + .log_append_mbuf = log_fcb_append_mbuf, .log_append_mbuf_body = log_fcb_append_mbuf_body, - .log_walk = log_fcb_walk, - .log_walk_sector = log_fcb_walk_area, - .log_flush = log_fcb_flush, + .log_walk = log_fcb_walk, + .log_walk_sector = log_fcb_walk_area, + .log_flush = log_fcb_flush, + .log_read_entry_len = log_fcb_read_entry_len, #if MYNEWT_VAL(LOG_STORAGE_INFO) - .log_storage_info = log_fcb_storage_info, + .log_storage_info = log_fcb_storage_info, #endif #if MYNEWT_VAL(LOG_STORAGE_WATERMARK) - .log_set_watermark = log_fcb_set_watermark, + .log_set_watermark = log_fcb_set_watermark, + .log_len_in_medium = log_fcb_len_in_medium, #endif - .log_registered = log_fcb_registered, + .log_registered = log_fcb_registered, }; #endif diff --git a/sys/log/full/src/log_fcb2.c b/sys/log/full/src/log_fcb2.c index c8a5d07b20..9413fa1d22 100644 --- a/sys/log/full/src/log_fcb2.c +++ b/sys/log/full/src/log_fcb2.c @@ -202,14 +202,14 @@ log_fcb2_start_append(struct log *log, int len, struct fcb2_entry *loc) * to satisfy the flash hardware's write alignment restrictions. */ static int -log_fcb2_hdr_body_bytes(uint8_t align, uint8_t hdr_len) +log_fcb2_hdr_body_bytes(uint16_t align, uint16_t len) { - uint8_t mod; + uint16_t mod; /* Assume power-of-two alignment for faster modulo calculation. */ assert((align & (align - 1)) == 0); - mod = hdr_len & (align - 1); + mod = len & (align - 1); if (mod == 0) { return 0; } @@ -217,22 +217,234 @@ log_fcb2_hdr_body_bytes(uint8_t align, uint8_t hdr_len) return align - mod; } +static int +log_fcb2_write_mbuf(struct fcb2_entry *loc, struct os_mbuf *om, int off) +{ + int rc; + + while (om) { + rc = fcb2_write(loc, off, om->om_data, om->om_len); + if (rc != 0) { + return SYS_EIO; + } + + off += om->om_len; + om = SLIST_NEXT(om, om_next); + } + + return SYS_EOK; +} + + +#if MYNEWT_VAL(LOG_FLAGS_TLV_SUPPORT) +static int +log_fcb2_mbuf_single_tlv_write(struct os_mbuf *om, struct log_tlv *tlv, + void *val, uint8_t f_align, + struct fcb2_entry *loc, int len) +{ + uint16_t offset = 0; + int alignment = 0; + int rc = 0; + uint8_t buf[LOG_FCB2_MAX_ALIGN] = {0}; + + /* Writes the following reverse TLVs, value first then length and + * then tag: + * + * Reverse TLV: + * --------------------------------------------------------- + * | Value | Value alignment | | TLV alignment | + * --------------------------------------------------------- + * TLV alignment is necessary here to aid in writing the next TLV + * from updated loc->fe_data_off. + * + * - Value is at alignment boundary + * - struct tlv is at alignment boundary + * + * Both can be read independently. + */ + rc = os_mbuf_append(om, val, tlv->len); + if (rc) { + return rc; + } + offset += tlv->len; + + /* Calculate value alignment */ + alignment = log_fcb2_hdr_body_bytes(f_align, tlv->len); + rc = os_mbuf_append(om, buf, alignment); + if (rc) { + return rc; + } + offset += alignment; + + rc = os_mbuf_append(om, tlv, sizeof(*tlv)); + if (rc) { + return rc; + } + offset += sizeof(*tlv); + + /* Calculate tlv alignment */ + alignment = log_fcb2_hdr_body_bytes(f_align, offset); + offset += alignment; + + rc = os_mbuf_append(om, buf, alignment); + if (rc) { + return rc; + } + + rc = log_fcb2_write_mbuf(loc, om, len); + if (rc) { + return rc; + } + + return rc; +} + +static int +log_fcb2_single_tlv_write(uint8_t *buf, uint16_t buflen, struct log_tlv *tlv, + void *val, uint8_t f_align, struct fcb2_entry *loc, + uint16_t *f_offset) +{ + uint16_t offset = 0; + int alignment = 0; + int rc = 0; + + memset(buf, 0, buflen); + + /* Writes the following reverse TLVs, value first then length and + * then tag: + * + * Reverse TLV: + * --------------------------------------------------------- + * | Value | Value alignment | | TLV alignment | + * --------------------------------------------------------- + * TLV alignment is necessary here to aid in writing the next TLV + * from updated loc.fe_data_off. + * + * - Value is at alignment boundary + * - struct tlv is at alignment boundary + * + * Both can be read independently. + */ + memcpy(buf, val, tlv->len); + offset += tlv->len; + + /* Calculate value alignment */ + alignment = log_fcb2_hdr_body_bytes(f_align, offset); + offset += alignment; + + memcpy(buf + offset, tlv, sizeof(*tlv)); + offset += sizeof(*tlv); + + /* Calculate tlv alignment */ + alignment = log_fcb2_hdr_body_bytes(f_align, offset); + offset += alignment; + + rc = fcb2_write(loc, *f_offset, buf, offset); + if (rc != 0) { + return rc; + } + + *f_offset += offset; + + return rc; +} + +static int +log_fcb2_tlvs_write(struct log *log, uint8_t *buf, uint16_t buflen, + struct fcb2_entry *loc, uint16_t *f_offset) +{ + int rc = 0; + struct log_tlv tlv; + uint8_t num_tlvs = 0; + + (void)tlv; +#if MYNEWT_VAL(LOG_TLV_NUM_ENTRIES) + tlv.tag = LOG_TLV_NUM_ENTRIES; + tlv.len = LOG_NUM_ENTRIES_SIZE; + rc = log_fcb2_single_tlv_write(buf, buflen, &tlv, &log->l_num_entries, + loc->fe_range->fsr_align, loc, f_offset); + log->l_num_entries++; + num_tlvs++; +#endif + + /* Always write the number of TLVS TLV at the end + * if num_tlvs > 1 + */ +#if MYNEWT_VAL(LOG_TLV_NUM_TLVS) + if (num_tlvs > 1) { + tlv.tag = LOG_TLV_NUM_TLVS; + tlv.len = LOG_NUM_TLVS_SIZE; + rc = log_fcb2_single_tlv_write(buf, buflen, &tlv, &num_tlvs, + loc->fe_range->fsr_align, loc, f_offset); + } +#endif + + return rc; +} + +static int +log_fcb2_mbuf_tlvs_write(struct log *log, struct os_mbuf *om, + struct fcb2_entry *loc, int len) +{ + int rc = 0; + struct fcb2 *fcb; + struct fcb_log *fcb_log; + struct log_tlv tlv; + uint8_t num_tlvs = 0; + + fcb_log = (struct fcb_log *)log->l_arg; + fcb = &fcb_log->fl_fcb; + + (void)fcb; + (void)fcb_log; + (void)tlv; + (void)num_tlvs; + +#if MYNEWT_VAL(LOG_TLV_NUM_ENTRIES) + tlv.tag = LOG_TLV_NUM_ENTRIES; + tlv.len = LOG_NUM_ENTRIES_SIZE; + rc = log_fcb2_mbuf_single_tlv_write(om, &tlv, &log->l_num_entries, + loc->fe_range->fsr_align, loc, len); + log->l_num_entries++; +#endif + + /* Always write the number of TLVS TLV at the end + * if num_tlvs > 1 + */ +#if MYNEWT_VAL(LOG_TLV_NUM_TLVS) + if (num_tlvs > 1) { + tlv.tag = LOG_TLV_NUM_TLVS; + tlv.len = LOG_NUM_TLVS_SIZE; + rc = log_fcb2_mbuf_single_tlv_write(om, &tlv, &num_tlvs, + loc->fe_range->fsr_align, + loc, len); + } +#endif + + return rc; +} +#endif + static int log_fcb2_append_body(struct log *log, const struct log_entry_hdr *hdr, const void *body, int body_len) { - uint8_t buf[LOG_BASE_ENTRY_HDR_SIZE + LOG_IMG_HASHLEN + - LOG_FCB2_MAX_ALIGN - 1]; + uint8_t buf[LOG_FCB_FLAT_BUF_SIZE] = {0}; struct fcb2_entry loc; const uint8_t *u8p; int hdr_alignment; - int chunk_sz; + int trailer_alignment = 0; + uint16_t chunk_sz = 0; int rc; uint16_t hdr_len; + uint16_t trailer_len; hdr_len = log_hdr_len(hdr); + trailer_len = log_trailer_len(log, hdr); + + (void)trailer_alignment; - rc = log_fcb2_start_append(log, hdr_len + body_len, &loc); + rc = log_fcb2_start_append(log, hdr_len + body_len + trailer_len, &loc); if (rc != 0) { return rc; } @@ -271,11 +483,63 @@ log_fcb2_append_body(struct log *log, const struct log_entry_hdr *hdr, u8p += hdr_alignment; body_len -= hdr_alignment; + if (hdr->ue_flags & LOG_FLAGS_TLV_SUPPORT) { + memset(buf, 0, sizeof(buf)); + /* Calculate trailer alignment */ + trailer_alignment = log_fcb2_hdr_body_bytes(loc.fe_range->fsr_align, chunk_sz + body_len); + +#if MYNEWT_VAL(LOG_FLAGS_TLV_SUPPORT) + uint16_t offset = 0; + uint16_t padding = 0; + + if (body_len > 0) { + padding = trailer_alignment ? loc.fe_range->fsr_align - trailer_alignment : 0; + rc = fcb2_write(&loc, chunk_sz, u8p, body_len - padding); + if (rc != 0) { + return rc; + } - if (body_len > 0) { - rc = fcb2_write(&loc, chunk_sz, u8p, body_len); - if (rc != 0) { - return rc; + chunk_sz += body_len - padding; + + u8p = u8p + body_len - padding; + memcpy(buf, u8p, padding); + offset = padding; + offset += trailer_alignment; + /* Writes the following: + * ----------------------------------------------------------------- + * | body: body_len - padding from end of body | trailer_alignment | + * ----------------------------------------------------------------- + */ + rc = fcb2_write(&loc, chunk_sz, buf, offset); + if (rc != 0) { + return rc; + } + + chunk_sz += offset; + /* The first TLV gets appended after the padding + trailer_alignment + * Trailers start from updated chunk_sz offset. + */ + rc = log_fcb2_tlvs_write(log, buf, sizeof(buf), &loc, &chunk_sz); + if (rc) { + return rc; + } + } +#else + if (body_len > 0) { + rc = fcb2_write(&loc, chunk_sz, u8p, body_len); + if (rc != 0) { + return rc; + } + chunk_sz += body_len; + } +#endif + } else { + if (body_len > 0) { + rc = fcb2_write(&loc, chunk_sz, u8p, body_len); + if (rc != 0) { + return rc; + } + chunk_sz += body_len; } } @@ -298,24 +562,6 @@ log_fcb2_append(struct log *log, void *buf, int len) len - hdr_len); } -static int -log_fcb2_write_mbuf(struct fcb2_entry *loc, struct os_mbuf *om, int off) -{ - int rc; - - while (om) { - rc = fcb2_write(loc, off, om->om_data, om->om_len); - if (rc != 0) { - return SYS_EIO; - } - - off += om->om_len; - om = SLIST_NEXT(om, om_next); - } - - return 0; -} - static int log_fcb2_append_mbuf_body(struct log *log, const struct log_entry_hdr *hdr, struct os_mbuf *om) @@ -336,7 +582,7 @@ log_fcb2_append_mbuf_body(struct log *log, const struct log_entry_hdr *hdr, } #endif - len = log_hdr_len(hdr) + os_mbuf_len(om); + len = log_hdr_len(hdr) + os_mbuf_len(om) + log_trailer_len(log, hdr); rc = log_fcb2_start_append(log, len, &loc); if (rc != 0) { return rc; @@ -356,9 +602,23 @@ log_fcb2_append_mbuf_body(struct log *log, const struct log_entry_hdr *hdr, } len += LOG_IMG_HASHLEN; } - rc = log_fcb2_write_mbuf(&loc, om, len); - if (rc != 0) { - return rc; + + if (hdr->ue_flags & LOG_FLAGS_TLV_SUPPORT) { +#if MYNEWT_VAL(LOG_FLAGS_TLV_SUPPORT) + /* The first TLV gets appended after the padding + trailer_alignment + * Trailers start from updated loc.fe_data_off. Write everything + * together + */ + rc = log_fcb2_mbuf_tlvs_write(log, om, &loc, len); + if (rc != 0) { + return rc; + } +#endif + } else { + rc = log_fcb2_write_mbuf(&loc, om, len); + if (rc != 0) { + return rc; + } } rc = fcb2_append_finish(&loc); @@ -369,6 +629,18 @@ log_fcb2_append_mbuf_body(struct log *log, const struct log_entry_hdr *hdr, return 0; } +static int +log_fcb2_len_in_medium(struct log *log, uint16_t len) +{ + struct fcb_log *fl; + struct fcb2 *fcb; + + fl = (struct fcb_log *)log->l_arg; + fcb = &fl->fl_fcb; + + return fcb2_len_in_flash(fcb->f_active.fe_range, len); +} + static int log_fcb2_append_mbuf(struct log *log, struct os_mbuf *om) { @@ -411,6 +683,20 @@ log_fcb2_append_mbuf(struct log *log, struct os_mbuf *om) return rc; } +static uint16_t +log_fcb2_read_entry_len(struct log *log, const void *dptr) +{ + struct fcb2_entry *loc; + + loc = (struct fcb2_entry *)dptr; + + if (!log || !dptr) { + return 0; + } + + return loc->fe_data_len; +} + static int log_fcb2_read(struct log *log, const void *dptr, void *buf, uint16_t off, uint16_t len) { @@ -895,6 +1181,8 @@ const struct log_handler log_fcb_handler = { .log_append_mbuf_body = log_fcb2_append_mbuf_body, .log_walk = log_fcb2_walk, .log_flush = log_fcb2_flush, + .log_read_entry_len = log_fcb2_read_entry_len, + .log_len_in_medium = log_fcb2_len_in_medium, #if MYNEWT_VAL(LOG_STORAGE_INFO) .log_storage_info = log_fcb2_storage_info, #endif diff --git a/sys/log/full/src/log_shell.c b/sys/log/full/src/log_shell.c index 5c2a1c00b6..0acfaf0791 100644 --- a/sys/log/full/src/log_shell.c +++ b/sys/log/full/src/log_shell.c @@ -54,10 +54,26 @@ shell_log_dump_entry(struct log *log, struct log_offset *log_offset, int blksz; bool read_data = ueh->ue_etype != LOG_ETYPE_CBOR; bool read_hash = ueh->ue_flags & LOG_FLAGS_IMG_HASH; +#if MYNEWT_VAL(LOG_FLAGS_TLV_SUPPORT) && MYNEWT_VAL(LOG_TLV_NUM_ENTRIES) + bool read_num_entries = ueh->ue_flags & LOG_FLAGS_TLV_SUPPORT; +#else + bool read_num_entries = false; +#endif + uint32_t entries = 0; dlen = min(len, 128); if (read_data) { +#if MYNEWT_VAL(LOG_FLAGS_TLV_SUPPORT) + dlen -= log_len_in_medium(log, sizeof(struct log_tlv)); + + rc = log_read_trailer(log, dptr, LOG_TLV_NUM_ENTRIES, &entries); + if (!rc) { + dlen -= log_len_in_medium(log, LOG_NUM_ENTRIES_SIZE); + } else { + console_printf("failed to read trailer\n"); + } +#endif rc = log_read_body(log, dptr, data, 0, dlen); if (rc < 0) { return rc; @@ -69,6 +85,17 @@ shell_log_dump_entry(struct log *log, struct log_offset *log_offset, console_printf("[ih=0x%x%x%x%x]", ueh->ue_imghash[0], ueh->ue_imghash[1], ueh->ue_imghash[2], ueh->ue_imghash[3]); } + + if (read_num_entries) { +#if MYNEWT_VAL(LOG_FLAGS_TLV_SUPPORT) + dlen -= log_len_in_medium(log, sizeof(struct log_tlv)); + rc = log_read_trailer(log, dptr, LOG_TLV_NUM_ENTRIES, &entries); + if (!rc) { + dlen -= log_len_in_medium(log, LOG_NUM_ENTRIES_SIZE); + } +#endif + console_printf("[ne=%u]", (unsigned int)entries); + } console_printf(" [%llu] ", ueh->ue_ts); #if MYNEWT_VAL(LOG_SHELL_SHOW_INDEX) console_printf(" [ix=%lu] ", ueh->ue_index); @@ -113,6 +140,8 @@ shell_log_dump_cmd(int argc, char **argv) bool stream; bool partial_match = false; bool clear_log; + bool num_entries = false; + uint32_t entries; int i; int rc; @@ -126,6 +155,16 @@ shell_log_dump_cmd(int argc, char **argv) /* the -c option is to clear a log (or logs). */ if (!strcmp(argv[i], "-c")) { clear_log = true; + } else if (argc == 3 && !strcmp(argv[i], "-ne")) { + num_entries = true; + log_name = argv[i+1]; + break; + } else if (argc == 5 && !strcmp(argv[i], "-ne") && + !strcmp(argv[i+2], "-i")) { + num_entries = true; + log_name = argv[i+1]; + log_limit = parse_ll_bounds(argv[i+3], 1, 1000000, &rc); + break; } else if (isdigit((unsigned char)argv[i][0])) { log_limit = parse_ll_bounds(argv[i], 1, 1000000, &rc); if (clear_log) { @@ -167,6 +206,13 @@ shell_log_dump_cmd(int argc, char **argv) if (rc != 0) { goto err; } + } else if (num_entries) { + rc = log_get_entries(log, log_limit, &entries); + if (!rc) { + console_printf("entries: %u\n", (unsigned int)entries); + } else { + console_printf("Invalid or empty log, rc=%d!\n", rc); + } } else { console_printf("Dumping log %s\n", log->l_name); diff --git a/sys/log/full/syscfg.yml b/sys/log/full/syscfg.yml index 356753eaa9..3118e220f4 100644 --- a/sys/log/full/syscfg.yml +++ b/sys/log/full/syscfg.yml @@ -38,6 +38,18 @@ syscfg.defs: 1 - enable. value: 0 + LOG_FLAGS_TLV_SUPPORT: + description: > + Enable logging TLV with custom data types in every log entry + 0 - disable; 1 - enable. + value: 0 + + LOG_TLV_NUM_ENTRIES: + description: > + Enable logging number entries using TLV in every log entry, max number is 2^32 + 0 - disable; 1 - enable. + value: 0 + LOG_FCB: description: 'Support logging to FCB.' value: 0